250 Commits

Author SHA1 Message Date
Sam Bull
0346ec8b6d Update ci.yaml 2021-01-14 13:58:08 +00:00
Sam Bull
2f6bf14120 Add mypy to CI. 2020-12-18 18:14:01 +00:00
Sam Bull
aa184593f8 Merge branch 'ci' into typing 2020-12-18 18:12:01 +00:00
Sam Bull
cfa326b502 Update ci.yaml 2020-12-18 18:10:41 +00:00
Sam Bull
3836f750bc Delete .travis.yml 2020-12-18 18:08:53 +00:00
Sam Bull
117eb19e1e Create ci.yaml 2020-12-18 18:07:48 +00:00
Sam Bull
b3b5367460 Add type annotations. 2020-12-18 17:58:38 +00:00
dependabot-preview[bot]
2247eb72f9 Bump aiohttp from 3.7.2 to 3.7.3 (#363)
Bumps [aiohttp](https://github.com/aio-libs/aiohttp) from 3.7.2 to 3.7.3.
- [Release notes](https://github.com/aio-libs/aiohttp/releases)
- [Changelog](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst)
- [Commits](https://github.com/aio-libs/aiohttp/compare/v3.7.2...v3.7.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-12-11 14:26:19 +02:00
dependabot-preview[bot]
75f317fe2d Bump aiopg[sa] from 1.0.0 to 1.1.0 (#367)
Bumps [aiopg[sa]](https://github.com/aio-libs/aiopg) from 1.0.0 to 1.1.0.
- [Release notes](https://github.com/aio-libs/aiopg/releases)
- [Changelog](https://github.com/aio-libs/aiopg/blob/master/CHANGES.txt)
- [Commits](https://github.com/aio-libs/aiopg/compare/v1.0.0...v1.1.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-12-11 14:26:01 +02:00
dependabot-preview[bot]
2c17f8eb7a Bump cryptography from 3.3 to 3.3.1 (#366)
Bumps [cryptography](https://github.com/pyca/cryptography) from 3.3 to 3.3.1.
- [Release notes](https://github.com/pyca/cryptography/releases)
- [Changelog](https://github.com/pyca/cryptography/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/3.3...3.3.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-12-11 12:52:01 +02:00
dependabot-preview[bot]
4623aa0cca Bump cryptography from 3.2.1 to 3.3 (#365)
Bumps [cryptography](https://github.com/pyca/cryptography) from 3.2.1 to 3.3.
- [Release notes](https://github.com/pyca/cryptography/releases)
- [Changelog](https://github.com/pyca/cryptography/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/3.2.1...3.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-12-09 10:15:15 +02:00
dependabot-preview[bot]
101c19f8c9 Bump aiohttp from 3.6.3 to 3.7.2 (#358)
Bumps [aiohttp](https://github.com/aio-libs/aiohttp) from 3.6.3 to 3.7.2.
- [Release notes](https://github.com/aio-libs/aiohttp/releases)
- [Changelog](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst)
- [Commits](https://github.com/aio-libs/aiohttp/compare/v3.6.3...v3.7.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-11-13 10:31:12 +02:00
dependabot-preview[bot]
9131976657 Bump sphinx from 3.3.0 to 3.3.1 (#362)
Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 3.3.0 to 3.3.1.
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/3.x/CHANGES)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v3.3.0...v3.3.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-11-13 10:22:24 +02:00
dependabot-preview[bot]
ba6d455e8d Bump sphinx from 3.2.1 to 3.3.0 (#361)
Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 3.2.1 to 3.3.0.
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/3.x/CHANGES)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v3.2.1...v3.3.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-11-03 07:49:03 +02:00
dependabot-preview[bot]
ae2d4d8d25 Bump cryptography from 3.2 to 3.2.1 (#360)
Bumps [cryptography](https://github.com/pyca/cryptography) from 3.2 to 3.2.1.
- [Release notes](https://github.com/pyca/cryptography/releases)
- [Changelog](https://github.com/pyca/cryptography/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/3.2...3.2.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-11-02 23:10:08 +02:00
dependabot-preview[bot]
57893dc274 Bump cryptography from 3.0 to 3.2 (#357)
Bumps [cryptography](https://github.com/pyca/cryptography) from 3.0 to 3.2.
- [Release notes](https://github.com/pyca/cryptography/releases)
- [Changelog](https://github.com/pyca/cryptography/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/3.0...3.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-10-31 20:12:48 +02:00
dependabot-preview[bot]
15068563cc Bump pytest from 6.1.1 to 6.1.2
Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.1.1 to 6.1.2.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/6.1.1...6.1.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-10-29 05:45:09 +00:00
dependabot-preview[bot]
b78b525864 Bump aiohttp from 3.6.2 to 3.6.3
Bumps [aiohttp](https://github.com/aio-libs/aiohttp) from 3.6.2 to 3.6.3.
- [Release notes](https://github.com/aio-libs/aiohttp/releases)
- [Changelog](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst)
- [Commits](https://github.com/aio-libs/aiohttp/compare/v3.6.2...v3.6.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-10-13 05:48:23 +00:00
dependabot-preview[bot]
235330ae1e Bump passlib from 1.7.3 to 1.7.4
Bumps [passlib](https://passlib.readthedocs.io) from 1.7.3 to 1.7.4.

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-10-09 05:46:46 +00:00
dependabot-preview[bot]
19c044f6ad Bump passlib from 1.7.2 to 1.7.3
Bumps [passlib](https://passlib.readthedocs.io) from 1.7.2 to 1.7.3.

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-10-07 05:44:15 +00:00
dependabot-preview[bot]
8662c2ac8f Bump flake8 from 3.8.3 to 3.8.4
Bumps [flake8](https://gitlab.com/pycqa/flake8) from 3.8.3 to 3.8.4.
- [Release notes](https://gitlab.com/pycqa/flake8/tags)
- [Commits](https://gitlab.com/pycqa/flake8/compare/3.8.3...3.8.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-10-05 08:34:48 +00:00
dependabot-preview[bot]
c85f3b660d Bump pytest from 6.1.0 to 6.1.1
Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.1.0 to 6.1.1.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/6.1.0...6.1.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-10-05 06:29:36 +00:00
dependabot-preview[bot]
9bb8c41786 Bump pytest from 6.0.2 to 6.1.0
Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.0.2 to 6.1.0.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/6.0.2...6.1.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-09-28 05:51:44 +00:00
dependabot-preview[bot]
1751e8bf55 Bump pytest from 6.0.1 to 6.0.2
Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.0.1 to 6.0.2.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/6.0.1...6.0.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-09-14 07:59:04 +00:00
dependabot-preview[bot]
06ef997a7c Bump coverage from 5.2.1 to 5.3
Bumps [coverage](https://github.com/nedbat/coveragepy) from 5.2.1 to 5.3.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/coverage-5.2.1...coverage-5.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-09-14 07:21:27 +00:00
dependabot-preview[bot]
65c94f624f Bump pytest-mock from 3.3.0 to 3.3.1
Bumps [pytest-mock](https://github.com/pytest-dev/pytest-mock) from 3.3.0 to 3.3.1.
- [Release notes](https://github.com/pytest-dev/pytest-mock/releases)
- [Changelog](https://github.com/pytest-dev/pytest-mock/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-mock/compare/v3.3.0...v3.3.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-27 05:50:50 +00:00
dependabot-preview[bot]
cb0aa10a25 Bump pytest-mock from 3.2.0 to 3.3.0
Bumps [pytest-mock](https://github.com/pytest-dev/pytest-mock) from 3.2.0 to 3.3.0.
- [Release notes](https://github.com/pytest-dev/pytest-mock/releases)
- [Changelog](https://github.com/pytest-dev/pytest-mock/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-mock/compare/v3.2.0...v3.3.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-24 06:30:52 +00:00
dependabot-preview[bot]
67816eb354 Bump pytest-cov from 2.10.0 to 2.10.1
Bumps [pytest-cov](https://github.com/pytest-dev/pytest-cov) from 2.10.0 to 2.10.1.
- [Release notes](https://github.com/pytest-dev/pytest-cov/releases)
- [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-cov/compare/v2.10.0...v2.10.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-17 09:19:18 +00:00
dependabot-preview[bot]
9aa6c4eea3 Bump sphinx from 3.2.0 to 3.2.1
Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 3.2.0 to 3.2.1.
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/3.x/CHANGES)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v3.2.0...v3.2.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-17 07:18:04 +00:00
dependabot-preview[bot]
e41852d763 Bump sphinx from 3.1.2 to 3.2.0
Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 3.1.2 to 3.2.0.
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/3.x/CHANGES)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v3.1.2...v3.2.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-10 06:40:21 +00:00
dependabot-preview[bot]
80728460b9 Bump pytest from 6.0.0 to 6.0.1
Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.0.0 to 6.0.1.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/6.0.0...6.0.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-31 06:54:27 +00:00
dependabot-preview[bot]
f86069281f Bump pytest from 5.4.3 to 6.0.0
Bumps [pytest](https://github.com/pytest-dev/pytest) from 5.4.3 to 6.0.0.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/5.4.3...6.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-29 06:43:00 +00:00
dependabot-preview[bot]
2b90dc7be2 Bump coverage from 5.2 to 5.2.1
Bumps [coverage](https://github.com/nedbat/coveragepy) from 5.2 to 5.2.1.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/coverage-5.2...coverage-5.2.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-27 06:51:27 +00:00
dependabot-preview[bot]
ea83d1c4e4 Bump cryptography from 2.9.2 to 3.0
Bumps [cryptography](https://github.com/pyca/cryptography) from 2.9.2 to 3.0.
- [Release notes](https://github.com/pyca/cryptography/releases)
- [Changelog](https://github.com/pyca/cryptography/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/2.9.2...3.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-21 07:04:43 +00:00
dependabot-preview[bot]
05eef37ac6 Bump pytest-mock from 3.1.1 to 3.2.0
Bumps [pytest-mock](https://github.com/pytest-dev/pytest-mock) from 3.1.1 to 3.2.0.
- [Release notes](https://github.com/pytest-dev/pytest-mock/releases)
- [Changelog](https://github.com/pytest-dev/pytest-mock/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-mock/compare/v3.1.1...v3.2.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-20 11:27:44 +00:00
dependabot-preview[bot]
1b34d7de74 Bump sphinx from 3.1.1 to 3.1.2
Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 3.1.1 to 3.1.2.
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/3.x/CHANGES)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v3.1.1...v3.1.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-20 10:52:23 +00:00
dependabot-preview[bot]
cb242e9c09 Bump coverage from 5.1 to 5.2
Bumps [coverage](https://github.com/nedbat/coveragepy) from 5.1 to 5.2.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/coverage-5.1...coverage-5.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-20 07:04:16 +00:00
dependabot-preview[bot]
d903ffda50 Bump hiredis from 1.0.1 to 1.1.0
Bumps [hiredis](https://github.com/redis/hiredis-py) from 1.0.1 to 1.1.0.
- [Release notes](https://github.com/redis/hiredis-py/releases)
- [Changelog](https://github.com/redis/hiredis-py/blob/master/CHANGELOG.md)
- [Commits](https://github.com/redis/hiredis-py/compare/v1.0.1...v1.1.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-20 07:02:19 +00:00
dependabot-preview[bot]
2bc9eb88b1 Bump sphinx from 3.1.0 to 3.1.1
Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 3.1.0 to 3.1.1.
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/3.x/CHANGES)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v3.1.0...v3.1.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-06-15 08:46:15 +00:00
dependabot-preview[bot]
106c322b1a Bump pytest-cov from 2.9.0 to 2.10.0
Bumps [pytest-cov](https://github.com/pytest-dev/pytest-cov) from 2.9.0 to 2.10.0.
- [Release notes](https://github.com/pytest-dev/pytest-cov/releases)
- [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-cov/compare/v2.9.0...v2.10.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-06-15 08:09:25 +00:00
dependabot-preview[bot]
e3c6d00665 Bump flake8 from 3.8.2 to 3.8.3
Bumps [flake8](https://gitlab.com/pycqa/flake8) from 3.8.2 to 3.8.3.
- [Release notes](https://gitlab.com/pycqa/flake8/tags)
- [Commits](https://gitlab.com/pycqa/flake8/compare/3.8.2...3.8.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-06-09 07:46:42 +00:00
dependabot-preview[bot]
78867ce3c1 Bump sphinx from 3.0.4 to 3.1.0
Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 3.0.4 to 3.1.0.
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/3.x/CHANGES)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v3.0.4...v3.1.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-06-09 07:42:38 +00:00
dependabot-preview[bot]
0133d23d4a Bump pytest-mock from 3.1.0 to 3.1.1
Bumps [pytest-mock](https://github.com/pytest-dev/pytest-mock) from 3.1.0 to 3.1.1.
- [Release notes](https://github.com/pytest-dev/pytest-mock/releases)
- [Changelog](https://github.com/pytest-dev/pytest-mock/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-mock/compare/v3.1.0...v3.1.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-06-05 06:33:18 +00:00
dependabot-preview[bot]
e00a5eeb49 Bump pytest from 5.4.2 to 5.4.3
Bumps [pytest](https://github.com/pytest-dev/pytest) from 5.4.2 to 5.4.3.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/5.4.2...5.4.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-06-03 08:03:53 +00:00
dependabot-preview[bot]
323d28b625 Bump sphinx from 3.0.3 to 3.0.4
Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 3.0.3 to 3.0.4.
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/3.x/CHANGES)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v3.0.3...v3.0.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-05-27 06:37:53 +00:00
dependabot-preview[bot]
c6a8fd5a0e Bump pytest-cov from 2.8.1 to 2.9.0
Bumps [pytest-cov](https://github.com/pytest-dev/pytest-cov) from 2.8.1 to 2.9.0.
- [Release notes](https://github.com/pytest-dev/pytest-cov/releases)
- [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-cov/compare/v2.8.1...v2.9.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-05-25 08:54:00 +00:00
dependabot-preview[bot]
94ee8c2348 Bump flake8 from 3.8.1 to 3.8.2
Bumps [flake8](https://gitlab.com/pycqa/flake8) from 3.8.1 to 3.8.2.
- [Release notes](https://gitlab.com/pycqa/flake8/tags)
- [Commits](https://gitlab.com/pycqa/flake8/compare/3.8.1...3.8.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-05-25 06:59:30 +00:00
dependabot-preview[bot]
84277f5f2e Bump flake8 from 3.7.9 to 3.8.1
Bumps [flake8](https://gitlab.com/pycqa/flake8) from 3.7.9 to 3.8.1.
- [Release notes](https://gitlab.com/pycqa/flake8/tags)
- [Commits](https://gitlab.com/pycqa/flake8/compare/3.7.9...3.8.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-05-12 07:43:12 +00:00
dependabot-preview[bot]
c88e176c07 Bump pytest from 5.4.1 to 5.4.2
Bumps [pytest](https://github.com/pytest-dev/pytest) from 5.4.1 to 5.4.2.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/5.4.1...5.4.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-05-11 07:38:29 +00:00
dependabot-preview[bot]
2ffed0380f Bump sphinx from 3.0.2 to 3.0.3
Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 3.0.2 to 3.0.3.
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/3.x/CHANGES)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v3.0.2...v3.0.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-04-27 06:58:30 +00:00
dependabot-preview[bot]
f24a9b2914 Bump cryptography from 2.9.1 to 2.9.2
Bumps [cryptography](https://github.com/pyca/cryptography) from 2.9.1 to 2.9.2.
- [Release notes](https://github.com/pyca/cryptography/releases)
- [Changelog](https://github.com/pyca/cryptography/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/2.9.1...2.9.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-04-23 06:44:52 +00:00
dependabot-preview[bot]
52420cd2ba Bump cryptography from 2.9 to 2.9.1
Bumps [cryptography](https://github.com/pyca/cryptography) from 2.9 to 2.9.1.
- [Release notes](https://github.com/pyca/cryptography/releases)
- [Changelog](https://github.com/pyca/cryptography/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/2.9...2.9.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-04-22 06:43:34 +00:00
dependabot-preview[bot]
ac4bd3620f Bump sphinx from 3.0.1 to 3.0.2
Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 3.0.1 to 3.0.2.
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/3.x/CHANGES)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v3.0.1...v3.0.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-04-20 07:48:51 +00:00
dependabot-preview[bot]
46d13348e8 Bump pytest-mock from 3.0.0 to 3.1.0
Bumps [pytest-mock](https://github.com/pytest-dev/pytest-mock) from 3.0.0 to 3.1.0.
- [Release notes](https://github.com/pytest-dev/pytest-mock/releases)
- [Changelog](https://github.com/pytest-dev/pytest-mock/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-mock/compare/v3.0.0...v3.1.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-04-20 07:25:45 +00:00
dependabot-preview[bot]
aea0d5ba21 Bump coverage from 5.0.4 to 5.1
Bumps [coverage](https://github.com/nedbat/coveragepy) from 5.0.4 to 5.1.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/coverage-5.0.4...coverage-5.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-04-13 08:19:34 +00:00
dependabot-preview[bot]
72e9a80fee Bump sphinx from 3.0.0 to 3.0.1
Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 3.0.0 to 3.0.1.
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/3.x/CHANGES)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v3.0.0...v3.0.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-04-13 06:55:37 +00:00
dependabot-preview[bot]
09f7b7e855 Bump sphinx from 2.4.4 to 3.0.0
Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 2.4.4 to 3.0.0.
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/3.x/CHANGES)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v2.4.4...v3.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-04-06 07:00:34 +00:00
dependabot-preview[bot]
0729ca10c8 Bump cryptography from 2.8 to 2.9
Bumps [cryptography](https://github.com/pyca/cryptography) from 2.8 to 2.9.
- [Release notes](https://github.com/pyca/cryptography/releases)
- [Changelog](https://github.com/pyca/cryptography/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/2.8...2.9)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-04-03 06:53:13 +00:00
dependabot-preview[bot]
173da83582 Bump pytest-mock from 2.0.0 to 3.0.0
Bumps [pytest-mock](https://github.com/pytest-dev/pytest-mock) from 2.0.0 to 3.0.0.
- [Release notes](https://github.com/pytest-dev/pytest-mock/releases)
- [Changelog](https://github.com/pytest-dev/pytest-mock/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-mock/compare/v2.0.0...v3.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-04-01 06:45:41 +00:00
dependabot-preview[bot]
7494e75fd1 Bump coverage from 5.0.3 to 5.0.4
Bumps [coverage](https://github.com/nedbat/coveragepy) from 5.0.3 to 5.0.4.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/coverage-5.0.3...coverage-5.0.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-17 06:32:16 +00:00
dependabot-preview[bot]
e5bd591a17 Bump pytest from 5.3.5 to 5.4.1
Bumps [pytest](https://github.com/pytest-dev/pytest) from 5.3.5 to 5.4.1.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/5.3.5...5.4.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-16 06:41:33 +00:00
dependabot-preview[bot]
50ed7703c1 Bump sphinx from 2.4.3 to 2.4.4
Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 2.4.3 to 2.4.4.
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/3.x/CHANGES)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v2.4.3...v2.4.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-06 06:29:35 +00:00
dependabot-preview[bot]
02dc750bc7 Bump sphinx from 2.4.2 to 2.4.3
Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 2.4.2 to 2.4.3.
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/3.x/CHANGES)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v2.4.2...v2.4.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-24 06:49:29 +00:00
dependabot-preview[bot]
c36a654393 Bump sphinx from 2.4.1 to 2.4.2
Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 2.4.1 to 2.4.2.
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/3.x/CHANGES)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v2.4.1...v2.4.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-19 06:32:37 +00:00
dependabot-preview[bot]
85df85a1c2 Bump sphinx from 2.4.0 to 2.4.1
Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 2.4.0 to 2.4.1.
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/2.0/CHANGES)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v2.4.0...v2.4.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-12 06:32:15 +00:00
dependabot-preview[bot]
859689f82c Bump sphinx from 2.3.1 to 2.4.0
Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 2.3.1 to 2.4.0.
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/2.0/CHANGES)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v2.3.1...v2.4.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-10 06:49:40 +00:00
dependabot-preview[bot]
e4bb720132 Bump pytest from 5.3.4 to 5.3.5
Bumps [pytest](https://github.com/pytest-dev/pytest) from 5.3.4 to 5.3.5.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/5.3.4...5.3.5)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-30 06:30:24 +00:00
dependabot-preview[bot]
ee8b55af0f Bump pytest from 5.3.3 to 5.3.4
Bumps [pytest](https://github.com/pytest-dev/pytest) from 5.3.3 to 5.3.4.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/5.3.3...5.3.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-21 06:41:24 +00:00
dependabot-preview[bot]
f6bb8f1564 Bump pytest from 5.3.2 to 5.3.3
Bumps [pytest](https://github.com/pytest-dev/pytest) from 5.3.2 to 5.3.3.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/5.3.2...5.3.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-20 06:56:57 +00:00
dependabot-preview[bot]
56cc1b46be Bump coverage from 5.0.2 to 5.0.3
Bumps [coverage](https://github.com/nedbat/coveragepy) from 5.0.2 to 5.0.3.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/coverage-5.0.2...coverage-5.0.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-13 07:30:45 +00:00
dependabot-preview[bot]
6599dd4250 Bump pytest-mock from 1.13.0 to 2.0.0
Bumps [pytest-mock](https://github.com/pytest-dev/pytest-mock) from 1.13.0 to 2.0.0.
- [Release notes](https://github.com/pytest-dev/pytest-mock/releases)
- [Changelog](https://github.com/pytest-dev/pytest-mock/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-mock/compare/v1.13.0...v2.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-06 07:29:59 +00:00
dependabot-preview[bot]
9ea0ae319a Bump coverage from 5.0.1 to 5.0.2
Bumps [coverage](https://github.com/nedbat/coveragepy) from 5.0.1 to 5.0.2.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/coverage-5.0.1...coverage-5.0.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-06 06:44:31 +00:00
dependabot-preview[bot]
14c03dba69 Bump coverage from 5.0 to 5.0.1
Bumps [coverage](https://github.com/nedbat/coveragepy) from 5.0 to 5.0.1.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/coverage-5.0...coverage-5.0.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-23 07:55:52 +00:00
dependabot-preview[bot]
fd0228240a Bump sphinx from 2.3.0 to 2.3.1
Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 2.3.0 to 2.3.1.
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/master/CHANGES)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v2.3.0...v2.3.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-23 06:37:59 +00:00
dependabot-preview[bot]
88ecee7ee1 Bump pytest from 5.3.1 to 5.3.2
Bumps [pytest](https://github.com/pytest-dev/pytest) from 5.3.1 to 5.3.2.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/5.3.1...5.3.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-16 11:14:26 +00:00
dependabot-preview[bot]
cc1eaf6c92 Bump sphinx from 2.2.2 to 2.3.0
Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 2.2.2 to 2.3.0.
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/master/CHANGES)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v2.2.2...v2.3.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-16 09:03:35 +00:00
dependabot-preview[bot]
74281bd7e4 Bump coverage from 4.5.4 to 5.0
Bumps [coverage](https://github.com/nedbat/coveragepy) from 4.5.4 to 5.0.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/coverage-4.5.4...coverage-5.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-16 06:43:50 +00:00
Thijs Triemstra
9f9ca363c9 hash is a reserved symbol name (#282) 2019-12-10 23:10:54 +02:00
dependabot-preview[bot]
8dfe89594a Bump pytest-mock from 1.12.1 to 1.13.0
Bumps [pytest-mock](https://github.com/pytest-dev/pytest-mock) from 1.12.1 to 1.13.0.
- [Release notes](https://github.com/pytest-dev/pytest-mock/releases)
- [Changelog](https://github.com/pytest-dev/pytest-mock/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-mock/compare/v1.12.1...v1.13.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-06 06:39:35 +00:00
dependabot-preview[bot]
eedb79b560 Bump sphinx from 2.2.1 to 2.2.2
Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 2.2.1 to 2.2.2.
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/master/CHANGES)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v2.2.1...v2.2.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-03 08:11:44 +00:00
dependabot-preview[bot]
139d8d9974 Bump aioredis from 1.3.0 to 1.3.1
Bumps [aioredis](https://github.com/aio-libs/aioredis) from 1.3.0 to 1.3.1.
- [Release notes](https://github.com/aio-libs/aioredis/releases)
- [Changelog](https://github.com/aio-libs/aioredis/blob/master/CHANGES.txt)
- [Commits](https://github.com/aio-libs/aioredis/compare/v1.3.0...v1.3.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-03 07:00:24 +00:00
dependabot-preview[bot]
e3eecf1bd0 Bump pytest from 5.3.0 to 5.3.1
Bumps [pytest](https://github.com/pytest-dev/pytest) from 5.3.0 to 5.3.1.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/5.3.0...5.3.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-27 06:36:45 +00:00
dependabot-preview[bot]
e5ce21edcf Bump passlib from 1.7.1 to 1.7.2
Bumps [passlib](https://bitbucket.org/ecollins/passlib) from 1.7.1 to 1.7.2.
- [Commits](https://bitbucket.org/ecollins/passlib/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-25 06:43:02 +00:00
dependabot-preview[bot]
21bba9ec12 Bump pytest-mock from 1.12.0 to 1.12.1
Bumps [pytest-mock](https://github.com/pytest-dev/pytest-mock) from 1.12.0 to 1.12.1.
- [Release notes](https://github.com/pytest-dev/pytest-mock/releases)
- [Changelog](https://github.com/pytest-dev/pytest-mock/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-mock/compare/v1.12.0...v1.12.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-21 06:33:55 +00:00
dependabot-preview[bot]
1a80a79b69 Bump pytest-mock from 1.11.2 to 1.12.0
Bumps [pytest-mock](https://github.com/pytest-dev/pytest-mock) from 1.11.2 to 1.12.0.
- [Release notes](https://github.com/pytest-dev/pytest-mock/releases)
- [Changelog](https://github.com/pytest-dev/pytest-mock/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-mock/compare/v1.11.2...v1.12.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-20 06:59:16 +00:00
dependabot-preview[bot]
ce30bd4544 Bump pytest from 5.2.4 to 5.3.0
Bumps [pytest](https://github.com/pytest-dev/pytest) from 5.2.4 to 5.3.0.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/5.2.4...5.3.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-20 06:32:26 +00:00
dependabot-preview[bot]
99408d151e Bump pytest from 5.2.3 to 5.2.4
Bumps [pytest](https://github.com/pytest-dev/pytest) from 5.2.3 to 5.2.4.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/5.2.3...5.2.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-18 06:43:57 +00:00
dependabot-preview[bot]
11c5b691b7 Bump pytest from 5.2.2 to 5.2.3
Bumps [pytest](https://github.com/pytest-dev/pytest) from 5.2.2 to 5.2.3.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/5.2.2...5.2.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-15 06:35:49 +00:00
dependabot-preview[bot]
0ae8668ad2 Bump hiredis from 1.0.0 to 1.0.1 (#274)
Bumps [hiredis](https://github.com/redis/hiredis-py) from 1.0.0 to 1.0.1.
- [Release notes](https://github.com/redis/hiredis-py/releases)
- [Changelog](https://github.com/redis/hiredis-py/blob/master/CHANGELOG.md)
- [Commits](https://github.com/redis/hiredis-py/compare/v1.0.0...v1.0.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-14 16:25:29 +02:00
dependabot-preview[bot]
f58d9b5c7a Bump aiohttp-session from 2.8.0 to 2.9.0
Bumps [aiohttp-session](https://github.com/aio-libs/aiohttp_session) from 2.8.0 to 2.9.0.
- [Release notes](https://github.com/aio-libs/aiohttp_session/releases)
- [Changelog](https://github.com/aio-libs/aiohttp-session/blob/master/CHANGES.txt)
- [Commits](https://github.com/aio-libs/aiohttp_session/compare/v2.8.0...v2.9.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-05 08:50:33 +00:00
dependabot-preview[bot]
7e15f918b7 Bump flake8 from 3.7.8 to 3.7.9
Bumps [flake8](https://gitlab.com/pycqa/flake8) from 3.7.8 to 3.7.9.
- [Release notes](https://gitlab.com/pycqa/flake8/tags)
- [Commits](https://gitlab.com/pycqa/flake8/compare/3.7.8...3.7.9)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-29 06:39:50 +00:00
dependabot-preview[bot]
0b16e3a745 Bump sphinx from 2.2.0 to 2.2.1
Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 2.2.0 to 2.2.1.
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/master/CHANGES)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v2.2.0...v2.2.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-28 07:15:59 +00:00
dependabot-preview[bot]
c5f4c63892 Bump pytest from 5.2.1 to 5.2.2
Bumps [pytest](https://github.com/pytest-dev/pytest) from 5.2.1 to 5.2.2.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/5.2.1...5.2.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-25 06:38:42 +00:00
dependabot-preview[bot]
94c7af6c8d Bump pytest-mock from 1.11.1 to 1.11.2
Bumps [pytest-mock](https://github.com/pytest-dev/pytest-mock) from 1.11.1 to 1.11.2.
- [Release notes](https://github.com/pytest-dev/pytest-mock/releases)
- [Changelog](https://github.com/pytest-dev/pytest-mock/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-mock/compare/v1.11.1...v1.11.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-24 06:52:04 +00:00
dependabot-preview[bot]
775b1ccffc Bump cryptography from 2.7 to 2.8
Bumps [cryptography](https://github.com/pyca/cryptography) from 2.7 to 2.8.
- [Release notes](https://github.com/pyca/cryptography/releases)
- [Changelog](https://github.com/pyca/cryptography/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/2.7...2.8)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-17 14:32:54 +00:00
dependabot-preview[bot]
8e2d1bdf6b Bump aiohttp from 3.6.1 to 3.6.2
Bumps [aiohttp](https://github.com/aio-libs/aiohttp) from 3.6.1 to 3.6.2.
- [Release notes](https://github.com/aio-libs/aiohttp/releases)
- [Changelog](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst)
- [Commits](https://github.com/aio-libs/aiohttp/compare/v3.6.1...v3.6.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-10 11:25:52 +00:00
dependabot-preview[bot]
be08d06057 Bump pytest from 5.2.0 to 5.2.1
Bumps [pytest](https://github.com/pytest-dev/pytest) from 5.2.0 to 5.2.1.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/5.2.0...5.2.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-07 14:26:29 +00:00
dependabot-preview[bot]
1bcf612222 Bump pytest-cov from 2.7.1 to 2.8.1
Bumps [pytest-cov](https://github.com/pytest-dev/pytest-cov) from 2.7.1 to 2.8.1.
- [Release notes](https://github.com/pytest-dev/pytest-cov/releases)
- [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-cov/compare/v2.7.1...v2.8.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-07 10:32:14 +00:00
dependabot-preview[bot]
96ee5d2cb3 Bump pytest-mock from 1.11.0 to 1.11.1
Bumps [pytest-mock](https://github.com/pytest-dev/pytest-mock) from 1.11.0 to 1.11.1.
- [Release notes](https://github.com/pytest-dev/pytest-mock/releases)
- [Changelog](https://github.com/pytest-dev/pytest-mock/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-mock/compare/v1.11.0...v1.11.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-07 08:21:34 +00:00
dependabot-preview[bot]
534043e109 Bump pytest from 5.1.3 to 5.2.0
Bumps [pytest](https://github.com/pytest-dev/pytest) from 5.1.3 to 5.2.0.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/5.1.3...5.2.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-30 08:23:29 +00:00
dependabot-preview[bot]
4572e2c23c Bump pytest-mock from 1.10.4 to 1.11.0
Bumps [pytest-mock](https://github.com/pytest-dev/pytest-mock) from 1.10.4 to 1.11.0.
- [Release notes](https://github.com/pytest-dev/pytest-mock/releases)
- [Changelog](https://github.com/pytest-dev/pytest-mock/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-mock/compare/1.10.4...v1.11.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-30 07:57:06 +00:00
dependabot-preview[bot]
0cd61422fc Bump aioredis from 1.2.0 to 1.3.0
Bumps [aioredis](https://github.com/aio-libs/aioredis) from 1.2.0 to 1.3.0.
- [Release notes](https://github.com/aio-libs/aioredis/releases)
- [Changelog](https://github.com/aio-libs/aioredis/blob/master/CHANGES.txt)
- [Commits](https://github.com/aio-libs/aioredis/compare/v1.2.0...v1.3.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-25 08:00:25 +00:00
dependabot-preview[bot]
5667dfd0e1 Bump aiopg from 0.16.0 to 1.0.0
Bumps [aiopg](https://github.com/aio-libs/aiopg) from 0.16.0 to 1.0.0.
- [Release notes](https://github.com/aio-libs/aiopg/releases)
- [Changelog](https://github.com/aio-libs/aiopg/blob/master/CHANGES.txt)
- [Commits](https://github.com/aio-libs/aiopg/compare/v0.16.0...v1.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-24 06:56:31 +00:00
dependabot-preview[bot]
cb300bb5ee Bump pytest from 5.1.2 to 5.1.3
Bumps [pytest](https://github.com/pytest-dev/pytest) from 5.1.2 to 5.1.3.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/5.1.2...5.1.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-23 07:18:19 +00:00
dependabot-preview[bot]
a25d215b43 Bump aiohttp from 3.6.0 to 3.6.1 (#258)
Bumps [aiohttp](https://github.com/aio-libs/aiohttp) from 3.6.0 to 3.6.1.
- [Release notes](https://github.com/aio-libs/aiohttp/releases)
- [Changelog](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst)
- [Commits](https://github.com/aio-libs/aiohttp/compare/v3.6.0...v3.6.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-20 17:33:59 +03:00
dependabot-preview[bot]
74345a25ef Bump aiohttp from 3.4.4 to 3.6.0
Bumps [aiohttp](https://github.com/aio-libs/aiohttp) from 3.4.4 to 3.6.0.
- [Release notes](https://github.com/aio-libs/aiohttp/releases)
- [Changelog](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst)
- [Commits](https://github.com/aio-libs/aiohttp/compare/v3.4.4...v3.6.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-18 12:29:12 +00:00
dependabot-preview[bot]
3cd857dca8 Bump aiohttp-session from 2.7.0 to 2.8.0
Bumps [aiohttp-session](https://github.com/aio-libs/aiohttp_session) from 2.7.0 to 2.8.0.
- [Release notes](https://github.com/aio-libs/aiohttp_session/releases)
- [Changelog](https://github.com/aio-libs/aiohttp-session/blob/master/CHANGES.txt)
- [Commits](https://github.com/aio-libs/aiohttp_session/compare/v2.7.0...v2.8.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-18 11:33:06 +00:00
dependabot-preview[bot]
9007a7ca55 Bump coverage from 4.5.2 to 4.5.4
Bumps [coverage](https://github.com/nedbat/coveragepy) from 4.5.2 to 4.5.4.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/coverage-4.5.2...coverage-4.5.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-17 11:26:21 +00:00
dependabot-preview[bot]
b87e58efe7 Bump sphinx from 1.8.2 to 2.2.0
Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 1.8.2 to 2.2.0.
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/master/CHANGES)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v1.8.2...v2.2.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-17 09:36:19 +00:00
dependabot-preview[bot]
ba6fbd0708 Bump aiopg from 0.15.0 to 0.16.0
Bumps [aiopg](https://github.com/aio-libs/aiopg) from 0.15.0 to 0.16.0.
- [Release notes](https://github.com/aio-libs/aiopg/releases)
- [Commits](https://github.com/aio-libs/aiopg/compare/v0.15.0...v0.16.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-17 07:09:31 +00:00
dependabot-preview[bot]
342991c21d Bump flake8 from 3.6.0 to 3.7.8
Bumps [flake8](https://gitlab.com/pycqa/flake8) from 3.6.0 to 3.7.8.
- [Release notes](https://gitlab.com/pycqa/flake8/tags)
- [Commits](https://gitlab.com/pycqa/flake8/compare/3.6.0...3.7.8)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-17 06:59:58 +00:00
dependabot-preview[bot]
c3e7a4c8bb Bump pytest from 4.0.2 to 5.1.2
Bumps [pytest](https://github.com/pytest-dev/pytest) from 4.0.2 to 5.1.2.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/4.0.2...5.1.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-16 21:31:56 +00:00
dependabot-preview[bot]
c81b89a9e7 Bump pytest-cov from 2.6.0 to 2.7.1 (#249)
Bumps [pytest-cov](https://github.com/pytest-dev/pytest-cov) from 2.6.0 to 2.7.1.
- [Release notes](https://github.com/pytest-dev/pytest-cov/releases)
- [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-cov/compare/v2.6.0...v2.7.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-17 00:03:44 +03:00
dependabot-preview[bot]
30b07a6033 Bump cryptography from 2.4.2 to 2.7
Bumps [cryptography](https://github.com/pyca/cryptography) from 2.4.2 to 2.7.
- [Release notes](https://github.com/pyca/cryptography/releases)
- [Changelog](https://github.com/pyca/cryptography/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/2.4.2...2.7)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-16 20:57:12 +00:00
dependabot-preview[bot]
e745334204 Bump hiredis from 0.3.0 to 1.0.0
Bumps [hiredis](https://github.com/redis/hiredis-py) from 0.3.0 to 1.0.0.
- [Release notes](https://github.com/redis/hiredis-py/releases)
- [Changelog](https://github.com/redis/hiredis-py/blob/master/CHANGELOG.md)
- [Commits](https://github.com/redis/hiredis-py/compare/v0.3.0...v1.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-16 20:12:01 +00:00
Andrew Svetlov
05ebfe1142 Reduce build matrix 2019-09-16 22:07:46 +03:00
dependabot-preview[bot]
22a3bd36e1 Bump pytest-mock from 1.10.0 to 1.10.4
Bumps [pytest-mock](https://github.com/pytest-dev/pytest-mock) from 1.10.0 to 1.10.4.
- [Release notes](https://github.com/pytest-dev/pytest-mock/releases)
- [Changelog](https://github.com/pytest-dev/pytest-mock/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-mock/compare/v1.10.0...1.10.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-16 18:56:31 +00:00
pyup.io bot
901cf1a7e0 Scheduled weekly dependency update for week 50 (#203)
* Update pytest from 4.0.1 to 4.0.2

* Update pyjwt from 1.7.0 to 1.7.1
2018-12-17 19:40:55 +02:00
pyup.io bot
82cff61379 Scheduled weekly dependency update for week 48 (#200)
* Update pytest from 3.10.1 to 4.0.1

* Update coverage from 4.5.1 to 4.5.2

* Update hiredis from 0.2.0 to 0.3.0

* Update cryptography from 2.4.1 to 2.4.2

* Update pyjwt from 1.6.4 to 1.7.0
2018-12-03 19:54:17 +02:00
pyup.io bot
cb0e17d9c5 Scheduled weekly dependency update for week 45 (#197)
* Update pytest from 3.10.0 to 3.10.1

* Update sphinx from 1.8.1 to 1.8.2

* Update cryptography from 2.3.1 to 2.4.1
2018-11-13 00:19:08 +02:00
pyup.io bot
27c95969c2 Update pytest from 3.9.3 to 3.10.0 (#196) 2018-11-06 10:59:52 +02:00
pyup.io bot
0b2e3cd6c0 Scheduled weekly dependency update for week 43 (#195)
* Update flake8 from 3.5.0 to 3.6.0

* Update pytest from 3.9.1 to 3.9.3

* Update aioredis from 1.1.0 to 1.2.0
2018-10-30 14:50:30 +01:00
pyup.io bot
dab8b6f248 Update pytest from 3.8.2 to 3.9.1 (#194) 2018-10-23 07:56:11 +03:00
pyup.io bot
460ddfd50c Scheduled weekly dependency update for week 41 (#193)
* Update async-timeout from 3.0 to 3.0.1

* Update aiohttp-session from 2.6.0 to 2.7.0
2018-10-15 23:28:04 +03:00
pyup.io bot
354b1a8995 Update pytest from 3.8.1 to 3.8.2 (#192) 2018-10-09 10:27:19 +03:00
imgbot[bot]
9b428003d0 [ImgBot] optimizes images (#191)
/docs/_static/aiohttp-icon-128x128.png -- 18.93kb -> 17.33kb (8.43%)
2018-10-06 22:40:24 +03:00
pyup.io bot
124c83ee24 Scheduled weekly dependency update for week 38 (#190)
* Update pytest from 3.7.4 to 3.8.1

* Update pytest-cov from 2.5.1 to 2.6.0

* Update sphinx from 1.7.8 to 1.8.1

* Update aiohttp-session from 2.5.1 to 2.6.0

* Update aiohttp from 3.4.2 to 3.4.4
2018-09-28 08:20:32 +03:00
Andrew Svetlov
74381e8cc2 Fix badges in README 2018-09-27 10:36:27 +03:00
Andrew Svetlov
fdf8a39607 Use request.config_dict for accessing to policies 2018-09-27 10:30:18 +03:00
Andrew Svetlov
bdb64ed010 Fix #164: switch to aio-libs-bot account for deployment 2018-09-06 13:17:33 +03:00
Andrew Svetlov
9b1d08c661 Update to 0.3.0 2018-09-06 13:06:55 +03:00
pyup.io bot
097f7ecc43 Scheduled weekly dependency update for week 35 (#185)
* Update pytest from 3.6.1 to 3.7.4

* Update sphinx from 1.7.5 to 1.7.8

* Update aiopg from 0.14.0 to 0.15.0

* Update cryptography from 2.2.2 to 2.3.1

* Update aiohttp from 3.3.2 to 3.4.2
2018-09-06 10:37:55 +03:00
pyup.io bot
ca38b38a0e Update aiohttp from 3.3.1 to 3.3.2 (#170) 2018-06-18 20:27:40 +03:00
alex-eri
bb63715634 example not working (#168) 2018-06-13 23:19:25 +03:00
Skorpeo
79e811ea79 Update usage.rst (#167) 2018-06-13 14:10:13 +03:00
pyup.io bot
4c824c34c1 Scheduled weekly dependency update for week 23 (#166)
* Update pytest from 3.5.1 to 3.6.1

* Update sphinx from 1.7.4 to 1.7.5

* Update aiohttp from 3.2.1 to 3.3.1

* Update pyjwt from 1.6.3 to 1.6.4
2018-06-11 22:27:07 +03:00
Oleh Kuchuk
42769df454 JWTIdentityPolicy polishing (#161)
* Polishing JWT policy

* Simplify tests

* Minor cleaning
2018-05-21 22:07:14 +03:00
pyup.io bot
ff2171d6c5 Scheduled weekly dependency update for week 20 (#162)
* Update aiohttp-session from 2.4.0 to 2.5.1

* Update aiopg from 0.13.2 to 0.14.0

* Update aiohttp from 3.2.0 to 3.2.1

* Update pyjwt from 1.6.1 to 1.6.3
2018-05-21 22:04:26 +03:00
pyup.io bot
6638432aac Scheduled weekly dependency update for week 18 (#159)
* Update pytest from 3.5.0 to 3.5.1

* Update pytest-mock from 1.6.3 to 1.10.0

* Update sphinx from 1.7.3 to 1.7.4

* Update aiohttp-session from 2.3.0 to 2.4.0

* Update aiohttp from 3.1.3 to 3.2.0

* Pin pyjwt to latest version 1.6.1
2018-05-07 20:09:01 +03:00
Alexander Pantyukhin
78e752e65f add JWTIdentityPolicy into __init__ file. (#157) 2018-05-01 11:06:35 +03:00
Patryk Lorenowicz
f8dcc4a6de Rewrite 'simple example' in docs, added it to demo dir (#154) 2018-04-26 12:15:12 +03:00
Alexander Pantyukhin
27ffe6dc3c init for jwt identity (#147) 2018-04-25 23:52:36 +03:00
pyup.io bot
29166f4743 Update sphinx from 1.7.2 to 1.7.3 (#153) 2018-04-24 22:52:10 +03:00
pyup.io bot
b982e2136c Update aiohttp from 3.1.2 to 3.1.3 (#149) 2018-04-19 13:15:19 +03:00
Alexander Pantyukhin
797d892ac1 fix setup to read version on windows (#145)
* fix setup to read version on windows

* remove redundat parameter U
2018-04-11 14:20:01 +03:00
pyup.io bot
c5c39ce2b8 Update aiohttp from 3.1.1 to 3.1.2 (#146) 2018-04-11 13:23:35 +03:00
pyup.io bot
46e50fede8 Scheduled weekly dependency update for week 13 (#142)
* Update cryptography from 2.2.1 to 2.2.2

* Update aiohttp from 3.1.0 to 3.1.1
2018-04-07 16:23:00 +03:00
Alexander Pantyukhin
c172da2b42 fix_readme (#143) 2018-04-06 21:29:38 +03:00
pyup.io bot
6e0cedaac7 Scheduled weekly dependency update for week 12 (#141)
* Update pytest from 3.4.2 to 3.5.0

* Update sphinx from 1.7.1 to 1.7.2

* Update cryptography from 2.2 to 2.2.1

* Update aiohttp from 3.0.9 to 3.1.0
2018-03-28 09:17:24 +07:00
pyup.io bot
475b666a8e Scheduled weekly dependency update for week 11 (#140)
* Update cryptography from 2.1.4 to 2.2

* Update aiohttp from 3.0.7 to 3.0.9
2018-03-23 14:46:29 +07:00
pyup.io bot
363f3b71c0 Scheduled weekly dependency update for week 10 (#138)
* Update pytest from 3.4.1 to 3.4.2

* Update aiohttp from 3.0.6 to 3.0.7
2018-03-12 19:20:07 +02:00
Oleh Kuchuk
9da55517b2 correct example linking (#136) 2018-03-06 14:21:40 +02:00
pyup.io bot
d375b22f1b Scheduled weekly dependency update for week 09 (#135)
* Update pytest from 3.3.2 to 3.4.1

* Update coverage from 4.4.2 to 4.5.1

* Update sphinx from 1.6.6 to 1.7.1

* Update aiohttp-session from 2.1.0 to 2.3.0

* Update aioredis from 1.0.0 to 1.1.0

* Update aiohttp from 2.3.9 to 3.0.6
2018-03-05 19:38:35 +02:00
Andrew Svetlov
4506c306a7 Relax travis matrix 2018-02-26 17:50:56 +02:00
Phil Elson
9b9b848fdd Two trivial typos. (#129) 2018-02-01 10:50:58 +02:00
Eduard Nabokov
1679f6713b Update docs and demo with login required, has permission (#128)
* Work on

* Update docs with login_required and has_permission
2018-01-24 12:29:20 +02:00
pyup.io bot
f9628b0ac1 Update aiohttp from 2.3.7 to 2.3.9 (#127) 2018-01-23 11:31:22 +02:00
pyup.io bot
f8940c0696 Scheduled weekly dependency update for week 01 (#126)
* Update pytest from 3.3.1 to 3.3.2

* Update sphinx from 1.6.5 to 1.6.6

* Update aiopg from 0.13.1 to 0.13.2
2018-01-08 23:42:12 +02:00
Grygorii Yermolenko
5d1195b85d Small updates in readme and docs (#125)
- add info about installation with extra ([]session])
- add links to examples
- move `Public api` header into related section
2018-01-03 12:09:11 +02:00
Andrew Svetlov
8360095011 Fix years 2018-01-02 14:31:39 +02:00
Grygorii Yermolenko
d89f6b7e3d Fix in demos related to async-await syntax (#123)
- remove 3.4 version from setup.py
- add cryprography package to requirements since it is used in
dictionary_auth
- add a few missed async kwords
2018-01-02 14:31:19 +02:00
pyup.io bot
db7dbd9b07 Scheduled weekly dependency update for week 00 (#124)
* Update pytest from 3.2.5 to 3.3.1

* Update aiohttp-session from 1.2.1 to 2.1.0

* Update aiohttp from 2.3.3 to 2.3.7

* Update pytest-aiohttp from 0.1.3 to 0.3.0
2018-01-02 14:28:32 +02:00
Andrew Svetlov
5b2ff779c3 Switch to async/await syntax 2017-12-13 16:51:46 +02:00
pyup.io bot
b9dee120c3 Scheduled weekly dependency update for week 47 (#115)
* Update pytest from 3.2.3 to 3.2.5

* Update aiohttp-session from 1.2.0 to 1.2.1

* Update aioredis from 0.3.5 to 1.0.0

* Update aiohttp from 2.3.2 to 2.3.3
2017-11-22 19:59:14 +02:00
Andrew Svetlov
aff9a6a915 Bump to 0.2.0 2017-11-17 17:54:46 +02:00
Andrew Lytvyn
92e6fec6f5 is_anonymous, login_required, has_permission helpers (#114)
* add is_anonymous helper function and login_required, has_permission decorators

* add docs for `is_anonymous`, `login_required` and `has_permission` functions

* permission can be `enum.Enum` object; cover with tests

* isort fix
2017-11-17 17:51:40 +02:00
pyup.io bot
810312b508 Scheduled weekly dependency update for week 46 (#113)
* Update coverage from 4.4.1 to 4.4.2

* Update aiohttp-session from 1.0.1 to 1.2.0

* Update aioredis from 0.3.4 to 0.3.5

* Update aiohttp from 2.3.1 to 2.3.2
2017-11-13 16:46:55 +02:00
pyup.io bot
18a04b879e Scheduled weekly dependency update for week 44 (#111)
* Update flake8 from 3.4.1 to 3.5.0

* Update sphinx from 1.6.4 to 1.6.5

* Update aioredis from 0.3.3 to 0.3.4

* Update aiohttp from 2.2.5 to 2.3.1
2017-10-30 16:41:06 +02:00
Andrew Svetlov
cd833edb6c Update trove classifiers 2017-10-17 12:41:11 +03:00
Andrew Svetlov
0694e6e084 Add autodeployment on travis 2017-10-17 12:39:18 +03:00
Andrew Svetlov
63870d992e Bump to 0.1.2 2017-10-17 12:37:09 +03:00
Alex Kuzmenko
aef24fae3d aiohttp-session is not required (#107)
* aiohttp_session is not required

* fix code coverage

* has_aiohttp_session -> HAS_AIOHTTP_SESSION
2017-10-17 12:32:53 +03:00
Nikolay Novik
747ec05cfb Merge pull request #109 from alxpy/alxpy-patch-7
Added new python versions to travis-ci
2017-10-10 16:51:15 +03:00
Alex Kuzmenko
66391b9f25 added new python versions to travis-ci 2017-10-10 16:44:17 +03:00
pyup.io bot
a46ca6ec68 Scheduled weekly dependency update for week 41 (#106)
* Update pytest from 3.2.2 to 3.2.3

* Update sphinx from 1.6.3 to 1.6.4
2017-10-10 14:39:07 +03:00
Devin Fee
1a9ab6424e added simplistic dictionary_auth example (#105) 2017-09-19 11:54:37 +03:00
pyup.io bot
b0895806af Scheduled weekly dependency update for week 38 (#104)
* Update pytest-cov from 2.4.0 to 2.5.1

* Update coverage from 4.3.4 to 4.4.1

* Update pytest-aiohttp from 0.1.2 to 0.1.3
2017-09-18 18:27:15 +03:00
Nikolay Novik
dbac083096 Merge pull request #102 from aio-libs/pyup-update-aiohttp-session-1.0.0-to-1.0.1
Update aiohttp-session to 1.0.1
2017-09-14 21:11:53 +03:00
pyup.io bot
5811ab90c8 Update pytest from 3.2.0 to 3.2.2 (#99) 2017-09-14 13:20:20 +03:00
Andrew Svetlov
4a0a078976 Create .pyup.yml 2017-09-14 13:20:00 +03:00
pyup-bot
22c51b5fd0 Update aiohttp-session from 1.0.0 to 1.0.1 2017-09-14 13:19:18 +03:00
pyup.io bot
921506c3c4 Update aiopg from 0.13.0 to 0.13.1 (#100) 2017-09-14 13:18:49 +03:00
pyup.io bot
d30a158345 Update flake8 from 3.3.0 to 3.4.1 (#97) 2017-08-04 12:59:21 +03:00
pyup.io bot
df198ae8d1 Update aiohttp from 2.2.3 to 2.2.5 (#96) 2017-08-04 12:26:39 +03:00
pyup.io bot
05a4cc03d2 Update aiohttp-session from 0.8.0 to 1.0.0 (#91) 2017-08-04 12:25:48 +03:00
pyup.io bot
bbb41dd3ad Update pytest from 3.1.3 to 3.2.0 (#94) 2017-08-02 09:29:27 +03:00
pyup.io bot
f716fb353b Update pytest from 3.1.2 to 3.1.3 (#89) 2017-07-24 09:59:09 +03:00
Thijs Triemstra
e99ce6ba23 update passlib url (#90) 2017-07-24 09:58:54 +03:00
pyup.io bot
6ebf9355fc Update aiohttp from 2.2.2 to 2.2.3 (#88) 2017-07-04 19:26:50 +03:00
pyup.io bot
d473f57e8e Update aioredis from 0.3.2 to 0.3.3 (#84) 2017-07-03 13:04:48 +03:00
pyup.io bot
7ab68c9f6d Update sphinx from 1.6.2 to 1.6.3 (#85) 2017-07-03 13:04:30 +03:00
pyup.io bot
b7dbe3ae16 Update aiohttp from 2.2.0 to 2.2.2 (#87) 2017-07-03 13:04:10 +03:00
Nikolay Novik
1b52d4b76b Merge pull request #82 from aio-libs/pyup-update-aiohttp-2.1.0-to-2.2.0
Update aiohttp to 2.2.0
2017-06-29 00:31:08 +03:00
Nikolay Novik
5d89f5feed Merge pull request #83 from aio-libs/pyup-update-aioredis-0.3.1-to-0.3.2
Update aioredis to 0.3.2
2017-06-29 00:30:54 +03:00
pyup-bot
640ae0fe72 Update aioredis from 0.3.1 to 0.3.2 2017-06-21 11:29:34 +03:00
pyup.io bot
352d1f4526 Update pytest from 3.1.1 to 3.1.2 (#81) 2017-06-20 16:10:45 +03:00
pyup-bot
aab14aedae Update aiohttp from 2.1.0 to 2.2.0 2017-06-20 14:51:33 +03:00
Nikolay Novik
6e0864d088 Merge pull request #80 from aio-libs/pyup-update-pytest-3.1.0-to-3.1.1
Update pytest to 3.1.1
2017-06-08 22:23:59 +03:00
pyup-bot
4de9d8f5f9 Update pytest from 3.1.0 to 3.1.1 2017-05-31 05:14:57 -07:00
Thanos Lefteris
1009a29a63 Add asyncio trove classifier (#69) 2017-05-28 14:08:53 -07:00
pyup.io bot
867c8d8e07 Update pytest from 3.0.7 to 3.1.0 (#77) 2017-05-28 14:08:13 -07:00
pyup.io bot
118f1f473a Update sphinx from 1.5.5 to 1.6.2 (#79) 2017-05-28 14:07:47 -07:00
pyup.io bot
d276618899 Update aioredis from 0.3.0 to 0.3.1 (#71) 2017-05-26 09:37:32 -07:00
pyup.io bot
86a7733815 Update aiohttp from 2.0.7 to 2.1.0 (#78) 2017-05-26 09:37:13 -07:00
pyup.io bot
8432f680e4 Update passlib from 1.7.0 to 1.7.1 (#67) 2017-04-13 20:45:28 +03:00
pyup.io bot
0d2d2a1c96 Update aiohttp from 2.0.6 to 2.0.7 (#66) 2017-04-13 19:47:20 +03:00
Nikolay Novik
d714f82319 Merge pull request #38 from aio-libs/pyup-update-aioredis-0.2.9-to-0.3.0
Update aioredis to 0.3.0
2017-04-09 10:36:28 +03:00
Nikolay Novik
14bd43fe4f Merge pull request #58 from aio-libs/pyup-update-flake8-3.2.1-to-3.3.0
Update flake8 to 3.3.0
2017-04-09 10:35:50 +03:00
Nikolay Novik
401ebf130a Merge pull request #62 from aio-libs/pyup-update-sphinx-1.5.3-to-1.5.5
Update sphinx to 1.5.5
2017-04-09 10:35:38 +03:00
Nikolay Novik
c84a82d3dc Merge pull request #63 from aio-libs/pyup-update-aiohttp-2.0.3-to-2.0.6
Update aiohttp to 2.0.6
2017-04-09 10:35:27 +03:00
pyup-bot
08bdad3d85 Update aiohttp from 2.0.3 to 2.0.6 2017-04-06 18:26:21 +03:00
pyup-bot
d7b6a911b9 Update sphinx from 1.5.3 to 1.5.5 2017-04-03 18:48:41 +03:00
pyup-bot
65cebd3ff0 Update flake8 from 3.2.1 to 3.3.0 2017-03-26 00:59:55 +02:00
Nikolay Novik
c13d9b4c70 Merge pull request #49 from aio-libs/pyup-update-sphinx-1.5.2-to-1.5.3
Update sphinx to 1.5.3
2017-03-26 00:59:35 +02:00
Nikolay Novik
d591ad3caa Merge pull request #50 from aio-libs/pyup-update-pytest-3.0.6-to-3.0.7
Update pytest to 3.0.7
2017-03-26 00:59:25 +02:00
Nikolay Novik
73e55280b7 Merge pull request #57 from aio-libs/pyup-update-aiohttp-1.2.0-to-2.0.3
Update aiohttp to 2.0.3
2017-03-25 17:10:03 +02:00
pyup-bot
367d388cff Update aiohttp from 1.2.0 to 2.0.3 2017-03-24 23:50:06 +02:00
Nickolai Novik
d652f29df5 make compatible tests 2017-03-22 00:10:14 +02:00
pyup-bot
face5ddaa2 Update pytest from 3.0.6 to 3.0.7 2017-03-14 23:25:40 +02:00
pyup-bot
c523b4fa49 Update sphinx from 1.5.2 to 1.5.3 2017-02-25 22:30:33 -09:00
Nikolay Novik
6e4355ce3c Merge pull request #40 from alxpy/alxpy-patch-2
Fix code coverage
2017-01-25 16:16:15 +02:00
Nikolay Novik
4c92553761 Merge pull request #41 from alxpy/alxpy-patch-3
Add some labels
2017-01-25 16:15:52 +02:00
Alex Kuzmenko
d76ecf59fc Add pypi label 2017-01-25 13:29:57 +02:00
Alex Kuzmenko
a990a657c4 Add some labels 2017-01-25 00:51:02 +02:00
Alex Kuzmenko
ede5beeb41 Fix code coverage 2017-01-25 00:39:39 +02:00
Nikolay Novik
d22d3a1d1a Merge pull request #36 from aio-libs/pyup-update-sphinx-1.5.1-to-1.5.2
Update sphinx to 1.5.2
2017-01-24 22:40:35 +02:00
pyup-bot
962e022090 Update aioredis from 0.2.9 to 0.3.0 2017-01-24 22:30:10 +02:00
pyup-bot
4b1740a8e3 Update sphinx from 1.5.1 to 1.5.2 2017-01-24 22:29:42 +02:00
Nikolay Novik
a2bf4c9c00 Merge pull request #34 from aio-libs/pyup-update-pytest-3.0.5-to-3.0.6
Update pytest to 3.0.6
2017-01-24 22:29:18 +02:00
Nikolay Novik
c4f3c06476 Merge pull request #35 from aio-libs/pyup-update-coverage-4.3-to-4.3.4
Update coverage to 4.3.4
2017-01-24 22:29:02 +02:00
pyup-bot
929468b684 Update coverage from 4.3 to 4.3.4 2017-01-24 22:11:22 +02:00
pyup-bot
7e68c44de6 Update pytest from 3.0.5 to 3.0.6 2017-01-24 22:11:15 +02:00
Nikolay Novik
7d4a4802f3 Merge pull request #33 from aio-libs/jettify-patch-1
Update .travis.yml
2017-01-24 22:10:49 +02:00
Nikolay Novik
7bd5c37c8a Update .travis.yml 2017-01-24 22:06:19 +02:00
Nikolay Novik
87942913c9 Merge pull request #30 from alxpy/update_readme
Update readme
2017-01-24 14:50:49 +02:00
Nikolay Novik
69743859a1 Merge pull request #32 from alxpy/travis_ci_labels
Add travis-ci labels
2017-01-24 14:49:09 +02:00
Alex Kuzmenko
1d596c4a3d Add travis-ci labels 2017-01-24 14:36:34 +02:00
Nikolay Novik
88b8ffbf5c Merge pull request #20 from alanc10n/DocOptionsFix
Remove unknown option github_style
2017-01-24 12:59:59 +02:00
Alex Kuzmenko
076c7f1d5f Update readme 2017-01-24 02:31:06 +02:00
Alan Christianson
474209d945 Remove unknown option github_style 2017-01-09 13:46:48 -07:00
pyup.io bot
131ee39bf6 Update coverage from 4.2 to 4.3 (#17) 2016-12-28 05:53:49 +02:00
pyup.io bot
8163d72b2d Update aiohttp from 1.1.6 to 1.2.0 (#15) 2016-12-28 05:53:14 +02:00
Nikolay Novik
679db05664 Merge pull request #14 from aio-libs/pyup-update-sphinx-1.5-to-1.5.1
Update sphinx to 1.5.1
2016-12-13 18:17:03 +02:00
pyup-bot
1ace967956 Update sphinx from 1.5 to 1.5.1 2016-12-13 18:17:14 +03:00
pyup.io bot
67d5590439 Update pytest from 3.0.4 to 3.0.5 (#13) 2016-12-05 18:37:59 +02:00
pyup.io bot
deae9e74e1 Update sphinx from 1.4.9 to 1.5 (#12) 2016-12-05 14:03:16 +02:00
pyup.io bot
76a6ecf86a Update aiohttp-session from 0.7.1 to 0.8.0 (#11) 2016-12-05 14:03:01 +02:00
pyup.io bot
2fc73acfb7 Update aiopg from 0.12.0 to 0.13.0 (#10) 2016-12-02 16:09:24 +02:00
pyup.io bot
2202eb3faa Update aiohttp from 1.1.5 to 1.1.6 (#9) 2016-12-02 15:37:00 +02:00
pyup.io bot
9cd055b36e Initial Update (#8)
* Pin flake8 to latest version 3.2.1

* Update passlib from 1.6.5 to 1.7.0

* Pin aiohttp to latest version 1.1.5

* Pin aiohttp-session to latest version 0.7.1

* Update aioredis from 0.2.8 to 0.2.9

* Pin pep257 to latest version 0.7.0

* Pin pytest-aiohttp to latest version 0.1.2

* Pin aiopg to latest version 0.12.0

* Pin pytest to latest version 3.0.4

* Pin sphinx to latest version 1.4.9

* Pin coverage to latest version 4.2

* Pin pytest-cov to latest version 2.4.0
2016-11-24 13:13:11 +02:00
48 changed files with 1651 additions and 660 deletions

38
.github/workflows/ci.yaml vendored Normal file
View File

@@ -0,0 +1,38 @@
name: Test
on: pull_request
jobs:
mypy:
name: Check annotations with Mypy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- run: pip install aiohttp mypy
- run: mypy
test:
name: Tests
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.6, 3.7, 3.8, 3.9]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
pip install --upgrade pip
pip install -r requirements-dev.txt
pip install codecov
- name: Run tests
run: |
make coverage
- name: Upload coverage to Codecov
run: |
codecov

1
.gitignore vendored
View File

@@ -56,3 +56,4 @@ docs/_build/
target/
coverage
.pytest_cache

37
.mypy.ini Normal file
View File

@@ -0,0 +1,37 @@
[mypy]
files = aiohttp_security, demo, tests
check_untyped_defs = True
follow_imports_for_stubs = True
disallow_any_decorated = True
disallow_any_generics = True
disallow_incomplete_defs = True
disallow_subclassing_any = True
disallow_untyped_calls = True
disallow_untyped_decorators = True
disallow_untyped_defs = True
implicit_reexport = False
no_implicit_optional = True
show_error_codes = True
strict_equality = True
warn_incomplete_stub = True
warn_redundant_casts = True
warn_unreachable = True
warn_unused_ignores = True
disallow_any_unimported = True
warn_return_any = True
[mypy-aiohttp_security.abc.*]
disallow_any_decorated = False
[mypy-tests.*]
disallow_any_decorated = False
disallow_untyped_defs = False
[mypy-aiopg.*]
ignore_missing_imports = True
[mypy-aioredis.*]
ignore_missing_imports = True
[mypy-passlib.*]
ignore_missing_imports = True

4
.pyup.yml Normal file
View File

@@ -0,0 +1,4 @@
# Label PRs with `deps-update` label
label_prs: deps-update
schedule: every week

View File

@@ -1,22 +0,0 @@
language: python
python:
- 3.4
- 3.5
- nightly
install:
- pip install --upgrade pip
- pip install -r requirements-dev.txt
- pip install codecov
script:
- flake8 aiohttp_security tests
- coverage run --source=aiohttp_security setup.py test
after_success:
- codecov
env:
matrix:
- PYTHONASYNCIODEBUG=x
- PYTHONASYNCIODEBUG=

View File

@@ -1,2 +1,33 @@
Changes
=======
0.4.0 (2018-09-27)
------------------
- Bump minimal supported ``aiohttp`` version to 3.2
- Use ``request.config_dict`` for accessing ``jinja2`` environment. It
allows to reuse jinja rendering engine from parent application.
0.3.0 (2018-09-06)
------------------
- Deprecate ``login_required`` and ``has_permission`` decorators.
Use ``check_authorized`` and ``check_permission`` helper functions instead.
- Bump supported ``aiohttp`` version to 3.0+
- Enable strong warnings mode for test suite, clean-up all deprecation
warnings.
- Polish documentation
0.2.0 (2017-11-17)
------------------
- Add ``is_anonymous``, ``login_required``, ``has_permission`` helpers (#114)
0.1.2 (2017-10-17)
------------------
- Make aiohttp-session optional dependency (#107)

View File

@@ -186,7 +186,7 @@ Apache License
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2015-2016 Andrew Svetlov
Copyright 2015-2018 Andrew Svetlov and aio-libs team.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -1,22 +1,52 @@
aiohttp_security
================
.. image:: https://travis-ci.com/aio-libs/aiohttp-security.svg?branch=master
:target: https://travis-ci.com/aio-libs/aiohttp-security
.. image:: https://codecov.io/github/aio-libs/aiohttp-security/coverage.svg?branch=master
:target: https://codecov.io/github/aio-libs/aiohttp-security
.. image:: https://readthedocs.org/projects/aiohttp-security/badge/?version=latest
:target: https://aiohttp-security.readthedocs.io/
.. image:: https://img.shields.io/pypi/v/aiohttp-security.svg
:target: https://pypi.python.org/pypi/aiohttp-security
The library provides identity and autorization for `aiohttp.web`__.
The library provides identity and authorization for `aiohttp.web`__.
.. _aiohttp_web: http://aiohttp.readthedocs.org/en/latest/web.html
__ aiohttp_web_
Usage
-----
To install type ``pip install aiohttp_security``.
Launch ``make doc`` and see examples or look under **demo** directory for a
sample project.
Installation
------------
Simplest case (authorization via cookies) ::
$ pip install aiohttp_security
With `aiohttp-session` support ::
$ pip install aiohttp_security[session]
Examples
--------
Take a look at examples:
`Basic example`_
`Example with DB auth`_
.. _`Basic example`: docs/example.rst
.. _`Example with db auth`: docs/example_db_auth.rst
and demos at **demo** directory.
Documentation
-------------
https://aiohttp-security.readthedocs.io/
Develop
-------
``pip install -r requirements-dev``
``pip install -r requirements-dev.txt``
License

View File

@@ -1,13 +1,18 @@
from .abc import AbstractIdentityPolicy, AbstractAuthorizationPolicy
from .api import remember, forget, setup, authorized_userid, permits
from .abc import AbstractAuthorizationPolicy, AbstractIdentityPolicy
from .api import (authorized_userid, forget, has_permission,
is_anonymous, login_required, permits, remember,
setup, check_authorized, check_permission)
from .cookies_identity import CookiesIdentityPolicy
from .session_identity import SessionIdentityPolicy
from .jwt_identity import JWTIdentityPolicy
__version__ = '0.1.1'
__version__ = '0.4.0'
__all__ = ('AbstractIdentityPolicy', 'AbstractAuthorizationPolicy',
'CookiesIdentityPolicy', 'SessionIdentityPolicy',
'JWTIdentityPolicy',
'remember', 'forget', 'authorized_userid',
'permits', 'setup')
'permits', 'setup', 'is_anonymous',
'login_required', 'has_permission',
'check_authorized', 'check_permission')

View File

@@ -1,21 +1,23 @@
import abc
import asyncio
from enum import Enum
from typing import Any, Optional, Union
from aiohttp import web
# see http://plope.com/pyramid_auth_design_api_postmortem
class AbstractIdentityPolicy(metaclass=abc.ABCMeta):
@asyncio.coroutine
@abc.abstractmethod
def identify(self, request):
async def identify(self, request: web.Request) -> Optional[str]:
"""Return the claimed identity of the user associated request or
``None`` if no identity can be found associated with the request."""
pass
@asyncio.coroutine
@abc.abstractmethod
def remember(self, request, response, identity, **kwargs):
async def remember(self, request: web.Request, response: web.StreamResponse,
identity: str, **kwargs: Any) -> None:
"""Remember identity.
Modify response object by filling it's headers with remembered user.
@@ -25,9 +27,8 @@ class AbstractIdentityPolicy(metaclass=abc.ABCMeta):
"""
pass
@asyncio.coroutine
@abc.abstractmethod
def forget(self, request, response):
async def forget(self, request: web.Request, response: web.StreamResponse) -> None:
""" Modify response which can be used to 'forget' the
current identity on subsequent requests."""
pass
@@ -35,9 +36,9 @@ class AbstractIdentityPolicy(metaclass=abc.ABCMeta):
class AbstractAuthorizationPolicy(metaclass=abc.ABCMeta):
@asyncio.coroutine
@abc.abstractmethod
def permits(self, identity, permission, context=None):
async def permits(self, identity: str, permission: Union[str, Enum],
context: Any = None) -> bool:
"""Check user permissions.
Return True if the identity is allowed the permission in the
@@ -45,9 +46,8 @@ class AbstractAuthorizationPolicy(metaclass=abc.ABCMeta):
"""
pass
@asyncio.coroutine
@abc.abstractmethod
def authorized_userid(self, identity):
async def authorized_userid(self, identity: str) -> Optional[str]:
"""Retrieve authorized user id.
Return the user_id of the user identified by the identity

View File

@@ -1,24 +1,33 @@
import asyncio
import enum
import warnings
from functools import wraps
from typing import Any, Callable, Optional, TypeVar, Union
from aiohttp import web
from aiohttp_security.abc import (AbstractIdentityPolicy,
AbstractAuthorizationPolicy)
from aiohttp_security.abc import AbstractAuthorizationPolicy, AbstractIdentityPolicy
IDENTITY_KEY = 'aiohttp_security_identity_policy'
AUTZ_KEY = 'aiohttp_security_autz_policy'
# _AIP/_AAP are shorthand for Optional[policy] when we retrieve from request.
_AAP = Optional[AbstractAuthorizationPolicy]
_AIP = Optional[AbstractIdentityPolicy]
_Handler = TypeVar('_Handler', bound=Union[Callable[[web.Request], Any],
Callable[[object, web.Request], Any]])
@asyncio.coroutine
def remember(request, response, identity, **kwargs):
async def remember(request: web.Request, response: web.StreamResponse,
identity: str, **kwargs: Any) -> None:
"""Remember identity into response.
The action is performed by identity_policy.remember()
Usually the idenity is stored in user cookies homehow but may be
Usually the identity is stored in user cookies somehow but may be
pushed into custom header also.
"""
assert isinstance(identity, str), identity
assert identity
identity_policy = request.app.get(IDENTITY_KEY)
identity_policy = request.config_dict.get(IDENTITY_KEY)
if identity_policy is None:
text = ("Security subsystem is not initialized, "
"call aiohttp_security.setup(...) first")
@@ -26,17 +35,16 @@ def remember(request, response, identity, **kwargs):
# output and rendered page we add same message to *reason* and
# *text* arguments.
raise web.HTTPInternalServerError(reason=text, text=text)
yield from identity_policy.remember(request, response, identity, **kwargs)
await identity_policy.remember(request, response, identity, **kwargs)
@asyncio.coroutine
def forget(request, response):
async def forget(request: web.Request, response: web.StreamResponse) -> None:
"""Forget previously remembered identity.
Usually it clears cookie or server-side storage to forget user
session.
"""
identity_policy = request.app.get(IDENTITY_KEY)
identity_policy = request.config_dict.get(IDENTITY_KEY)
if identity_policy is None:
text = ("Security subsystem is not initialized, "
"call aiohttp_security.setup(...) first")
@@ -44,37 +52,129 @@ def forget(request, response):
# output and rendered page we add same message to *reason* and
# *text* arguments.
raise web.HTTPInternalServerError(reason=text, text=text)
yield from identity_policy.forget(request, response)
await identity_policy.forget(request, response)
@asyncio.coroutine
def authorized_userid(request):
identity_policy = request.app.get(IDENTITY_KEY)
autz_policy = request.app.get(AUTZ_KEY)
async def authorized_userid(request: web.Request) -> Optional[str]:
identity_policy: _AIP = request.config_dict.get(IDENTITY_KEY)
autz_policy: _AAP = request.config_dict.get(AUTZ_KEY)
if identity_policy is None or autz_policy is None:
return None
identity = yield from identity_policy.identify(request)
identity = await identity_policy.identify(request)
if identity is None:
return None # non-registered user has None user_id
user_id = yield from autz_policy.authorized_userid(identity)
user_id = await autz_policy.authorized_userid(identity)
return user_id
@asyncio.coroutine
def permits(request, permission, context=None):
assert isinstance(permission, str), permission
async def permits(request: web.Request, permission: Union[str, enum.Enum],
context: Any = None) -> bool:
assert isinstance(permission, (str, enum.Enum)), permission
assert permission
identity_policy = request.app.get(IDENTITY_KEY)
autz_policy = request.app.get(AUTZ_KEY)
identity_policy: _AIP = request.config_dict.get(IDENTITY_KEY)
autz_policy: _AAP = request.config_dict.get(AUTZ_KEY)
if identity_policy is None or autz_policy is None:
return True
identity = yield from identity_policy.identify(request)
# non-registered user still may has some permissions
access = yield from autz_policy.permits(identity, permission, context)
identity = await identity_policy.identify(request)
# non-registered user still may have some permissions
access = await autz_policy.permits(identity, permission, context)
return access
def setup(app, identity_policy, autz_policy):
async def is_anonymous(request: web.Request) -> bool:
"""Check if user is anonymous.
User is considered anonymous if there is not identity
in request.
"""
identity_policy = request.config_dict.get(IDENTITY_KEY)
if identity_policy is None:
return True
identity = await identity_policy.identify(request)
if identity is None:
return True
return False
async def check_authorized(request: web.Request) -> str:
"""Checker that raises HTTPUnauthorized for anonymous users.
"""
userid = await authorized_userid(request)
if userid is None:
raise web.HTTPUnauthorized()
return userid
def login_required(fn: _Handler) -> _Handler:
"""Decorator that restrict access only for authorized users.
User is considered authorized if authorized_userid
returns some value.
"""
@wraps(fn)
async def wrapped(*args: Union[object, web.Request]) -> Any:
request = args[-1]
if not isinstance(request, web.Request):
msg = ("Incorrect decorator usage. "
"Expecting `def handler(request)` "
"or `def handler(self, request)`.")
raise RuntimeError(msg)
await check_authorized(request)
return await fn(*args) # type: ignore[arg-type]
warnings.warn("login_required decorator is deprecated, "
"use check_authorized instead",
DeprecationWarning)
return wrapped # type: ignore[return-value]
async def check_permission(request: web.Request, permission: Union[str, enum.Enum],
context: Any = None) -> None:
"""Checker that passes only to authoraised users with given permission.
If user is not authorized - raises HTTPUnauthorized,
if user is authorized and does not have permission -
raises HTTPForbidden.
"""
await check_authorized(request)
allowed = await permits(request, permission, context)
if not allowed:
raise web.HTTPForbidden()
def has_permission(permission: Union[str, enum.Enum], context: Any = None): # type: ignore
"""Decorator that restricts access only for authorized users
with correct permissions.
If user is not authorized - raises HTTPUnauthorized,
if user is authorized and does not have permission -
raises HTTPForbidden.
"""
def wrapper(fn): # type: ignore
@wraps(fn)
async def wrapped(*args, **kwargs): # type: ignore
request = args[-1]
if not isinstance(request, web.Request):
msg = ("Incorrect decorator usage. "
"Expecting `def handler(request)` "
"or `def handler(self, request)`.")
raise RuntimeError(msg)
await check_permission(request, permission, context)
return await fn(*args, **kwargs)
return wrapped
warnings.warn("has_permission decorator is deprecated, "
"use check_permission instead",
DeprecationWarning)
return wrapper
def setup(app: web.Application, identity_policy: AbstractIdentityPolicy,
autz_policy: AbstractAuthorizationPolicy) -> None:
assert isinstance(identity_policy, AbstractIdentityPolicy), identity_policy
assert isinstance(autz_policy, AbstractAuthorizationPolicy), autz_policy

View File

@@ -5,33 +5,32 @@ more handy.
"""
import asyncio
from aiohttp import web
from typing import Any, NewType, Optional, Union, cast
from .abc import AbstractIdentityPolicy
sentinel = object()
_Sentinel = NewType('_Sentinel', object)
sentinel = _Sentinel(object())
class CookiesIdentityPolicy(AbstractIdentityPolicy):
def __init__(self):
def __init__(self) -> None:
self._cookie_name = 'AIOHTTP_SECURITY'
self._max_age = 30 * 24 * 3600
@asyncio.coroutine
def identify(self, request):
identity = request.cookies.get(self._cookie_name)
return identity
async def identify(self, request: web.Request) -> Optional[str]:
return request.cookies.get(self._cookie_name)
@asyncio.coroutine
def remember(self, request, response, identity, max_age=sentinel,
**kwargs):
async def remember(self, request: web.Request, response: web.StreamResponse,
identity: str, max_age: Union[_Sentinel, Optional[int]] = sentinel,
**kwargs: Any) -> None:
if max_age is sentinel:
max_age = self._max_age
max_age = cast(Optional[int], max_age)
response.set_cookie(self._cookie_name, identity,
max_age=max_age, **kwargs)
@asyncio.coroutine
def forget(self, request, response):
async def forget(self, request: web.Request, response: web.StreamResponse) -> None:
response.del_cookie(self._cookie_name)

View File

@@ -0,0 +1,51 @@
"""Identity policy for storing info in the jwt token.
"""
from typing import Optional
from aiohttp import web
from .abc import AbstractIdentityPolicy
try:
import jwt
HAS_JWT = True
except ImportError: # pragma: no cover
HAS_JWT = False
AUTH_HEADER_NAME = 'Authorization'
AUTH_SCHEME = 'Bearer '
class JWTIdentityPolicy(AbstractIdentityPolicy):
def __init__(self, secret: str, algorithm: str = 'HS256'):
if not HAS_JWT:
raise RuntimeError('Please install `PyJWT`')
self.secret = secret
self.algorithm = algorithm
async def identify(self, request: web.Request) -> Optional[str]:
header_identity = request.headers.get(AUTH_HEADER_NAME)
if header_identity is None:
return None
if not header_identity.startswith(AUTH_SCHEME):
raise ValueError('Invalid authorization scheme. ' +
'Should be `{}<token>`'.format(AUTH_SCHEME))
token = header_identity.split(' ')[1].strip()
identity = jwt.decode(token,
self.secret,
algorithms=[self.algorithm])
return identity
async def remember(self, request: web.Request, response: web.StreamResponse,
identity: str, **kwargs: None) -> None:
pass
async def forget(self, request: web.Request, response: web.StreamResponse) -> None:
pass

View File

View File

@@ -4,29 +4,34 @@ aiohttp_session.setup() should be called on application initialization
to configure aiohttp_session properly.
"""
import asyncio
from aiohttp import web
try:
from aiohttp_session import get_session
HAS_AIOHTTP_SESSION = True
except ImportError: # pragma: no cover
HAS_AIOHTTP_SESSION = False
from .abc import AbstractIdentityPolicy
class SessionIdentityPolicy(AbstractIdentityPolicy):
def __init__(self, session_key='AIOHTTP_SECURITY'):
def __init__(self, session_key: str = 'AIOHTTP_SECURITY'):
self._session_key = session_key
@asyncio.coroutine
def identify(self, request):
session = yield from get_session(request)
if not HAS_AIOHTTP_SESSION: # pragma: no cover
raise ImportError(
'SessionIdentityPolicy requires `aiohttp_session`')
async def identify(self, request: web.Request) -> str:
session = await get_session(request)
return session.get(self._session_key)
@asyncio.coroutine
def remember(self, request, response, identity, **kwargs):
session = yield from get_session(request)
async def remember(self, request: web.Request, response: web.StreamResponse,
identity: str, **kwargs: None) -> None:
session = await get_session(request)
session[self._session_key] = identity
@asyncio.coroutine
def forget(self, request, response):
session = yield from get_session(request)
async def forget(self, request: web.Request, response: web.StreamResponse) -> None:
session = await get_session(request)
session.pop(self._session_key, None)

0
demo/__init__.py Normal file
View File

View File

View File

@@ -0,0 +1,62 @@
from enum import Enum
from typing import Any, Optional, Union
import sqlalchemy as sa
from aiohttp_security.abc import AbstractAuthorizationPolicy
from passlib.hash import sha256_crypt
from . import db
class DBAuthorizationPolicy(AbstractAuthorizationPolicy):
def __init__(self, dbengine: Any):
self.dbengine = dbengine
async def authorized_userid(self, identity: str) -> Optional[str]:
async with self.dbengine.acquire() as conn:
where = sa.and_(db.users.c.login == identity,
sa.not_(db.users.c.disabled)) # type: ignore[no-untyped-call]
query = db.users.count().where(where)
ret = await conn.scalar(query)
if ret:
return identity
else:
return None
async def permits(self, identity: str, permission: Union[str, Enum],
context: None = None) -> bool:
async with self.dbengine.acquire() as conn:
where = sa.and_(db.users.c.login == identity,
sa.not_(db.users.c.disabled)) # type: ignore[no-untyped-call]
query = db.users.select().where(where)
ret = await conn.execute(query)
user = await ret.fetchone()
if user is not None:
user_id = user[0]
is_superuser = user[3]
if is_superuser:
return True
where = db.permissions.c.user_id == user_id
query = db.permissions.select().where(where)
ret = await conn.execute(query)
result = await ret.fetchall()
if ret is not None:
for record in result:
if record.perm_name == permission:
return True
return False
async def check_credentials(db_engine: Any, username: str, password: str) -> bool:
async with db_engine.acquire() as conn:
where = sa.and_(db.users.c.login == username,
sa.not_(db.users.c.disabled)) # type: ignore[no-untyped-call]
query = db.users.select().where(where)
ret = await conn.execute(query)
user = await ret.fetchone()
if user is not None:
hashed = user[2]
return sha256_crypt.verify(password, hashed) # type: ignore[no-any-return]
return False

View File

@@ -0,0 +1,82 @@
from textwrap import dedent
from typing import NoReturn
from aiohttp import web
from aiohttp_security import (
remember, forget, authorized_userid,
check_permission, check_authorized,
)
from .db_auth import check_credentials
class Web(object):
index_template = dedent("""
<!doctype html>
<head></head>
<body>
<p>{message}</p>
<form action="/login" method="post">
Login:
<input type="text" name="login">
Password:
<input type="password" name="password">
<input type="submit" value="Login">
</form>
<a href="/logout">Logout</a>
</body>
""")
async def index(self, request: web.Request) -> web.Response:
username = await authorized_userid(request)
if username:
template = self.index_template.format(
message='Hello, {username}!'.format(username=username))
else:
template = self.index_template.format(message='You need to login')
response = web.Response(body=template.encode())
return response
async def login(self, request: web.Request) -> NoReturn:
invalid_resp = web.HTTPUnauthorized(body=b'Invalid username/password combination')
form = await request.post()
login = form.get('login')
password = form.get('password')
db_engine = request.app['db_engine']
if not (isinstance(login, str) and isinstance(password, str)):
raise invalid_resp
if await check_credentials(db_engine, login, password):
response = web.HTTPFound('/')
await remember(request, response, login)
raise response
raise invalid_resp
async def logout(self, request: web.Request) -> web.Response:
await check_authorized(request)
response = web.Response(body=b'You have been logged out')
await forget(request, response)
return response
async def internal_page(self, request: web.Request) -> web.Response:
await check_permission(request, 'public')
response = web.Response(
body=b'This page is visible for all registered users')
return response
async def protected_page(self, request: web.Request) -> web.Response:
await check_permission(request, 'protected')
response = web.Response(body=b'You are on protected page')
return response
def configure(self, app: web.Application) -> None:
router = app.router
router.add_route('GET', '/', self.index, name='index')
router.add_route('POST', '/login', self.login, name='login')
router.add_route('GET', '/logout', self.logout, name='logout')
router.add_route('GET', '/public', self.internal_page, name='public')
router.add_route('GET', '/protected', self.protected_page,
name='protected')

View File

@@ -1,4 +1,5 @@
import asyncio
from typing import Any, Tuple
from aiohttp import web
from aiohttp_session import setup as setup_session
@@ -9,19 +10,18 @@ from aiopg.sa import create_engine
from aioredis import create_pool
from demo.db_auth import DBAuthorizationPolicy
from demo.handlers import Web
from demo.database_auth.db_auth import DBAuthorizationPolicy
from demo.database_auth.handlers import Web
@asyncio.coroutine
def init(loop):
redis_pool = yield from create_pool(('localhost', 6379))
db_engine = yield from create_engine(user='aiohttp_security',
async def init(loop: asyncio.AbstractEventLoop) -> Tuple[Any, ...]:
redis_pool = await create_pool(('localhost', 6379))
db_engine = await create_engine(user='aiohttp_security',
password='aiohttp_security',
database='aiohttp_security',
host='127.0.0.1')
app = web.Application(loop=loop)
app.db_engine = db_engine
app = web.Application()
app['db_engine'] = db_engine
setup_session(app, RedisStorage(redis_pool))
setup_security(app,
SessionIdentityPolicy(),
@@ -31,24 +31,23 @@ def init(loop):
web_handlers.configure(app)
handler = app.make_handler()
srv = yield from loop.create_server(handler, '127.0.0.1', 8080)
srv = await loop.create_server(handler, '127.0.0.1', 8080)
print('Server started at http://127.0.0.1:8080')
return srv, app, handler
@asyncio.coroutine
def finalize(srv, app, handler):
async def finalize(srv: Any, app: Any, handler: Any) -> None:
sock = srv.sockets[0]
app.loop.remove_reader(sock.fileno())
sock.close()
yield from handler.finish_connections(1.0)
await handler.finish_connections(1.0)
srv.close()
yield from srv.wait_closed()
yield from app.finish()
await srv.wait_closed()
await app.finish()
def main():
def main() -> None:
loop = asyncio.get_event_loop()
srv, app, handler = loop.run_until_complete(init(loop))
try:

View File

@@ -1,67 +0,0 @@
import asyncio
import sqlalchemy as sa
from aiohttp_security.abc import AbstractAuthorizationPolicy
from passlib.hash import sha256_crypt
from . import db
class DBAuthorizationPolicy(AbstractAuthorizationPolicy):
def __init__(self, dbengine):
self.dbengine = dbengine
@asyncio.coroutine
def authorized_userid(self, identity):
with (yield from self.dbengine) as conn:
where = sa.and_(db.users.c.login == identity,
sa.not_(db.users.c.disabled))
query = db.users.count().where(where)
ret = yield from conn.scalar(query)
if ret:
return identity
else:
return None
@asyncio.coroutine
def permits(self, identity, permission, context=None):
if identity is None:
return False
with (yield from self.dbengine) as conn:
where = sa.and_(db.users.c.login == identity,
sa.not_(db.users.c.disabled))
query = db.users.select().where(where)
ret = yield from conn.execute(query)
user = yield from ret.fetchone()
if user is not None:
user_id = user[0]
is_superuser = user[3]
if is_superuser:
return True
where = db.permissions.c.user_id == user_id
query = db.permissions.select().where(where)
ret = yield from conn.execute(query)
result = yield from ret.fetchall()
if ret is not None:
for record in result:
if record.perm_name == permission:
return True
return False
@asyncio.coroutine
def check_credentials(db_engine, username, password):
with (yield from db_engine) as conn:
where = sa.and_(db.users.c.login == username,
sa.not_(db.users.c.disabled))
query = db.users.select().where(where)
ret = yield from conn.execute(query)
user = yield from ret.fetchone()
if user is not None:
hash = user[2]
return sha256_crypt.verify(password, hash)
return False

View File

View File

@@ -0,0 +1,39 @@
from enum import Enum
from typing import Dict, Optional, Union
from aiohttp_security.abc import AbstractAuthorizationPolicy
from .users import User
class DictionaryAuthorizationPolicy(AbstractAuthorizationPolicy):
def __init__(self, user_map: Dict[str, User]):
super().__init__()
self.user_map = user_map
async def authorized_userid(self, identity: str) -> Optional[str]:
"""Retrieve authorized user id.
Return the user_id of the user identified by the identity
or 'None' if no user exists related to the identity.
"""
return identity if identity in self.user_map else None
async def permits(self, identity: str, permission: Union[str, Enum],
context: None = None) -> bool:
"""Check user permissions.
Return True if the identity is allowed the permission in the
current context, else return False.
"""
# pylint: disable=unused-argument
user = self.user_map.get(identity)
if not user:
return False
return permission in user.permissions
async def check_credentials(user_map: Dict[str, User], username: str, password: str) -> bool:
user = user_map.get(username)
if not user:
return False
return user.password == password

View File

@@ -0,0 +1,98 @@
from textwrap import dedent
from typing import Dict, NoReturn
from aiohttp import web
from aiohttp_security import (
remember, forget, authorized_userid,
check_permission, check_authorized,
)
from .authz import check_credentials
from .users import User
index_template = dedent("""
<!doctype html>
<head></head>
<body>
<p>{message}</p>
<form action="/login" method="post">
Login:
<input type="text" name="username">
Password:
<input type="password" name="password">
<input type="submit" value="Login">
</form>
<a href="/logout">Logout</a>
</body>
""")
async def index(request: web.Request) -> web.Response:
username = await authorized_userid(request)
if username:
template = index_template.format(
message='Hello, {username}!'.format(username=username))
else:
template = index_template.format(message='You need to login')
return web.Response(
text=template,
content_type='text/html',
)
async def login(request: web.Request) -> NoReturn:
user_map: Dict[str, User] = request.app['user_map']
invalid_response = web.HTTPUnauthorized(body='Invalid username / password combination')
form = await request.post()
username = form.get('username')
password = form.get('password')
if not (isinstance(username, str) and isinstance(password, str)):
raise invalid_response
verified = await check_credentials(user_map, username, password)
if verified:
response = web.HTTPFound('/')
await remember(request, response, username)
raise response
raise invalid_response
async def logout(request: web.Request) -> web.Response:
await check_authorized(request)
response = web.Response(
text='You have been logged out',
content_type='text/html',
)
await forget(request, response)
return response
async def internal_page(request: web.Request) -> web.Response:
await check_permission(request, 'public')
response = web.Response(
text='This page is visible for all registered users',
content_type='text/html',
)
return response
async def protected_page(request: web.Request) -> web.Response:
await check_permission(request, 'protected')
response = web.Response(
text='You are on protected page',
content_type='text/html',
)
return response
def configure_handlers(app: web.Application) -> None:
router = app.router
router.add_get('/', index, name='index')
router.add_post('/login', login, name='login')
router.add_get('/logout', logout, name='logout')
router.add_get('/public', internal_page, name='public')
router.add_get('/protected', protected_page, name='protected')

View File

@@ -0,0 +1,33 @@
import base64
from cryptography import fernet
from aiohttp import web
from aiohttp_session import setup as setup_session
from aiohttp_session.cookie_storage import EncryptedCookieStorage
from aiohttp_security import setup as setup_security
from aiohttp_security import SessionIdentityPolicy
from demo.dictionary_auth.authz import DictionaryAuthorizationPolicy
from demo.dictionary_auth.handlers import configure_handlers
from demo.dictionary_auth.users import user_map
def make_app() -> web.Application:
app = web.Application()
app['user_map'] = user_map
configure_handlers(app)
# secret_key must be 32 url-safe base64-encoded bytes
fernet_key = fernet.Fernet.generate_key()
secret_key = base64.urlsafe_b64decode(fernet_key)
storage = EncryptedCookieStorage(secret_key, cookie_name='API_SESSION')
setup_session(app, storage)
policy = SessionIdentityPolicy()
setup_security(app, policy, DictionaryAuthorizationPolicy(user_map))
return app
if __name__ == '__main__':
web.run_app(make_app(), port=9000)

View File

@@ -0,0 +1,15 @@
from typing import NamedTuple, Tuple
class User(NamedTuple):
username: str
password: str
permissions: Tuple[str, ...]
user_map = {
user.username: user for user in [
User('devin', 'password', ('public',)),
User('jack', 'password', ('public', 'protected',)),
]
}

View File

@@ -1,95 +0,0 @@
import asyncio
import functools
from aiohttp import web
from aiohttp_security import remember, forget, authorized_userid, permits
from .db_auth import check_credentials
def require(permission):
def wrapper(f):
@asyncio.coroutine
@functools.wraps(f)
def wrapped(self, request):
has_perm = yield from permits(request, permission)
if not has_perm:
message = 'User has no permission {}'.format(permission)
raise web.HTTPForbidden(body=message.encode())
return (yield from f(self, request))
return wrapped
return wrapper
class Web(object):
index_template = """
<!doctype html>
<head>
</head>
<body>
<p>{message}</p>
<form action="/login" method="post">
Login:
<input type="text" name="login">
Password:
<input type="password" name="password">
<input type="submit" value="Login">
</form>
<a href="/logout">Logout</a>
</body>
"""
@asyncio.coroutine
def index(self, request):
username = yield from authorized_userid(request)
if username:
template = self.index_template.format(
message='Hello, {username}!'.format(username=username))
else:
template = self.index_template.format(message='You need to login')
response = web.Response(body=template.encode())
return response
@asyncio.coroutine
def login(self, request):
response = web.HTTPFound('/')
form = yield from request.post()
login = form.get('login')
password = form.get('password')
db_engine = request.app.db_engine
if (yield from check_credentials(db_engine, login, password)):
yield from remember(request, response, login)
return response
return web.HTTPUnauthorized(
body=b'Invalid username/password combination')
@require('public')
@asyncio.coroutine
def logout(self, request):
response = web.Response(body=b'You have been logged out')
yield from forget(request, response)
return response
@require('public')
@asyncio.coroutine
def internal_page(self, request):
response = web.Response(
body=b'This page is visible for all registered users')
return response
@require('protected')
@asyncio.coroutine
def protected_page(self, request):
response = web.Response(body=b'You are on protected page')
return response
def configure(self, app):
router = app.router
router.add_route('GET', '/', self.index, name='index')
router.add_route('POST', '/login', self.login, name='login')
router.add_route('GET', '/logout', self.logout, name='logout')
router.add_route('GET', '/public', self.internal_page, name='public')
router.add_route('GET', '/protected', self.protected_page,
name='protected')

View File

@@ -0,0 +1,96 @@
from enum import Enum
from typing import NoReturn, Optional, Union
from aiohttp import web
from aiohttp_session import SimpleCookieStorage, session_middleware
from aiohttp_security import check_permission, \
is_anonymous, remember, forget, \
setup as setup_security, SessionIdentityPolicy
from aiohttp_security.abc import AbstractAuthorizationPolicy
# Demo authorization policy for only one user.
# User 'jack' has only 'listen' permission.
# For more complicated authorization policies see examples
# in the 'demo' directory.
class SimpleJack_AuthorizationPolicy(AbstractAuthorizationPolicy):
async def authorized_userid(self, identity: str) -> Optional[str]:
"""Retrieve authorized user id.
Return the user_id of the user identified by the identity
or 'None' if no user exists related to the identity.
"""
return identity if identity == 'jack' else None
async def permits(self, identity: str, permission: Union[str, Enum],
context: None = None) -> bool:
"""Check user permissions.
Return True if the identity is allowed the permission
in the current context, else return False.
"""
return identity == 'jack' and permission in ('listen',)
async def handler_root(request: web.Request) -> web.Response:
is_logged = not await is_anonymous(request)
return web.Response(text='''<html><head></head><body>
Hello, I'm Jack, I'm {logged} logged in.<br /><br />
<a href="/login">Log me in</a><br />
<a href="/logout">Log me out</a><br /><br />
Check my permissions,
when i'm logged in and logged out.<br />
<a href="/listen">Can I listen?</a><br />
<a href="/speak">Can I speak?</a><br />
</body></html>'''.format(
logged='' if is_logged else 'NOT',
), content_type='text/html')
async def handler_login_jack(request: web.Request) -> NoReturn:
redirect_response = web.HTTPFound('/')
await remember(request, redirect_response, 'jack')
raise redirect_response
async def handler_logout(request: web.Request) -> NoReturn:
redirect_response = web.HTTPFound('/')
await forget(request, redirect_response)
raise redirect_response
async def handler_listen(request: web.Request) -> web.Response:
await check_permission(request, 'listen')
return web.Response(body="I can listen!")
async def handler_speak(request: web.Request) -> web.Response:
await check_permission(request, 'speak')
return web.Response(body="I can speak!")
async def make_app() -> web.Application:
#
# WARNING!!!
# Never use SimpleCookieStorage on production!!!
# Its highly insecure!!!
#
# make app
middleware = session_middleware(SimpleCookieStorage())
app = web.Application(middlewares=[middleware])
# add the routes
app.router.add_route('GET', '/', handler_root)
app.router.add_route('GET', '/login', handler_login_jack)
app.router.add_route('GET', '/logout', handler_logout)
app.router.add_route('GET', '/listen', handler_listen)
app.router.add_route('GET', '/speak', handler_speak)
# set up policies
policy = SessionIdentityPolicy()
setup_security(app, policy, SimpleJack_AuthorizationPolicy())
return app
if __name__ == '__main__':
web.run_app(make_app(), port=9000)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -142,9 +142,9 @@ html_theme_options = {
'logo': 'aiohttp-icon-128x128.png',
'description': 'Authorization and identity for aoihttp',
'github_user': 'aio-libs',
'github_repo': 'aiohttp_security',
'github_repo': 'aiohttp-security',
'github_button': True,
'github_style': 'star',
'github_type': 'star',
'github_banner': True,
'travis_button': True,
'codecov_button': True,

View File

@@ -7,68 +7,97 @@ How to Make a Simple Server With Authorization
Simple example::
import asyncio
from aiohttp import web
@asyncio.coroutine
def root_handler(request):
text = "Alive and kicking!"
return web.Response(body=text.encode('utf-8'))
# option 2: auth at a higher level?
# set user_id and allowed in the wsgi handler
@protect('view_user')
@asyncio.coroutine
def user_handler(request):
name = request.match_info.get('name', "Anonymous")
text = "Hello, " + name
return web.Response(body=text.encode('utf-8'))
from aiohttp_session import SimpleCookieStorage, session_middleware
from aiohttp_security import check_permission, \
is_anonymous, remember, forget, \
setup as setup_security, SessionIdentityPolicy
from aiohttp_security.abc import AbstractAuthorizationPolicy
# option 3: super low
# wsgi doesn't do anything
@asyncio.coroutine
def user_update_handler(request):
# identity, asked_permission
user_id = yield from identity_policy.identify(request)
identity = yield from auth_policy.authorized_user_id(user_id)
allowed = yield from request.auth_policy.permits(
identity, asked_permission
)
if not allowed:
# how is this pluggable as well?
# ? return NotAllowedStream()
raise NotAllowedResponse()
# Demo authorization policy for only one user.
# User 'jack' has only 'listen' permission.
# For more complicated authorization policies see examples
# in the 'demo' directory.
class SimpleJack_AuthorizationPolicy(AbstractAuthorizationPolicy):
async def authorized_userid(self, identity):
"""Retrieve authorized user id.
Return the user_id of the user identified by the identity
or 'None' if no user exists related to the identity.
"""
if identity == 'jack':
return identity
update_user()
async def permits(self, identity, permission, context=None):
"""Check user permissions.
Return True if the identity is allowed the permission
in the current context, else return False.
"""
return identity == 'jack' and permission in ('listen',)
@asyncio.coroutine
def init(loop):
# set up identity and auth
auth_policy = DictionaryAuthorizationPolicy({'me': ('view_user',),
'you': ('view_user',
'edit_user',)})
identity_policy = CookieIdentityPolicy()
auth = authorization_middleware(auth_policy, identity_policy)
# wsgi app
app = web.Application(loop=loop, middlewares=*auth)
async def handler_root(request):
is_logged = not await is_anonymous(request)
return web.Response(text='''<html><head></head><body>
Hello, I'm Jack, I'm {logged} logged in.<br /><br />
<a href="/login">Log me in</a><br />
<a href="/logout">Log me out</a><br /><br />
Check my permissions,
when i'm logged in and logged out.<br />
<a href="/listen">Can I listen?</a><br />
<a href="/speak">Can I speak?</a><br />
</body></html>'''.format(
logged='' if is_logged else 'NOT',
), content_type='text/html')
async def handler_login_jack(request):
redirect_response = web.HTTPFound('/')
await remember(request, redirect_response, 'jack')
raise redirect_response
async def handler_logout(request):
redirect_response = web.HTTPFound('/')
await forget(request, redirect_response)
raise redirect_response
async def handler_listen(request):
await check_permission(request, 'listen')
return web.Response(body="I can listen!")
async def handler_speak(request):
await check_permission(request, 'speak')
return web.Response(body="I can speak!")
async def make_app():
#
# WARNING!!!
# Never use SimpleCookieStorage on production!!!
# Its highly insecure!!!
#
# make app
middleware = session_middleware(SimpleCookieStorage())
app = web.Application(middlewares=[middleware])
# add the routes
app.router.add_route('GET', '/', root_handler)
app.router.add_route('GET', '/{user}', user_handler)
app.router.add_route('GET', '/{user}/edit', user_update_handler)
app.add_routes([
web.get('/', handler_root),
web.get('/login', handler_login_jack),
web.get('/logout', handler_logout),
web.get('/listen', handler_listen),
web.get('/speak', handler_speak)])
# get it started
srv = yield from loop.create_server(app.make_handler(),
'127.0.0.1', 8080)
print("Server started at http://127.0.0.1:8080")
return srv
# set up policies
policy = SessionIdentityPolicy()
setup_security(app, policy, SimpleJack_AuthorizationPolicy())
return app
loop = asyncio.get_event_loop()
loop.run_until_complete(init(loop))
try:
loop.run_forever()
except KeyboardInterrupt:
pass # TODO put handler cleanup here
if __name__ == '__main__':
web.run_app(make_app(), port=9000)

View File

@@ -12,7 +12,7 @@ the `demo source`_.
https://github.com/aio-libs/aiohttp_security/tree/master/demo
.. _passlib:
https://pythonhosted.org/passlib/
https://passlib.readthedocs.io
Database
--------
@@ -21,12 +21,14 @@ Launch these sql scripts to init database and fill it with sample data:
``psql template1 < demo/sql/init_db.sql``
and then
and
``psql template1 < demo/sql/sample_data.sql``
You will have two tables for storing users and their permissions
Now you have two tables:
- for storing users
+--------------+
| users |
@@ -42,7 +44,7 @@ You will have two tables for storing users and their permissions
| disabled |
+--------------+
and second table is permissions table:
- for storing their permissions
+-----------------+
| permissions |
@@ -51,7 +53,7 @@ and second table is permissions table:
+-----------------+
| user_id |
+-----------------+
| permission_name |
| perm_name |
+-----------------+
@@ -63,48 +65,46 @@ First one should have these methods: *identify*, *remember* and *forget*.
For second one: *authorized_userid* and *permits*. We will use built-in
*SessionIdentityPolicy* and write our own database-based authorization policy.
In our example we will lookup database by user login and if present return
In our example we will lookup database by user login and if presents then return
this identity::
@asyncio.coroutine
def authorized_userid(self, identity):
with (yield from self.dbengine) as conn:
async def authorized_userid(self, identity):
async with self.dbengine as conn:
where = sa.and_(db.users.c.login == identity,
sa.not_(db.users.c.disabled))
query = db.users.count().where(where)
ret = yield from conn.scalar(query)
ret = await conn.scalar(query)
if ret:
return identity
else:
return None
For permission check we will fetch the user first, check if he is superuser
For permission checking we will fetch the user first, check if he is superuser
(all permissions are allowed), otherwise check if permission is explicitly set
for that user::
@asyncio.coroutine
def permits(self, identity, permission, context=None):
async def permits(self, identity, permission, context=None):
if identity is None:
return False
with (yield from self.dbengine) as conn:
async with self.dbengine as conn:
where = sa.and_(db.users.c.login == identity,
sa.not_(db.users.c.disabled))
query = db.users.select().where(where)
ret = yield from conn.execute(query)
user = yield from ret.fetchone()
ret = await conn.execute(query)
user = await ret.fetchone()
if user is not None:
user_id = user[0]
is_superuser = user[4]
is_superuser = user[3]
if is_superuser:
return True
where = db.permissions.c.user_id == user_id
query = db.permissions.select().where(where)
ret = yield from conn.execute(query)
result = yield from ret.fetchall()
ret = await conn.execute(query)
result = await ret.fetchall()
if ret is not None:
for record in result:
if record.perm_name == permission:
@@ -127,14 +127,13 @@ Once we have all the code in place we can install it for our application::
from .db_auth import DBAuthorizationPolicy
@asyncio.coroutine
def init(loop):
redis_pool = yield from create_pool(('localhost', 6379))
dbengine = yield from create_engine(user='aiohttp_security',
async def init(loop):
redis_pool = await create_pool(('localhost', 6379))
dbengine = await create_engine(user='aiohttp_security',
password='aiohttp_security',
database='aiohttp_security',
host='127.0.0.1')
app = web.Application(loop=loop)
app = web.Application()
setup_session(app, RedisStorage(redis_pool))
setup_security(app,
SessionIdentityPolicy(),
@@ -143,39 +142,33 @@ Once we have all the code in place we can install it for our application::
Now we have authorization and can decorate every other view with access rights
based on permissions. This simple decorator (for class-based handlers) will
help to do that::
based on permissions. There are already implemented two helpers::
def require(permission):
def wrapper(f):
@asyncio.coroutine
@functools.wraps(f)
def wrapped(self, request):
has_perm = yield from permits(request, permission)
if not has_perm:
message = 'User has no permission {}'.format(permission)
raise web.HTTPForbidden(body=message.encode())
return (yield from f(self, request))
return wrapped
return wrapper
from aiohttp_security import check_authorized, check_permission
For each view you need to protect just apply the decorator on it::
For each view you need to protect - just apply the decorator on it::
class Web:
@require('protected')
@asyncio.coroutine
def protected_page(self, request):
async def protected_page(self, request):
await check_permission(request, 'protected')
response = web.Response(body=b'You are on protected page')
return response
or::
If someone will try to access this protected page he will see::
class Web:
async def logout(self, request):
await check_authorized(request)
response = web.Response(body=b'You have been logged out')
await forget(request, response)
return response
403, User has no permission "protected"
If someone try to access that protected page he will see::
403: Forbidden
The best part about it is that you can implement any logic you want until it
The best part of it - you can implement any logic you want until it
follows the API conventions.
Launch application
@@ -183,18 +176,17 @@ Launch application
For working with passwords there is a good library passlib_. Once you've
created some users you want to check their credentials on login. Similar
function may do what you trying to accomplish::
function may do what you are trying to accomplish::
from passlib.hash import sha256_crypt
@asyncio.coroutine
def check_credentials(db_engine, username, password):
with (yield from db_engine) as conn:
async def check_credentials(db_engine, username, password):
async with db_engine as conn:
where = sa.and_(db.users.c.login == username,
sa.not_(db.users.c.disabled))
query = db.users.select().where(where)
ret = yield from conn.execute(query)
user = yield from ret.fetchone()
ret = await conn.execute(query)
user = await ret.fetchone()
if user is not None:
hash = user[2]
return sha256_crypt.verify(password, hash)
@@ -203,8 +195,8 @@ function may do what you trying to accomplish::
Final step is to launch your application::
python demo/main.py
python demo/database_auth/main.py
Try to login with admin/moderator/user accounts (with *password* password)
Try to login with admin/moderator/user accounts (with **password** password)
and access **/public** or **/protected** endpoints.

View File

@@ -3,16 +3,10 @@ aiohttp_security
The library provides security for :ref:`aiohttp.web<aiohttp-web>`.
Usage
-----
The current version is |version|
License
-------
``aiohttp_security`` is offered under the Apache 2 license.
Contents:
Contents
--------
.. toctree::
:maxdepth: 2
@@ -23,7 +17,10 @@ Contents:
example_db_auth
glossary
License
-------
``aiohttp_security`` is offered under the Apache 2 license.
Indices and tables
==================

View File

@@ -13,6 +13,19 @@
Public API functions
====================
.. function:: setup(app, identity_policy, autz_policy)
Setup :mod:`aiohttp` application with security policies.
:param app: aiohttp :class:`aiohttp.web.Application` instance.
:param identity_policy: indentification policy, an
:class:`AbstractIdentityPolicy` instance.
:param autz_policy: authorization policy, an
:class:`AbstractAuthorizationPolicy` instance.
.. coroutinefunction:: remember(request, response, identity, **kwargs)
Remember *identity* in *response*, e.g. by storing a cookie or
@@ -21,7 +34,7 @@ Public API functions
The action is performed by registered
:meth:`AbstractIdentityPolicy.remember`.
Usually the *idenity* is stored in user cookies homehow for using by
Usually the *identity* is stored in user cookies somehow for using by
:func:`authorized_userid` and :func:`permits`.
:param request: :class:`aiohttp.web.Request` object.
@@ -50,6 +63,41 @@ Public API functions
descendants like :class:`aiohttp.web.Response`.
.. coroutinefunction:: check_authorized(request)
Checker that doesn't pass if user is not authorized by *request*.
:param request: :class:`aiohttp.web.Request` object.
:return str: authorized user ID if success
:raise: :class:`aiohttp.web.HTTPUnauthorized` for anonymous users.
Usage::
async def handler(request):
await check_authorized(request)
# this line is never executed for anonymous users
.. coroutinefunction:: check_permission(request, permission)
Checker that doesn't pass if user has no requested permission.
:param request: :class:`aiohttp.web.Request` object.
:raise: :class:`aiohttp.web.HTTPUnauthorized` for anonymous users.
:raise: :class:`aiohttp.web.HTTPForbidden` if user is
authorized but has no access rights.
Usage::
async def handler(request):
await check_permission(request, 'read')
# this line is never executed if a user has no read permission
.. coroutinefunction:: authorized_userid(request)
Retrieve :term:`userid`.
@@ -78,7 +126,8 @@ Public API functions
:param request: :class:`aiohttp.web.Request` object.
:param str permission: requested :term:`permission`.
:param permission: Requested :term:`permission`. :class:`str` or
:class:`enum.Enum` object.
:param context: additional object may be passed into
:meth:`AbstractAuthorizationPolicy.permission`
@@ -88,17 +137,43 @@ Public API functions
``False`` otherwise.
.. function:: setup(app, identity_policy, autz_policy)
.. coroutinefunction:: is_anonymous(request)
Setup :mod:`aiohttp` application with security policies.
Checks if user is anonymous user.
:param app: aiohttp :class:`aiohttp.web.Application` instance.
Return ``True`` if user is not remembered in request, otherwise
returns ``False``.
:param identity_policy: indentification policy, an
:class:`AbstractIdentityPolicy` instance.
:param request: :class:`aiohttp.web.Request` object.
:param autz_policy: authorization policy, an
:class:`AbstractAuthorizationPolicy` instance.
.. decorator:: login_required
Decorator for handlers that checks if user is authorized.
Raises :class:`aiohttp.web.HTTPUnauthorized` if user is not authorized.
.. deprecated:: 0.3
Use :func:`check_authorized` async function.
.. decorator:: has_permission(permission)
Decorator for handlers that checks if user is authorized
and has correct permission.
Raises :class:`aiohttp.web.HTTPUnauthorized` if user is not
authorized.
Raises :class:`aiohttp.web.HTTPForbidden` if user is
authorized but has no access rights.
:param str permission: requested :term:`permission`.
.. deprecated:: 0.3
Use :func:`check_authorized` async function.
Abstract policies

View File

@@ -11,43 +11,132 @@
First of all, what is *aiohttp_security* about?
It is a set of public API functions and standard for implementation details.
*aiohttp-security* is a set of public API functions as well as a
reference standard for implementation details for securing access to
assets served by a wsgi server.
API is implementation agnostic, all client code should not call policy
code (see below) directly but use API only.
Assets are secured using authentication and authorization as explained
below. *aiohttp-security* is part of the
`aio-libs <https://github.com/aio-libs>`_ project which takes advantage
of asynchronous processing using Python's asyncio library.
Via API application can remember/forget user in local session
(:func:`remember`/:func:`forget`), retrieve :term:`userid`
(:func:`authorized_userid`) and check :term:`permission` for
remembered user (:func:`permits`).
The library internals are built on top of two policies:
:term:`authentication` and :term:`authorization`. There are abstract
base classes for both concepts as well as several implementations
shipped with the library. End user is free to build own implemetations
if needed.
Public API
==========
The API is agnostic to the low level implementation details such that
all client code only needs to implement the endpoints as provided by
the API (instead of calling policy code directly (see explanation
below)).
Via the API an application can:
(i) remember a user in a local session (:func:`remember`),
(ii) forget a user in a local session (:func:`forget`),
(iii) retrieve the :term:`userid` (:func:`authorized_userid`) of a
remembered user from an :term:`identity` (discussed below), and
(iv) check the :term:`permission` of a remembered user (:func:`permits`).
The library internals are built on top of two concepts:
1) :term:`authentication`, and
2) :term:`authorization`.
There are abstract base classes for both types as well as several
pre-built implementations that are shipped with the library. However,
the end user is free to build their own implementations.
The library comes with two pre-built identity policies; one that uses
cookies, and one that uses sessions [#f1]_. It is envisioned that in
most use cases developers will use one of the provided identity
policies (Cookie or Session) and implement their own authorization
policy.
The workflow is as follows:
1) User is authenticated. This has to be implemented by the developer.
2) Once user is authenticated an identity string has to be created for
that user. This has to be implemented by the developer.
3) The identity string is passed to the Identity Policy's remember
method and the user is now remembered (Cookie or Session if using
built-in). *Only once a user is remembered can the other API
methods:* :func:`permits`, :func:`forget`, *and*
:func:`authorized_userid` *be invoked* .
4) If the user tries to access a restricted asset the :func:`permits`
method is called. Usually assets are protected using the
:func:`check_permission` helper. This should return True if
permission is granted.
The :func:`permits` method is implemented by the developer as part of
the :class:`AbstractAuthorizationPolicy` and passed to the
application at runtime via setup.
In addition a :func:`check_authorized` also
exists that requires no permissions (i.e. doesn't call :func:`permits`
method) but only requires that the user is remembered
(i.e. authenticated/logged in).
Authentication
==============
Actions related to retrieving, storing and removing user's
:term:`identity`.
Authentication is the process where a user's identity is verified. It
confirms who the user is. This is traditionally done using a user name
and password (note: this is not the only way).
Authenticated user has no access rights, the system even has no
knowledge is there the user still registered in DB.
A authenticated user has no access rights, rather an authenticated
user merely confirms that the user exists and that the user is who
they say they are.
If :class:`aiohttp.web.Request` has an :term:`identity` it means the user has
some ID that should be checked by :term:`authorization` policy.
In *aiohttp_security* the developer is responsible for their own
authentication mechanism. *aiohttp_security* only requires that the
authentication result in a identity string which corresponds to a
user's id in the underlying system.
.. note::
:term:`identity` is a string that is shared between the browser and
the server. Therefore it is recommended that a random string
such as a uuid or hash is used rather than things like a
database primary key, user login/email, etc.
Identity Policy
===============
Once a user is authenticated the *aiohttp_security* API is invoked for
storing, retrieving, and removing a user's :term:`identity`. This is
accommplished via AbstractIdentityPolicy's :func:`remember`,
:func:`identify`, and :func:`forget` methods. The Identity Policy is
therefore the mechanism by which a authenticated user is persisted in
the system.
*aiohttp_security* has two built in identity policy's for this
purpose. :class:`CookiesIdentityPolicy` that uses cookies and
:class:`SessionIdentityPolicy` that uses sessions via
``aiohttp-session`` library.
Authorization
==============
Once a user is authenticated (see above) it means that the user has an
:term:`identity`. This :term:`identity` can now be used for checking
access rights or :term:`permission` using a :term:`authorization`
policy.
The authorization policy's :func:`permits()` method is used for this purpose.
When :class:`aiohttp.web.Request` has an :term:`identity` it means the
user has been authenticated and therefore has an :term:`identity` that
can be checked by the :term:`authorization` policy.
As noted above, :term:`identity` is a string that is shared between
the browser and the server. Therefore it is recommended that a
random string such as a uuid or hash is used rather than things like
a database primary key, user login/email, etc.
identity is a string shared between browser and server.
Thus it's not supposed to be database primary key, user login/email etc.
Random string like uuid or hash is better choice.
.. rubric:: Footnotes
.. [#f1] jwt - json web tokens in the works

View File

@@ -1,14 +1,18 @@
-e .
flake8
pytest
pytest-cov
coverage
sphinx
pep257
aiohttp_session
aiopg[sa]
aioredis==0.2.8
hiredis==0.2.0
passlib==1.6.5
aiohttp
pytest-aiohttp
flake8==3.8.4
async-timeout==3.0.1
pytest==6.1.2
pytest-cov==2.10.1
pytest-mock==3.3.1
coverage==5.3
sphinx==3.3.1
pep257==0.7.0
aiohttp-session==2.9.0
aiopg[sa]==1.1.0
aioredis==1.3.1
hiredis==1.1.0
passlib==1.7.4
cryptography==3.3.1
aiohttp==3.7.3
pytest-aiohttp==0.3.0
pyjwt==1.7.1

4
setup.cfg Normal file
View File

@@ -0,0 +1,4 @@
[tool:pytest]
testpaths = tests
filterwarnings=
error

View File

@@ -1,4 +1,3 @@
import codecs
from setuptools import setup, find_packages
import os
import re
@@ -16,8 +15,8 @@ class PyTest(TestCommand):
raise SystemExit(errno)
with codecs.open(os.path.join(os.path.abspath(os.path.dirname(
__file__)), 'aiohttp_security', '__init__.py'), 'r', 'latin1') as fp:
with open(os.path.join(os.path.abspath(os.path.dirname(
__file__)), 'aiohttp_security', '__init__.py'), 'r', encoding='latin1') as fp:
try:
version = re.findall(r"^__version__ = '([^']+)'$", fp.read(), re.M)[0]
except IndexError:
@@ -27,10 +26,12 @@ with codecs.open(os.path.join(os.path.abspath(os.path.dirname(
def read(f):
return open(os.path.join(os.path.dirname(__file__), f)).read().strip()
install_requires = ['aiohttp>=0.18']
install_requires = ['aiohttp>=3.2.0']
tests_require = install_requires + ['pytest']
extras_require = {'session': 'aiohttp-session'}
setup(name='aiohttp-security',
version=version,
description=("security for aiohttp.web"),
@@ -40,9 +41,12 @@ setup(name='aiohttp-security',
'Intended Audience :: Developers',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Topic :: Internet :: WWW/HTTP'],
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Topic :: Internet :: WWW/HTTP',
'Framework :: AsyncIO',
],
author='Andrew Svetlov',
author_email='andrew.svetlov@gmail.com',
url='https://github.com/aio-libs/aiohttp_security/',

0
tests/__init__.py Normal file
View File

View File

@@ -1,5 +1,3 @@
import asyncio
from aiohttp import web
from aiohttp_security import (remember, forget,
AbstractAuthorizationPolicy)
@@ -10,99 +8,85 @@ from aiohttp_security.api import IDENTITY_KEY
class Autz(AbstractAuthorizationPolicy):
@asyncio.coroutine
def permits(self, identity, permission, context=None):
async def permits(self, identity, permission, context=None):
pass
@asyncio.coroutine
def authorized_userid(self, identity):
async def authorized_userid(self, identity):
pass
@asyncio.coroutine
def test_remember(loop, test_client):
async def test_remember(loop, aiohttp_client):
@asyncio.coroutine
def handler(request):
async def handler(request):
response = web.Response()
yield from remember(request, response, 'Andrew')
await remember(request, response, 'Andrew')
return response
app = web.Application(loop=loop)
app = web.Application()
_setup(app, CookiesIdentityPolicy(), Autz())
app.router.add_route('GET', '/', handler)
client = yield from test_client(app)
resp = yield from client.get('/')
client = await aiohttp_client(app)
resp = await client.get('/')
assert 200 == resp.status
assert 'Andrew' == resp.cookies['AIOHTTP_SECURITY'].value
yield from resp.release()
@asyncio.coroutine
def test_identify(loop, test_client):
async def test_identify(loop, aiohttp_client):
@asyncio.coroutine
def create(request):
async def create(request):
response = web.Response()
yield from remember(request, response, 'Andrew')
await remember(request, response, 'Andrew')
return response
@asyncio.coroutine
def check(request):
async def check(request):
policy = request.app[IDENTITY_KEY]
user_id = yield from policy.identify(request)
user_id = await policy.identify(request)
assert 'Andrew' == user_id
return web.Response()
app = web.Application(loop=loop)
app = web.Application()
_setup(app, CookiesIdentityPolicy(), Autz())
app.router.add_route('GET', '/', check)
app.router.add_route('POST', '/', create)
client = yield from test_client(app)
resp = yield from client.post('/')
client = await aiohttp_client(app)
resp = await client.post('/')
assert 200 == resp.status
yield from resp.release()
resp = yield from client.get('/')
await resp.release()
resp = await client.get('/')
assert 200 == resp.status
yield from resp.release()
@asyncio.coroutine
def test_forget(loop, test_client):
async def test_forget(loop, aiohttp_client):
@asyncio.coroutine
def index(request):
async def index(request):
return web.Response()
@asyncio.coroutine
def login(request):
async def login(request):
response = web.HTTPFound(location='/')
yield from remember(request, response, 'Andrew')
return response
await remember(request, response, 'Andrew')
raise response
@asyncio.coroutine
def logout(request):
async def logout(request):
response = web.HTTPFound(location='/')
yield from forget(request, response)
return response
await forget(request, response)
raise response
app = web.Application(loop=loop)
app = web.Application()
_setup(app, CookiesIdentityPolicy(), Autz())
app.router.add_route('GET', '/', index)
app.router.add_route('POST', '/login', login)
app.router.add_route('POST', '/logout', logout)
client = yield from test_client(app)
resp = yield from client.post('/login')
client = await aiohttp_client(app)
resp = await client.post('/login')
assert 200 == resp.status
assert resp.url.endswith('/')
assert str(resp.url).endswith('/')
cookies = client.session.cookie_jar.filter_cookies(
client.make_url('/'))
assert 'Andrew' == cookies['AIOHTTP_SECURITY'].value
yield from resp.release()
resp = yield from client.post('/logout')
resp = await client.post('/logout')
assert 200 == resp.status
assert resp.url.endswith('/')
assert str(resp.url).endswith('/')
cookies = client.session.cookie_jar.filter_cookies(
client.make_url('/'))
assert 'AIOHTTP_SECURITY' not in cookies
yield from resp.release()

View File

@@ -1,123 +1,348 @@
import asyncio
import enum
import pytest
from aiohttp import web
from aiohttp_security import (remember,
authorized_userid, permits,
AbstractAuthorizationPolicy)
from aiohttp_security import setup as _setup
from aiohttp_security import (AbstractAuthorizationPolicy, authorized_userid,
forget, has_permission, is_anonymous,
login_required, permits, remember,
check_authorized, check_permission)
from aiohttp_security.cookies_identity import CookiesIdentityPolicy
class Autz(AbstractAuthorizationPolicy):
@asyncio.coroutine
def permits(self, identity, permission, context=None):
async def permits(self, identity, permission, context=None):
if identity == 'UserID':
return permission in {'read', 'write'}
else:
return False
@asyncio.coroutine
def authorized_userid(self, identity):
async def authorized_userid(self, identity):
if identity == 'UserID':
return 'Andrew'
else:
return None
@asyncio.coroutine
def test_authorized_userid(loop, test_client):
async def test_authorized_userid(loop, aiohttp_client):
@asyncio.coroutine
def login(request):
async def login(request):
response = web.HTTPFound(location='/')
yield from remember(request, response, 'UserID')
return response
await remember(request, response, 'UserID')
raise response
@asyncio.coroutine
def check(request):
userid = yield from authorized_userid(request)
async def check(request):
userid = await authorized_userid(request)
assert 'Andrew' == userid
return web.Response(text=userid)
app = web.Application(loop=loop)
app = web.Application()
_setup(app, CookiesIdentityPolicy(), Autz())
app.router.add_route('GET', '/', check)
app.router.add_route('POST', '/login', login)
client = yield from test_client(app)
client = await aiohttp_client(app)
resp = yield from client.post('/login')
resp = await client.post('/login')
assert 200 == resp.status
txt = yield from resp.text()
txt = await resp.text()
assert 'Andrew' == txt
yield from resp.release()
@asyncio.coroutine
def test_authorized_userid_not_authorized(loop, test_client):
async def test_authorized_userid_not_authorized(loop, aiohttp_client):
@asyncio.coroutine
def check(request):
userid = yield from authorized_userid(request)
async def check(request):
userid = await authorized_userid(request)
assert userid is None
return web.Response()
app = web.Application(loop=loop)
app = web.Application()
_setup(app, CookiesIdentityPolicy(), Autz())
app.router.add_route('GET', '/', check)
client = yield from test_client(app)
client = await aiohttp_client(app)
resp = yield from client.get('/')
resp = await client.get('/')
assert 200 == resp.status
yield from resp.release()
@asyncio.coroutine
def test_permits(loop, test_client):
async def test_permits_enum_permission(loop, aiohttp_client):
class Permission(enum.Enum):
READ = '101'
WRITE = '102'
UNKNOWN = '103'
@asyncio.coroutine
def login(request):
class Autz(AbstractAuthorizationPolicy):
async def permits(self, identity, permission, context=None):
if identity == 'UserID':
return permission in {Permission.READ, Permission.WRITE}
else:
return False
async def authorized_userid(self, identity):
if identity == 'UserID':
return 'Andrew'
else:
return None
async def login(request):
response = web.HTTPFound(location='/')
yield from remember(request, response, 'UserID')
return response
await remember(request, response, 'UserID')
raise response
@asyncio.coroutine
def check(request):
ret = yield from permits(request, 'read')
async def check(request):
ret = await permits(request, Permission.READ)
assert ret
ret = yield from permits(request, 'write')
ret = await permits(request, Permission.WRITE)
assert ret
ret = yield from permits(request, 'unknown')
ret = await permits(request, Permission.UNKNOWN)
assert not ret
return web.Response()
app = web.Application(loop=loop)
app = web.Application()
_setup(app, CookiesIdentityPolicy(), Autz())
app.router.add_route('GET', '/', check)
app.router.add_route('POST', '/login', login)
client = yield from test_client(app)
resp = yield from client.post('/login')
client = await aiohttp_client(app)
resp = await client.post('/login')
assert 200 == resp.status
yield from resp.release()
@asyncio.coroutine
def test_permits_unauthorized(loop, test_client):
async def test_permits_unauthorized(loop, aiohttp_client):
@asyncio.coroutine
def check(request):
ret = yield from permits(request, 'read')
async def check(request):
ret = await permits(request, 'read')
assert not ret
ret = yield from permits(request, 'write')
ret = await permits(request, 'write')
assert not ret
ret = yield from permits(request, 'unknown')
ret = await permits(request, 'unknown')
assert not ret
return web.Response()
app = web.Application(loop=loop)
app = web.Application()
_setup(app, CookiesIdentityPolicy(), Autz())
app.router.add_route('GET', '/', check)
client = yield from test_client(app)
resp = yield from client.get('/')
client = await aiohttp_client(app)
resp = await client.get('/')
assert 200 == resp.status
yield from resp.release()
async def test_is_anonymous(loop, aiohttp_client):
async def index(request):
is_anon = await is_anonymous(request)
if is_anon:
raise web.HTTPUnauthorized()
return web.Response()
async def login(request):
response = web.HTTPFound(location='/')
await remember(request, response, 'UserID')
raise response
async def logout(request):
response = web.HTTPFound(location='/')
await forget(request, response)
raise response
app = web.Application()
_setup(app, CookiesIdentityPolicy(), Autz())
app.router.add_route('GET', '/', index)
app.router.add_route('POST', '/login', login)
app.router.add_route('POST', '/logout', logout)
client = await aiohttp_client(app)
resp = await client.get('/')
assert web.HTTPUnauthorized.status_code == resp.status
await client.post('/login')
resp = await client.get('/')
assert web.HTTPOk.status_code == resp.status
await client.post('/logout')
resp = await client.get('/')
assert web.HTTPUnauthorized.status_code == resp.status
async def test_login_required(loop, aiohttp_client):
with pytest.raises(DeprecationWarning):
@login_required
async def index(request):
return web.Response()
async def login(request):
response = web.HTTPFound(location='/')
await remember(request, response, 'UserID')
raise response
async def logout(request):
response = web.HTTPFound(location='/')
await forget(request, response)
raise response
app = web.Application()
_setup(app, CookiesIdentityPolicy(), Autz())
app.router.add_route('GET', '/', index)
app.router.add_route('POST', '/login', login)
app.router.add_route('POST', '/logout', logout)
client = await aiohttp_client(app)
resp = await client.get('/')
assert web.HTTPUnauthorized.status_code == resp.status
await client.post('/login')
resp = await client.get('/')
assert web.HTTPOk.status_code == resp.status
await client.post('/logout')
resp = await client.get('/')
assert web.HTTPUnauthorized.status_code == resp.status
async def test_check_authorized(loop, aiohttp_client):
async def index(request):
await check_authorized(request)
return web.Response()
async def login(request):
response = web.HTTPFound(location='/')
await remember(request, response, 'UserID')
raise response
async def logout(request):
response = web.HTTPFound(location='/')
await forget(request, response)
raise response
app = web.Application()
_setup(app, CookiesIdentityPolicy(), Autz())
app.router.add_route('GET', '/', index)
app.router.add_route('POST', '/login', login)
app.router.add_route('POST', '/logout', logout)
client = await aiohttp_client(app)
resp = await client.get('/')
assert web.HTTPUnauthorized.status_code == resp.status
await client.post('/login')
resp = await client.get('/')
assert web.HTTPOk.status_code == resp.status
await client.post('/logout')
resp = await client.get('/')
assert web.HTTPUnauthorized.status_code == resp.status
async def test_has_permission(loop, aiohttp_client):
with pytest.warns(DeprecationWarning):
@has_permission('read')
async def index_read(request):
return web.Response()
@has_permission('write')
async def index_write(request):
return web.Response()
@has_permission('forbid')
async def index_forbid(request):
return web.Response()
async def login(request):
response = web.HTTPFound(location='/')
await remember(request, response, 'UserID')
return response
async def logout(request):
response = web.HTTPFound(location='/')
await forget(request, response)
raise response
app = web.Application()
_setup(app, CookiesIdentityPolicy(), Autz())
app.router.add_route('GET', '/permission/read', index_read)
app.router.add_route('GET', '/permission/write', index_write)
app.router.add_route('GET', '/permission/forbid', index_forbid)
app.router.add_route('POST', '/login', login)
app.router.add_route('POST', '/logout', logout)
client = await aiohttp_client(app)
resp = await client.get('/permission/read')
assert web.HTTPUnauthorized.status_code == resp.status
resp = await client.get('/permission/write')
assert web.HTTPUnauthorized.status_code == resp.status
resp = await client.get('/permission/forbid')
assert web.HTTPUnauthorized.status_code == resp.status
await client.post('/login')
resp = await client.get('/permission/read')
assert web.HTTPOk.status_code == resp.status
resp = await client.get('/permission/write')
assert web.HTTPOk.status_code == resp.status
resp = await client.get('/permission/forbid')
assert web.HTTPForbidden.status_code == resp.status
await client.post('/logout')
resp = await client.get('/permission/read')
assert web.HTTPUnauthorized.status_code == resp.status
resp = await client.get('/permission/write')
assert web.HTTPUnauthorized.status_code == resp.status
resp = await client.get('/permission/forbid')
assert web.HTTPUnauthorized.status_code == resp.status
async def test_check_permission(loop, aiohttp_client):
async def index_read(request):
await check_permission(request, 'read')
return web.Response()
async def index_write(request):
await check_permission(request, 'write')
return web.Response()
async def index_forbid(request):
await check_permission(request, 'forbid')
return web.Response()
async def login(request):
response = web.HTTPFound(location='/')
await remember(request, response, 'UserID')
raise response
async def logout(request):
response = web.HTTPFound(location='/')
await forget(request, response)
raise response
app = web.Application()
_setup(app, CookiesIdentityPolicy(), Autz())
app.router.add_route('GET', '/permission/read', index_read)
app.router.add_route('GET', '/permission/write', index_write)
app.router.add_route('GET', '/permission/forbid', index_forbid)
app.router.add_route('POST', '/login', login)
app.router.add_route('POST', '/logout', logout)
client = await aiohttp_client(app)
resp = await client.get('/permission/read')
assert web.HTTPUnauthorized.status_code == resp.status
resp = await client.get('/permission/write')
assert web.HTTPUnauthorized.status_code == resp.status
resp = await client.get('/permission/forbid')
assert web.HTTPUnauthorized.status_code == resp.status
await client.post('/login')
resp = await client.get('/permission/read')
assert web.HTTPOk.status_code == resp.status
resp = await client.get('/permission/write')
assert web.HTTPOk.status_code == resp.status
resp = await client.get('/permission/forbid')
assert web.HTTPForbidden.status_code == resp.status
await client.post('/logout')
resp = await client.get('/permission/read')
assert web.HTTPUnauthorized.status_code == resp.status
resp = await client.get('/permission/write')
assert web.HTTPUnauthorized.status_code == resp.status
resp = await client.get('/permission/forbid')
assert web.HTTPUnauthorized.status_code == resp.status

View File

@@ -0,0 +1,82 @@
import jwt
import pytest
from aiohttp import web
from aiohttp_security import setup as _setup
from aiohttp_security import AbstractAuthorizationPolicy
from aiohttp_security.api import IDENTITY_KEY
from aiohttp_security.jwt_identity import JWTIdentityPolicy
@pytest.fixture
def make_token():
def factory(payload, secret):
return jwt.encode(
payload,
secret,
algorithm='HS256',
)
return factory
class Autz(AbstractAuthorizationPolicy):
async def permits(self, identity, permission, context=None):
pass
async def authorized_userid(self, identity):
pass
async def test_no_pyjwt_installed(mocker):
mocker.patch('aiohttp_security.jwt_identity.jwt', None)
with pytest.raises(RuntimeError):
JWTIdentityPolicy('secret')
async def test_identify(loop, make_token, aiohttp_client):
kwt_secret_key = 'Key'
token = make_token({'login': 'Andrew'}, kwt_secret_key)
async def check(request):
policy = request.app[IDENTITY_KEY]
identity = await policy.identify(request)
assert 'Andrew' == identity['login']
return web.Response()
app = web.Application()
_setup(app, JWTIdentityPolicy(kwt_secret_key), Autz())
app.router.add_route('GET', '/', check)
client = await aiohttp_client(app)
headers = {'Authorization': 'Bearer {}'.format(token.decode('utf-8'))}
resp = await client.get('/', headers=headers)
assert 200 == resp.status
async def test_identify_broken_scheme(loop, make_token, aiohttp_client):
kwt_secret_key = 'Key'
token = make_token({'login': 'Andrew'}, kwt_secret_key)
async def check(request):
policy = request.app[IDENTITY_KEY]
try:
await policy.identify(request)
except ValueError as exc:
raise web.HTTPBadRequest(reason=str(exc))
return web.Response()
app = web.Application()
_setup(app, JWTIdentityPolicy(kwt_secret_key), Autz())
app.router.add_route('GET', '/', check)
client = await aiohttp_client(app)
headers = {'Authorization': 'Token {}'.format(token.decode('utf-8'))}
resp = await client.get('/', headers=headers)
assert 400 == resp.status
assert 'Invalid authorization scheme' in resp.reason

View File

@@ -1,42 +1,34 @@
import asyncio
from aiohttp import web
from aiohttp_security import authorized_userid, permits
@asyncio.coroutine
def test_authorized_userid(loop, test_client):
async def test_authorized_userid(loop, aiohttp_client):
@asyncio.coroutine
def check(request):
userid = yield from authorized_userid(request)
async def check(request):
userid = await authorized_userid(request)
assert userid is None
return web.Response()
app = web.Application(loop=loop)
app = web.Application()
app.router.add_route('GET', '/', check)
client = yield from test_client(app)
resp = yield from client.get('/')
client = await aiohttp_client(app)
resp = await client.get('/')
assert 200 == resp.status
yield from resp.release()
@asyncio.coroutine
def test_permits(loop, test_client):
async def test_permits(loop, aiohttp_client):
@asyncio.coroutine
def check(request):
ret = yield from permits(request, 'read')
async def check(request):
ret = await permits(request, 'read')
assert ret
ret = yield from permits(request, 'write')
ret = await permits(request, 'write')
assert ret
ret = yield from permits(request, 'unknown')
ret = await permits(request, 'unknown')
assert ret
return web.Response()
app = web.Application(loop=loop)
app = web.Application()
app.router.add_route('GET', '/', check)
client = yield from test_client(app)
resp = yield from client.get('/')
client = await aiohttp_client(app)
resp = await client.get('/')
assert 200 == resp.status
yield from resp.release()

View File

@@ -1,42 +1,34 @@
import asyncio
from aiohttp import web
from aiohttp_security import remember, forget
@asyncio.coroutine
def test_remember(loop, test_client):
async def test_remember(loop, aiohttp_client):
@asyncio.coroutine
def do_remember(request):
async def do_remember(request):
response = web.Response()
yield from remember(request, response, 'Andrew')
await remember(request, response, 'Andrew')
app = web.Application(loop=loop)
app = web.Application()
app.router.add_route('POST', '/', do_remember)
client = yield from test_client(app)
resp = yield from client.post('/')
client = await aiohttp_client(app)
resp = await client.post('/')
assert 500 == resp.status
assert (('Security subsystem is not initialized, '
'call aiohttp_security.setup(...) first') ==
resp.reason)
yield from resp.release()
@asyncio.coroutine
def test_forget(loop, test_client):
async def test_forget(loop, aiohttp_client):
@asyncio.coroutine
def do_forget(request):
async def do_forget(request):
response = web.Response()
yield from forget(request, response)
await forget(request, response)
app = web.Application(loop=loop)
app = web.Application()
app.router.add_route('POST', '/', do_forget)
client = yield from test_client(app)
resp = yield from client.post('/')
client = await aiohttp_client(app)
resp = await client.post('/')
assert 500 == resp.status
assert (('Security subsystem is not initialized, '
'call aiohttp_security.setup(...) first') ==
resp.reason)
yield from resp.release()

View File

@@ -1,4 +1,3 @@
import asyncio
import pytest
from aiohttp import web
@@ -13,117 +12,99 @@ from aiohttp_session import setup as setup_session
class Autz(AbstractAuthorizationPolicy):
@asyncio.coroutine
def permits(self, identity, permission, context=None):
async def permits(self, identity, permission, context=None):
pass
@asyncio.coroutine
def authorized_userid(self, identity):
async def authorized_userid(self, identity):
pass
@pytest.fixture
def make_app(loop):
app = web.Application(loop=loop)
def make_app():
app = web.Application()
setup_session(app, SimpleCookieStorage())
setup_security(app, SessionIdentityPolicy(), Autz())
return app
@asyncio.coroutine
def test_remember(make_app, test_client):
async def test_remember(make_app, aiohttp_client):
@asyncio.coroutine
def handler(request):
async def handler(request):
response = web.Response()
yield from remember(request, response, 'Andrew')
await remember(request, response, 'Andrew')
return response
@asyncio.coroutine
def check(request):
session = yield from get_session(request)
async def check(request):
session = await get_session(request)
assert session['AIOHTTP_SECURITY'] == 'Andrew'
return web.HTTPOk()
return web.Response()
app = make_app()
app.router.add_route('GET', '/', handler)
app.router.add_route('GET', '/check', check)
client = yield from test_client(app)
resp = yield from client.get('/')
client = await aiohttp_client(app)
resp = await client.get('/')
assert 200 == resp.status
yield from resp.release()
resp = yield from client.get('/check')
resp = await client.get('/check')
assert 200 == resp.status
yield from resp.release()
@asyncio.coroutine
def test_identify(make_app, test_client):
async def test_identify(make_app, aiohttp_client):
@asyncio.coroutine
def create(request):
async def create(request):
response = web.Response()
yield from remember(request, response, 'Andrew')
await remember(request, response, 'Andrew')
return response
@asyncio.coroutine
def check(request):
async def check(request):
policy = request.app[IDENTITY_KEY]
user_id = yield from policy.identify(request)
user_id = await policy.identify(request)
assert 'Andrew' == user_id
return web.Response()
app = make_app()
app.router.add_route('GET', '/', check)
app.router.add_route('POST', '/', create)
client = yield from test_client(app)
resp = yield from client.post('/')
client = await aiohttp_client(app)
resp = await client.post('/')
assert 200 == resp.status
yield from resp.release()
resp = yield from client.get('/')
resp = await client.get('/')
assert 200 == resp.status
yield from resp.release()
@asyncio.coroutine
def test_forget(make_app, test_client):
async def test_forget(make_app, aiohttp_client):
@asyncio.coroutine
def index(request):
session = yield from get_session(request)
return web.HTTPOk(text=session.get('AIOHTTP_SECURITY', ''))
async def index(request):
session = await get_session(request)
return web.Response(text=session.get('AIOHTTP_SECURITY', ''))
@asyncio.coroutine
def login(request):
async def login(request):
response = web.HTTPFound(location='/')
yield from remember(request, response, 'Andrew')
return response
await remember(request, response, 'Andrew')
raise response
@asyncio.coroutine
def logout(request):
async def logout(request):
response = web.HTTPFound('/')
yield from forget(request, response)
return response
await forget(request, response)
raise response
app = make_app()
app.router.add_route('GET', '/', index)
app.router.add_route('POST', '/login', login)
app.router.add_route('POST', '/logout', logout)
client = yield from test_client(app)
client = await aiohttp_client(app)
resp = yield from client.post('/login')
resp = await client.post('/login')
assert 200 == resp.status
assert resp.url.endswith('/')
txt = yield from resp.text()
assert str(resp.url).endswith('/')
txt = await resp.text()
assert 'Andrew' == txt
yield from resp.release()
resp = yield from client.post('/logout')
resp = await client.post('/logout')
assert 200 == resp.status
assert resp.url.endswith('/')
txt = yield from resp.text()
assert str(resp.url).endswith('/')
txt = await resp.text()
assert '' == txt
yield from resp.release()