Compare commits

..

216 Commits

Author SHA1 Message Date
7471415e7f new release: 0.10.0-rc3 2020-09-10 13:13:32 +02:00
9339d496f9 root: use PASSBOOK_TAG for static container 2020-09-10 13:13:27 +02:00
e72000eb06 new release: 0.10.0-rc2 2020-09-10 13:11:34 +02:00
ec5ff7c14d ci: fix docker-compose failing during release tag 2020-09-10 13:10:51 +02:00
43cb08b433 new release: 0.10.0-rc1 2020-09-10 13:05:12 +02:00
95a1c7b6d5 docs: remove manual upgrade instructions as they are automatic now 2020-09-10 13:04:56 +02:00
031a3d8719 build(deps): bump sentry-sdk from 0.17.3 to 0.17.4 (#207)
Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 0.17.3 to 0.17.4.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGES.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/0.17.3...0.17.4)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-09-10 09:54:50 +02:00
430905295d root: automate system migrations, move docker to lifecycle folder 2020-09-10 00:18:39 +02:00
1356a8108b docs: add docs for outposts 2020-09-09 19:34:19 +02:00
37dcf264e5 docs: add docs for proxy provider 2020-09-09 19:21:36 +02:00
296e1f4962 docs: improve documentation for providers 2020-09-09 19:14:12 +02:00
a0e81650d7 docs: update wording in upgrade guide 2020-09-09 18:55:01 +02:00
894cee6123 docs: add upgrade instructions for upcoming 0.10 2020-09-09 18:39:05 +02:00
a7be0379f4 e2e: fix tests using promptstages 2020-09-09 18:38:49 +02:00
2d6b57839d root: set fixed docker tags in compose 2020-09-09 18:21:53 +02:00
455e39a8bd helm: make replicas configurable 2020-09-09 18:21:27 +02:00
a7d8ac888a docs: update example flows 2020-09-09 17:23:26 +02:00
349e536d14 flows/tests: add tests to ensure flows in documentation are valid 2020-09-09 17:23:16 +02:00
cddc9bc1b7 flows/tests: update transfer tests to use same rollback function as importer 2020-09-09 17:22:44 +02:00
6d27408a10 transfer/exporter: ensure policies are exported before stages, ensure policies for new prompt stages are included 2020-09-09 17:22:24 +02:00
50a5959f6c flows/importer: fix validate writing to database not being reverted 2020-09-09 17:21:43 +02:00
18f42a0edf flows/importer: fix multiple uses of an importer instance causing errors 2020-09-09 17:21:16 +02:00
860ba994a6 policies/api: fix PolicyBinding's target being validated against the wrong pks 2020-09-09 17:20:37 +02:00
1776b72356 stages/prompt: remove PolicyBindingModel from PromptStage *breaking*
This resolves issues caused by the multiple primary keys, but also requires re-creation of the model.
2020-09-09 17:16:43 +02:00
8db60b3e83 docs: add example flows
closes #36
2020-09-08 23:18:42 +02:00
3b6341bf41 flow/transfer: fix pk's not being replaced in lists 2020-09-08 23:01:42 +02:00
3b97389833 asgi: revert ignore lifespan requests, remove healthcheck events from sentry
fixes PASSBOOK-5K
2020-09-08 18:29:01 +02:00
102d536a72 flows: fix incorrect pk being used in FlowStageBinding Form 2020-09-08 18:18:06 +02:00
9712be847c policies/api: fix target returning pbm_uuid instead of proper primary key of the object 2020-09-08 18:05:50 +02:00
f0b5e8143e admin: fix flow export view raising error 2020-09-08 16:49:15 +02:00
cc061e5b16 build(deps): bump channels-redis from 3.0.1 to 3.1.0 (#205)
Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-09-07 15:18:05 +02:00
fd8514331b build(deps): bump boto3 from 1.14.54 to 1.14.56 (#203)
Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-09-07 14:44:06 +02:00
1dc63776a5 ci: deploy to master.passbook.beryju.org on master (#113) 2020-09-07 11:59:15 +02:00
87b14e8761 flows/planner: optimise db queries during plan building 2020-09-07 11:27:02 +02:00
28893b9695 flows/transfer: fix missing unique fields for PolicyBinding 2020-09-07 11:26:37 +02:00
bb9ae28be8 build(deps): bump psycopg2-binary from 2.8.5 to 2.8.6 (#202)
Bumps [psycopg2-binary](https://github.com/psycopg/psycopg2) from 2.8.5 to 2.8.6.
- [Release notes](https://github.com/psycopg/psycopg2/releases)
- [Changelog](https://github.com/psycopg/psycopg2/blob/master/NEWS)
- [Commits](https://github.com/psycopg/psycopg2/commits)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-09-07 11:21:13 +02:00
0c05fd47f5 build(deps): bump ldap3 from 2.8 to 2.8.1 (#204)
Bumps [ldap3](https://github.com/cannatag/ldap3) from 2.8 to 2.8.1.
- [Release notes](https://github.com/cannatag/ldap3/releases)
- [Changelog](https://github.com/cannatag/ldap3/blob/dev/_changelog.txt)
- [Commits](https://github.com/cannatag/ldap3/compare/v2.8...v2.8.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-09-07 10:16:25 +02:00
fea44486c3 docker: use static worker count for docker (2 workers + 4 threads) 2020-09-06 22:16:12 +02:00
bf4763d946 asgi: ignore lifespan requests, remove healthcheck events from sentry 2020-09-06 16:51:50 +02:00
219e16f8e5 *: use direct sentry Hub for start_span 2020-09-06 16:12:17 +02:00
6ebefc9f17 root: fix some logs not being json 2020-09-06 15:52:54 +02:00
80e8a3d63c helm: fix arguments not being arrys 2020-09-06 15:52:22 +02:00
dd017e7190 flows: fix exporting and importing for models with multiple unique fields 2020-09-06 01:07:06 +02:00
268de20872 Proxy v2 (#189) 2020-09-03 00:04:12 +02:00
14e47f3195 flows: fix default flows not having titles 2020-09-02 13:05:34 +02:00
6d289aea48 build(deps): bump boto3 from 1.14.51 to 1.14.53 (#199)
Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-09-02 10:16:45 +02:00
529fd081a0 build(deps): bump sentry-sdk from 0.17.1 to 0.17.2 (#198)
Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 0.17.1 to 0.17.2.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGES.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/0.17.1...0.17.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-09-02 09:53:58 +02:00
02e3c78720 build(deps): bump django from 3.1 to 3.1.1 (#200)
Bumps [django](https://github.com/django/django) from 3.1 to 3.1.1.
- [Release notes](https://github.com/django/django/releases)
- [Commits](https://github.com/django/django/compare/3.1...3.1.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-09-02 09:24:10 +02:00
abc78d6633 build(deps): bump django-storages from 1.9.1 to 1.10 (#197)
Bumps [django-storages](https://github.com/jschneier/django-storages) from 1.9.1 to 1.10.
- [Release notes](https://github.com/jschneier/django-storages/releases)
- [Changelog](https://github.com/jschneier/django-storages/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/jschneier/django-storages/compare/1.9.1...1.10)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-31 10:36:24 +02:00
3f3dfc0a28 build(deps): bump boto3 from 1.14.50 to 1.14.51 (#195)
Bumps [boto3](https://github.com/boto/boto3) from 1.14.50 to 1.14.51.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.14.50...1.14.51)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-30 19:10:50 +02:00
5bd27bce3f build(deps): bump sentry-sdk from 0.17.0 to 0.17.1 (#196)
Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 0.17.0 to 0.17.1.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGES.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/0.17.0...0.17.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-08-30 12:41:57 +02:00
c39d136383 flows: add title field 2020-08-28 15:23:03 +02:00
a977184577 flows: export export/import functions in UI 2020-08-28 15:06:25 +02:00
b7ca40d98e build(deps): bump boto3 from 1.14.49 to 1.14.50 (#194)
Bumps [boto3](https://github.com/boto/boto3) from 1.14.49 to 1.14.50.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.14.49...1.14.50)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-28 09:13:21 +02:00
b2cb794865 build(deps): bump @patternfly/patternfly in /passbook/static/static (#192)
Bumps [@patternfly/patternfly](https://github.com/patternfly/patternfly) from 4.31.6 to 4.35.2.
- [Release notes](https://github.com/patternfly/patternfly/releases)
- [Changelog](https://github.com/patternfly/patternfly/blob/master/RELEASE-NOTES.md)
- [Commits](https://github.com/patternfly/patternfly/compare/prerelease-v4.31.6...prerelease-v4.35.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-08-27 10:38:27 +02:00
874f03e4dd build(deps): bump boto3 from 1.14.48 to 1.14.49 (#193)
Bumps [boto3](https://github.com/boto/boto3) from 1.14.48 to 1.14.49.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.14.48...1.14.49)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-27 10:19:48 +02:00
8f08d78bf1 build(deps): bump sentry-sdk from 0.16.5 to 0.17.0 (#190)
Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 0.16.5 to 0.17.0.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGES.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/0.16.5...0.17.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-08-26 10:58:01 +02:00
2661f2bbb3 build(deps): bump boto3 from 1.14.47 to 1.14.48 (#191)
Bumps [boto3](https://github.com/boto/boto3) from 1.14.47 to 1.14.48.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.14.47...1.14.48)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-26 08:58:16 +02:00
7d321e8aa8 helm: make image name configurable, make postgres and redis charts optional 2020-08-25 18:02:51 +02:00
a732beb72b helm: update to v2 chart 2020-08-25 17:58:05 +02:00
0996775ebf helm: cleanup 2020-08-25 17:51:33 +02:00
4147e8d1a7 helm: remove unmaintained monitoring 2020-08-25 17:45:56 +02:00
983bbb622d helm: fix invalid domain 2020-08-25 17:45:03 +02:00
885f8bae9f helm: remove mount of configmap, read entirely from env 2020-08-25 17:43:37 +02:00
aaa662199c build(deps): bump django-prometheus from 2.0.0 to 2.1.0 (#188)
Bumps [django-prometheus](https://github.com/korfuri/django-prometheus) from 2.0.0 to 2.1.0.
- [Release notes](https://github.com/korfuri/django-prometheus/releases)
- [Changelog](https://github.com/korfuri/django-prometheus/blob/master/CHANGELOG.md)
- [Commits](https://github.com/korfuri/django-prometheus/compare/2.0.0...2.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-08-24 14:25:47 +02:00
0e0898c3cf Flow exporting/importing (#187)
* stages/*: Add SerializerModel as base model, implement serializer property

* flows: add initial flow exporter and importer

* policies/*: implement .serializer for all policies

* root: fix missing dacite requirement
2020-08-22 00:42:15 +02:00
8b17e8be99 build(deps): bump codemirror in /passbook/static/static (#185)
Bumps [codemirror](https://github.com/codemirror/CodeMirror) from 5.56.0 to 5.57.0.
- [Release notes](https://github.com/codemirror/CodeMirror/releases)
- [Changelog](https://github.com/codemirror/CodeMirror/blob/master/CHANGELOG.md)
- [Commits](https://github.com/codemirror/CodeMirror/compare/5.56.0...5.57.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-08-21 10:52:03 +02:00
a082222b58 build(deps): bump boto3 from 1.14.45 to 1.14.47 (#186)
Bumps [boto3](https://github.com/boto/boto3) from 1.14.45 to 1.14.47.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.14.45...1.14.47)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-21 10:34:16 +02:00
9826bb4d01 root: fix sentry's being passed incorrectly 2020-08-20 23:12:54 +02:00
f7c629ec9b root: when error_reporting is enabled, don't sent pii data by default 2020-08-20 22:19:49 +02:00
e2aeb96a6a root: fix invalid import for clean_expired_models 2020-08-20 21:53:20 +02:00
ff810c689f Replace Elastic APM with Sentry APM (#183) 2020-08-20 20:39:21 +02:00
0eb94df1f7 providers/oauth2: fix redirect_uri not being checked correctly if multiple redirect_uris are configured 2020-08-20 16:41:00 +02:00
86597df159 build(deps): bump boto3 from 1.14.43 to 1.14.45 (#181)
Bumps [boto3](https://github.com/boto/boto3) from 1.14.43 to 1.14.45.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.14.43...1.14.45)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
Co-authored-by: Jens L <jens@beryju.org>
2020-08-20 09:09:56 +02:00
0394adaf46 *: fix general Linting errors 2020-08-19 10:49:14 +02:00
c7a2410b1d OAuth Provider Rewrite (#182) 2020-08-19 10:32:44 +02:00
b9076b5fd4 build(deps): bump @patternfly/patternfly from 4.31.4 to 4.31.6 in /passbook/static/static (#179)
Bumps [@patternfly/patternfly](https://github.com/patternfly/patternfly) from 4.31.4 to 4.31.6.
- [Release notes](https://github.com/patternfly/patternfly/releases)
- [Changelog](https://github.com/patternfly/patternfly/blob/master/RELEASE-NOTES.md)
- [Commits](https://github.com/patternfly/patternfly/compare/prerelease-v4.31.4...prerelease-v4.31.6)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-18 21:42:39 +02:00
c07a45083f build(deps-dev): bump unittest-xml-reporting from 3.0.3 to 3.0.4 (#180)
Bumps [unittest-xml-reporting](https://github.com/xmlrunner/unittest-xml-reporting) from 3.0.3 to 3.0.4.
- [Release notes](https://github.com/xmlrunner/unittest-xml-reporting/releases)
- [Commits](https://github.com/xmlrunner/unittest-xml-reporting/compare/3.0.3...3.0.4)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-18 21:42:20 +02:00
4b10fa3d93 build(deps): bump boto3 from 1.14.42 to 1.14.43 (#177)
Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-17 12:41:10 +02:00
c910dc9a3c build(deps-dev): bump unittest-xml-reporting from 3.0.2 to 3.0.3 (#175)
Bumps [unittest-xml-reporting](https://github.com/xmlrunner/unittest-xml-reporting) from 3.0.2 to 3.0.3.
- [Release notes](https://github.com/xmlrunner/unittest-xml-reporting/releases)
- [Commits](https://github.com/xmlrunner/unittest-xml-reporting/compare/3.0.2...3.0.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-08-17 12:16:46 +02:00
882dc60292 build(deps): bump sentry-sdk from 0.16.4 to 0.16.5 (#176) 2020-08-17 11:52:20 +02:00
7923468a01 admin: fix incorrect view name for groups 2020-08-16 17:41:48 +02:00
9ebbb51cf7 Merge pull request #157 from BeryJu/dependabot/pip/django-3.1
build(deps): bump django from 3.0.9 to 3.1
2020-08-15 21:44:54 +02:00
bd25cadb71 lib: fix config possibly iterating None 2020-08-15 21:12:38 +02:00
7334599efd *: update JSON fields to django 3.1 2020-08-15 21:04:22 +02:00
54f0728005 build(deps): bump django from 3.0.9 to 3.1
Bumps [django](https://github.com/django/django) from 3.0.9 to 3.1.
- [Release notes](https://github.com/django/django/releases)
- [Commits](https://github.com/django/django/compare/3.0.9...3.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-14 21:25:04 +00:00
e0c7637382 Merge pull request #170 from BeryJu/dependabot/npm_and_yarn/passbook/static/static/patternfly/patternfly-4.31.4
build(deps): bump @patternfly/patternfly from 4.23.3 to 4.31.4 in /passbook/static/static
2020-08-14 23:20:56 +02:00
086a3c0548 build(deps): bump @patternfly/patternfly in /passbook/static/static
Bumps [@patternfly/patternfly](https://github.com/patternfly/patternfly) from 4.23.3 to 4.31.4.
- [Release notes](https://github.com/patternfly/patternfly/releases)
- [Changelog](https://github.com/patternfly/patternfly/blob/master/RELEASE-NOTES.md)
- [Commits](https://github.com/patternfly/patternfly/compare/prerelease-v4.23.3...prerelease-v4.31.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-14 20:58:38 +00:00
65efbbd7ee Merge pull request #160 from BeryJu/dependabot/pip/django-prometheus-2.1.0.dev61
build(deps): bump django-prometheus from 2.1.0.dev54 to 2.1.0.dev61
2020-08-14 22:25:35 +02:00
5cc045e3c9 build(deps): bump django-prometheus from 2.1.0.dev54 to 2.1.0.dev61
Bumps [django-prometheus](https://github.com/korfuri/django-prometheus) from 2.1.0.dev54 to 2.1.0.dev61.
- [Release notes](https://github.com/korfuri/django-prometheus/releases)
- [Changelog](https://github.com/korfuri/django-prometheus/blob/master/CHANGELOG.md)
- [Commits](https://github.com/korfuri/django-prometheus/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-14 20:04:40 +00:00
56d259ce75 Merge pull request #172 from BeryJu/dependabot/pip/sentry-sdk-0.16.4
build(deps): bump sentry-sdk from 0.16.3 to 0.16.4
2020-08-14 22:00:24 +02:00
8919bade55 build(deps): bump sentry-sdk from 0.16.3 to 0.16.4
Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 0.16.3 to 0.16.4.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGES.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/0.16.3...0.16.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-14 19:33:46 +00:00
703d511089 Merge pull request #173 from BeryJu/dependabot/pip/django-otp-1.0.0
build(deps): bump django-otp from 0.9.4 to 1.0.0
2020-08-14 21:29:34 +02:00
aabedfc3e4 build(deps): bump django-otp from 0.9.4 to 1.0.0
Bumps [django-otp](https://github.com/django-otp/django-otp) from 0.9.4 to 1.0.0.
- [Release notes](https://github.com/django-otp/django-otp/releases)
- [Changelog](https://github.com/django-otp/django-otp/blob/master/CHANGES.rst)
- [Commits](https://github.com/django-otp/django-otp/compare/v0.9.4...v1.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-14 17:49:44 +00:00
0f154dee11 Merge pull request #167 from BeryJu/dependabot/pip/docker-4.3.0
build(deps-dev): bump docker from 4.2.2 to 4.3.0
2020-08-14 19:45:39 +02:00
a5c46d7e72 build(deps-dev): bump docker from 4.2.2 to 4.3.0
Bumps [docker](https://github.com/docker/docker-py) from 4.2.2 to 4.3.0.
- [Release notes](https://github.com/docker/docker-py/releases)
- [Commits](https://github.com/docker/docker-py/compare/4.2.2...4.3.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-14 17:10:06 +00:00
bbd59698e1 Merge pull request #174 from BeryJu/dependabot/pip/boto3-1.14.42
build(deps): bump boto3 from 1.14.41 to 1.14.42
2020-08-14 19:06:09 +02:00
3b0216bc00 build(deps): bump boto3 from 1.14.41 to 1.14.42
Bumps [boto3](https://github.com/boto/boto3) from 1.14.41 to 1.14.42.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.14.41...1.14.42)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-14 16:41:51 +00:00
b4fc32afac e2e: fix typo, log when docker healthcheck fails 2020-08-14 18:09:49 +02:00
45df127f18 e2e: lock mailhog docker image 2020-08-14 17:55:44 +02:00
55cf49bb8a root: attempt to fix broken e2e tests 2020-08-14 17:39:41 +02:00
00ce2a90f1 e2e: lock version of selenium/chrome 2020-08-14 10:53:37 +02:00
de77e1e41e Merge pull request #171 from BeryJu/dependabot/pip/boto3-1.14.41
build(deps): bump boto3 from 1.14.40 to 1.14.41
2020-08-13 10:49:17 +02:00
e40c07e997 build(deps): bump boto3 from 1.14.40 to 1.14.41
Bumps [boto3](https://github.com/boto/boto3) from 1.14.40 to 1.14.41.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.14.40...1.14.41)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-13 05:15:58 +00:00
d4b0bbb368 Merge pull request #165 from BeryJu/dependabot/pip/ldap3-2.8 2020-08-12 23:01:49 +02:00
d05f077ba0 Merge pull request #169 from BeryJu/dependabot/pip/boto3-1.14.40
build(deps): bump boto3 from 1.14.39 to 1.14.40
2020-08-12 23:01:30 +02:00
ca322d1e2c build(deps): bump boto3 from 1.14.39 to 1.14.40
Bumps [boto3](https://github.com/boto/boto3) from 1.14.39 to 1.14.40.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.14.39...1.14.40)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-12 05:18:00 +00:00
3c9631b287 build(deps): bump ldap3 from 2.7 to 2.8
Bumps [ldap3](https://github.com/cannatag/ldap3) from 2.7 to 2.8.
- [Release notes](https://github.com/cannatag/ldap3/releases)
- [Changelog](https://github.com/cannatag/ldap3/blob/dev/_changelog.txt)
- [Commits](https://github.com/cannatag/ldap3/compare/v2.7...v2.8)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-11 14:40:31 +00:00
16c2332c14 Merge pull request #168 from BeryJu/dependabot/pip/boto3-1.14.39
build(deps): bump boto3 from 1.14.37 to 1.14.39
2020-08-11 16:36:36 +02:00
2723b2091f build(deps): bump boto3 from 1.14.37 to 1.14.39
Bumps [boto3](https://github.com/boto/boto3) from 1.14.37 to 1.14.39.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.14.37...1.14.39)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-11 05:20:33 +00:00
7b454ff72a Merge pull request #161 from BeryJu/dependabot/pip/pylint-django-2.3.0
build(deps-dev): bump pylint-django from 2.2.0 to 2.3.0
2020-08-07 14:06:17 +02:00
4578bf6f29 build(deps-dev): bump pylint-django from 2.2.0 to 2.3.0
Bumps [pylint-django](https://github.com/PyCQA/pylint-django) from 2.2.0 to 2.3.0.
- [Release notes](https://github.com/PyCQA/pylint-django/releases)
- [Changelog](https://github.com/PyCQA/pylint-django/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/PyCQA/pylint-django/compare/v2.2.0...v2.3.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-07 10:51:40 +00:00
a991632396 Merge pull request #164 from BeryJu/dependabot/pip/boto3-1.14.37
build(deps): bump boto3 from 1.14.36 to 1.14.37
2020-08-07 12:47:50 +02:00
81d2f8c728 build(deps): bump boto3 from 1.14.36 to 1.14.37
Bumps [boto3](https://github.com/boto/boto3) from 1.14.36 to 1.14.37.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.14.36...1.14.37)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-07 05:13:58 +00:00
b42164a6b6 Merge pull request #162 from BeryJu/dependabot/pip/django-otp-0.9.4
build(deps): bump django-otp from 0.9.3 to 0.9.4
2020-08-06 10:07:24 +02:00
5857552b73 Merge pull request #163 from BeryJu/dependabot/pip/boto3-1.14.36
build(deps): bump boto3 from 1.14.35 to 1.14.36
2020-08-06 10:07:07 +02:00
0645dde90c build(deps): bump boto3 from 1.14.35 to 1.14.36
Bumps [boto3](https://github.com/boto/boto3) from 1.14.35 to 1.14.36.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.14.35...1.14.36)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-06 05:17:07 +00:00
494a8226a4 build(deps): bump django-otp from 0.9.3 to 0.9.4
Bumps [django-otp](https://github.com/django-otp/django-otp) from 0.9.3 to 0.9.4.
- [Release notes](https://github.com/django-otp/django-otp/releases)
- [Changelog](https://github.com/django-otp/django-otp/blob/master/CHANGES.rst)
- [Commits](https://github.com/django-otp/django-otp/compare/v0.9.3...v0.9.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-06 05:15:35 +00:00
aedd5f3f99 Merge pull request #158 from BeryJu/dependabot/pip/boto3-1.14.35
build(deps): bump boto3 from 1.14.34 to 1.14.35
2020-08-05 16:24:21 +02:00
8a1ff7cb5b build(deps): bump boto3 from 1.14.34 to 1.14.35
Bumps [boto3](https://github.com/boto/boto3) from 1.14.34 to 1.14.35.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.14.34...1.14.35)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-05 05:16:29 +00:00
e0a9cc0e26 Merge pull request #156 from BeryJu/dependabot/pip/boto3-1.14.34
build(deps): bump boto3 from 1.14.33 to 1.14.34
2020-08-04 14:18:36 +02:00
8f240b5303 build(deps): bump boto3 from 1.14.33 to 1.14.34
Bumps [boto3](https://github.com/boto/boto3) from 1.14.33 to 1.14.34.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.14.33...1.14.34)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-04 09:48:59 +00:00
ea39a5e952 Merge pull request #155 from BeryJu/dependabot/pip/django-3.0.9
build(deps): bump django from 3.0.8 to 3.0.9
2020-08-04 11:44:56 +02:00
ac539268cb build(deps): bump django from 3.0.8 to 3.0.9
Bumps [django](https://github.com/django/django) from 3.0.8 to 3.0.9.
- [Release notes](https://github.com/django/django/releases)
- [Commits](https://github.com/django/django/compare/3.0.8...3.0.9)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-04 05:15:37 +00:00
ed72a2c959 helm: fix APM secret_token not being applied correctly 2020-08-03 20:55:44 +02:00
e5cd9a4a2a Merge pull request #151 from BeryJu/dependabot/pip/django-prometheus-2.1.0.dev54
build(deps): bump django-prometheus from 2.1.0.dev52 to 2.1.0.dev54
2020-08-03 10:02:17 +02:00
d4f530f80b build(deps): bump django-prometheus from 2.1.0.dev52 to 2.1.0.dev54
Bumps [django-prometheus](https://github.com/korfuri/django-prometheus) from 2.1.0.dev52 to 2.1.0.dev54.
- [Release notes](https://github.com/korfuri/django-prometheus/releases)
- [Changelog](https://github.com/korfuri/django-prometheus/blob/master/CHANGELOG.md)
- [Commits](https://github.com/korfuri/django-prometheus/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-03 07:24:25 +00:00
282a518e00 Merge pull request #152 from BeryJu/dependabot/pip/autopep8-1.5.4
build(deps-dev): bump autopep8 from 1.5.3 to 1.5.4
2020-08-03 09:20:27 +02:00
5d50d99f59 Merge pull request #153 from BeryJu/dependabot/pip/sentry-sdk-0.16.3
build(deps): bump sentry-sdk from 0.16.2 to 0.16.3
2020-08-03 09:20:06 +02:00
d56a98e561 build(deps): bump sentry-sdk from 0.16.2 to 0.16.3
Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 0.16.2 to 0.16.3.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGES.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/0.16.2...0.16.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-03 07:01:01 +00:00
0cfdbd92d8 build(deps-dev): bump autopep8 from 1.5.3 to 1.5.4
Bumps [autopep8](https://github.com/hhatto/autopep8) from 1.5.3 to 1.5.4.
- [Release notes](https://github.com/hhatto/autopep8/releases)
- [Commits](https://github.com/hhatto/autopep8/compare/v1.5.3...v1.5.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-03 07:00:21 +00:00
6262923398 Merge pull request #154 from BeryJu/dependabot/pip/celery-4.4.7
build(deps): bump celery from 4.4.6 to 4.4.7
2020-08-03 08:56:33 +02:00
f96b1b58f3 build(deps): bump celery from 4.4.6 to 4.4.7
Bumps [celery](https://github.com/celery/celery) from 4.4.6 to 4.4.7.
- [Release notes](https://github.com/celery/celery/releases)
- [Changelog](https://github.com/celery/celery/blob/master/Changelog.rst)
- [Commits](https://github.com/celery/celery/compare/v4.4.6...v4.4.7)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-03 05:24:44 +00:00
fdf372912a Merge pull request #150 from pessimist101/patch-1
fix/Spelling error in SECURITY.md
2020-08-01 22:47:24 +02:00
2e517258fa fix/Spelling error in SECURITY.md 2020-08-01 21:38:07 +01:00
316ac78e49 new release: 0.9.0-stable 2020-08-01 22:17:59 +02:00
de2b67b111 providers/app_gw: improve templates 2020-08-01 22:13:12 +02:00
e1bbbe6671 providers/app_gw: disable client authz to use passbook 2020-08-01 20:53:55 +02:00
8b3839343c providers/oidc: remove static lookup for OIDCProvider, get related object for app_gw 2020-08-01 20:53:33 +02:00
7897ca4744 providers/app_gw: fix Client scopes and URLs 2020-08-01 20:33:38 +02:00
2fd00c6c9d Merge pull request #149 from BeryJu/dependabot/pip/boto3-1.14.33
build(deps): bump boto3 from 1.14.31 to 1.14.33
2020-08-01 20:25:20 +02:00
80f7f82fa4 build(deps): bump boto3 from 1.14.31 to 1.14.33
Bumps [boto3](https://github.com/boto/boto3) from 1.14.31 to 1.14.33.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.14.31...1.14.33)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-01 18:10:27 +00:00
1a21012911 providers/app_gw: fix URL Validation not working for internal and external host 2020-08-01 20:02:43 +02:00
d4a5269bf1 *: Adjust forms to only show respective types of Flows and PropertyMappings 2020-08-01 20:02:23 +02:00
fcf70a3cd4 providers/app_gw: Fix K8s template labels, add missing ISSUER_URL 2020-08-01 19:47:40 +02:00
e9411d856c docs: add notice that AWS requires POST binding 2020-08-01 19:42:33 +02:00
1a6dd00681 providers/saml: fix X509Data container linebreaks 2020-08-01 19:38:59 +02:00
330bd0932b providers/saml: fix NotOnOrAfter using incorrect timestamp 2020-08-01 19:38:41 +02:00
250e77f40f Merge pull request #147 from BeryJu/dependabot/pip/boto3-1.14.31
build(deps): bump boto3 from 1.14.30 to 1.14.31
2020-07-30 09:18:52 +02:00
ef71aba544 build(deps): bump boto3 from 1.14.30 to 1.14.31
Bumps [boto3](https://github.com/boto/boto3) from 1.14.30 to 1.14.31.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.14.30...1.14.31)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-30 05:18:20 +00:00
567a8f53da ci: add codeql analysis 2020-07-29 09:14:17 +02:00
88c87aa205 Merge pull request #146 from BeryJu/dependabot/pip/boto3-1.14.30
build(deps): bump boto3 from 1.14.28 to 1.14.30
2020-07-29 09:12:33 +02:00
90ac3d56ca build(deps): bump boto3 from 1.14.28 to 1.14.30
Bumps [boto3](https://github.com/boto/boto3) from 1.14.28 to 1.14.30.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.14.28...1.14.30)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-29 05:20:31 +00:00
a298e9e2ca Merge pull request #144 from BeryJu/dependabot/pip/coverage-5.2.1
build(deps-dev): bump coverage from 5.2 to 5.2.1
2020-07-27 08:59:32 +02:00
abdf86d9c9 build(deps-dev): 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 05:23:03 +00:00
c58658d820 new release: 0.9.0-rc2 2020-07-26 23:34:36 +02:00
a9b5e6ea13 flows: fix shell not showing spinner after submit 2020-07-26 22:15:50 +02:00
ddb0fdee98 providers/app_gw: generate docker-compose in code 2020-07-26 22:01:37 +02:00
83205f1b49 providers/app_gw: use full URL with protocol for internal/external_host 2020-07-26 22:01:20 +02:00
7221800a16 Merge pull request #143 from BeryJu/dependabot/pip/boto3-1.14.28
build(deps): bump boto3 from 1.14.26 to 1.14.28
2020-07-26 00:10:20 +02:00
4515cb6bbe build(deps): bump boto3 from 1.14.26 to 1.14.28
Bumps [boto3](https://github.com/boto/boto3) from 1.14.26 to 1.14.28.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.14.26...1.14.28)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-25 21:00:05 +00:00
7f9da11eba Merge pull request #139 from BeryJu/dependabot/pip/pylint-django-2.2.0
build(deps-dev): bump pylint-django from 2.1.0 to 2.2.0
2020-07-25 22:53:05 +02:00
da69d2611d build(deps-dev): bump pylint-django from 2.1.0 to 2.2.0
Bumps [pylint-django](https://github.com/PyCQA/pylint-django) from 2.1.0 to 2.2.0.
- [Release notes](https://github.com/PyCQA/pylint-django/releases)
- [Changelog](https://github.com/PyCQA/pylint-django/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/PyCQA/pylint-django/compare/v2.1.0...v2.2.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-25 20:20:48 +00:00
3b4be5695a gatekeeper: fix non-existent templates being copied 2020-07-25 22:13:15 +02:00
9d68c9550b gatekeeper: automatically redirect to passbook 2020-07-25 21:45:36 +02:00
3b2d469780 e2e: ensure that PasswordStage's change_flow is set correctly 2020-07-25 21:37:22 +02:00
ae629d1159 providers/oauth: remove LoginRequired from AuthorizationFlowInitView as user is redirected within 2020-07-25 21:36:50 +02:00
72a6f9cbe0 providers/saml: remove LoginRequired from SAMLSSOView as user is redirected within 2020-07-25 21:36:28 +02:00
9793b7461b providers/oidc: remove LoginRequired from AuthorizationFlowInitView as user is redirected within 2020-07-25 21:35:38 +02:00
9c1a824dc4 providers/app_gw: fix Issuer URL being incorrect, fix incorrect length cookie secret 2020-07-25 21:34:14 +02:00
738ced3327 e2e: CI -> TF_BUILD 2020-07-23 20:03:35 +02:00
ed1ee1fa55 Merge pull request #138 from BeryJu/dependabot/pip/boto3-1.14.26
build(deps): bump boto3 from 1.14.25 to 1.14.26
2020-07-23 19:49:54 +02:00
95776bbc56 build(deps): bump boto3 from 1.14.25 to 1.14.26
Bumps [boto3](https://github.com/boto/boto3) from 1.14.25 to 1.14.26.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.14.25...1.14.26)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-23 17:48:38 +00:00
62a4beb3d6 Merge pull request #140 from BeryJu/dependabot/pip/sentry-sdk-0.16.2
build(deps): bump sentry-sdk from 0.16.1 to 0.16.2
2020-07-23 19:45:08 +02:00
466a825f5b Merge pull request #141 from BeryJu/dependabot/pip/urllib3-1.25.10
build(deps): bump urllib3 from 1.25.9 to 1.25.10
2020-07-23 19:44:52 +02:00
3ffed279d7 e2e: fix flow setup stage test not finding link 2020-07-23 11:04:59 +02:00
4b6b36b2d2 build(deps): bump urllib3 from 1.25.9 to 1.25.10
Bumps [urllib3](https://github.com/urllib3/urllib3) from 1.25.9 to 1.25.10.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/1.25.10/CHANGES.rst)
- [Commits](https://github.com/urllib3/urllib3/compare/1.25.9...1.25.10)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-23 05:18:49 +00:00
2a8f63bf86 build(deps): bump sentry-sdk from 0.16.1 to 0.16.2
Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 0.16.1 to 0.16.2.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGES.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/0.16.1...0.16.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-23 05:17:21 +00:00
3c12cf96a9 Merge pull request #137 from BeryJu/dependabot/pip/boto3-1.14.25
build(deps): bump boto3 from 1.14.24 to 1.14.25
2020-07-22 13:01:35 +02:00
d787caf0e4 build(deps): bump boto3 from 1.14.24 to 1.14.25
Bumps [boto3](https://github.com/boto/boto3) from 1.14.24 to 1.14.25.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.14.24...1.14.25)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-22 05:14:06 +00:00
0fc2f32d3d Merge pull request #135 from BeryJu/dependabot/npm_and_yarn/passbook/static/static/codemirror-5.56.0
build(deps): bump codemirror from 5.55.0 to 5.56.0 in /passbook/static/static
2020-07-21 10:30:50 +02:00
894d5da1d8 Merge pull request #136 from BeryJu/dependabot/pip/boto3-1.14.24
build(deps): bump boto3 from 1.14.23 to 1.14.24
2020-07-21 10:30:35 +02:00
985d20d025 build(deps): bump boto3 from 1.14.23 to 1.14.24
Bumps [boto3](https://github.com/boto/boto3) from 1.14.23 to 1.14.24.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.14.23...1.14.24)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-21 05:19:53 +00:00
94f3e6d0c5 build(deps): bump codemirror in /passbook/static/static
Bumps [codemirror](https://github.com/codemirror/CodeMirror) from 5.55.0 to 5.56.0.
- [Release notes](https://github.com/codemirror/CodeMirror/releases)
- [Changelog](https://github.com/codemirror/CodeMirror/blob/master/CHANGELOG.md)
- [Commits](https://github.com/codemirror/CodeMirror/compare/5.55.0...5.56.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-21 05:16:34 +00:00
0a196608c7 Merge pull request #134 from BeryJu/consent-mode
Add different Modes to Consent Stage
2020-07-20 19:14:33 +02:00
d33f0fb2cf Merge branch 'master' into consent-mode
# Conflicts:
#	passbook/stages/consent/models.py
2020-07-20 18:56:38 +02:00
ffff69ada0 stages/consent: add unittests for new modes 2020-07-20 18:47:52 +02:00
37a432267d Squashed commit of the following:
commit 88029a4335
Author: Jens Langhammer <jens.langhammer@beryju.org>
Date:   Mon Jul 20 16:55:55 2020 +0200

    admin: update to work with new form

commit 4040eb9619
Author: Jens Langhammer <jens.langhammer@beryju.org>
Date:   Mon Jul 20 16:43:30 2020 +0200

    *: remove path-based import from all PropertyMappings

commit c9663a08da
Author: Jens Langhammer <jens.langhammer@beryju.org>
Date:   Mon Jul 20 16:33:34 2020 +0200

    flows: update work with new stages

commit a3d92ebc0a
Author: Jens Langhammer <jens.langhammer@beryju.org>
Date:   Mon Jul 20 16:23:30 2020 +0200

    stages/*: remove path-based import from all stages

commit 6fa825e372
Author: Jens Langhammer <jens.langhammer@beryju.org>
Date:   Mon Jul 20 16:03:55 2020 +0200

    providers/*: remove path-based import from all providers

commit 6aefd072c8
Author: Jens Langhammer <jens.langhammer@beryju.org>
Date:   Mon Jul 20 15:58:48 2020 +0200

    policies/*: remove path-based import from all policies

commit ac2dd3611f
Author: Jens Langhammer <jens.langhammer@beryju.org>
Date:   Mon Jul 20 15:11:27 2020 +0200

    sources/*: remove path-based import from all sources

commit 74e628ce9c
Author: Jens Langhammer <jens.langhammer@beryju.org>
Date:   Mon Jul 20 14:43:38 2020 +0200

    ui: allow overriding of verbose_name

commit d4ee18ee32
Author: Jens Langhammer <jens.langhammer@beryju.org>
Date:   Mon Jul 20 14:08:27 2020 +0200

    sources/oauth: migrate from discordapp.com to discord.com
2020-07-20 18:17:14 +02:00
88029a4335 admin: update to work with new form 2020-07-20 17:57:06 +02:00
4040eb9619 *: remove path-based import from all PropertyMappings 2020-07-20 16:54:23 +02:00
c9663a08da flows: update work with new stages 2020-07-20 16:33:34 +02:00
a3d92ebc0a stages/*: remove path-based import from all stages 2020-07-20 16:28:45 +02:00
6fa825e372 providers/*: remove path-based import from all providers 2020-07-20 16:05:09 +02:00
6aefd072c8 policies/*: remove path-based import from all policies 2020-07-20 16:05:09 +02:00
ac2dd3611f sources/*: remove path-based import from all sources 2020-07-20 16:05:09 +02:00
74e628ce9c ui: allow overriding of verbose_name 2020-07-20 14:43:38 +02:00
d4ee18ee32 sources/oauth: migrate from discordapp.com to discord.com 2020-07-20 14:08:27 +02:00
9ff3ee7c0c Merge branch 'master' into consent-mode 2020-07-20 13:59:09 +02:00
418b94a45a e2e: fix grafana docker image tag 2020-07-20 13:58:50 +02:00
1393078fe6 e2e: fix oauth/oidc tests not working with current grafana 2020-07-20 13:49:07 +02:00
50612991fa stages/consent: start implementing user consent 2020-07-20 13:19:58 +02:00
37b2400cdb lib: move SAML timestring utils into lib 2020-07-20 11:35:16 +02:00
05c3393669 Merge pull request #133 from BeryJu/expiring-models
core: separate expiry logic from tokens and make re-usable
2020-07-20 11:17:37 +02:00
c60d1e1f9a core: separate expiry logic from tokens and make re-usable 2020-07-20 10:57:12 +02:00
2be7d3191f Merge pull request #132 from BeryJu/dependabot/pip/boto3-1.14.23
build(deps): bump boto3 from 1.14.22 to 1.14.23
2020-07-20 09:10:14 +02:00
aa692fdacb Merge pull request #131 from BeryJu/dependabot/npm_and_yarn/passbook/static/static/patternfly/patternfly-4.23.3
build(deps): bump @patternfly/patternfly from 4.16.7 to 4.23.3 in /passbook/static/static
2020-07-20 09:09:58 +02:00
c163637bfd build(deps): bump boto3 from 1.14.22 to 1.14.23
Bumps [boto3](https://github.com/boto/boto3) from 1.14.22 to 1.14.23.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.14.22...1.14.23)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-20 05:20:24 +00:00
5552aca079 build(deps): bump @patternfly/patternfly in /passbook/static/static
Bumps [@patternfly/patternfly](https://github.com/patternfly/patternfly) from 4.16.7 to 4.23.3.
- [Release notes](https://github.com/patternfly/patternfly/releases)
- [Changelog](https://github.com/patternfly/patternfly/blob/master/RELEASE-NOTES.md)
- [Commits](https://github.com/patternfly/patternfly/compare/prerelease-v4.16.7...prerelease-v4.23.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-20 05:14:37 +00:00
ff2456dcfa root: clean log output, always show logger 2020-07-19 22:48:52 +02:00
539264c396 Merge pull request #130 from BeryJu/dependabot/pip/boto3-1.14.22
build(deps): bump boto3 from 1.14.21 to 1.14.22
2020-07-17 10:48:26 +02:00
1acfaf1562 build(deps): bump boto3 from 1.14.21 to 1.14.22
Bumps [boto3](https://github.com/boto/boto3) from 1.14.21 to 1.14.22.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.14.21...1.14.22)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-17 05:20:16 +00:00
a81e277cfa Merge pull request #128 from BeryJu/dependabot/npm_and_yarn/passbook/static/static/fortawesome/fontawesome-free-5.14.0
build(deps): bump @fortawesome/fontawesome-free from 5.13.1 to 5.14.0 in /passbook/static/static
2020-07-16 16:01:42 +02:00
b4cb78f33f Merge pull request #129 from BeryJu/dependabot/pip/boto3-1.14.21
build(deps): bump boto3 from 1.14.20 to 1.14.21
2020-07-16 16:01:20 +02:00
35c0a9532f build(deps): bump boto3 from 1.14.20 to 1.14.21
Bumps [boto3](https://github.com/boto/boto3) from 1.14.20 to 1.14.21.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.14.20...1.14.21)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-16 05:18:26 +00:00
aff074420b build(deps): bump @fortawesome/fontawesome-free
Bumps [@fortawesome/fontawesome-free](https://github.com/FortAwesome/Font-Awesome) from 5.13.1 to 5.14.0.
- [Release notes](https://github.com/FortAwesome/Font-Awesome/releases)
- [Changelog](https://github.com/FortAwesome/Font-Awesome/blob/master/CHANGELOG.md)
- [Commits](https://github.com/FortAwesome/Font-Awesome/compare/5.13.1...5.14.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-16 05:15:24 +00:00
edbea9ccff audit: fix list not having loginrequired
closes #127
2020-07-15 18:34:53 +02:00
336 changed files with 13089 additions and 3824 deletions

View File

@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.9.0-rc1
current_version = 0.10.0-rc3
tag = True
commit = True
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-(?P<release>.*)
@ -19,6 +19,8 @@ values =
[bumpversion:file:docs/installation/docker-compose.md]
[bumpversion:file:docker-compose.yml]
[bumpversion:file:helm/values.yaml]
[bumpversion:file:helm/Chart.yaml]

View File

@ -1,7 +1,7 @@
[run]
source = passbook
omit =
*/wsgi.py
*/asgi.py
manage.py
*/migrations/*
*/apps.py

View File

@ -1,20 +0,0 @@
# Generated by FOSSA CLI (https://github.com/fossas/fossa-cli)
# Visit https://fossa.com to learn more
version: 2
cli:
server: https://app.fossa.com
fetcher: custom
project: git@github.com:BeryJu/passbook.git
analyze:
modules:
- name: static
type: npm
target: passbook/static/static
path: passbook/static/static
- name: .
type: pip
target: .
path: .
options:
strategy: pipenv

54
.github/workflows/codeql-analysis.yml vendored Normal file
View File

@ -0,0 +1,54 @@
name: "CodeQL"
on:
push:
branches: [master, admin-more-info, ci-deploy-dev, gh-pages, provider-saml-v2]
pull_request:
# The branches below must be a subset of the branches above
branches: [master]
schedule:
- cron: '0 20 * * 2'
jobs:
analyse:
name: Analyse
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
# Override language selection by uncommenting this and choosing your languages
# with:
# languages: go, javascript, csharp, python, cpp, java
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View File

@ -16,14 +16,14 @@ jobs:
- name: Building Docker Image
run: docker build
--no-cache
-t beryju/passbook:0.9.0-rc1
-t beryju/passbook:0.10.0-rc3
-t beryju/passbook:latest
-f Dockerfile .
- name: Push Docker Container to Registry (versioned)
run: docker push beryju/passbook:0.9.0-rc1
run: docker push beryju/passbook:0.10.0-rc3
- name: Push Docker Container to Registry (latest)
run: docker push beryju/passbook:latest
build-gatekeeper:
build-proxy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
@ -34,16 +34,16 @@ jobs:
run: docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
- name: Building Docker Image
run: |
cd gatekeeper
cd proxy
docker build \
--no-cache \
-t beryju/passbook-gatekeeper:0.9.0-rc1 \
-t beryju/passbook-gatekeeper:latest \
-t beryju/passbook-proxy:0.10.0-rc3 \
-t beryju/passbook-proxy:latest \
-f Dockerfile .
- name: Push Docker Container to Registry (versioned)
run: docker push beryju/passbook-gatekeeper:0.9.0-rc1
run: docker push beryju/passbook-proxy:0.10.0-rc3
- name: Push Docker Container to Registry (latest)
run: docker push beryju/passbook-gatekeeper:latest
run: docker push beryju/passbook-proxy:latest
build-static:
runs-on: ubuntu-latest
services:
@ -66,11 +66,11 @@ jobs:
run: docker build
--no-cache
--network=$(docker network ls | grep github | awk '{print $1}')
-t beryju/passbook-static:0.9.0-rc1
-t beryju/passbook-static:0.10.0-rc3
-t beryju/passbook-static:latest
-f static.Dockerfile .
- name: Push Docker Container to Registry (versioned)
run: docker push beryju/passbook-static:0.9.0-rc1
run: docker push beryju/passbook-static:0.10.0-rc3
- name: Push Docker Container to Registry (latest)
run: docker push beryju/passbook-static:latest
test-release:
@ -100,5 +100,5 @@ jobs:
SENTRY_PROJECT: passbook
SENTRY_URL: https://sentry.beryju.org
with:
tagName: 0.9.0-rc1
environment: production
tagName: 0.10.0-rc3
environment: beryjuorg-prod

View File

@ -13,6 +13,7 @@ jobs:
- uses: actions/checkout@master
- name: Pre-release test
run: |
export PASSBOOK_TAG=latest
docker-compose pull -q
docker build \
--no-cache \

View File

@ -1,6 +1,6 @@
[MASTER]
disable=redefined-outer-name,arguments-differ,no-self-use,cyclic-import,fixme,locally-disabled,too-many-ancestors,too-few-public-methods,import-outside-toplevel,bad-continuation,signature-differs
disable=arguments-differ,no-self-use,fixme,locally-disabled,too-many-ancestors,too-few-public-methods,import-outside-toplevel,bad-continuation,signature-differs,similarities,cyclic-import
load-plugins=pylint_django,pylint.extensions.bad_builtin
extension-pkg-whitelist=lxml
const-rgx=[a-zA-Z0-9_]{1,40}$

View File

@ -11,25 +11,22 @@ RUN pip install pipenv && \
FROM python:3.8-slim-buster
COPY --from=locker /app/requirements.txt /app/
COPY --from=locker /app/requirements-dev.txt /app/
WORKDIR /app/
WORKDIR /
COPY --from=locker /app/requirements.txt /
COPY --from=locker /app/requirements-dev.txt /
RUN apt-get update && \
apt-get install -y --no-install-recommends postgresql-client-11 && \
apt-get install -y --no-install-recommends postgresql-client-11 build-essential && \
rm -rf /var/lib/apt/ && \
pip install -r requirements.txt --no-cache-dir && \
adduser --system --no-create-home --uid 1000 --group --home /app passbook
pip install -r /requirements.txt --no-cache-dir && \
apt-get remove --purge -y build-essential && \
apt-get autoremove --purge && \
adduser --system --no-create-home --uid 1000 --group --home /passbook passbook
COPY ./passbook/ /app/passbook
COPY ./manage.py /app/
COPY ./docker/uwsgi.ini /app/
COPY ./docker/bootstrap.sh /bootstrap.sh
COPY ./docker/wait_for_db.py /app/wait_for_db.py
WORKDIR /app/
COPY ./passbook/ /passbook
COPY ./manage.py /
COPY ./lifecycle/ /lifecycle
USER passbook
ENTRYPOINT [ "/bootstrap.sh" ]
ENTRYPOINT [ "/lifecycle/bootstrap.sh" ]

20
Makefile Normal file
View File

@ -0,0 +1,20 @@
all: lint-fix lint coverage gen
coverage:
coverage run --concurrency=multiprocessing manage.py test passbook --failfast
coverage combine
coverage html
coverage report
lint-fix:
isort -rc .
black .
lint:
pyright
bandit -r .
pylint passbook
prospector
gen: coverage
./manage.py generate_swagger -o swagger.yaml -f yaml

25
Pipfile
View File

@ -13,8 +13,6 @@ django-dbbackup = "*"
django-filter = "*"
django-guardian = "*"
django-model-utils = "*"
django-oauth-toolkit = "*"
django-oidc-provider = "*"
django-otp = "*"
django-prometheus = "*"
django-recaptcha = "*"
@ -23,14 +21,15 @@ django-rest-framework = "*"
django-storages = "*"
djangorestframework-guardian = "*"
drf-yasg = "*"
kombu = "*"
facebook-sdk = "*"
ldap3 = "*"
lxml = "*"
oauthlib = "*"
packaging = "*"
psycopg2-binary = "*"
pycryptodome = "*"
pyuwsgi = "*"
pyjwkest = "*"
uvicorn = "*"
gunicorn = "*"
pyyaml = "*"
qrcode = "*"
requests-oauthlib = "*"
@ -40,8 +39,10 @@ signxml = "*"
structlog = "*"
swagger-spec-validator = "*"
urllib3 = {extras = ["secure"],version = "*"}
facebook-sdk = "*"
elastic-apm = "*"
dacite = "*"
channels = "*"
channels-redis = "*"
kubernetes = "*"
[requires]
python_version = "3.8"
@ -49,16 +50,14 @@ python_version = "3.8"
[dev-packages]
autopep8 = "*"
bandit = "*"
black = "==19.10b0"
bumpversion = "*"
colorama = "*"
coverage = "*"
django-debug-toolbar = "*"
docker = "*"
pylint = "*"
pylint-django = "*"
unittest-xml-reporting = "*"
black = "*"
selenium = "*"
docker = "*"
[pipenv]
allow_prereleases = true
unittest-xml-reporting = "*"
prospector = "*"

1109
Pipfile.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,6 @@
![Tests](https://img.shields.io/azure-devops/tests/beryjuorg/passbook/1?compact_message&style=flat-square)
[![Code Coverage](https://img.shields.io/codecov/c/gh/beryju/passbook?style=flat-square)](https://codecov.io/gh/BeryJu/passbook)
![Docker pulls](https://img.shields.io/docker/pulls/beryju/passbook.svg?style=flat-square)
![Docker pulls (gatekeeper)](https://img.shields.io/docker/pulls/beryju/passbook-gatekeeper.svg?style=flat-square)
![Latest version](https://img.shields.io/docker/v/beryju/passbook?sort=semver&style=flat-square)
![LGTM Grade](https://img.shields.io/lgtm/grade/python/github/BeryJu/passbook?style=flat-square)
@ -21,12 +20,12 @@ wget https://raw.githubusercontent.com/BeryJu/passbook/master/docker-compose.yml
# Optionally enable Error-reporting
# export PASSBOOK_ERROR_REPORTING=true
# Optionally deploy a different version
# export PASSBOOK_TAG=0.9.0-rc1
# export PASSBOOK_TAG=0.10.0-rc3
# If this is a productive installation, set a different PostgreSQL Password
# export PG_PASS=$(pwgen 40 1)
docker-compose pull
docker-compose up -d
docker-compose exec server ./manage.py migrate
docker-compose run --rm server migrate
```
For bigger setups, there is a Helm Chart in the `helm/` directory. This is documented [here](https://passbook.beryju.org//installation/kubernetes/)
@ -61,7 +60,6 @@ postgresql:
user: postgres
log_level: debug
error_reporting: false
```
## Security

View File

@ -10,4 +10,4 @@ As passbook is currently in a pre-stable, only the latest "stable" version is su
## Reporting a Vulnerability
To report a vulnerability, send am email to [security@beryju.org](mailto:security@beryju.org)
To report a vulnerability, send an email to [security@beryju.org](mailto:security@beryju.org)

View File

@ -261,18 +261,6 @@ stages:
command: 'buildAndPush'
Dockerfile: 'Dockerfile'
tags: 'gh-$(Build.SourceBranchName)'
- job: build_gatekeeper
pool:
vmImage: 'ubuntu-latest'
steps:
- task: Docker@2
inputs:
containerRegistry: 'dockerhub'
repository: 'beryju/passbook-gatekeeper'
command: 'buildAndPush'
Dockerfile: 'gatekeeper/Dockerfile'
buildContext: 'gatekeeper/'
tags: 'gh-$(Build.SourceBranchName)'
- job: build_static
pool:
vmImage: 'ubuntu-latest'
@ -297,3 +285,19 @@ stages:
repository: 'beryju/passbook-static'
command: 'push'
tags: 'gh-$(Build.SourceBranchName)'
- stage: Deploy
jobs:
- job: deploy_dev
pool:
vmImage: 'ubuntu-latest'
steps:
- task: HelmDeploy@0
inputs:
connectionType: 'Kubernetes Service Connection'
kubernetesServiceConnection: 'k8s-beryjuorg-prd'
namespace: 'passbook-dev'
command: 'upgrade'
chartType: 'FilePath'
chartPath: 'helm/'
releaseName: 'passbook-dev'
recreate: true

View File

@ -21,15 +21,14 @@ services:
labels:
- traefik.enable=false
server:
image: beryju/passbook:${PASSBOOK_TAG:-latest}
command:
- uwsgi
- uwsgi.ini
image: beryju/passbook:${PASSBOOK_TAG:-0.10.0-rc3}
command: server
environment:
- PASSBOOK_REDIS__HOST=redis
- PASSBOOK_ERROR_REPORTING=${PASSBOOK_ERROR_REPORTING:-false}
- PASSBOOK_POSTGRESQL__HOST=postgresql
- PASSBOOK_POSTGRESQL__PASSWORD=${PG_PASS:-thisisnotagoodpassword}
PASSBOOK_REDIS__HOST: redis
PASSBOOK_ERROR_REPORTING: ${PASSBOOK_ERROR_REPORTING:-false}
PASSBOOK_POSTGRESQL__HOST: postgresql
PASSBOOK_POSTGRESQL__PASSWORD: ${PG_PASS:-thisisnotagoodpassword}
PASSBOOK_LOG_LEVEL: debug
ports:
- 8000
networks:
@ -39,26 +38,20 @@ services:
- traefik.docker.network=internal
- traefik.frontend.rule=PathPrefix:/
worker:
image: beryju/passbook:${PASSBOOK_TAG:-latest}
command:
- celery
- worker
- --autoscale=10,3
- -E
- -B
- -A=passbook.root.celery
- -s=/tmp/celerybeat-schedule
image: beryju/passbook:${PASSBOOK_TAG:-0.10.0-rc3}
command: worker
networks:
- internal
labels:
- traefik.enable=false
environment:
- PASSBOOK_REDIS__HOST=redis
- PASSBOOK_ERROR_REPORTING=${PASSBOOK_ERROR_REPORTING:-false}
- PASSBOOK_POSTGRESQL__HOST=postgresql
- PASSBOOK_POSTGRESQL__PASSWORD=${PG_PASS:-thisisnotagoodpassword}
PASSBOOK_REDIS__HOST: redis
PASSBOOK_ERROR_REPORTING: ${PASSBOOK_ERROR_REPORTING:-false}
PASSBOOK_POSTGRESQL__HOST: postgresql
PASSBOOK_POSTGRESQL__PASSWORD: ${PG_PASS:-thisisnotagoodpassword}
PASSBOOK_LOG_LEVEL: debug
static:
image: beryju/passbook-static:latest
image: beryju/passbook-static:${PASSBOOK_TAG:-0.10.0-rc3}
networks:
- internal
labels:

View File

@ -1,3 +0,0 @@
#!/bin/bash -ex
/app/wait_for_db.py
"$@"

View File

@ -1,10 +0,0 @@
[uwsgi]
http = 0.0.0.0:8000
wsgi-file = passbook/root/wsgi.py
processes = 2
master = true
threads = 2
enable-threads = true
uid = passbook
gid = passbook
disable-logging = True

View File

@ -1,3 +0,0 @@
#!/bin/bash -x
pip install -U mkdocs mkdocs-material
mkdocs gh-deploy

View File

@ -0,0 +1,180 @@
{
"version": 1,
"entries": [
{
"identifiers": {
"pk": "773c6673-e4a2-423f-8d32-95b7b4a41cf3",
"slug": "default-enrollment-flow"
},
"model": "passbook_flows.flow",
"attrs": {
"name": "Default enrollment Flow",
"title": "Welcome to passbook!",
"designation": "enrollment"
}
},
{
"identifiers": {
"pk": "cb954fd4-65a5-4ad9-b1ee-180ee9559cf4"
},
"model": "passbook_stages_prompt.prompt",
"attrs": {
"field_key": "username",
"label": "Username",
"type": "text",
"required": true,
"placeholder": "Username",
"order": 0
}
},
{
"identifiers": {
"pk": "7db91ee8-4290-4e08-8d39-63f132402515"
},
"model": "passbook_stages_prompt.prompt",
"attrs": {
"field_key": "password",
"label": "Password",
"type": "password",
"required": true,
"placeholder": "Password",
"order": 0
}
},
{
"identifiers": {
"pk": "d30b5eb4-7787-4072-b1ba-65b46e928920"
},
"model": "passbook_stages_prompt.prompt",
"attrs": {
"field_key": "password_repeat",
"label": "Password (repeat)",
"type": "password",
"required": true,
"placeholder": "Password (repeat)",
"order": 1
}
},
{
"identifiers": {
"pk": "f78d977a-efa6-4cc2-9a0f-2621a9fd94d2"
},
"model": "passbook_stages_prompt.prompt",
"attrs": {
"field_key": "name",
"label": "Name",
"type": "text",
"required": true,
"placeholder": "Name",
"order": 0
}
},
{
"identifiers": {
"pk": "1ff91927-e33d-4615-95b0-c258e5f0df62"
},
"model": "passbook_stages_prompt.prompt",
"attrs": {
"field_key": "email",
"label": "Email",
"type": "email",
"required": true,
"placeholder": "Email",
"order": 1
}
},
{
"identifiers": {
"pk": "6c342b94-790d-425a-ae31-6196b6570722",
"name": "default-enrollment-prompt-second"
},
"model": "passbook_stages_prompt.promptstage",
"attrs": {
"fields": [
"f78d977a-efa6-4cc2-9a0f-2621a9fd94d2",
"1ff91927-e33d-4615-95b0-c258e5f0df62"
]
}
},
{
"identifiers": {
"pk": "20375f30-7fa7-4562-8f6e-0f61889f2963",
"name": "default-enrollment-prompt-first"
},
"model": "passbook_stages_prompt.promptstage",
"attrs": {
"fields": [
"cb954fd4-65a5-4ad9-b1ee-180ee9559cf4",
"7db91ee8-4290-4e08-8d39-63f132402515",
"d30b5eb4-7787-4072-b1ba-65b46e928920"
]
}
},
{
"identifiers": {
"pk": "77090897-eb3f-40db-81e6-b4074b1998c4",
"name": "default-enrollment-user-login"
},
"model": "passbook_stages_user_login.userloginstage",
"attrs": {
"session_duration": 0
}
},
{
"identifiers": {
"pk": "a4090add-f483-4ac6-8917-10b493ef843e",
"name": "default-enrollment-user-write"
},
"model": "passbook_stages_user_write.userwritestage",
"attrs": {}
},
{
"identifiers": {
"pk": "34e1e7d5-8eed-4549-bc7a-305069ff7df0",
"target": "773c6673-e4a2-423f-8d32-95b7b4a41cf3",
"stage": "20375f30-7fa7-4562-8f6e-0f61889f2963",
"order": 0
},
"model": "passbook_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
}
},
{
"identifiers": {
"pk": "e40467a6-3052-488c-a1b5-1ad7a80fe7b3",
"target": "773c6673-e4a2-423f-8d32-95b7b4a41cf3",
"stage": "6c342b94-790d-425a-ae31-6196b6570722",
"order": 1
},
"model": "passbook_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
}
},
{
"identifiers": {
"pk": "76bc594e-2715-49ab-bd40-994abd9a7b70",
"target": "773c6673-e4a2-423f-8d32-95b7b4a41cf3",
"stage": "a4090add-f483-4ac6-8917-10b493ef843e",
"order": 2
},
"model": "passbook_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
}
},
{
"identifiers": {
"pk": "2f324f6d-7646-4108-a6e2-e7f90985477f",
"target": "773c6673-e4a2-423f-8d32-95b7b4a41cf3",
"stage": "77090897-eb3f-40db-81e6-b4074b1998c4",
"order": 3
},
"model": "passbook_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
}
}
]
}

View File

@ -0,0 +1,223 @@
{
"version": 1,
"entries": [
{
"identifiers": {
"pk": "773c6673-e4a2-423f-8d32-95b7b4a41cf3",
"slug": "default-enrollment-flow"
},
"model": "passbook_flows.flow",
"attrs": {
"name": "Default enrollment Flow",
"title": "Welcome to passbook!",
"designation": "enrollment"
}
},
{
"identifiers": {
"pk": "cb954fd4-65a5-4ad9-b1ee-180ee9559cf4"
},
"model": "passbook_stages_prompt.prompt",
"attrs": {
"field_key": "username",
"label": "Username",
"type": "text",
"required": true,
"placeholder": "Username",
"order": 0
}
},
{
"identifiers": {
"pk": "7db91ee8-4290-4e08-8d39-63f132402515"
},
"model": "passbook_stages_prompt.prompt",
"attrs": {
"field_key": "password",
"label": "Password",
"type": "password",
"required": true,
"placeholder": "Password",
"order": 0
}
},
{
"identifiers": {
"pk": "d30b5eb4-7787-4072-b1ba-65b46e928920"
},
"model": "passbook_stages_prompt.prompt",
"attrs": {
"field_key": "password_repeat",
"label": "Password (repeat)",
"type": "password",
"required": true,
"placeholder": "Password (repeat)",
"order": 1
}
},
{
"identifiers": {
"pk": "f78d977a-efa6-4cc2-9a0f-2621a9fd94d2"
},
"model": "passbook_stages_prompt.prompt",
"attrs": {
"field_key": "name",
"label": "Name",
"type": "text",
"required": true,
"placeholder": "Name",
"order": 0
}
},
{
"identifiers": {
"pk": "1ff91927-e33d-4615-95b0-c258e5f0df62"
},
"model": "passbook_stages_prompt.prompt",
"attrs": {
"field_key": "email",
"label": "Email",
"type": "email",
"required": true,
"placeholder": "Email",
"order": 1
}
},
{
"identifiers": {
"pk": "9922212c-47a2-475a-9905-abeb5e621652"
},
"model": "passbook_policies_expression.expressionpolicy",
"attrs": {
"name": "policy-enrollment-password-equals",
"expression": "# Verifies that the passwords are equal\r\nreturn request.context['password'] == request.context['password_repeat']"
}
},{
"identifiers": {
"pk": "096e6282-6b30-4695-bd03-3b143eab5580",
"name": "default-enrollment-email-verficiation"
},
"model": "passbook_stages_email.emailstage",
"attrs": {
"host": "localhost",
"port": 25,
"username": "",
"use_tls": false,
"use_ssl": false,
"timeout": 10,
"from_address": "system@passbook.local",
"token_expiry": 30,
"subject": "passbook",
"template": "stages/email/for_email/account_confirmation.html"
}
},
{
"identifiers": {
"pk": "6c342b94-790d-425a-ae31-6196b6570722",
"name": "default-enrollment-prompt-second"
},
"model": "passbook_stages_prompt.promptstage",
"attrs": {
"fields": [
"f78d977a-efa6-4cc2-9a0f-2621a9fd94d2",
"1ff91927-e33d-4615-95b0-c258e5f0df62"
]
}
},
{
"identifiers": {
"pk": "20375f30-7fa7-4562-8f6e-0f61889f2963",
"name": "default-enrollment-prompt-first"
},
"model": "passbook_stages_prompt.promptstage",
"attrs": {
"fields": [
"cb954fd4-65a5-4ad9-b1ee-180ee9559cf4",
"7db91ee8-4290-4e08-8d39-63f132402515",
"d30b5eb4-7787-4072-b1ba-65b46e928920"
],
"validation_policies": [
"9922212c-47a2-475a-9905-abeb5e621652"
]
}
},
{
"identifiers": {
"pk": "77090897-eb3f-40db-81e6-b4074b1998c4",
"name": "default-enrollment-user-login"
},
"model": "passbook_stages_user_login.userloginstage",
"attrs": {
"session_duration": 0
}
},
{
"identifiers": {
"pk": "a4090add-f483-4ac6-8917-10b493ef843e",
"name": "default-enrollment-user-write"
},
"model": "passbook_stages_user_write.userwritestage",
"attrs": {}
},
{
"identifiers": {
"pk": "34e1e7d5-8eed-4549-bc7a-305069ff7df0",
"target": "773c6673-e4a2-423f-8d32-95b7b4a41cf3",
"stage": "20375f30-7fa7-4562-8f6e-0f61889f2963",
"order": 0
},
"model": "passbook_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
}
},
{
"identifiers": {
"pk": "e40467a6-3052-488c-a1b5-1ad7a80fe7b3",
"target": "773c6673-e4a2-423f-8d32-95b7b4a41cf3",
"stage": "6c342b94-790d-425a-ae31-6196b6570722",
"order": 1
},
"model": "passbook_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
}
},
{
"identifiers": {
"pk": "76bc594e-2715-49ab-bd40-994abd9a7b70",
"target": "773c6673-e4a2-423f-8d32-95b7b4a41cf3",
"stage": "a4090add-f483-4ac6-8917-10b493ef843e",
"order": 2
},
"model": "passbook_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
}
},
{
"identifiers": {
"pk": "1db34a14-8985-4184-b5c9-254cd585d94f",
"target": "773c6673-e4a2-423f-8d32-95b7b4a41cf3",
"stage": "096e6282-6b30-4695-bd03-3b143eab5580",
"order": 3
},
"model": "passbook_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
}
},
{
"identifiers": {
"pk": "2f324f6d-7646-4108-a6e2-e7f90985477f",
"target": "773c6673-e4a2-423f-8d32-95b7b4a41cf3",
"stage": "77090897-eb3f-40db-81e6-b4074b1998c4",
"order": 4
},
"model": "passbook_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
}
}
]
}

View File

@ -0,0 +1,49 @@
# Example Flows
!!! info
You can apply theses flows multiple times to stay updated, however this will discard all changes you've made.
## Enrollment (2 Stage)
Flow: right-click [here](enrollment-2-stage.json) and save the file.
Sign-up flow for new users, which prompts them for their username, email, password and name. No verification is done. Users are also immediately logged on after this flow.
## Enrollment with email verification
Flow: right-click [here](enrollment-email-verification.json) and save the file.
Same flow as above, with an extra email verification stage.
You'll probably have to adjust the Email stage and set your connection details.
## Two-factor Login
Flow: right-click [here](login-2fa.json) and save the file.
Login flow which follows the default pattern (username/email, then password), but also checks for the user's OTP token, if they have one configured
## Login with conditional Captcha
Flow: right-click [here](login-conditional-captcha.json) and save the file.
Login flow which conditionally shows the users a captcha, based on the reputation of their IP and Username.
By default, the captcha test keys are used. You can get a proper key [here](https://www.google.com/recaptcha/intro/v3.html)
## Recovery with email verification
Flow: right-click [here](recovery-email-verification.json) and save the file.
Recovery flow, the user is sent an email after they've identified themselves. After they click on the link in the email, they are prompted for a new password and immediately logged on.
## User deletion
Flow: right-click [here](unenrollment.json) and save the file.
Flow for users to delete their account,
!!! warning
This is done without any warning.

View File

@ -0,0 +1,111 @@
{
"version": 1,
"entries": [
{
"identifiers": {
"slug": "default-authentication-flow",
"pk": "563ece21-e9a4-47e5-a264-23ffd923e393"
},
"model": "passbook_flows.flow",
"attrs": {
"name": "Default Authentication Flow",
"title": "Welcome to passbook!",
"designation": "authentication"
}
},
{
"identifiers": {
"pk": "69d41125-3987-499b-8d74-ef27b54b88c8",
"name": "default-authentication-login"
},
"model": "passbook_stages_user_login.userloginstage",
"attrs": {
"session_duration": 0
}
},
{
"identifiers": {
"pk": "5f594f27-0def-488d-9855-fe604eb13de5",
"name": "default-authentication-identification"
},
"model": "passbook_stages_identification.identificationstage",
"attrs": {
"user_fields": [
"email",
"username"
],
"template": "stages/identification/login.html",
"enrollment_flow": null,
"recovery_flow": null
}
},
{
"identifiers": {
"pk": "37f709c3-8817-45e8-9a93-80a925d293c2",
"name": "default-authentication-flow-totp"
},
"model": "passbook_stages_otp_validate.otpvalidatestage",
"attrs": {}
},
{
"identifiers": {
"pk": "d8affa62-500c-4c5c-a01f-5835e1ffdf40",
"name": "default-authentication-password"
},
"model": "passbook_stages_password.passwordstage",
"attrs": {
"backends": [
"django.contrib.auth.backends.ModelBackend"
]
}
},
{
"identifiers": {
"pk": "a3056482-b692-4e3a-93f1-7351c6a351c7",
"target": "563ece21-e9a4-47e5-a264-23ffd923e393",
"stage": "5f594f27-0def-488d-9855-fe604eb13de5",
"order": 0
},
"model": "passbook_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
}
},
{
"identifiers": {
"pk": "4e8538cf-3e18-4a68-82ae-6df6725fa2e6",
"target": "563ece21-e9a4-47e5-a264-23ffd923e393",
"stage": "d8affa62-500c-4c5c-a01f-5835e1ffdf40",
"order": 1
},
"model": "passbook_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
}
},
{
"identifiers": {
"pk": "688aec6f-5622-42c6-83a5-d22072d7e798",
"target": "563ece21-e9a4-47e5-a264-23ffd923e393",
"stage": "37f709c3-8817-45e8-9a93-80a925d293c2",
"order": 2
},
"model": "passbook_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
}
},
{
"identifiers": {
"pk": "f3fede3a-a9b5-4232-9ec7-be7ff4194b27",
"target": "563ece21-e9a4-47e5-a264-23ffd923e393",
"stage": "69d41125-3987-499b-8d74-ef27b54b88c8",
"order": 3
},
"model": "passbook_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
}
}
]
}

View File

@ -0,0 +1,139 @@
{
"version": 1,
"entries": [
{
"identifiers": {
"slug": "default-authentication-flow",
"pk": "563ece21-e9a4-47e5-a264-23ffd923e393"
},
"model": "passbook_flows.flow",
"attrs": {
"name": "Default Authentication Flow",
"title": "Welcome to passbook!",
"designation": "authentication"
}
},
{
"identifiers": {
"name": "default-authentication-login",
"pk": "69d41125-3987-499b-8d74-ef27b54b88c8"
},
"model": "passbook_stages_user_login.userloginstage",
"attrs": {
"session_duration": 0
}
},
{
"identifiers": {
"name": "default-authentication-flow-captcha",
"pk": "a368cafc-1494-45e9-b75b-b5e7ac2bd3e4"
},
"model": "passbook_stages_captcha.captchastage",
"attrs": {
"public_key": "6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI",
"private_key": "6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe"
}
},
{
"identifiers": {
"name": "default-authentication-identification",
"pk": "5f594f27-0def-488d-9855-fe604eb13de5"
},
"model": "passbook_stages_identification.identificationstage",
"attrs": {
"user_fields": [
"email",
"username"
],
"template": "stages/identification/login.html",
"enrollment_flow": null,
"recovery_flow": null
}
},
{
"identifiers": {
"name": "default-authentication-password",
"pk": "d8affa62-500c-4c5c-a01f-5835e1ffdf40"
},
"model": "passbook_stages_password.passwordstage",
"attrs": {
"backends": [
"django.contrib.auth.backends.ModelBackend"
]
}
},
{
"identifiers": {
"pk": "a3056482-b692-4e3a-93f1-7351c6a351c7",
"target": "563ece21-e9a4-47e5-a264-23ffd923e393",
"stage": "5f594f27-0def-488d-9855-fe604eb13de5",
"order": 0
},
"model": "passbook_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
}
},
{
"identifiers": {
"pk": "4e8538cf-3e18-4a68-82ae-6df6725fa2e6",
"target": "563ece21-e9a4-47e5-a264-23ffd923e393",
"stage": "d8affa62-500c-4c5c-a01f-5835e1ffdf40",
"order": 1
},
"model": "passbook_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
}
},
{
"identifiers": {
"pk": "3bcd6af0-48a6-4e18-87f3-d251a1a58226",
"target": "563ece21-e9a4-47e5-a264-23ffd923e393",
"stage": "a368cafc-1494-45e9-b75b-b5e7ac2bd3e4",
"order": 2
},
"model": "passbook_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
}
},
{
"identifiers": {
"pk": "f3fede3a-a9b5-4232-9ec7-be7ff4194b27",
"target": "563ece21-e9a4-47e5-a264-23ffd923e393",
"stage": "69d41125-3987-499b-8d74-ef27b54b88c8",
"order": 3
},
"model": "passbook_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
}
},
{
"identifiers": {
"pk": "688c9890-47ad-4327-a9e5-380e88d34be5"
},
"model": "passbook_policies_reputation.reputationpolicy",
"attrs": {
"name": "default-authentication-flow-conditional-captcha",
"check_ip": true,
"check_username": true,
"threshold": -5
}
},
{
"identifiers": {
"pk": "02e4d220-3448-44db-822e-c5255cf7c250",
"policy": "688c9890-47ad-4327-a9e5-380e88d34be5",
"target": "3bcd6af0-48a6-4e18-87f3-d251a1a58226",
"order": 0
},
"model": "passbook_policies.policybinding",
"attrs": {
"enabled": true,
"timeout": 30
}
}
]
}

View File

@ -1,36 +0,0 @@
# Login Flow
This document describes how a simple authentication flow can be created.
This flow is created automatically when passbook is installed.
1. Create an **Identification** stage
> Here you can select whichever fields the user can identify themselves with
> Select the Template **Default Login**, as this template shows the (optional) Flows
> Here you can also link optional enrollment and recovery flows.
2. Create a **Password** stage
> Select the Backend you want the password to be checked against. Select "passbook-internal Userdatabase".
3. Create a **User Login** stage
> This stage doesn't have any options.
4. Create a flow
> Create a flow with the delegation of **Authentication**
> Assign a name and a slug. The slug is used in the URL when the flow is executed.
5. Bind the stages to the flow
> Bind the **Identification** Stage with an order of 0
> Bind the **Password** Stage with an order of 1
> Bind the **User Login** Stage with an order of 2
![](login.png)
!!! notice
This flow can used by any user, authenticated and un-authenticated. This means any authenticated user that visits this flow can login again.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

View File

@ -0,0 +1,198 @@
{
"version": 1,
"entries": [
{
"identifiers": {
"pk": "a5993183-89c0-43d2-a7f4-ddffb17baba7",
"slug": "default-recovery-flow"
},
"model": "passbook_flows.flow",
"attrs": {
"name": "Default recovery flow",
"title": "Reset your password",
"designation": "recovery"
}
},
{
"identifiers": {
"pk": "1ff91927-e33d-4615-95b0-c258e5f0df62"
},
"model": "passbook_stages_prompt.prompt",
"attrs": {
"field_key": "email",
"label": "Email",
"type": "email",
"required": true,
"placeholder": "Email",
"order": 1
}
},
{
"identifiers": {
"pk": "7db91ee8-4290-4e08-8d39-63f132402515"
},
"model": "passbook_stages_prompt.prompt",
"attrs": {
"field_key": "password",
"label": "Password",
"type": "password",
"required": true,
"placeholder": "Password",
"order": 0
}
},
{
"identifiers": {
"pk": "d30b5eb4-7787-4072-b1ba-65b46e928920"
},
"model": "passbook_stages_prompt.prompt",
"attrs": {
"field_key": "password_repeat",
"label": "Password (repeat)",
"type": "password",
"required": true,
"placeholder": "Password (repeat)",
"order": 1
}
},
{
"identifiers": {
"pk": "cd042fc6-cc92-4b98-b7e6-f4729df798d8"
},
"model": "passbook_policies_expression.expressionpolicy",
"attrs": {
"name": "default-password-change-password-equal",
"expression": "# Check that both passwords are equal.\nreturn request.context['password'] == request.context['password_repeat']"
}
},
{
"identifiers": {
"pk": "e54045a7-6ecb-4ad9-ad37-28e72d8e565e",
"name": "default-recovery-identification"
},
"model": "passbook_stages_identification.identificationstage",
"attrs": {
"user_fields": [
"email",
"username"
],
"template": "stages/identification/recovery.html",
"enrollment_flow": null,
"recovery_flow": null
}
},
{
"identifiers": {
"pk": "3909fd60-b013-4668-8806-12e9507dab97",
"name": "default-recovery-user-write"
},
"model": "passbook_stages_user_write.userwritestage",
"attrs": {}
},
{
"identifiers": {
"pk": "66f948dc-3f74-42b2-b26b-b8b9df109efb",
"name": "default-recovery-email"
},
"model": "passbook_stages_email.emailstage",
"attrs": {
"host": "localhost",
"port": 25,
"username": "",
"use_tls": false,
"use_ssl": false,
"timeout": 10,
"from_address": "system@passbook.local",
"token_expiry": 30,
"subject": "passbook",
"template": "stages/email/for_email/password_reset.html"
}
},
{
"identifiers": {
"pk": "975d5502-1e22-4d10-b560-fbc5bd70ff4d",
"name": "default-password-change-prompt"
},
"model": "passbook_stages_prompt.promptstage",
"attrs": {
"fields": [
"7db91ee8-4290-4e08-8d39-63f132402515",
"d30b5eb4-7787-4072-b1ba-65b46e928920"
],
"validation_policies": [
"cd042fc6-cc92-4b98-b7e6-f4729df798d8"
]
}
},
{
"identifiers": {
"pk": "fcdd4206-0d35-4ad2-a59f-5a72422936bb",
"name": "default-recovery-user-login"
},
"model": "passbook_stages_user_login.userloginstage",
"attrs": {
"session_duration": 0
}
},
{
"identifiers": {
"pk": "7af7558e-2196-4b9f-a08e-d38420b7cfbb",
"target": "a5993183-89c0-43d2-a7f4-ddffb17baba7",
"stage": "e54045a7-6ecb-4ad9-ad37-28e72d8e565e",
"order": 0
},
"model": "passbook_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
}
},
{
"identifiers": {
"pk": "29446fd6-dd93-4e92-9830-2d81debad5ae",
"target": "a5993183-89c0-43d2-a7f4-ddffb17baba7",
"stage": "66f948dc-3f74-42b2-b26b-b8b9df109efb",
"order": 1
},
"model": "passbook_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
}
},
{
"identifiers": {
"pk": "1219d06e-2c06-4c5b-a162-78e3959c6cf0",
"target": "a5993183-89c0-43d2-a7f4-ddffb17baba7",
"stage": "975d5502-1e22-4d10-b560-fbc5bd70ff4d",
"order": 2
},
"model": "passbook_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
}
},
{
"identifiers": {
"pk": "66de86ba-0707-46a0-8475-ff2e260d6935",
"target": "a5993183-89c0-43d2-a7f4-ddffb17baba7",
"stage": "3909fd60-b013-4668-8806-12e9507dab97",
"order": 3
},
"model": "passbook_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
}
},
{
"identifiers": {
"pk": "9cec2334-d4a2-4895-a2b2-bc5ae4e9639a",
"target": "a5993183-89c0-43d2-a7f4-ddffb17baba7",
"stage": "fcdd4206-0d35-4ad2-a59f-5a72422936bb",
"order": 4
},
"model": "passbook_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
}
}
]
}

View File

@ -0,0 +1,37 @@
{
"version": 1,
"entries": [
{
"identifiers": {
"pk": "59a576ce-2f23-4a63-b63a-d18dc7e550f5",
"slug": "default-unenrollment-flow"
},
"model": "passbook_flows.flow",
"attrs": {
"name": "Default unenrollment flow",
"title": "Delete your account",
"designation": "unenrollment"
}
},
{
"identifiers": {
"pk": "c62ac2a4-2735-4a0f-abd0-8523d68c1209",
"name": "default-unenrollment-user-delete"
},
"model": "passbook_stages_user_delete.userdeletestage",
"attrs": {}
},
{
"identifiers": {
"pk": "eb9aff2b-b95d-40b3-ad08-233aa77bbcf3",
"target": "59a576ce-2f23-4a63-b63a-d18dc7e550f5",
"stage": "c62ac2a4-2735-4a0f-abd0-8523d68c1209",
"order": 0
},
"model": "passbook_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
}
}
]
}

View File

@ -16,15 +16,15 @@ wget https://raw.githubusercontent.com/BeryJu/passbook/master/docker-compose.yml
# Optionally enable Error-reporting
# export PASSBOOK_ERROR_REPORTING=true
# Optionally deploy a different version
# export PASSBOOK_TAG=0.9.0-rc1
# export PASSBOOK_TAG=0.10.0-rc3
# If this is a productive installation, set a different PostgreSQL Password
# export PG_PASS=$(pwgen 40 1)
docker-compose pull
docker-compose up -d
docker-compose exec server ./manage.py migrate
docker-compose run --rm server migrate
```
The compose file references the current latest version, which can be overridden with the `SERVER_TAG` environment variable.
The compose file statically references the latest version available at the time of downloading, which can be overridden with the `SERVER_TAG` environment variable.
If you plan to use this setup for production, it is also advised to change the PostgreSQL password by setting `PG_PASS` to a password of your choice.

View File

@ -5,34 +5,30 @@ For a mid to high-load installation, Kubernetes is recommended. passbook is inst
This installation automatically applies database migrations on startup. After the installation is done, you can use `pbadmin` as username and password.
```
# Default values for passbook.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
# passbook version to use. Defaults to latest stable version
# image:
# tag:
###################################
# Values directly affecting passbook
###################################
image:
name: beryju/passbook
name_static: beryju/passbook-static
tag: 0.9.0-stable
nameOverride: ""
serverReplicas: 1
workerReplicas: 1
config:
# Optionally specify fixed secret_key, otherwise generated automatically
# secret_key: _k*@6h2u2@q-dku57hhgzb7tnx*ba9wodcb^s9g0j59@=y(@_o
# Enable error reporting
error_reporting: false
error_reporting:
enabled: false
environment: customer
send_pii: false
# Log level used by web and worker
# Can be either debug, info, warning, error
log_level: warning
# Optionally enable Elastic APM Support
apm:
enabled: false
server_url: ""
secret_token: ""
verify_server_cert: true
# This Helm chart ships with built-in Prometheus ServiceMonitors and Rules.
# This requires the CoreOS Prometheus Operator.
monitoring:
enabled: false
# Enable Database Backups to S3
# backup:
@ -41,20 +37,15 @@ monitoring:
# bucket: s3-bucket
# host: s3-host
ingress:
enabled: false
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
path: /
hosts:
- passbook.k8s.local
tls: []
# - secretName: chart-example-tls
# hosts:
# - passbook.k8s.local
###################################
# Values controlling dependencies
###################################
# These settings configure the packaged PostgreSQL and Redis chart.
install:
postgresql: true
redis: true
# These values influence the bundled postgresql and redis charts, but are also used by passbook to connect
postgresql:
postgresqlDatabase: passbook
@ -66,4 +57,16 @@ redis:
enabled: false
# https://stackoverflow.com/a/59189742
disableCommands: []
ingress:
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
path: /
hosts:
- passbook.k8s.local
tls: []
# - secretName: chart-example-tls
# hosts:
# - passbook.k8s.local
```

View File

@ -16,6 +16,7 @@ Create an application in passbook and note the slug, as this will be used later.
- ACS URL: `https://signin.aws.amazon.com/saml`
- Audience: `urn:amazon:webservices`
- Issuer: `passbook`
- Binding: `Post`
You can of course use a custom signing certificate, and adjust durations.

26
docs/outposts/outposts.md Normal file
View File

@ -0,0 +1,26 @@
# Outposts
An outpost is a single deployment of a passbook component, which can be deployed in a completely separate environment. Currently, only the Proxy Provider is supported as outpost.
![](outposts.png)
Upon creation, a service account and a token is generated. The service account only has permissions to read the outpost and provider configuration. This token is used by the Outpost to connect to passbook.
To deploy an outpost, you can for example use this docker-compose snippet:
```yaml
version: 3.5
services:
passbook_proxy:
image: beryju/passbook-proxy:0.10.0-stable
ports:
- 4180:4180
- 4443:4443
environment:
PASSBOOK_HOST: https://your-passbook.tld
PASSBOOK_INSECURE: 'true'
PASSBOOK_TOKEN: token-generated-by-passbook
```
In future versions, this snippet will be automatically generated. You will also be able to deploy an outpost directly into a kubernetes cluster.w

BIN
docs/outposts/outposts.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

View File

@ -19,3 +19,7 @@ LDAP Property Mappings are used when you define a LDAP Source. These mappings de
- Autogenerated LDAP Mapping: sn -> last_name
These are configured with most common LDAP setups.
## Scope Mapping
Scope Mappings are used by the OAuth2 Provider to map information from passbook to OAuth2/OpenID Claims.

View File

@ -1,24 +0,0 @@
# Providers
Providers allow external applications to authenticate against passbook and use its user information.
## OpenID Provider
This provider utilises the commonly used OpenID Connect variation of OAuth2.
## OAuth2 Provider
This provider is slightly different than the OpenID Provider. While it uses the same basic OAuth2 Protocol, it provides a GitHub-compatible endpoint. This allows you to integrate applications which don't support custom OpenID providers.
The API exposes username, email, name, and groups in a GitHub-compatible format.
This provider currently supports the following scopes:
- `openid`: Access OpenID Userinfo
- `userinfo`: Access OpenID Userinfo
- `email`: Access OpenID Email
- `user:email`: GitHub Compatibility: User Email
- `read:org`: GitHub Compatibility: User Groups
## SAML Provider
This provider allows you to integrate enterprise software using the SAML2 Protocol. It supports signed requests and uses [Property Mappings](property-mappings/index.md#saml-property-mapping) to determine which fields are exposed and what values they return. This makes it possible to expose vendor-specific fields.
Default fields are exposed through auto-generated Property Mappings, which are prefixed with "Autogenerated".

31
docs/providers/oauth2.md Normal file
View File

@ -0,0 +1,31 @@
# OAuth2 Provider
This provider supports both generic OAuth2 as well as OpenID Connect
Scopes can be configured using Scope Mappings, a type of [Property Mappings](../property-mappings/index.md#scope-mapping).
Endpoint | URL
---------|---
Authorization | `/application/o/authorize/`
Token | `/application/o/token/`
User Info | `/application/o/userinfo/`
End Session | `/application/o/end-session/`
Introspect | `/application/o/end-session/`
JWKS | `/application/o/<application slug>/jwks/`
OpenID Configuration | `/application/o/<application slug>/.well-known/openid-configuration`
## GitHub Compatibility
This provider also exposes a GitHub-compatible endpoint. This endpoint can be used by applications, which support authenticating against GitHub Enterprise, but not generic OpenID Connect.
To use any of the GitHub Compatibility scopes, you have to use the GitHub Compatibility Endpoints.
Endpoint | URL
---------|---
Authorization | `/login/oauth/authorize`
Token | `/login/oauth/access_token`
User Info | `/user`
User Teams Info | `/user/teams`
To access the user's email address, a scope of `user:email` is required. To access their groups, `read:org` is required. Because these scopes are handled by a different endpoint, they are not customisable as a Scope Mapping.

16
docs/providers/proxy.md Normal file
View File

@ -0,0 +1,16 @@
# Proxy Provider
!!! info
This provider is to be used in conjunction with [Outposts](../outposts/outposts.md)
This provider protects applications, which have no built-in support for OAuth2 or SAML. This is done by running a lightweight Reverse Proxy in front of the application, which authenticates the requests.
passbook Proxy is based on [oauth2_proxy](https://github.com/oauth2-proxy/oauth2-proxy), but has been integrated more tightly with passbook.
The Proxy these extra headers to the application:
Header Name | Value
-------------|-------
X-Auth-Request-User | The user's unique identifier
X-Auth-Request-Email | The user's email address
X-Auth-Request-Preferred-Username | The user's username

12
docs/providers/saml.md Normal file
View File

@ -0,0 +1,12 @@
# SAML Provider
This provider allows you to integrate enterprise software using the SAML2 Protocol. It supports signed requests and uses [Property Mappings](../property-mappings/index.md#saml-property-mapping) to determine which fields are exposed and what values they return. This makes it possible to expose vendor-specific fields.
Default fields are exposed through auto-generated Property Mappings, which are prefixed with "Autogenerated".
Endpoint | URL
---------|---
SSO (Redirect binding) | `/application/saml/<application slug>/sso/binding/redirect/`
SSO (POST binding) | `/application/saml/<application slug>/sso/binding/post/`
IdP-initiated login | `/application/saml/<application slug>/sso/binding/init/`
Metadata Download | `/application/saml/<application slug>/metadata/`

73
docs/upgrading/to-0.10.md Normal file
View File

@ -0,0 +1,73 @@
# Upgrading to 0.10
This update brings a lot of big features, such as:
- New OAuth2/OpenID Provider
This new provider merges both OAuth2 and OpenID. It is based on the codebase of the old provider, which has been simplified and cleaned from the ground up. Support for Property Mappings has also been added. Because of this change, OpenID and OAuth2 Providers will have to be re-created.
- Proxy Provider
Due to this new OAuth2 Provider, the Application Gateway Provider, now simply called "Proxy Provider" has been revamped as well. The new passbook Proxy integrates more tightly with passbook via the new Outposts system. The new proxy also supports multiple applications per proxy instance, can configure TLS based on passbook Keypairs, and more.
See [Proxy](../providers/proxy.md)
- Outpost System
This is a new Object type, currently used only by the Proxy Provider. It manages the creation and permissions of service accounts, which are used by the outposts to communicate with passbook.
See [Outposts](../outposts/outposts.md)
- Flow Import/Export
Flows can now be imported and exported. This feature can be used as a backup system, or to share complex flows with other people. Example flows have also been added to the documentation to help you get going with passbook.
## Under the hood
- passbook now runs on Django 3.1 and Channels with complete ASGI enabled
- uwsgi has been replaced with Gunicorn and uvicorn
- Elastic APM has been replaced with Sentry Performance metrics
- Flow title is now configurable separately from the name
- All logging output is now json
## Upgrading
### docker-compose
The docker-compose file has been updated, please download the latest from `https://raw.githubusercontent.com/BeryJu/passbook/master/docker-compose.yml`.
By default, the new compose file uses a fixed version to prevent unintended updates.
Before updating the file, stop all containers. Then download the file, pull the new containers and start the database.
```
docker-compose down
docker-compose pull
docker-compose up --no-start
docker-compose start redis postgrseql
docker-compose run --rm server migrate
docker-compose up -d
```
### Helm
A few options have changed:
- `error_reporting` was changed from a simple boolean to a dictionary:
```yaml
error_reporting:
enabled: false
environment: customer
send_pii: false
```
- The `apm` and `monitoring` blocks have been removed.
- `serverReplicas` and `workerReplicas` have been added
### Upgrading
This upgrade only applies if you are upgrading from a running 0.9 instance. Passbook detects this on startup, and automatically executes this upgrade.
Because this upgrade brings the new OAuth2 Provider, the old providers will be lost in the process. Make sure to take note of the providers you want to bring over.
Another side-effect of this upgrade is the change of OAuth2 URLs, see [here](../providers/oauth2.md).

View File

@ -1,4 +1,4 @@
# Upgrading from 0.8.x
# Upgrading to 0.9
Due to some database changes that had to be rather sooner than later, there is no possibility to directly upgrade. You must extract the data before hand and import it again. It is recommended to spin up a second instance of passbook to do this.

View File

@ -2,7 +2,7 @@ version: '3.7'
services:
chrome:
image: selenium/standalone-chrome
image: selenium/standalone-chrome:3.141.59-20200525
volumes:
- /dev/shm:/dev/shm
network_mode: host

View File

@ -6,3 +6,4 @@ services:
volumes:
- /dev/shm:/dev/shm
network_mode: host
restart: always

View File

@ -2,22 +2,24 @@
from time import sleep
from django.test import override_settings
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as ec
from docker import DockerClient, from_env
from docker.models.containers import Container
from docker.types import Healthcheck
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as ec
from structlog import get_logger
from e2e.utils import USER, SeleniumTestCase
from passbook.flows.models import Flow, FlowDesignation, FlowStageBinding
from passbook.policies.expression.models import ExpressionPolicy
from passbook.policies.models import PolicyBinding
from passbook.stages.email.models import EmailStage, EmailTemplates
from passbook.stages.identification.models import IdentificationStage
from passbook.stages.prompt.models import FieldTypes, Prompt, PromptStage
from passbook.stages.user_login.models import UserLoginStage
from passbook.stages.user_write.models import UserWriteStage
LOGGER = get_logger()
class TestFlowsEnroll(SeleniumTestCase):
"""Test Enroll flow"""
@ -30,12 +32,12 @@ class TestFlowsEnroll(SeleniumTestCase):
"""Setup test IdP container"""
client: DockerClient = from_env()
container = client.containers.run(
image="mailhog/mailhog",
image="mailhog/mailhog:v1.0.1",
detach=True,
network_mode="host",
auto_remove=True,
healthcheck=Healthcheck(
test=["CMD", "wget", "-s", "http://localhost:8025"],
test=["CMD", "wget", "--spider", "http://localhost:8025"],
interval=5 * 100 * 1000000,
start_period=1 * 100 * 1000000,
),
@ -45,6 +47,7 @@ class TestFlowsEnroll(SeleniumTestCase):
status = container.attrs.get("State", {}).get("Health", {}).get("Status")
if status == "healthy":
return container
LOGGER.info("Container failed healthcheck")
sleep(1)
def tearDown(self):
@ -75,9 +78,16 @@ class TestFlowsEnroll(SeleniumTestCase):
field_key="email", label="E-Mail", order=1, type=FieldTypes.EMAIL
)
# Password checking policy
password_policy = ExpressionPolicy.objects.create(
name="policy-enrollment-password-equals",
expression="return request.context['password'] == request.context['password_repeat']",
)
# Stages
first_stage = PromptStage.objects.create(name="prompt-stage-first")
first_stage.fields.set([username_prompt, password, password_repeat])
first_stage.validation_policies.set([password_policy])
first_stage.save()
second_stage = PromptStage.objects.create(name="prompt-stage-second")
second_stage.fields.set([name_field, email])
@ -85,15 +95,6 @@ class TestFlowsEnroll(SeleniumTestCase):
user_write = UserWriteStage.objects.create(name="enroll-user-write")
user_login = UserLoginStage.objects.create(name="enroll-user-login")
# Password checking policy
password_policy = ExpressionPolicy.objects.create(
name="policy-enrollment-password-equals",
expression="return request.context['password'] == request.context['password_repeat']",
)
PolicyBinding.objects.create(
target=first_stage, policy=password_policy, order=0
)
flow = Flow.objects.create(
name="default-enrollment-flow",
slug="default-enrollment-flow",
@ -170,9 +171,16 @@ class TestFlowsEnroll(SeleniumTestCase):
field_key="email", label="E-Mail", order=1, type=FieldTypes.EMAIL
)
# Password checking policy
password_policy = ExpressionPolicy.objects.create(
name="policy-enrollment-password-equals",
expression="return request.context['password'] == request.context['password_repeat']",
)
# Stages
first_stage = PromptStage.objects.create(name="prompt-stage-first")
first_stage.fields.set([username_prompt, password, password_repeat])
first_stage.validation_policies.set([password_policy])
first_stage.save()
second_stage = PromptStage.objects.create(name="prompt-stage-second")
second_stage.fields.set([name_field, email])
@ -186,15 +194,6 @@ class TestFlowsEnroll(SeleniumTestCase):
user_write = UserWriteStage.objects.create(name="enroll-user-write")
user_login = UserLoginStage.objects.create(name="enroll-user-login")
# Password checking policy
password_policy = ExpressionPolicy.objects.create(
name="policy-enrollment-password-equals",
expression="return request.context['password'] == request.context['password_repeat']",
)
PolicyBinding.objects.create(
target=first_stage, policy=password_policy, order=0
)
flow = Flow.objects.create(
name="default-enrollment-flow",
slug="default-enrollment-flow",

View File

@ -8,6 +8,8 @@ from selenium.webdriver.common.keys import Keys
from e2e.utils import USER, SeleniumTestCase
from passbook.core.models import User
from passbook.flows.models import Flow, FlowDesignation
from passbook.stages.password.models import PasswordStage
class TestFlowsStageSetup(SeleniumTestCase):
@ -15,6 +17,16 @@ class TestFlowsStageSetup(SeleniumTestCase):
def test_password_change(self):
"""test password change flow"""
# Ensure that password stage has change_flow set
flow = Flow.objects.get(
slug="default-password-change", designation=FlowDesignation.STAGE_SETUP,
)
stages = PasswordStage.objects.filter(name="default-authentication-password")
stage = stages.first()
stage.change_flow = flow
stage.save()
new_password = "".join(
SystemRandom().choice(string.ascii_uppercase + string.digits)
for _ in range(8)
@ -29,6 +41,7 @@ class TestFlowsStageSetup(SeleniumTestCase):
self.driver.find_element(By.ID, "id_password").send_keys(Keys.ENTER)
self.driver.find_element(By.CSS_SELECTOR, ".pf-c-page__header").click()
self.driver.find_element(By.XPATH, "//a[contains(@href, '/-/user/')]").click()
self.wait_for_url(self.url("passbook_core:user-settings"))
self.driver.find_element(By.LINK_TEXT, "Change password").click()
self.driver.find_element(By.ID, "id_password").send_keys(new_password)
self.driver.find_element(By.ID, "id_password_repeat").click()

View File

@ -1,22 +1,28 @@
"""test OAuth Provider flow"""
from time import sleep
from oauth2_provider.generators import generate_client_id, generate_client_secret
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from docker import DockerClient, from_env
from docker.models.containers import Container
from docker.types import Healthcheck
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from structlog import get_logger
from e2e.utils import USER, SeleniumTestCase
from passbook.core.models import Application
from passbook.flows.models import Flow
from passbook.policies.expression.models import ExpressionPolicy
from passbook.policies.models import PolicyBinding
from passbook.providers.oauth.models import OAuth2Provider
from passbook.providers.oauth2.generators import (
generate_client_id,
generate_client_secret,
)
from passbook.providers.oauth2.models import ClientTypes, OAuth2Provider, ResponseTypes
LOGGER = get_logger()
class TestProviderOAuth(SeleniumTestCase):
class TestProviderOAuth2Github(SeleniumTestCase):
"""test OAuth Provider flow"""
def setUp(self):
@ -29,7 +35,7 @@ class TestProviderOAuth(SeleniumTestCase):
"""Setup client grafana container which we test OAuth against"""
client: DockerClient = from_env()
container = client.containers.run(
image="grafana/grafana:latest",
image="grafana/grafana:7.1.0",
detach=True,
network_mode="host",
auto_remove=True,
@ -40,18 +46,18 @@ class TestProviderOAuth(SeleniumTestCase):
),
environment={
"GF_AUTH_GITHUB_ENABLED": "true",
"GF_AUTH_GITHUB_allow_sign_up": "true",
"GF_AUTH_GITHUB_ALLOW_SIGN_UP": "true",
"GF_AUTH_GITHUB_CLIENT_ID": self.client_id,
"GF_AUTH_GITHUB_CLIENT_SECRET": self.client_secret,
"GF_AUTH_GITHUB_SCOPES": "user:email,read:org",
"GF_AUTH_GITHUB_AUTH_URL": self.url(
"passbook_providers_oauth:github-authorize"
"passbook_providers_oauth2_github:github-authorize"
),
"GF_AUTH_GITHUB_TOKEN_URL": self.url(
"passbook_providers_oauth:github-access-token"
"passbook_providers_oauth2_github:github-access-token"
),
"GF_AUTH_GITHUB_API_URL": self.url(
"passbook_providers_oauth:github-user"
"passbook_providers_oauth2_github:github-user"
),
"GF_LOG_LEVEL": "debug",
},
@ -61,6 +67,7 @@ class TestProviderOAuth(SeleniumTestCase):
status = container.attrs.get("State", {}).get("Health", {}).get("Status")
if status == "healthy":
return container
LOGGER.info("Container failed healthcheck")
sleep(1)
def tearDown(self):
@ -76,12 +83,11 @@ class TestProviderOAuth(SeleniumTestCase):
)
provider = OAuth2Provider.objects.create(
name="grafana",
client_type=OAuth2Provider.CLIENT_CONFIDENTIAL,
authorization_grant_type=OAuth2Provider.GRANT_AUTHORIZATION_CODE,
client_id=self.client_id,
client_secret=self.client_secret,
client_type=ClientTypes.CONFIDENTIAL,
response_type=ResponseTypes.CODE,
redirect_uris="http://localhost:3000/login/github",
skip_authorization=True,
authorization_flow=authorization_flow,
)
Application.objects.create(
@ -103,23 +109,20 @@ class TestProviderOAuth(SeleniumTestCase):
USER().username,
)
self.assertEqual(
self.driver.find_element(
By.XPATH,
"/html/body/grafana-app/div/div/div/react-profile-wrapper/form[1]/div[1]/div/input",
).get_attribute("value"),
self.driver.find_element(By.CSS_SELECTOR, "input[name=name]").get_attribute(
"value"
),
USER().username,
)
self.assertEqual(
self.driver.find_element(
By.XPATH,
"/html/body/grafana-app/div/div/div/react-profile-wrapper/form[1]/div[2]/div/input",
By.CSS_SELECTOR, "input[name=email]"
).get_attribute("value"),
USER().email,
)
self.assertEqual(
self.driver.find_element(
By.XPATH,
"/html/body/grafana-app/div/div/div/react-profile-wrapper/form[1]/div[3]/div/input",
By.CSS_SELECTOR, "input[name=login]"
).get_attribute("value"),
USER().username,
)
@ -133,12 +136,11 @@ class TestProviderOAuth(SeleniumTestCase):
)
provider = OAuth2Provider.objects.create(
name="grafana",
client_type=OAuth2Provider.CLIENT_CONFIDENTIAL,
authorization_grant_type=OAuth2Provider.GRANT_AUTHORIZATION_CODE,
client_id=self.client_id,
client_secret=self.client_secret,
client_type=ClientTypes.CONFIDENTIAL,
response_type=ResponseTypes.CODE,
redirect_uris="http://localhost:3000/login/github",
skip_authorization=True,
authorization_flow=authorization_flow,
)
app = Application.objects.create(
@ -160,7 +162,7 @@ class TestProviderOAuth(SeleniumTestCase):
).text,
)
self.assertEqual(
"GitHub Compatibility: User Email",
"GitHub Compatibility: Access you Email addresses",
self.driver.find_element(
By.XPATH, "/html/body/div[2]/div/main/div/form/div[2]/ul/li[1]"
).text,
@ -175,23 +177,20 @@ class TestProviderOAuth(SeleniumTestCase):
USER().username,
)
self.assertEqual(
self.driver.find_element(
By.XPATH,
"/html/body/grafana-app/div/div/div/react-profile-wrapper/form[1]/div[1]/div/input",
).get_attribute("value"),
self.driver.find_element(By.CSS_SELECTOR, "input[name=name]").get_attribute(
"value"
),
USER().username,
)
self.assertEqual(
self.driver.find_element(
By.XPATH,
"/html/body/grafana-app/div/div/div/react-profile-wrapper/form[1]/div[2]/div/input",
By.CSS_SELECTOR, "input[name=email]"
).get_attribute("value"),
USER().email,
)
self.assertEqual(
self.driver.find_element(
By.XPATH,
"/html/body/grafana-app/div/div/div/react-profile-wrapper/form[1]/div[3]/div/input",
By.CSS_SELECTOR, "input[name=login]"
).get_attribute("value"),
USER().username,
)
@ -205,12 +204,11 @@ class TestProviderOAuth(SeleniumTestCase):
)
provider = OAuth2Provider.objects.create(
name="grafana",
client_type=OAuth2Provider.CLIENT_CONFIDENTIAL,
authorization_grant_type=OAuth2Provider.GRANT_AUTHORIZATION_CODE,
client_id=self.client_id,
client_secret=self.client_secret,
client_type=ClientTypes.CONFIDENTIAL,
response_type=ResponseTypes.CODE,
redirect_uris="http://localhost:3000/login/github",
skip_authorization=True,
authorization_flow=authorization_flow,
)
app = Application.objects.create(

View File

@ -1,26 +1,41 @@
"""test OpenID Provider flow"""
"""test OAuth2 OpenID Provider flow"""
from time import sleep
from django.shortcuts import reverse
from oauth2_provider.generators import generate_client_id, generate_client_secret
from oidc_provider.models import Client, ResponseType
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as ec
from docker import DockerClient, from_env
from docker.models.containers import Container
from docker.types import Healthcheck
from e2e.utils import USER, SeleniumTestCase, ensure_rsa_key
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as ec
from structlog import get_logger
from e2e.utils import USER, SeleniumTestCase
from passbook.core.models import Application
from passbook.crypto.models import CertificateKeyPair
from passbook.flows.models import Flow
from passbook.policies.expression.models import ExpressionPolicy
from passbook.policies.models import PolicyBinding
from passbook.providers.oidc.models import OpenIDProvider
from passbook.providers.oauth2.constants import (
SCOPE_OPENID,
SCOPE_OPENID_EMAIL,
SCOPE_OPENID_PROFILE,
)
from passbook.providers.oauth2.generators import (
generate_client_id,
generate_client_secret,
)
from passbook.providers.oauth2.models import (
ClientTypes,
OAuth2Provider,
ResponseTypes,
ScopeMapping,
)
LOGGER = get_logger()
class TestProviderOIDC(SeleniumTestCase):
"""test OpenID Provider flow"""
class TestProviderOAuth2OIDC(SeleniumTestCase):
"""test OAuth with OpenID Provider flow"""
def setUp(self):
self.client_id = generate_client_id()
@ -32,7 +47,7 @@ class TestProviderOIDC(SeleniumTestCase):
"""Setup client grafana container which we test OIDC against"""
client: DockerClient = from_env()
container = client.containers.run(
image="grafana/grafana:latest",
image="grafana/grafana:7.1.0",
detach=True,
network_mode="host",
auto_remove=True,
@ -47,13 +62,13 @@ class TestProviderOIDC(SeleniumTestCase):
"GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET": self.client_secret,
"GF_AUTH_GENERIC_OAUTH_SCOPES": "openid email profile",
"GF_AUTH_GENERIC_OAUTH_AUTH_URL": (
self.live_server_url + reverse("passbook_providers_oidc:authorize")
self.url("passbook_providers_oauth2:authorize")
),
"GF_AUTH_GENERIC_OAUTH_TOKEN_URL": (
self.live_server_url + reverse("oidc_provider:token")
self.url("passbook_providers_oauth2:token")
),
"GF_AUTH_GENERIC_OAUTH_API_URL": (
self.live_server_url + reverse("oidc_provider:userinfo")
self.url("passbook_providers_oauth2:userinfo")
),
"GF_LOG_LEVEL": "debug",
},
@ -63,6 +78,7 @@ class TestProviderOIDC(SeleniumTestCase):
status = container.attrs.get("State", {}).get("Health", {}).get("Status")
if status == "healthy":
return container
LOGGER.info("Container failed healthcheck")
sleep(1)
def tearDown(self):
@ -76,23 +92,22 @@ class TestProviderOIDC(SeleniumTestCase):
authorization_flow = Flow.objects.get(
slug="default-provider-authorization-implicit-consent"
)
client = Client.objects.create(
provider = OAuth2Provider.objects.create(
name="grafana",
client_type="confidential",
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
_redirect_uris="http://localhost:3000/",
_scope="openid userinfo",
rsa_key=CertificateKeyPair.objects.first(),
redirect_uris="http://localhost:3000/",
authorization_flow=authorization_flow,
response_type=ResponseTypes.CODE,
)
# At least one of these objects must exist
ensure_rsa_key()
# This response_code object might exist or not, depending on the order the tests are run
rp_type, _ = ResponseType.objects.get_or_create(value="code")
client.response_types.set([rp_type])
client.save()
provider = OpenIDProvider.objects.create(
oidc_client=client, authorization_flow=authorization_flow,
provider.property_mappings.set(
ScopeMapping.objects.filter(
scope_name__in=[SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE]
)
)
provider.save()
Application.objects.create(
name="Grafana", slug="grafana", provider=provider,
)
@ -117,25 +132,22 @@ class TestProviderOIDC(SeleniumTestCase):
authorization_flow = Flow.objects.get(
slug="default-provider-authorization-implicit-consent"
)
client = Client.objects.create(
provider = OAuth2Provider.objects.create(
name="grafana",
client_type="confidential",
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
_redirect_uris="http://localhost:3000/login/generic_oauth",
_scope="openid profile email",
reuse_consent=False,
require_consent=False,
rsa_key=CertificateKeyPair.objects.first(),
redirect_uris="http://localhost:3000/login/generic_oauth",
authorization_flow=authorization_flow,
response_type=ResponseTypes.CODE,
)
# At least one of these objects must exist
ensure_rsa_key()
# This response_code object might exist or not, depending on the order the tests are run
rp_type, _ = ResponseType.objects.get_or_create(value="code")
client.response_types.set([rp_type])
client.save()
provider = OpenIDProvider.objects.create(
oidc_client=client, authorization_flow=authorization_flow,
provider.property_mappings.set(
ScopeMapping.objects.filter(
scope_name__in=[SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE]
)
)
provider.save()
Application.objects.create(
name="Grafana", slug="grafana", provider=provider,
)
@ -153,23 +165,20 @@ class TestProviderOIDC(SeleniumTestCase):
USER().name,
)
self.assertEqual(
self.driver.find_element(
By.XPATH,
"/html/body/grafana-app/div/div/div/react-profile-wrapper/form[1]/div[1]/div/input",
).get_attribute("value"),
self.driver.find_element(By.CSS_SELECTOR, "input[name=name]").get_attribute(
"value"
),
USER().name,
)
self.assertEqual(
self.driver.find_element(
By.XPATH,
"/html/body/grafana-app/div/div/div/react-profile-wrapper/form[1]/div[2]/div/input",
By.CSS_SELECTOR, "input[name=email]"
).get_attribute("value"),
USER().email,
)
self.assertEqual(
self.driver.find_element(
By.XPATH,
"/html/body/grafana-app/div/div/div/react-profile-wrapper/form[1]/div[3]/div/input",
By.CSS_SELECTOR, "input[name=login]"
).get_attribute("value"),
USER().email,
)
@ -181,25 +190,22 @@ class TestProviderOIDC(SeleniumTestCase):
authorization_flow = Flow.objects.get(
slug="default-provider-authorization-explicit-consent"
)
client = Client.objects.create(
provider = OAuth2Provider.objects.create(
name="grafana",
client_type="confidential",
authorization_flow=authorization_flow,
response_type=ResponseTypes.CODE,
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
_redirect_uris="http://localhost:3000/login/generic_oauth",
_scope="openid profile email",
reuse_consent=False,
require_consent=False,
rsa_key=CertificateKeyPair.objects.first(),
redirect_uris="http://localhost:3000/login/generic_oauth",
)
# At least one of these objects must exist
ensure_rsa_key()
# This response_code object might exist or not, depending on the order the tests are run
rp_type, _ = ResponseType.objects.get_or_create(value="code")
client.response_types.set([rp_type])
client.save()
provider = OpenIDProvider.objects.create(
oidc_client=client, authorization_flow=authorization_flow,
provider.property_mappings.set(
ScopeMapping.objects.filter(
scope_name__in=[SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE]
)
)
provider.save()
app = Application.objects.create(
name="Grafana", slug="grafana", provider=provider,
)
@ -235,23 +241,20 @@ class TestProviderOIDC(SeleniumTestCase):
USER().name,
)
self.assertEqual(
self.driver.find_element(
By.XPATH,
"/html/body/grafana-app/div/div/div/react-profile-wrapper/form[1]/div[1]/div/input",
).get_attribute("value"),
self.driver.find_element(By.CSS_SELECTOR, "input[name=name]").get_attribute(
"value"
),
USER().name,
)
self.assertEqual(
self.driver.find_element(
By.XPATH,
"/html/body/grafana-app/div/div/div/react-profile-wrapper/form[1]/div[2]/div/input",
By.CSS_SELECTOR, "input[name=email]"
).get_attribute("value"),
USER().email,
)
self.assertEqual(
self.driver.find_element(
By.XPATH,
"/html/body/grafana-app/div/div/div/react-profile-wrapper/form[1]/div[3]/div/input",
By.CSS_SELECTOR, "input[name=login]"
).get_attribute("value"),
USER().email,
)
@ -263,25 +266,22 @@ class TestProviderOIDC(SeleniumTestCase):
authorization_flow = Flow.objects.get(
slug="default-provider-authorization-explicit-consent"
)
client = Client.objects.create(
provider = OAuth2Provider.objects.create(
name="grafana",
client_type="confidential",
authorization_flow=authorization_flow,
response_type=ResponseTypes.CODE,
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
_redirect_uris="http://localhost:3000/login/generic_oauth",
_scope="openid profile email",
reuse_consent=False,
require_consent=False,
rsa_key=CertificateKeyPair.objects.first(),
redirect_uris="http://localhost:3000/login/generic_oauth",
)
# At least one of these objects must exist
ensure_rsa_key()
# This response_code object might exist or not, depending on the order the tests are run
rp_type, _ = ResponseType.objects.get_or_create(value="code")
client.response_types.set([rp_type])
client.save()
provider = OpenIDProvider.objects.create(
oidc_client=client, authorization_flow=authorization_flow,
provider.property_mappings.set(
ScopeMapping.objects.filter(
scope_name__in=[SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE]
)
)
provider.save()
app = Application.objects.create(
name="Grafana", slug="grafana", provider=provider,
)

View File

@ -1,12 +1,13 @@
"""test SAML Provider flow"""
from time import sleep
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from docker import DockerClient, from_env
from docker.models.containers import Container
from docker.types import Healthcheck
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from structlog import get_logger
from e2e.utils import USER, SeleniumTestCase
from passbook.core.models import Application
from passbook.crypto.models import CertificateKeyPair
@ -19,6 +20,8 @@ from passbook.providers.saml.models import (
SAMLProvider,
)
LOGGER = get_logger()
class TestProviderSAML(SeleniumTestCase):
"""test SAML Provider flow"""
@ -54,6 +57,7 @@ class TestProviderSAML(SeleniumTestCase):
status = container.attrs.get("State", {}).get("Health", {}).get("Status")
if status == "healthy":
return container
LOGGER.info("Container failed healthcheck")
sleep(1)
def tearDown(self):

View File

@ -1,18 +1,21 @@
"""test SAML Source"""
from time import sleep
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as ec
from docker import DockerClient, from_env
from docker.models.containers import Container
from docker.types import Healthcheck
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as ec
from structlog import get_logger
from e2e.utils import SeleniumTestCase
from passbook.crypto.models import CertificateKeyPair
from passbook.flows.models import Flow
from passbook.sources.saml.models import SAMLBindingTypes, SAMLSource
LOGGER = get_logger()
IDP_CERT = """-----BEGIN CERTIFICATE-----
MIIDXTCCAkWgAwIBAgIJALmVVuDWu4NYMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
@ -76,7 +79,7 @@ class TestSourceSAML(SeleniumTestCase):
"""Setup test IdP container"""
client: DockerClient = from_env()
container = client.containers.run(
image="kristophjunge/test-saml-idp",
image="kristophjunge/test-saml-idp:1.15",
detach=True,
network_mode="host",
auto_remove=True,
@ -97,6 +100,7 @@ class TestSourceSAML(SeleniumTestCase):
status = container.attrs.get("State", {}).get("Health", {}).get("Status")
if status == "healthy":
return container
LOGGER.info("Container failed healthcheck")
sleep(1)
def tearDown(self):

View File

@ -2,21 +2,23 @@
from os.path import abspath
from time import sleep
from oauth2_provider.generators import generate_client_secret
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as ec
from yaml import safe_dump
from docker import DockerClient, from_env
from docker.models.containers import Container
from docker.types import Healthcheck
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as ec
from structlog import get_logger
from yaml import safe_dump
from e2e.utils import SeleniumTestCase
from passbook.flows.models import Flow
from passbook.providers.oauth2.generators import generate_client_secret
from passbook.sources.oauth.models import OAuthSource
TOKEN_URL = "http://127.0.0.1:5556/dex/token"
CONFIG_PATH = "/tmp/dex.yml"
LOGGER = get_logger()
class TestSourceOAuth(SeleniumTestCase):
@ -79,13 +81,14 @@ class TestSourceOAuth(SeleniumTestCase):
interval=5 * 100 * 1000000,
start_period=1 * 100 * 1000000,
),
volumes={abspath(CONFIG_PATH): {"bind": "/config.yml", "mode": "ro",}},
volumes={abspath(CONFIG_PATH): {"bind": "/config.yml", "mode": "ro"}},
)
while True:
container.reload()
status = container.attrs.get("State", {}).get("Health", {}).get("Status")
if status == "healthy":
return container
LOGGER.info("Container failed healthcheck")
sleep(1)
def create_objects(self):

View File

@ -6,7 +6,6 @@ from inspect import getmembers, isfunction
from os import environ, makedirs
from time import time
from Cryptodome.PublicKey import RSA
from django.apps import apps
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from django.db import connection, transaction
@ -28,16 +27,6 @@ def USER() -> User: # noqa
return User.objects.get(username="pbadmin")
def ensure_rsa_key():
"""Ensure that at least one RSAKey Object exists, create one if none exist"""
from oidc_provider.models import RSAKey
if not RSAKey.objects.exists():
key = RSA.generate(2048)
rsakey = RSAKey(key=key.exportKey("PEM").decode("utf8"))
rsakey.save()
class SeleniumTestCase(StaticLiveServerTestCase):
"""StaticLiveServerTestCase which automatically creates a Webdriver instance"""
@ -58,7 +47,7 @@ class SeleniumTestCase(StaticLiveServerTestCase):
)
def tearDown(self):
if "CI" in environ:
if "TF_BUILD" in environ:
screenshot_file = (
f"selenium_screenshots/{self.__class__.__name__}_{time()}.png"
)

View File

@ -1,8 +0,0 @@
FROM quay.io/oauth2-proxy/oauth2-proxy
COPY templates /templates
ENV OAUTH2_PROXY_EMAIL_DOMAINS=*
ENV OAUTH2_PROXY_PROVIDER=oidc
ENV OAUTH2_PROXY_CUSTOM_TEMPLATES_DIR=/templates
ENV OAUTH2_PROXY_HTTP_ADDRESS=:4180

View File

@ -1,18 +0,0 @@
{{define "error.html"}}
<!DOCTYPE html>
<html lang="en" charset="utf-8">
<head>
<title>{{.Title}}</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
</head>
<body>
<h2>{{.Title}}</h2>
<p>{{.Message}}</p>
<hr>
<p><a href="{{.ProxyPrefix}}/sign_in">Sign In</a></p>
</body>
</html>
{{end}}

View File

@ -1,119 +0,0 @@
{{define "sign_in.html"}}
<!DOCTYPE html>
<html lang="en" charset="utf-8">
<head>
<title>Sign In with passbook</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
line-height: 1.42857143;
color: #333;
background: #f0f0f0;
}
.signin {
display: block;
margin: 20px auto;
max-width: 400px;
background: #fff;
border: 1px solid #ccc;
border-radius: 10px;
padding: 20px;
}
.center {
text-align: center;
}
.btn {
color: #fff;
background-color: #428bca;
border: 1px solid #357ebd;
-webkit-border-radius: 4;
-moz-border-radius: 4;
border-radius: 4px;
font-size: 14px;
padding: 6px 12px;
text-decoration: none;
cursor: pointer;
}
.btn:hover {
background-color: #3071a9;
border-color: #285e8e;
text-decoration: none;
}
label {
display: inline-block;
max-width: 100%;
margin-bottom: 5px;
font-weight: 700;
}
input {
display: block;
width: 100%;
height: 34px;
padding: 6px 12px;
font-size: 14px;
line-height: 1.42857143;
color: #555;
background-color: #fff;
background-image: none;
border: 1px solid #ccc;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
-o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
margin: 0;
box-sizing: border-box;
}
footer {
display: block;
font-size: 10px;
color: #aaa;
text-align: center;
margin-bottom: 10px;
}
footer a {
display: inline-block;
height: 25px;
line-height: 25px;
color: #aaa;
text-decoration: underline;
}
footer a:hover {
color: #aaa;
}
</style>
</head>
<body>
<div class="signin center">
<form method="GET" action="{{.ProxyPrefix}}/start">
<input type="hidden" name="rd" value="{{.Redirect}}">
<button type="submit" class="btn">Sign in with passbook</button><br />
</form>
</div>
<script>
if (window.location.hash) {
(function () {
var inputs = document.getElementsByName('rd');
for (var i = 0; i < inputs.length; i++) {
inputs[i].value += window.location.hash;
}
})();
}
</script>
</body>
</html>
{{end}}

View File

@ -1,9 +1,9 @@
dependencies:
- name: postgresql
repository: https://kubernetes-charts.storage.googleapis.com/
version: 6.5.8
repository: https://charts.bitnami.com/bitnami
version: 9.3.2
- name: redis
repository: https://kubernetes-charts.storage.googleapis.com/
version: 9.5.1
digest: sha256:f18b5dc8d0be13d584407405c60d10b6b84d25f7fa8aaa3dd0e5385c38f5c516
generated: "2019-12-14T13:33:48.4341939Z"
repository: https://charts.bitnami.com/bitnami
version: 10.7.16
digest: sha256:fd31e2e2b9ff17a5ed906a77a4f15ffa1ab7f5aecaea1e5db77f0d199ae4f19e
generated: "2020-08-25T17:57:49.684549+02:00"

View File

@ -1,6 +1,15 @@
apiVersion: v1
appVersion: "0.9.0-rc1"
apiVersion: v2
appVersion: "0.10.0-rc3"
description: A Helm chart for passbook.
name: passbook
version: "0.9.0-rc1"
icon: https://git.beryju.org/uploads/-/system/project/avatar/108/logo.png
version: "0.10.0-rc3"
icon: https://github.com/BeryJu/passbook/blob/master/passbook/static/static/passbook/logo.svg
dependencies:
- name: postgresql
version: 9.3.2
repository: https://charts.bitnami.com/bitnami
condition: install.postgresql
- name: redis
version: 10.7.16
repository: https://charts.bitnami.com/bitnami
condition: install.redis

View File

@ -1,9 +0,0 @@
dependencies:
- name: postgresql
repository: https://kubernetes-charts.storage.googleapis.com/
version: 6.5.8
- name: redis
repository: https://kubernetes-charts.storage.googleapis.com/
version: 9.5.1
digest: sha256:476834fb82f66bc7242c4a5e7343d0a859d8307cb301256beb0eb749983014e4
generated: "2019-11-07T10:21:30.902415+01:00"

View File

@ -1,7 +0,0 @@
dependencies:
- name: postgresql
version: 6.5.8
repository: https://kubernetes-charts.storage.googleapis.com/
- name: redis
version: 9.5.1
repository: https://kubernetes-charts.storage.googleapis.com/

View File

@ -1,19 +1,5 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
1. Access passbook using the following URL:
{{- range .Values.ingress.hosts }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "passbook.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get svc -w {{ include "passbook.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "passbook.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "passbook.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:8000
{{- end }}
2. Login to passbook using the user "pbadmin" and the password "pbadmin".

View File

@ -3,26 +3,17 @@ kind: ConfigMap
metadata:
name: {{ include "passbook.fullname" . }}-config
data:
config.yml: |
postgresql:
host: "{{ .Release.Name }}-postgresql"
name: "{{ .Values.postgresql.postgresqlDatabase }}"
user: postgres
{{- if .Values.backup }}
backup:
access_key: "{{ .Values.backup.access_key }}"
secret_key: "{{ .Values.backup.secret_key }}"
bucket: "{{ .Values.backup.bucket }}"
host: "{{ .Values.backup.host }}"
{{- end}}
redis:
host: "{{ .Release.Name }}-redis-master"
cache_db: 0
message_queue_db: 1
error_reporting: {{ .Values.config.error_reporting }}
log_level: "{{ .Values.config.log_level }}"
apm:
enabled: {{ .Values.config.apm.enabled }}
server_url: "{{ .Values.config.apm.server_url }}"
secret_token: "{{ .Values.config.apm.server_token }}"
verify_server_cert: {{ .Values.config.apm.verify_server_cert }}
POSTGRESQL__HOST: "{{ .Release.Name }}-postgresql"
POSTGRESQL__NAME: "{{ .Values.postgresql.postgresqlDatabase }}"
POSTGRESQL__USER: "{{ .Values.postgresql.postgresqlUsername }}"
{{- if .Values.backup }}
POSTGRESQL__BACKUP__ACCESS_KEY: "{{ .Values.backup.access_key }}"
POSTGRESQL__BACKUP__SECRET_KEY: "{{ .Values.backup.secret_key }}"
POSTGRESQL__BACKUP__BUCKET: "{{ .Values.backup.bucket }}"
POSTGRESQL__BACKUP__HOST: "{{ .Values.backup.host }}"
{{- end}}
REDIS__HOST: "{{ .Release.Name }}-redis-master"
ERROR_REPORTING__ENABLED: "{{ .Values.config.error_reporting.enabled }}"
ERROR_REPORTING__ENVIRONMENT: "{{ .Values.config.error_reporting.environment }}"
ERROR_REPORTING__SEND_PII: "{{ .Values.config.error_reporting.send_pii }}"
LOG_LEVEL: "{{ .Values.config.log_level }}"

View File

@ -1,4 +1,3 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "passbook.fullname" . -}}
apiVersion: extensions/v1beta1
kind: Ingress
@ -46,4 +45,3 @@ spec:
serviceName: {{ $fullName }}-static
servicePort: http
{{- end }}
{{- end }}

View File

@ -1,121 +0,0 @@
{{- if .Values.monitoring.enabled -}}
---
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: {{ include "passbook.fullname" . }}-static-rules
labels:
app.kubernetes.io/name: {{ include "passbook.name" . }}
helm.sh/chart: {{ include "passbook.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:
groups:
- name: Aggregate request counters
rules:
- record: job:django_http_requests_before_middlewares_total:sum_rate30s
expr: sum(rate(django_http_requests_before_middlewares_total[30s])) by (job)
- record: job:django_http_requests_unknown_latency_total:sum_rate30s
expr: sum(rate(django_http_requests_unknown_latency_total[30s])) by (job)
- record: job:django_http_ajax_requests_total:sum_rate30s
expr: sum(rate(django_http_ajax_requests_total[30s])) by (job)
- record: job:django_http_responses_before_middlewares_total:sum_rate30s
expr: sum(rate(django_http_responses_before_middlewares_total[30s])) by (job)
- record: job:django_http_requests_unknown_latency_including_middlewares_total:sum_rate30s
expr: sum(rate(django_http_requests_unknown_latency_including_middlewares_total[30s])) by (job)
- record: job:django_http_requests_body_total_bytes:sum_rate30s
expr: sum(rate(django_http_requests_body_total_bytes[30s])) by (job)
- record: job:django_http_responses_streaming_total:sum_rate30s
expr: sum(rate(django_http_responses_streaming_total[30s])) by (job)
- record: job:django_http_responses_body_total_bytes:sum_rate30s
expr: sum(rate(django_http_responses_body_total_bytes[30s])) by (job)
- record: job:django_http_requests_total:sum_rate30s
expr: sum(rate(django_http_requests_total_by_method[30s])) by (job)
- record: job:django_http_requests_total_by_method:sum_rate30s
expr: sum(rate(django_http_requests_total_by_method[30s])) by (job,method)
- record: job:django_http_requests_total_by_transport:sum_rate30s
expr: sum(rate(django_http_requests_total_by_transport[30s])) by (job,transport)
- record: job:django_http_requests_total_by_view:sum_rate30s
expr: sum(rate(django_http_requests_total_by_view_transport_method[30s])) by (job,view)
- record: job:django_http_requests_total_by_view_transport_method:sum_rate30s
expr: sum(rate(django_http_requests_total_by_view_transport_method[30s])) by (job,view,transport,method)
- record: job:django_http_responses_total_by_templatename:sum_rate30s
expr: sum(rate(django_http_responses_total_by_templatename[30s])) by (job,templatename)
- record: job:django_http_responses_total_by_status:sum_rate30s
expr: sum(rate(django_http_responses_total_by_status[30s])) by (job,status)
- record: job:django_http_responses_total_by_status_name_method:sum_rate30s
expr: sum(rate(django_http_responses_total_by_status_name_method[30s])) by (job,status,name,method)
- record: job:django_http_responses_total_by_charset:sum_rate30s
expr: sum(rate(django_http_responses_total_by_charset[30s])) by (job,charset)
- record: job:django_http_exceptions_total_by_type:sum_rate30s
expr: sum(rate(django_http_exceptions_total_by_type[30s])) by (job,type)
- record: job:django_http_exceptions_total_by_view:sum_rate30s
expr: sum(rate(django_http_exceptions_total_by_view[30s])) by (job,view)
- name: Aggregate latency histograms
rules:
- record: job:django_http_requests_latency_including_middlewares_seconds:quantile_rate30s
expr: histogram_quantile(0.50, sum(rate(django_http_requests_latency_including_middlewares_seconds_bucket[30s])) by (job, le))
labels:
quantile: "50"
- record: job:django_http_requests_latency_including_middlewares_seconds:quantile_rate30s
expr: histogram_quantile(0.95, sum(rate(django_http_requests_latency_including_middlewares_seconds_bucket[30s])) by (job, le))
labels:
quantile: "95"
- record: job:django_http_requests_latency_including_middlewares_seconds:quantile_rate30s
expr: histogram_quantile(0.99, sum(rate(django_http_requests_latency_including_middlewares_seconds_bucket[30s])) by (job, le))
labels:
quantile: "99"
- record: job:django_http_requests_latency_including_middlewares_seconds:quantile_rate30s
expr: histogram_quantile(0.999, sum(rate(django_http_requests_latency_including_middlewares_seconds_bucket[30s])) by (job, le))
labels:
quantile: "99.9"
- record: job:django_http_requests_latency_seconds:quantile_rate30s
expr: histogram_quantile(0.50, sum(rate(django_http_requests_latency_seconds_bucket[30s])) by (job, le))
labels:
quantile: "50"
- record: job:django_http_requests_latency_seconds:quantile_rate30s
expr: histogram_quantile(0.95, sum(rate(django_http_requests_latency_seconds_bucket[30s])) by (job, le))
labels:
quantile: "95"
- record: job:django_http_requests_latency_seconds:quantile_rate30s
expr: histogram_quantile(0.99, sum(rate(django_http_requests_latency_seconds_bucket[30s])) by (job, le))
labels:
quantile: "99"
- record: job:django_http_requests_latency_seconds:quantile_rate30s
expr: histogram_quantile(0.999, sum(rate(django_http_requests_latency_seconds_bucket[30s])) by (job, le))
labels:
quantile: "99.9"
- name: Aggregate model operations
rules:
- record: job:django_model_inserts_total:sum_rate1m
expr: sum(rate(django_model_inserts_total[1m])) by (job, model)
- record: job:django_model_updates_total:sum_rate1m
expr: sum(rate(django_model_updates_total[1m])) by (job, model)
- record: job:django_model_deletes_total:sum_rate1m
expr: sum(rate(django_model_deletes_total[1m])) by (job, model)
- name: Aggregate database operations
rules:
- record: job:django_db_new_connections_total:sum_rate30s
expr: sum(rate(django_db_new_connections_total[30s])) by (alias, vendor)
- record: job:django_db_new_connection_errors_total:sum_rate30s
expr: sum(rate(django_db_new_connection_errors_total[30s])) by (alias, vendor)
- record: job:django_db_execute_total:sum_rate30s
expr: sum(rate(django_db_execute_total[30s])) by (alias, vendor)
- record: job:django_db_execute_many_total:sum_rate30s
expr: sum(rate(django_db_execute_many_total[30s])) by (alias, vendor)
- record: job:django_db_errors_total:sum_rate30s
expr: sum(rate(django_db_errors_total[30s])) by (alias, vendor, type)
- name: Aggregate migrations
rules:
- record: job:django_migrations_applied_total:max
expr: max(django_migrations_applied_total) by (job, connection)
- record: job:django_migrations_unapplied_total:max
expr: max(django_migrations_unapplied_total) by (job, connection)
- name: Alerts
rules:
- alert: UnappliedMigrations
expr: job:django_migrations_unapplied_total:max > 0
for: 1m
labels:
severity: testing
{{- end }}

View File

@ -7,23 +7,23 @@ metadata:
helm.sh/chart: {{ include "passbook.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
k8s.passbook.io/component: static
k8s.passbook.beryju.org/component: static
spec:
selector:
matchLabels:
app.kubernetes.io/name: {{ include "passbook.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
k8s.passbook.io/component: static
k8s.passbook.beryju.org/component: static
template:
metadata:
labels:
app.kubernetes.io/name: {{ include "passbook.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
k8s.passbook.io/component: static
k8s.passbook.beryju.org/component: static
spec:
containers:
- name: {{ .Chart.Name }}-static
image: "beryju/passbook-static:{{ .Values.image.tag }}"
image: "{{ .Values.image.name_static }}:{{ .Values.image.tag }}"
imagePullPolicy: IfNotPresent
ports:
- name: http

View File

@ -7,7 +7,7 @@ metadata:
helm.sh/chart: {{ include "passbook.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
k8s.passbook.io/component: static
k8s.passbook.beryju.org/component: static
spec:
type: ClusterIP
ports:
@ -18,4 +18,4 @@ spec:
selector:
app.kubernetes.io/name: {{ include "passbook.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
k8s.passbook.io/component: static
k8s.passbook.beryju.org/component: static

View File

@ -1,17 +0,0 @@
{{- if .Values.monitoring.enabled -}}
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
labels:
app.kubernetes.io/name: {{ include "passbook.name" . }}
helm.sh/chart: {{ include "passbook.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
name: {{ include "passbook.fullname" . }}-static-monitoring
spec:
endpoints:
- port: http
selector:
matchLabels:
k8s.passbook.io/component: static
{{- end }}

View File

@ -7,35 +7,26 @@ metadata:
helm.sh/chart: {{ include "passbook.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
k8s.passbook.io/component: web
k8s.passbook.beryju.org/component: web
spec:
replicas: 2
replicas: {{ serverReplicas }}
selector:
matchLabels:
app.kubernetes.io/name: {{ include "passbook.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
k8s.passbook.io/component: web
k8s.passbook.beryju.org/component: web
template:
metadata:
labels:
app.kubernetes.io/name: {{ include "passbook.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
k8s.passbook.io/component: web
k8s.passbook.beryju.org/component: web
spec:
volumes:
- name: config-volume
configMap:
name: {{ include "passbook.fullname" . }}-config
initContainers:
- name: passbook-database-migrations
image: "beryju/passbook:{{ .Values.image.tag }}"
image: "{{ .Values.image.name }}:{{ .Values.image.tag }}"
imagePullPolicy: Always
args:
- ./manage.py
- migrate
volumeMounts:
- mountPath: /etc/passbook
name: config-volume
args: [migrate]
envFrom:
- configMapRef:
name: {{ include "passbook.fullname" . }}-config
@ -58,14 +49,9 @@ spec:
key: postgresql-password
containers:
- name: {{ .Chart.Name }}
image: "beryju/passbook:{{ .Values.image.tag }}"
image: "{{ .Values.image.name }}:{{ .Values.image.tag }}"
imagePullPolicy: Always
args:
- uwsgi
- uwsgi.ini
volumeMounts:
- mountPath: /etc/passbook
name: config-volume
args: [server]
envFrom:
- configMapRef:
name: {{ include "passbook.fullname" . }}-config
@ -74,18 +60,18 @@ spec:
- name: PASSBOOK_SECRET_KEY
valueFrom:
secretKeyRef:
name: {{ include "passbook.fullname" . }}-secret-key
key: secret_key
name: "{{ include "passbook.fullname" . }}-secret-key"
key: "secret_key"
- name: PASSBOOK_REDIS__PASSWORD
valueFrom:
secretKeyRef:
name: "{{ .Release.Name }}-redis"
key: redis-password
key: "redis-password"
- name: PASSBOOK_POSTGRESQL__PASSWORD
valueFrom:
secretKeyRef:
name: "{{ .Release.Name }}-postgresql"
key: postgresql-password
key: "postgresql-password"
ports:
- name: http
containerPort: 8000

View File

@ -7,7 +7,7 @@ metadata:
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
helm.sh/chart: {{ include "passbook.chart" . }}
k8s.passbook.io/component: web
k8s.passbook.beryju.org/component: web
spec:
type: ClusterIP
ports:
@ -18,4 +18,4 @@ spec:
selector:
app.kubernetes.io/name: {{ include "passbook.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
k8s.passbook.io/component: web
k8s.passbook.beryju.org/component: web

View File

@ -1,26 +0,0 @@
{{- if .Values.monitoring.enabled -}}
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
labels:
app.kubernetes.io/name: {{ include "passbook.name" . }}
helm.sh/chart: {{ include "passbook.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
name: {{ include "passbook.fullname" . }}-web-monitoring
spec:
endpoints:
- basicAuth:
password:
name: {{ include "passbook.fullname" . }}-secret-key
key: secret_key
username:
name: {{ include "passbook.fullname" . }}-secret-key
key: monitoring_username
port: http
path: /metrics/
interval: 10s
selector:
matchLabels:
k8s.passbook.io/component: web
{{- end }}

View File

@ -7,60 +7,46 @@ metadata:
helm.sh/chart: {{ include "passbook.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
k8s.passbook.io/component: worker
k8s.passbook.beryju.org/component: worker
spec:
replicas: 1
replicas: {{ workerReplicas }}
selector:
matchLabels:
app.kubernetes.io/name: {{ include "passbook.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
k8s.passbook.io/component: worker
k8s.passbook.beryju.org/component: worker
template:
metadata:
labels:
app.kubernetes.io/name: {{ include "passbook.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
k8s.passbook.io/component: worker
k8s.passbook.beryju.org/component: worker
spec:
volumes:
- name: config-volume
configMap:
name: {{ include "passbook.fullname" . }}-config
containers:
- name: {{ .Chart.Name }}
image: "beryju/passbook:{{ .Values.image.tag }}"
image: "{{ .Values.image.name }}:{{ .Values.image.tag }}"
imagePullPolicy: IfNotPresent
args:
- celery
- worker
- --autoscale=10,3
- -E
- -B
- -A=passbook.root.celery
- -s=/tmp/celerybeat-schedule
volumeMounts:
- mountPath: /etc/passbook
name: config-volume
args: [worker]
envFrom:
- configMapRef:
name: {{ include "passbook.fullname" . }}-config
prefix: PASSBOOK_
name: "{{ include "passbook.fullname" . }}-config"
prefix: "PASSBOOK_"
env:
- name: PASSBOOK_SECRET_KEY
valueFrom:
secretKeyRef:
name: {{ include "passbook.fullname" . }}-secret-key
name: "{{ include "passbook.fullname" . }}-secret-key"
key: secret_key
- name: PASSBOOK_REDIS__PASSWORD
valueFrom:
secretKeyRef:
name: "{{ .Release.Name }}-redis"
key: redis-password
key: "redis-password"
- name: PASSBOOK_POSTGRESQL__PASSWORD
valueFrom:
secretKeyRef:
name: "{{ .Release.Name }}-postgresql"
key: postgresql-password
key: "postgresql-password"
resources:
requests:
cpu: 150m

View File

@ -1,30 +1,27 @@
# Default values for passbook.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
###################################
# Values directly affecting passbook
###################################
image:
tag: 0.9.0-rc1
name: beryju/passbook
name_static: beryju/passbook-static
tag: 0.10.0-rc3
nameOverride: ""
serverReplicas: 1
workerReplicas: 1
config:
# Optionally specify fixed secret_key, otherwise generated automatically
# secret_key: _k*@6h2u2@q-dku57hhgzb7tnx*ba9wodcb^s9g0j59@=y(@_o
# Enable error reporting
error_reporting: false
error_reporting:
enabled: false
environment: customer
send_pii: false
# Log level used by web and worker
# Can be either debug, info, warning, error
log_level: warning
# Optionally enable Elastic APM Support
apm:
enabled: false
server_url: ""
secret_token: ""
verify_server_cert: true
# This Helm chart ships with built-in Prometheus ServiceMonitors and Rules.
# This requires the CoreOS Prometheus Operator.
monitoring:
enabled: false
# Enable Database Backups to S3
# backup:
@ -33,20 +30,15 @@ monitoring:
# bucket: s3-bucket
# host: s3-host
ingress:
enabled: false
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
path: /
hosts:
- passbook.k8s.local
tls: []
# - secretName: chart-example-tls
# hosts:
# - passbook.k8s.local
###################################
# Values controlling dependencies
###################################
# These settings configure the packaged PostgreSQL and Redis chart.
install:
postgresql: true
redis: true
# These values influence the bundled postgresql and redis charts, but are also used by passbook to connect
postgresql:
postgresqlDatabase: passbook
@ -58,3 +50,15 @@ redis:
enabled: false
# https://stackoverflow.com/a/59189742
disableCommands: []
ingress:
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
path: /
hosts:
- passbook.k8s.local
tls: []
# - secretName: chart-example-tls
# hosts:
# - passbook.k8s.local

14
lifecycle/bootstrap.sh Executable file
View File

@ -0,0 +1,14 @@
#!/bin/bash -e
python -m lifecycle.wait_for_db
printf '{"event": "Bootstrap completed", "level": "info", "logger": "bootstrap", "command": "%s"}\n' "$@"
if [[ "$1" == "server" ]]; then
gunicorn -c /lifecycle/gunicorn.conf.py passbook.root.asgi:application
elif [[ "$1" == "worker" ]]; then
celery worker --autoscale=10,3 -E -B -A=passbook.root.celery -s=/tmp/celerybeat-schedule
elif [[ "$1" == "migrate" ]]; then
# Run system migrations first, run normal migrations after
python -m lifecycle.migrate
python -m manage migrate
else
python -m manage "$@"
fi

View File

@ -0,0 +1,42 @@
"""Gunicorn config"""
import structlog
bind = "0.0.0.0:8000"
workers = 2
threads = 4
user = "passbook"
group = "passbook"
worker_class = "uvicorn.workers.UvicornWorker"
# Docker containers don't have /tmp as tmpfs
worker_tmp_dir = "/dev/shm"
logconfig_dict = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"json_formatter": {
"()": structlog.stdlib.ProcessorFormatter,
"processor": structlog.processors.JSONRenderer(),
"foreign_pre_chain": [
structlog.stdlib.add_log_level,
structlog.stdlib.add_logger_name,
structlog.processors.TimeStamper(),
structlog.processors.StackInfoRenderer(),
structlog.processors.format_exc_info,
],
}
},
"handlers": {
"error_console": {
"class": "logging.StreamHandler",
"formatter": "json_formatter",
},
"console": {"class": "logging.StreamHandler", "formatter": "json_formatter"},
},
"loggers": {
"uvicorn": {"handlers": ["console"], "level": "WARNING", "propagate": False},
"gunicorn": {"handlers": ["console"], "level": "INFO", "propagate": False},
},
}

55
lifecycle/migrate.py Executable file
View File

@ -0,0 +1,55 @@
#!/usr/bin/env python
"""System Migration handler"""
from importlib.util import module_from_spec, spec_from_file_location
from inspect import getmembers, isclass
from pathlib import Path
from typing import Any
from psycopg2 import connect
from structlog import get_logger
from passbook.lib.config import CONFIG
LOGGER = get_logger()
class BaseMigration:
"""Base System Migration"""
cur: Any
con: Any
def __init__(self, cur: Any, con: Any):
self.cur = cur
self.con = con
def needs_migration(self) -> bool:
"""Return true if Migration needs to be run"""
return False
def run(self):
"""Run the actual migration"""
if __name__ == "__main__":
conn = connect(
dbname=CONFIG.y("postgresql.name"),
user=CONFIG.y("postgresql.user"),
password=CONFIG.y("postgresql.password"),
host=CONFIG.y("postgresql.host"),
)
curr = conn.cursor()
for migration in Path(__file__).parent.absolute().glob("system_migrations/*.py"):
spec = spec_from_file_location("lifecycle.system_migrations", migration)
mod = module_from_spec(spec)
# pyright: reportGeneralTypeIssues=false
spec.loader.exec_module(mod)
for _, sub in getmembers(mod, isclass):
migration = sub(curr, conn)
if migration.needs_migration():
LOGGER.info("Migration needs to be applied", migration=sub)
migration.run()
LOGGER.info("Migration finished applying", migration=sub)

View File

@ -0,0 +1,50 @@
from os import system
from lifecycle.migrate import BaseMigration
SQL_STATEMENT = """delete from django_migrations where app = 'passbook_stages_prompt';
drop table passbook_stages_prompt_prompt cascade;
drop table passbook_stages_prompt_promptstage cascade;
drop table passbook_stages_prompt_promptstage_fields;
drop table corsheaders_corsmodel cascade;
drop table oauth2_provider_accesstoken cascade;
drop table oauth2_provider_grant cascade;
drop table oauth2_provider_refreshtoken cascade;
drop table oidc_provider_client cascade;
drop table oidc_provider_client_response_types cascade;
drop table oidc_provider_code cascade;
drop table oidc_provider_responsetype cascade;
drop table oidc_provider_rsakey cascade;
drop table oidc_provider_token cascade;
drop table oidc_provider_userconsent cascade;
drop table passbook_providers_app_gw_applicationgatewayprovider cascade;
delete from django_migrations where app = 'passbook_flows' and name = '0008_default_flows';
delete from django_migrations where app = 'passbook_flows' and name = '0009_source_flows';
delete from django_migrations where app = 'passbook_flows' and name = '0010_provider_flows';
delete from django_migrations where app = 'passbook_stages_password' and
name = '0002_passwordstage_change_flow';"""
class To010Migration(BaseMigration):
def needs_migration(self) -> bool:
self.cur.execute(
"select * from information_schema.tables where table_name='oidc_provider_client'"
)
return bool(self.cur.rowcount)
def system_crit(self, command):
retval = system(command) # nosec
if retval != 0:
raise Exception("Migration error")
def run(self):
self.cur.execute(SQL_STATEMENT)
self.con.commit()
self.system_crit("./manage.py migrate passbook_stages_prompt")
self.system_crit("./manage.py migrate passbook_flows 0008_default_flows --fake")
self.system_crit("./manage.py migrate passbook_flows 0009_source_flows --fake")
self.system_crit(
"./manage.py migrate passbook_flows 0010_provider_flows --fake"
)
self.system_crit("./manage.py migrate passbook_flows")
self.system_crit("./manage.py migrate passbook_stages_password --fake")

View File

@ -10,8 +10,7 @@ nav:
- Kubernetes: installation/kubernetes.md
- Flows:
Overview: flow/flows.md
Examples:
- Login: flow/examples/login.md
Examples: flow/examples/examples.md
- Stages:
- Captcha Stage: flow/stages/captcha/index.md
- Dummy Stage: flow/stages/dummy/index.md
@ -27,7 +26,11 @@ nav:
- User Logout Stage: flow/stages/user_logout.md
- User Write Stage: flow/stages/user_write.md
- Sources: sources.md
- Providers: providers.md
- Providers:
- OAuth2: providers/oauth2.md
- SAML: providers/saml.md
- Proxy: providers/proxy.md
- Outposts: outposts/outposts.md
- Expressions:
- Overview: expressions/index.md
- Reference:
@ -46,7 +49,9 @@ nav:
- Harbor: integrations/services/harbor/index.md
- Sentry: integrations/services/sentry/index.md
- Ansible Tower/AWX: integrations/services/tower-awx/index.md
- Upgrading from v0.8.x: upgrading-from-0.8.x.md
- Upgrading:
- to 0.9: upgrading/to-0.9.md
- to 0.10: upgrading/to-0.10.md
repo_name: "BeryJu/passbook"
repo_url: https://github.com/BeryJu/passbook

View File

@ -1,2 +1,2 @@
"""passbook"""
__version__ = "0.9.0-rc1"
__version__ = "0.10.0-rc3"

View File

@ -33,7 +33,7 @@ class YAMLString(str):
"""YAML String type"""
class YAMLField(forms.CharField):
class YAMLField(forms.JSONField):
"""Django's JSON Field converted to YAML"""
default_error_messages = {

View File

@ -46,6 +46,12 @@
{% trans 'Providers' %}
</a>
</li>
<li class="pf-c-nav__item">
<a href="{% url 'passbook_admin:outposts' %}"
class="pf-c-nav__link {% is_active 'passbook_admin:outposts' 'passbook_admin:outpost-create' 'passbook_admin:outpost-update' 'passbook_admin:outpost-delete' %}">
{% trans 'Outposts' %}
</a>
</li>
<li class="pf-c-nav__item">
<a href="{% url 'passbook_admin:property-mappings' %}"
class="pf-c-nav__link {% is_active 'passbook_admin:property-mappings' 'passbook_admin:property-mapping-create' 'passbook_admin:property-mapping-update' 'passbook_admin:property-mapping-delete' %}">

View File

@ -1,36 +0,0 @@
{% extends "administration/base.html" %}
{% load i18n %}
{% load passbook_utils %}
{% block content %}
<section class="pf-c-page__main-section pf-m-light">
<div class="pf-c-content">
<h1>
<i class="pf-icon pf-icon-applications"></i>
{% trans 'Request' %}
</h1>
</div>
</section>
<section class="pf-c-page__main-section pf-m-no-padding-mobile">
<div class="pf-c-card">
<table class="pf-c-table pf-m-compact pf-m-grid-xl" role="grid">
<thead>
<tr role="row">
<th role="columnheader" scope="col" style="min-width: 150px;">{% trans 'Key' %}</th>
<th role="columnheader" scope="col">{% trans 'Value' %}</th>
</tr>
</thead>
<tbody role="rowgroup">
{% for key, value in request_dict.items %}
<tr role="row">
<td role="cell">{{ key }}</td>
<td role="cell">{{ value }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</section>
</div>
{% endblock %}

View File

@ -0,0 +1,13 @@
{% extends base_template|default:"generic/form.html" %}
{% load i18n %}
{% block above_form %}
<h1>
{% trans 'Import Flow' %}
</h1>
{% endblock %}
{% block action %}
{% trans 'Import Flow' %}
{% endblock %}

View File

@ -20,6 +20,7 @@
<div class="pf-c-toolbar__content">
<div class="pf-c-toolbar__bulk-select">
<a href="{% url 'passbook_admin:flow-create' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a>
<a href="{% url 'passbook_admin:flow-import' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-secondary" type="button">{% trans 'Import' %}</a>
</div>
{% include 'partials/pagination.html' %}
</div>
@ -62,6 +63,7 @@
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:flow-update' pk=flow.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_admin:flow-delete' pk=flow.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:flow-execute' pk=flow.pk %}?next={{ request.get_full_path }}">{% trans 'Execute' %}</a>
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:flow-export' pk=flow.pk %}?next={{ request.get_full_path }}">{% trans 'Export' %}</a>
</td>
</tr>
{% endfor %}
@ -81,6 +83,7 @@
{% trans 'Currently no flows exist. Click the button below to create one.' %}
</div>
<a href="{% url 'passbook_admin:flow-create' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a>
<a href="{% url 'passbook_admin:flow-import' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-primary" type="button">{% trans 'Import' %}</a>
</div>
</div>
{% endif %}

View File

@ -0,0 +1,96 @@
{% extends "administration/base.html" %}
{% load i18n %}
{% load humanize %}
{% load passbook_utils %}
{% block head %}
{{ block.super }}
<style>
.pf-m-success {
color: var(--pf-global--success-color--100);
}
.pf-m-danger {
color: var(--pf-global--danger-color--100);
}
</style>
{% endblock %}
{% block content %}
<section class="pf-c-page__main-section pf-m-light">
<div class="pf-c-content">
<h1>
<i class="fas fa-map-marker"></i>
{% trans 'Outposts' %}
</h1>
<p>{% trans "Outposts are deployments of passbook components to support different environments and protocols, like reverse proxies." %}</p>
</div>
</section>
<section class="pf-c-page__main-section pf-m-no-padding-mobile">
<div class="pf-c-card">
{% if object_list %}
<div class="pf-c-toolbar">
<div class="pf-c-toolbar__content">
<div class="pf-c-toolbar__bulk-select">
<a href="{% url 'passbook_admin:flow-create' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a>
</div>
{% include 'partials/pagination.html' %}
</div>
</div>
<table class="pf-c-table pf-m-compact pf-m-grid-xl" role="grid">
<thead>
<tr role="row">
<th role="columnheader" scope="col">{% trans 'Name' %}</th>
<th role="columnheader" scope="col">{% trans 'Providers' %}</th>
<th role="columnheader" scope="col">{% trans 'Health' %}</th>
<th role="cell"></th>
</tr>
</thead>
<tbody role="rowgroup">
{% for outpost in object_list %}
<tr role="row">
<th role="columnheader">
<a href="{% url 'passbook_outposts:setup' outpost_pk=outpost.pk %}">{{ outpost.name }}</a>
</th>
<td role="cell">
<span>
{{ outpost.providers.all.select_subclasses|join:", " }}
</span>
</td>
<td role="cell">
{% with health=outpost.health %}
{% if health %}
<i class="fas fa-check pf-m-success"></i> {{ health|naturaltime }}
{% else %}
<i class="fas fa-times pf-m-danger"></i> Unhealthy
{% endif %}
{% endwith %}
</td>
<td>
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:outpost-update' pk=outpost.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_admin:outpost-delete' pk=outpost.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="pf-c-toolbar" id="page-layout-table-simple-toolbar-bottom">
{% include 'partials/pagination.html' %}
</div>
{% else %}
<div class="pf-c-empty-state">
<div class="pf-c-empty-state__content">
<i class="fas fa-cubes pf-c-empty-state__icon" aria-hidden="true"></i>
<h1 class="pf-c-title pf-m-lg">
{% trans 'No Outposts.' %}
</h1>
<div class="pf-c-empty-state__body">
{% trans 'Currently no outposts exist. Click the button below to create one.' %}
</div>
<a href="{% url 'passbook_admin:outpost-create' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a>
</div>
</div>
{% endif %}
</div>
</section>
{% endblock %}

View File

@ -36,7 +36,7 @@
<tr role="row">
<th role="columnheader">
<div>
<div>{{ token.pk }}</div>
<div>{{ token.pk.hex }}</div>
</div>
</th>
<td role="cell">
@ -51,7 +51,11 @@
</td>
<td role="cell">
<span>
{% if not token.expiring %}
-
{% else %}
{{ token.expires }}
{% endif %}
</span>
</td>
<td>

View File

@ -30,7 +30,7 @@
<div class="pf-l-stack__item">
<div class="pf-c-card">
<div class="pf-c-card__body">
<form action="" method="post" class="pf-c-form pf-m-horizontal">
<form action="" method="post" class="pf-c-form pf-m-horizontal" enctype="multipart/form-data">
{% include 'partials/form_horizontal.html' with form=form %}
{% block beneath_form %}
{% endblock %}

View File

@ -4,9 +4,9 @@ from django.urls import path
from passbook.admin.views import (
applications,
certificate_key_pair,
debug,
flows,
groups,
outposts,
overview,
policies,
policies_bindings,
@ -192,6 +192,7 @@ urlpatterns = [
# Flows
path("flows/", flows.FlowListView.as_view(), name="flows"),
path("flows/create/", flows.FlowCreateView.as_view(), name="flow-create",),
path("flows/import/", flows.FlowImportView.as_view(), name="flow-import",),
path(
"flows/<uuid:pk>/update/", flows.FlowUpdateView.as_view(), name="flow-update",
),
@ -200,6 +201,9 @@ urlpatterns = [
flows.FlowDebugExecuteView.as_view(),
name="flow-execute",
),
path(
"flows/<uuid:pk>/export/", flows.FlowExportView.as_view(), name="flow-export",
),
path(
"flows/<uuid:pk>/delete/", flows.FlowDeleteView.as_view(), name="flow-delete",
),
@ -235,13 +239,17 @@ urlpatterns = [
name="user-password-reset",
),
# Groups
path("group/", groups.GroupListView.as_view(), name="group"),
path("group/create/", groups.GroupCreateView.as_view(), name="group-create"),
path("groups/", groups.GroupListView.as_view(), name="groups"),
path("groups/create/", groups.GroupCreateView.as_view(), name="group-create"),
path(
"group/<uuid:pk>/update/", groups.GroupUpdateView.as_view(), name="group-update"
"groups/<uuid:pk>/update/",
groups.GroupUpdateView.as_view(),
name="group-update",
),
path(
"group/<uuid:pk>/delete/", groups.GroupDeleteView.as_view(), name="group-delete"
"groups/<uuid:pk>/delete/",
groups.GroupDeleteView.as_view(),
name="group-delete",
),
# Certificate-Key Pairs
path(
@ -264,8 +272,19 @@ urlpatterns = [
certificate_key_pair.CertificateKeyPairDeleteView.as_view(),
name="certificatekeypair-delete",
),
# Groups
path("groups/", groups.GroupListView.as_view(), name="groups"),
# Debug
path("debug/request/", debug.DebugRequestView.as_view(), name="debug-request"),
# Outposts
path("outposts/", outposts.OutpostListView.as_view(), name="outposts",),
path(
"outposts/create/", outposts.OutpostCreateView.as_view(), name="outpost-create",
),
path(
"outposts/<uuid:pk>/update/",
outposts.OutpostUpdateView.as_view(),
name="outpost-update",
),
path(
"outposts/<uuid:pk>/delete/",
outposts.OutpostDeleteView.as_view(),
name="outpost-delete",
),
]

View File

@ -1,15 +0,0 @@
"""passbook administration debug views"""
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import TemplateView
class DebugRequestView(LoginRequiredMixin, TemplateView):
"""Show debug info about request"""
template_name = "administration/debug/request.html"
def get_context_data(self, **kwargs):
kwargs["request_dict"] = {}
for key in dir(self.request):
kwargs["request_dict"][key] = getattr(self.request, key)
return super().get_context_data(**kwargs)

View File

@ -1,19 +1,23 @@
"""passbook Flow administration"""
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.mixins import (
PermissionRequiredMixin as DjangoPermissionRequiredMixin,
)
from django.contrib.messages.views import SuccessMessageMixin
from django.http import HttpRequest, HttpResponse
from django.http import HttpRequest, HttpResponse, JsonResponse
from django.urls import reverse_lazy
from django.utils.translation import ugettext as _
from django.views.generic import DetailView, ListView, UpdateView
from django.views.generic import DetailView, FormView, ListView, UpdateView
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
from passbook.admin.views.utils import DeleteMessageView
from passbook.flows.forms import FlowForm
from passbook.flows.forms import FlowForm, FlowImportForm
from passbook.flows.models import Flow
from passbook.flows.planner import PLAN_CONTEXT_PENDING_USER
from passbook.flows.transfer.common import DataclassEncoder
from passbook.flows.transfer.exporter import FlowExporter
from passbook.flows.transfer.importer import FlowImporter
from passbook.flows.views import SESSION_KEY_PLAN, FlowPlanner
from passbook.lib.utils.urls import redirect_with_qs
from passbook.lib.views import CreateAssignPermView
@ -88,3 +92,42 @@ class FlowDebugExecuteView(LoginRequiredMixin, PermissionRequiredMixin, DetailVi
return redirect_with_qs(
"passbook_flows:flow-executor-shell", self.request.GET, flow_slug=flow.slug,
)
class FlowImportView(LoginRequiredMixin, FormView):
"""Import flow from JSON Export; only allowed for superusers
as these flows can contain python code"""
form_class = FlowImportForm
template_name = "administration/flow/import.html"
success_url = reverse_lazy("passbook_admin:flows")
def dispatch(self, request, *args, **kwargs):
if not request.user.is_superuser:
return self.handle_no_permission()
return super().dispatch(request, *args, **kwargs)
def form_valid(self, form: FlowImportForm) -> HttpResponse:
importer = FlowImporter(form.cleaned_data["flow"].read().decode())
successful = importer.apply()
if not successful:
messages.error(self.request, _("Failed to import flow."))
else:
messages.success(self.request, _("Successfully imported flow."))
return super().form_valid(form)
class FlowExportView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
"""Export Flow"""
model = Flow
permission_required = "passbook_flows.export_flow"
# pylint: disable=unused-argument
def get(self, request: HttpRequest, pk: str) -> HttpResponse:
"""Debug exectue flow, setting the current user as pending user"""
flow: Flow = self.get_object()
exporter = FlowExporter(flow)
response = JsonResponse(exporter.export(), encoder=DataclassEncoder, safe=False)
response["Content-Disposition"] = f'attachment; filename="{flow.slug}.json"'
return response

View File

@ -0,0 +1,67 @@
"""passbook Outpost administration"""
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.mixins import (
PermissionRequiredMixin as DjangoPermissionRequiredMixin,
)
from django.contrib.messages.views import SuccessMessageMixin
from django.urls import reverse_lazy
from django.utils.translation import ugettext as _
from django.views.generic import ListView, UpdateView
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
from passbook.admin.views.utils import DeleteMessageView
from passbook.lib.views import CreateAssignPermView
from passbook.outposts.forms import OutpostForm
from passbook.outposts.models import Outpost
class OutpostListView(LoginRequiredMixin, PermissionListMixin, ListView):
"""Show list of all outposts"""
model = Outpost
permission_required = "passbook_outposts.view_outpost"
ordering = "name"
paginate_by = 40
template_name = "administration/outpost/list.html"
class OutpostCreateView(
SuccessMessageMixin,
LoginRequiredMixin,
DjangoPermissionRequiredMixin,
CreateAssignPermView,
):
"""Create new Outpost"""
model = Outpost
form_class = OutpostForm
permission_required = "passbook_outposts.add_outpost"
template_name = "generic/create.html"
success_url = reverse_lazy("passbook_admin:outposts")
success_message = _("Successfully created Outpost")
class OutpostUpdateView(
SuccessMessageMixin, LoginRequiredMixin, PermissionRequiredMixin, UpdateView
):
"""Update outpost"""
model = Outpost
form_class = OutpostForm
permission_required = "passbook_outposts.change_outpost"
template_name = "generic/update.html"
success_url = reverse_lazy("passbook_admin:outposts")
success_message = _("Successfully updated Certificate-Key Pair")
class OutpostDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteMessageView):
"""Delete outpost"""
model = Outpost
permission_required = "passbook_outposts.delete_outpost"
template_name = "generic/delete.html"
success_url = reverse_lazy("passbook_admin:outposts")
success_message = _("Successfully deleted Certificate-Key Pair")

View File

@ -6,7 +6,7 @@ from django.contrib.messages.views import SuccessMessageMixin
from django.http import Http404
from django.views.generic import DeleteView, ListView, UpdateView
from passbook.lib.utils.reflection import all_subclasses, path_to_class
from passbook.lib.utils.reflection import all_subclasses
from passbook.lib.views import CreateAssignPermView
@ -40,7 +40,7 @@ class InheritanceCreateView(CreateAssignPermView):
)
except StopIteration as exc:
raise Http404 from exc
return path_to_class(model.form)
return model.form(model)
def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
kwargs = super().get_context_data(**kwargs)
@ -61,9 +61,7 @@ class InheritanceUpdateView(UpdateView):
return kwargs
def get_form_class(self):
form_class_path = self.get_object().form
form_class = path_to_class(form_class_path)
return form_class
return self.get_object().form()
def get_object(self, queryset=None):
return (

View File

@ -1,10 +1,8 @@
"""passbook api urls"""
from django.urls import include, path
from passbook.api.v1.urls import urlpatterns as v1_urls
from passbook.api.v2.urls import urlpatterns as v2_urls
urlpatterns = [
path("v1/", include(v1_urls)),
path("v2beta/", include(v2_urls)),
]

View File

@ -1,22 +0,0 @@
"""Passbook v1 OpenID API"""
from django.http import JsonResponse
from django.views import View
from oauth2_provider.views.mixins import ScopedResourceMixin
class OpenIDUserInfoView(ScopedResourceMixin, View):
"""Passbook v1 OpenID API"""
required_scopes = ["openid:userinfo"]
def get(self, request, *_, **__):
"""Passbook v1 OpenID API"""
payload = {
"sub": request.user.uuid.int,
"name": request.user.get_full_name(),
"given_name": request.user.name,
"family_name": "",
"preferred_username": request.user.username,
"email": request.user.email,
}
return JsonResponse(payload)

View File

@ -1,6 +0,0 @@
"""Passbook API URLs"""
from django.urls import path
from passbook.api.v1.openid import OpenIDUserInfoView
urlpatterns = [path("openid/", OpenIDUserInfoView.as_view(), name="openid")]

View File

@ -6,15 +6,17 @@ from drf_yasg.views import get_schema_view
from rest_framework import routers
from passbook.api.permissions import CustomObjectPermissions
from passbook.api.v2.messages import MessagesViewSet
from passbook.audit.api import EventViewSet
from passbook.core.api.applications import ApplicationViewSet
from passbook.core.api.groups import GroupViewSet
from passbook.core.api.messages import MessagesViewSet
from passbook.core.api.propertymappings import PropertyMappingViewSet
from passbook.core.api.providers import ProviderViewSet
from passbook.core.api.sources import SourceViewSet
from passbook.core.api.users import UserViewSet
from passbook.crypto.api import CertificateKeyPairViewSet
from passbook.flows.api import FlowStageBindingViewSet, FlowViewSet, StageViewSet
from passbook.outposts.api import OutpostViewSet
from passbook.policies.api import PolicyBindingViewSet, PolicyViewSet
from passbook.policies.dummy.api import DummyPolicyViewSet
from passbook.policies.expiry.api import PasswordExpiryPolicyViewSet
@ -23,9 +25,8 @@ from passbook.policies.group_membership.api import GroupMembershipPolicyViewSet
from passbook.policies.hibp.api import HaveIBeenPwendPolicyViewSet
from passbook.policies.password.api import PasswordPolicyViewSet
from passbook.policies.reputation.api import ReputationPolicyViewSet
from passbook.providers.app_gw.api import ApplicationGatewayProviderViewSet
from passbook.providers.oauth.api import OAuth2ProviderViewSet
from passbook.providers.oidc.api import OpenIDProviderViewSet
from passbook.providers.oauth2.api import OAuth2ProviderViewSet, ScopeMappingViewSet
from passbook.providers.proxy.api import OutpostConfigViewSet, ProxyProviderViewSet
from passbook.providers.saml.api import SAMLPropertyMappingViewSet, SAMLProviderViewSet
from passbook.sources.ldap.api import LDAPPropertyMappingViewSet, LDAPSourceViewSet
from passbook.sources.oauth.api import OAuthSourceViewSet
@ -48,10 +49,14 @@ from passbook.stages.user_write.api import UserWriteStageViewSet
router = routers.DefaultRouter()
router.register("root/messages", MessagesViewSet, basename="messages")
router.register("core/applications", ApplicationViewSet)
router.register("core/groups", GroupViewSet)
router.register("core/users", UserViewSet)
router.register("core/messages", MessagesViewSet, basename="messages")
router.register("outposts/outposts", OutpostViewSet)
router.register("outposts/proxy", OutpostConfigViewSet)
router.register("crypto/certificatekeypairs", CertificateKeyPairViewSet)
router.register("audit/events", EventViewSet)
@ -70,14 +75,14 @@ router.register("policies/password", PasswordPolicyViewSet)
router.register("policies/reputation", ReputationPolicyViewSet)
router.register("providers/all", ProviderViewSet)
router.register("providers/applicationgateway", ApplicationGatewayProviderViewSet)
router.register("providers/oauth", OAuth2ProviderViewSet)
router.register("providers/openid", OpenIDProviderViewSet)
router.register("providers/proxy", ProxyProviderViewSet)
router.register("providers/oauth2", OAuth2ProviderViewSet)
router.register("providers/saml", SAMLProviderViewSet)
router.register("propertymappings/all", PropertyMappingViewSet)
router.register("propertymappings/ldap", LDAPPropertyMappingViewSet)
router.register("propertymappings/saml", SAMLPropertyMappingViewSet)
router.register("propertymappings/scope", ScopeMappingViewSet)
router.register("stages/all", StageViewSet)
router.register("stages/captcha", CaptchaStageViewSet)

View File

@ -2,7 +2,6 @@
import uuid
import django.contrib.postgres.fields.jsonb
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
@ -48,12 +47,7 @@ class Migration(migrations.Migration):
),
("date", models.DateTimeField(auto_now_add=True)),
("app", models.TextField()),
(
"context",
django.contrib.postgres.fields.jsonb.JSONField(
blank=True, default=dict
),
),
("context", models.JSONField(blank=True, default=dict),),
("client_ip", models.GenericIPAddressField(null=True)),
("created", models.DateTimeField(auto_now_add=True)),
(

View File

@ -7,12 +7,11 @@ from uuid import UUID, uuid4
from django.conf import settings
from django.contrib.auth.models import AnonymousUser
from django.contrib.contenttypes.models import ContentType
from django.contrib.postgres.fields import JSONField
from django.core.exceptions import ValidationError
from django.db import models
from django.http import HttpRequest
from django.utils.translation import gettext as _
from django.views.debug import CLEANSED_SUBSTITUTE, HIDDEN_SETTINGS
from django.views.debug import SafeExceptionReporterFilter
from guardian.shortcuts import get_anonymous_user
from structlog import get_logger
@ -26,8 +25,8 @@ def cleanse_dict(source: Dict[Any, Any]) -> Dict[Any, Any]:
final_dict = {}
for key, value in source.items():
try:
if HIDDEN_SETTINGS.search(key):
final_dict[key] = CLEANSED_SUBSTITUTE
if SafeExceptionReporterFilter.hidden_settings.search(key):
final_dict[key] = SafeExceptionReporterFilter.cleansed_substitute
else:
final_dict[key] = value
except TypeError:
@ -100,7 +99,7 @@ class Event(models.Model):
action = models.TextField(choices=EventAction.as_choices())
date = models.DateTimeField(auto_now_add=True)
app = models.TextField()
context = JSONField(default=dict, blank=True)
context = models.JSONField(default=dict, blank=True)
client_ip = models.GenericIPAddressField(null=True)
created = models.DateTimeField(auto_now_add=True)

View File

@ -1,11 +1,12 @@
"""passbook Event administration"""
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import ListView
from guardian.mixins import PermissionListMixin
from passbook.audit.models import Event
class EventListView(PermissionListMixin, ListView):
class EventListView(PermissionListMixin, LoginRequiredMixin, ListView):
"""Show list of all invitations"""
model = Event

View File

@ -18,7 +18,7 @@ def admin_autoregister(app: AppConfig):
pass
for app in apps.get_app_configs():
if app.label.startswith("passbook_"):
LOGGER.debug("Registering application for dj-admin", app=app.label)
admin_autoregister(app)
for _app in apps.get_app_configs():
if _app.label.startswith("passbook_"):
LOGGER.debug("Registering application for dj-admin", app=_app.label)
admin_autoregister(_app)

View File

@ -9,10 +9,11 @@ from passbook.lib.widgets import GroupedModelChoiceField
class ApplicationForm(forms.ModelForm):
"""Application Form"""
provider = GroupedModelChoiceField(
queryset=Provider.objects.all().order_by("pk").select_subclasses(),
required=False,
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["provider"].queryset = (
Provider.objects.all().order_by("pk").select_subclasses()
)
class Meta:
@ -32,6 +33,7 @@ class ApplicationForm(forms.ModelForm):
"meta_icon_url": forms.TextInput(),
"meta_publisher": forms.TextInput(),
}
field_classes = {"provider": GroupedModelChoiceField}
labels = {
"meta_launch_url": _("Launch URL"),
"meta_icon_url": _("Icon URL"),

View File

@ -4,7 +4,6 @@ import uuid
import django.contrib.auth.models
import django.contrib.auth.validators
import django.contrib.postgres.fields.jsonb
import django.db.models.deletion
import django.utils.timezone
import guardian.mixins
@ -109,12 +108,7 @@ class Migration(migrations.Migration):
("uuid", models.UUIDField(default=uuid.uuid4, editable=False)),
("name", models.TextField(help_text="User's display name.")),
("password_change_date", models.DateTimeField(auto_now_add=True)),
(
"attributes",
django.contrib.postgres.fields.jsonb.JSONField(
blank=True, default=dict
),
),
("attributes", models.JSONField(blank=True, default=dict),),
],
options={"permissions": (("reset_user_password", "Reset Password"),),},
bases=(guardian.mixins.GuardianUserMixin, models.Model),
@ -264,12 +258,7 @@ class Migration(migrations.Migration):
),
),
("name", models.CharField(max_length=80, verbose_name="name")),
(
"attributes",
django.contrib.postgres.fields.jsonb.JSONField(
blank=True, default=dict
),
),
("attributes", models.JSONField(blank=True, default=dict),),
(
"parent",
models.ForeignKey(

Some files were not shown because too many files have changed in this diff Show More