Skip to content

Commit

Permalink
Rename the library, support for DI, v1 🚀
Browse files Browse the repository at this point in the history
  • Loading branch information
RobertoPrevato authored Dec 28, 2022
1 parent 617840f commit 053aa70
Show file tree
Hide file tree
Showing 54 changed files with 1,484 additions and 878 deletions.
54 changes: 35 additions & 19 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ on:
- "*"

env:
PROJECT_NAME: guardpost
PROJECT_NAME: neoteroi

jobs:
build:
Expand All @@ -29,7 +29,7 @@ jobs:
submodules: false

- name: Use Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}

Expand Down Expand Up @@ -61,8 +61,13 @@ jobs:
- name: Run tests
run: |
pip install -e .
pytest --doctest-modules --junitxml=junit/pytest-results-${{ matrix.python-version }}.xml --cov=$PROJECT_NAME --cov-report=xml tests/
- name: Test examples
run: |
for f in ./examples/*.py; do echo "Processing $f file..." && python $f; done
- name: Upload pytest test results
uses: actions/upload-artifact@master
with:
Expand All @@ -75,19 +80,19 @@ jobs:
bash <(curl -s https://codecov.io/bash)
- name: Install distribution dependencies
run: pip install --upgrade twine setuptools wheel
if: matrix.python-version == 3.8 || matrix.python-version == 3.9
run: pip install --upgrade build
if: matrix.python-version == 3.10

- name: Create distribution package
run: python setup.py sdist bdist_wheel
if: matrix.python-version == 3.8 || matrix.python-version == 3.9
run: python -m build
if: matrix.python-version == 3.10

- name: Upload distribution package
uses: actions/upload-artifact@master
with:
name: dist-package-${{ matrix.python-version }}
name: dist
path: dist
if: matrix.python-version == 3.8 || matrix.python-version == 3.9
if: matrix.python-version == 3.10

publish:
runs-on: ubuntu-latest
Expand All @@ -97,17 +102,28 @@ jobs:
- name: Download a distribution artifact
uses: actions/download-artifact@v2
with:
name: dist-package-3.9
name: dist
path: dist
- name: Publish distribution 📦 to Test PyPI
uses: pypa/gh-action-pypi-publish@master

- name: Use Python 3.11
uses: actions/setup-python@v1
with:
skip_existing: true
user: __token__
password: ${{ secrets.test_pypi_password }}
repository_url: https://test.pypi.org/legacy/
python-version: '3.11'

- name: Install dependencies
run: |
pip install twine
- name: Publish distribution 📦 to Test PyPI
run: |
twine upload -r testpypi dist/*
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.test_pypi_password2 }}

- name: Publish distribution 📦 to PyPI
uses: pypa/gh-action-pypi-publish@master
with:
user: __token__
password: ${{ secrets.pypi_password }}
run: |
twine upload -r pypi dist/*
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.pypi_password2 }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ __pycache__
*.egg-info
*.tar.gz
.mypy_cache
junit
coverage.xml
40 changes: 26 additions & 14 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,39 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.0.0] - 2022-12-xx :star:
- Renames the library to `neoteroi-auth`.
- Adopts PEP 420 and renames the main namespace from `guardpost` to `neoteroi.auth`
- Adds built-in support for dependency injection, using the new `ContainerProtocol`
in `neoteroi-di` (new version of `rodi`).
- Removes the synchronous code API, maintaining only the asynchronous code API
for `AuthenticationStrategy.authenticate` and `AuthorizationStrategy.authorize`.
- Replaces `setup.py` with `pyproject.toml`.
- Reduces imports verbosity.
- Improves the `identity_getter` code API.
- Corrects `Identity.__getitem__` to raise `KeyError` if a claim is missing.

## [0.1.0] - 2022-11-06 :snake:
- Workflow maintenance
- Workflow maintenance.

## [0.0.9] - 2021-11-14 :swan:
- Adds `sub`, `access_token`, and `refresh_token` properties to the `Identity`
- Adds `sub`, `access_token`, and `refresh_token` properties to the `Identity`.
class
- Adds `py.typed` file
- Adds `py.typed` file.

## [0.0.8] - 2021-10-31 :shield:
- Adds classes to handle `JWT`s validation, but only for `RSA` keys
- Fixes issue (wrong arrangement in test) #5
- Includes `Python 3.10` in the CI/CD matrix
- Enforces `black` and `isort` in the CI pipeline
- Adds classes to handle `JWT`s validation, but only for `RSA` keys.
- Fixes issue (wrong arrangement in test) #5.
- Includes `Python 3.10` in the CI/CD matrix.
- Enforces `black` and `isort` in the CI pipeline.

## [0.0.7] - 2021-01-31 :grapes:
- Corrects a bug in the `Policy` class (#2)
- Changes the type annotation of `Identity` claims (#3)
- Corrects a bug in the `Policy` class (#2).
- Changes the type annotation of `Identity` claims (#3).

## [0.0.6] - 2020-12-12 :octocat:
- Completely migrates to GitHub Workflows
- Improves build to test Python 3.6 and 3.9
- Adds a changelog
- Improves badges
- Improves code quality using `flake8` and `black`
- Completely migrates to GitHub Workflows.
- Improves build to test Python 3.6 and 3.9.
- Adds a changelog.
- Improves badges.
- Improves code quality using `flake8` and `black`.
3 changes: 0 additions & 3 deletions MANIFEST.in

This file was deleted.

50 changes: 42 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,29 +1,63 @@
.PHONY: release test


lint-types:
mypy neoteroi --explicit-package-bases


artifacts: test
python setup.py sdist bdist_wheel
python -m build


clean:
rm -rf dist/


prepforbuild:
pip install --upgrade twine setuptools wheel
pip install build


build:
python -m build

uploadtest:
twine upload --repository-url https://test.pypi.org/legacy/ dist/*

test-release:
twine upload --repository testpypi dist/*

release: clean artifacts
twine upload --repository-url https://upload.pypi.org/legacy/ dist/*

release:
twine upload --repository pypi dist/*


test:
python -m pytest


testcov:
python -m pytest --cov-report html --cov=guardpost tests/
test-cov:
python -m pytest --cov-report html --cov=neoteroi tests/


lint: check-flake8 check-isort check-black

format:
@isort neoteroi 2>&1
@isort tests 2>&1
@black neoteroi 2>&1
@black tests 2>&1

check-flake8:
@echo "$(BOLD)Checking flake8$(RESET)"
@flake8 neoteroi 2>&1
@flake8 tests 2>&1


check-isort:
@echo "$(BOLD)Checking isort$(RESET)"
@isort --check-only neoteroi 2>&1
@isort --check-only tests 2>&1


check-black: ## Run the black tool in check mode only (won't modify files)
@echo "$(BOLD)Checking black$(RESET)"
@black --check neoteroi 2>&1
@black --check tests 2>&1
83 changes: 40 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,67 +1,64 @@
[![Build](https://github.com/Neoteroi/guardpost/workflows/Build/badge.svg)](https://github.com/Neoteroi/guardpost/actions?query=workflow%3ABuild)
[![pypi](https://img.shields.io/pypi/v/guardpost.svg?color=blue)](https://pypi.org/project/guardpost/)
[![versions](https://img.shields.io/pypi/pyversions/guardpost.svg)](https://github.com/Neoteroi/guardpost)
[![license](https://img.shields.io/github/license/Neoteroi/guardpost.svg)](https://github.com/Neoteroi/guardpost/blob/master/LICENSE)
[![codecov](https://codecov.io/gh/Neoteroi/guardpost/branch/master/graph/badge.svg?token=sBKZG2D1bZ)](https://codecov.io/gh/Neoteroi/guardpost)
[![pypi](https://img.shields.io/pypi/v/neoteroi-auth.svg?color=blue)](https://pypi.org/project/neoteroi-auth/)
[![versions](https://img.shields.io/pypi/pyversions/neoteroi-auth.svg)](https://github.com/Neoteroi/guardpost)
[![license](https://img.shields.io/github/license/Neoteroi/guardpost.svg)](https://github.com/Neoteroi/guardpost/blob/main/LICENSE)
[![codecov](https://codecov.io/gh/Neoteroi/guardpost/branch/main/graph/badge.svg?token=sBKZG2D1bZ)](https://codecov.io/gh/Neoteroi/guardpost)

# GuardPost
GuardPost provides a basic framework to handle authentication and authorization
in any kind of Python application.
# Authentication and authorization framework for Python apps
Basic framework to handle authentication and authorization in asynchronous
Python applications.

**Features:**

- strategy to implement authentication (who or what is using a service?)
- strategy to implement authorization (is the acting identity authorized to do a certain action?)
- support for dependency injection for classes handling authentication and
authorization requirements
- built-in support for JSON Web Tokens (JWTs) authentication

This library is freely inspired by [authorization in ASP.NET
Core](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies?view=aspnetcore-2.2);
although its implementation is extremely different.

## Installation

```bash
pip install guardpost
pip install neoteroi-auth
```

To install with support for `JSON Web Tokens (JWTs)` validation:

```
pip install guardpost[jwt]
pip install neoteroi-auth[jwt]
```

This library is freely inspired by [authorization in ASP.NET
Core](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies?view=aspnetcore-2.2);
although its implementation is extremely different.

Notable differences are:
1. GuardPost is abstracted from the code that executes it, so it's not bound to
the context of a web framework.
1. GuardPost implements both classes for use with synchronous code (not
necessarily I/O bound), and classes using `async/await` syntax (optimized
for authentication and authorization rules that involve I/O bound operations
such as web requests and communications with databases).
1. GuardPost leverages Python function decorators for the authorization part,
so any function can be wrapped to be executed after handling authorization.
1. The code API is simpler.

## More documentation and examples
For documentation and
[examples](https://github.com/RobertoPrevato/GuardPost/wiki/Examples), refer to
the project [Wiki](https://github.com/RobertoPrevato/GuardPost/wiki).

To see how `guardpost` is used in `blacksheep` web framework, read the
documentation here:
### Examples

* [Authentication](https://www.neoteroi.dev/blacksheep/authentication/)
* [Authorization](https://www.neoteroi.dev/blacksheep/authorization/)

## Both for async/await and synchronous code
GuardPost can be used both with async/await code and with synchronous code,
according to use cases and users' preference.
For examples, refer to the [examples folder](./examples).

## If you have doubts about authentication vs authorization...
`Authentication` answers the question: _Who is the user who is executing the
`Authentication` answers the question: _Who is the user who is initiating the
action?_, or more in general: _Who is the user, or what is the service, that is
executing the action?_.
initiating the action?_.

`Authorization` answers the question: _Is the user, or service, authorized to
do something?_.

Usually, to implement authorization, is necessary to have the context of the
entity that is executing the action. Anyway, the two things are logically
separated and GuardPost is designed to keep them separate.
entity that is executing the action.

## Usage in BlackSheep
`guardpost` is used in the [BlackSheep](https://www.neoteroi.dev/blacksheep/)
web framework to implement [authentication and authorization
`neoteroi-auth` is used in the second version of the
[BlackSheep](https://www.neoteroi.dev/blacksheep/) web framework, to implement
[authentication and authorization
strategies](https://www.neoteroi.dev/blacksheep/authentication/) for request
handlers.

To see how `neoteroi-auth` is used in `blacksheep` web framework, read:

* [Authentication](https://www.neoteroi.dev/blacksheep/authentication/)
* [Authorization](https://www.neoteroi.dev/blacksheep/authorization/)

# Documentation

Under construction. 🚧
31 changes: 31 additions & 0 deletions examples-summary.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""
Generates a README.md file for the examples folder.
"""

import glob
import importlib
import sys

examples = [file for file in glob.glob("./examples/*.py")]
examples.sort()
sys.path.append("./examples")

with open("./examples/README.md", mode="wt", encoding="utf8 ") as examples_readme:
examples_readme.write(
"<!-- generated file, to update use: python examples-summary.py -->\n\n"
)
examples_readme.write("""# Examples""")

for file_path in examples:
if "__init__" in file_path:
continue

module_name = file_path.replace("./examples/", "").replace(".py", "")

module = importlib.import_module(module_name)

if not module.__doc__:
continue

examples_readme.write(f"\n\n## {module_name}.py\n")
examples_readme.write(str(module.__doc__))
Loading

0 comments on commit 053aa70

Please sign in to comment.