From 406f69080b8a4b8c3a34ce3b05edfa0a7557493c Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Sat, 16 May 2020 16:02:42 +0200 Subject: [PATCH] Revert "*: providers and sources -> channels, PolicyModel to PolicyBindingModel that uses custom M2M through" This reverts commit 7ed3ceb960922883e6e4d2242ba1534a23818819. --- passbook/admin/forms/inlet.py | 4 - passbook/admin/forms/source.py | 4 + .../{outlet => provider}/list.html | 0 .../{inlet => source}/list.html | 0 passbook/admin/urls.py | 58 +- passbook/admin/views/overview.py | 11 +- .../admin/views/{policies.py => policy.py} | 2 +- .../admin/views/{inlets.py => providers.py} | 68 +- .../admin/views/{outlets.py => sources.py} | 64 +- passbook/admin/views/users.py | 8 +- passbook/api/permissions.py | 7 +- passbook/api/v2/urls.py | 34 +- passbook/audit/migrations/0001_initial.py | 29 +- .../migrations/0002_auto_20191028_0829.py | 16 + .../migrations/0003_auto_20191205_1407.py | 40 + .../migrations/0004_auto_20191205_1502.py | 19 + passbook/audit/tests/test_event.py | 2 +- passbook/channels/in_ldap/apps.py | 11 - passbook/channels/in_ldap/tasks.py | 33 - passbook/channels/in_oauth/api.py | 29 - passbook/channels/in_oauth/backends.py | 24 - .../in_oauth/migrations/0001_initial.py | 81 - passbook/channels/in_oauth/models.py | 159 - passbook/channels/in_oauth/settings.py | 15 - passbook/channels/in_saml/api.py | 28 - passbook/channels/in_saml/apps.py | 12 - .../in_saml/migrations/0001_initial.py | 68 - passbook/channels/in_saml/utils.py | 20 - passbook/channels/out_oauth/api.py | 29 - passbook/channels/out_oauth/apps.py | 12 - passbook/channels/out_oidc/settings.py | 9 - .../out_saml/migrations/0001_initial.py | 140 - passbook/channels/out_saml/settings.py | 6 - passbook/channels/out_samlv2/apps.py | 11 - passbook/core/api/applications.py | 2 +- passbook/core/api/inlets.py | 31 - passbook/core/api/outlets.py | 30 - passbook/core/api/policies.py | 2 +- passbook/core/api/providers.py | 30 + passbook/core/api/sources.py | 31 + passbook/core/forms/applications.py | 8 +- passbook/core/migrations/0001_initial.py | 301 +- .../migrations/0002_auto_20191010_1058.py | 17 + .../core/migrations/0002_nonce_description.py | 18 + .../migrations/0003_auto_20191011_0914.py | 31 + .../migrations/0003_merge_20191010_1541.py | 13 + .../migrations/0004_remove_policy_action.py | 14 + .../migrations/0005_merge_20191025_2022.py | 13 + .../0006_propertymapping_template.py | 19 + .../migrations/0007_auto_20200217_1934.py | 16 + .../migrations/0008_auto_20200220_1242.py | 29 + .../migrations/0009_auto_20200221_1410.py | 52 + .../migrations/0010_auto_20200221_2208.py | 33 + .../migrations/0011_auto_20200222_1822.py | 27 + .../core/migrations/0012_delete_factor.py | 14 + .../migrations/0013_delete_debugpolicy.py | 16 + .../core/migrations/0014_delete_invitation.py | 14 + passbook/core/models.py | 127 +- passbook/core/signals.py | 2 +- passbook/core/tasks.py | 10 +- passbook/core/templates/user/base.html | 12 +- .../templatetags/passbook_user_settings.py | 18 +- passbook/core/views/access.py | 15 +- passbook/crypto/migrations/0001_initial.py | 45 +- passbook/flows/migrations/0001_initial.py | 14 +- .../migrations/0003_auto_20200509_1258.py | 26 + .../migrations/0004_auto_20200510_2310.py | 27 + .../migrations/0005_auto_20200512_1158.py | 28 + .../policies/dummy/migrations/0001_initial.py | 9 +- passbook/policies/dummy/models.py | 2 +- passbook/policies/engine.py | 3 +- .../expiry/migrations/0001_initial.py | 8 +- passbook/policies/expiry/models.py | 2 +- .../expression/migrations/0001_initial.py | 8 +- passbook/policies/expression/models.py | 2 +- .../policies/hibp/migrations/0001_initial.py | 8 +- passbook/policies/hibp/models.py | 9 +- passbook/policies/migrations/0001_initial.py | 36 +- .../migrations/0002_auto_20200508_1230.py | 20 + .../migrations/0003_auto_20200508_1642.py | 24 + passbook/policies/models.py | 25 +- .../password/migrations/0001_initial.py | 8 +- passbook/policies/password/models.py | 2 +- passbook/policies/process.py | 3 +- .../reputation/migrations/0001_initial.py | 8 +- passbook/policies/reputation/models.py | 3 +- passbook/policies/tests/test_engine.py | 3 +- passbook/{channels => providers}/__init__.py | 0 .../in_ldap => providers/app_gw}/__init__.py | 0 .../out_app_gw => providers/app_gw}/api.py | 22 +- .../out_app_gw => providers/app_gw}/apps.py | 6 +- .../out_app_gw => providers/app_gw}/forms.py | 8 +- .../app_gw/migrations/0001_initial.py | 99 + .../migrations/0002_auto_20191111_1703.py | 18 + .../0003_applicationgatewayprovider.py} | 20 +- .../migrations/0004_auto_20200102_1505.py | 24 + .../app_gw}/migrations/__init__.py | 0 .../out_app_gw => providers/app_gw}/models.py | 14 +- .../app_gw/provider}/__init__.py | 0 .../app_gw/provider/kubernetes}/__init__.py | 0 .../templates/app_gw/docker-compose.yml | 0 .../templates/app_gw/k8s-manifest.yaml | 0 .../app_gw}/templates/app_gw/setup_modal.html | 2 +- .../out_app_gw => providers/app_gw}/urls.py | 2 +- .../out_app_gw => providers/app_gw}/views.py | 8 +- .../types => providers/oauth}/__init__.py | 0 passbook/providers/oauth/api.py | 29 + passbook/providers/oauth/apps.py | 12 + .../out_oauth => providers/oauth}/forms.py | 10 +- .../oauth}/migrations/0001_initial.py | 18 +- .../oauth/migrations}/__init__.py | 0 .../out_oauth => providers/oauth}/models.py | 16 +- .../out_oauth => providers/oauth}/settings.py | 4 +- .../templates/oauth2_provider/authorize.html | 0 .../templates/oauth2_provider/base.html | 0 .../oauth2_provider/setup_url_modal.html | 0 .../out_oauth => providers/oauth}/urls.py | 2 +- .../oauth/views}/__init__.py | 0 .../oauth}/views/github.py | 0 .../oauth}/views/oauth2.py | 28 +- .../migrations => providers/oidc}/__init__.py | 0 .../out_oidc => providers/oidc}/api.py | 14 +- .../out_oidc => providers/oidc}/apps.py | 10 +- .../out_oidc => providers/oidc}/auth.py | 14 +- .../out_oidc => providers/oidc}/claims.py | 0 .../out_oidc => providers/oidc}/forms.py | 8 +- .../oidc}/migrations/0001_initial.py | 16 +- .../oidc/migrations}/__init__.py | 0 .../out_oidc => providers/oidc}/models.py | 12 +- passbook/providers/oidc/settings.py | 9 + .../out_oidc => providers/oidc}/signals.py | 10 +- .../templates/oidc_provider/authorize.html | 0 .../oidc}/templates/oidc_provider/error.html | 0 .../oidc_provider/setup_url_modal.html | 0 .../out_app_gw => providers/saml}/__init__.py | 0 .../out_saml => providers/saml}/api.py | 18 +- .../out_saml => providers/saml}/apps.py | 8 +- .../out_saml => providers/saml}/exceptions.py | 0 .../out_saml => providers/saml}/forms.py | 10 +- .../providers/saml/migrations/0001_initial.py | 79 + .../migrations/0002_auto_20200214_1354.py | 61 + .../migrations/0003_auto_20200216_1109.py | 38 + .../migrations/0004_auto_20200217_1526.py | 41 + .../0005_remove_samlpropertymapping_values.py | 76 + .../migrations/0006_auto_20200217_2031.py | 26 + .../migrations/0007_auto_20200303_2157.py | 29 + .../migrations/0008_auto_20200305_1606.py | 16 + .../migrations/0009_auto_20200506_1551.py | 40 + .../saml}/migrations/__init__.py | 0 .../out_saml => providers/saml}/models.py | 26 +- .../saml/processors}/__init__.py | 0 .../saml}/processors/base.py | 31 +- .../saml}/processors/generic.py | 2 +- .../saml}/processors/salesforce.py | 4 +- .../saml}/processors/types.py | 0 passbook/providers/saml/settings.py | 6 + .../saml/idp/admin_metadata_modal.html | 0 .../templates/saml/idp/autosubmit_form.html | 0 .../saml}/templates/saml/idp/logged_out.html | 0 .../saml}/templates/saml/idp/login.html | 0 .../saml/idp/property_mapping_form.html | 0 .../templates/saml/xml/assertions/generic.xml | 0 .../saml/xml/assertions/google_apps.xml | 0 .../saml/xml/assertions/salesforce.xml | 0 .../saml}/templates/saml/xml/attributes.xml | 0 .../saml}/templates/saml/xml/metadata.xml | 0 .../saml}/templates/saml/xml/response.xml | 0 .../saml}/templates/saml/xml/signature.xml | 0 .../saml}/templates/saml/xml/subject.xml | 0 .../saml/tests}/__init__.py | 0 .../saml}/tests/test_utils_time.py | 2 +- .../out_saml => providers/saml}/urls.py | 2 +- .../saml}/utils/__init__.py | 0 .../saml}/utils/encoding.py | 0 .../out_saml => providers/saml}/utils/time.py | 0 .../saml}/utils/xml_render.py | 8 +- .../saml}/utils/xml_signing.py | 4 +- .../out_saml => providers/saml}/views.py | 38 +- .../samlv2}/__init__.py | 0 passbook/providers/samlv2/apps.py | 11 + .../out_samlv2 => providers/samlv2}/models.py | 0 .../samlv2/saml}/__init__.py | 0 .../samlv2}/saml/constants.py | 0 .../samlv2}/saml/parser.py | 6 +- .../samlv2}/saml/provider.py | 0 .../samlv2}/saml/utils.py | 0 .../out_samlv2 => providers/samlv2}/urls.py | 2 +- .../samlv2}/views/__init__.py | 0 .../samlv2}/views/authorize.py | 0 .../samlv2}/views/base.py | 4 +- .../samlv2}/views/idp_initiated.py | 0 .../samlv2}/views/slo.py | 0 .../samlv2}/views/sso.py | 9 +- .../commands/create_recovery_key.py | 16 +- passbook/recovery/tests.py | 14 +- passbook/recovery/urls.py | 4 +- passbook/recovery/views.py | 18 +- passbook/root/settings.py | 20 +- .../out_oidc => sources}/__init__.py | 0 .../migrations => sources/ldap}/__init__.py | 0 .../{channels/in_ldap => sources/ldap}/api.py | 22 +- passbook/sources/ldap/apps.py | 11 + .../in_ldap => sources/ldap}/auth.py | 10 +- .../in_ldap => sources/ldap}/connector.py | 52 +- .../in_ldap => sources/ldap}/forms.py | 12 +- .../ldap}/migrations/0001_initial.py | 73 +- .../migrations/0002_auto_20191011_0825.py | 20 + .../migrations/0003_auto_20191011_0825.py | 33 + .../migrations/0004_auto_20191011_0839.py | 35 + .../migrations/0005_auto_20191011_1059.py | 44 + .../migrations/0006_auto_20200216_1116.py | 60 + ...emove_ldappropertymapping_ldap_property.py | 46 + .../ldap/migrations}/__init__.py | 0 .../in_ldap => sources/ldap}/models.py | 14 +- .../in_ldap => sources/ldap}/settings.py | 4 +- passbook/sources/ldap/tasks.py | 33 + .../templates/ldap/property_mapping_form.html | 0 .../migrations => sources/oauth}/__init__.py | 0 passbook/sources/oauth/api.py | 29 + .../in_oauth => sources/oauth}/apps.py | 8 +- passbook/sources/oauth/backends.py | 24 + .../in_oauth => sources/oauth}/clients.py | 44 +- .../in_oauth => sources/oauth}/forms.py | 50 +- .../sources/oauth/migrations/0001_initial.py | 67 + .../migrations/0002_auto_20200217_1526.py | 35 + .../oauth/migrations}/__init__.py | 0 passbook/sources/oauth/models.py | 159 + passbook/sources/oauth/settings.py | 15 + .../oauth}/templates/oauth_client/user.html | 4 +- .../tests => sources/oauth/types}/__init__.py | 0 .../oauth}/types/azure_ad.py | 12 +- .../oauth}/types/discord.py | 14 +- .../oauth}/types/facebook.py | 14 +- .../oauth}/types/github.py | 10 +- .../oauth}/types/google.py | 14 +- .../oauth}/types/manager.py | 32 +- .../oauth}/types/reddit.py | 18 +- .../oauth}/types/twitter.py | 10 +- .../in_oauth => sources/oauth}/urls.py | 12 +- .../in_oauth => sources/oauth}/utils.py | 0 .../oauth/views}/__init__.py | 0 .../in_oauth => sources/oauth}/views/core.py | 174 +- .../oauth}/views/dispatcher.py | 12 +- .../in_oauth => sources/oauth}/views/user.py | 10 +- .../out_samlv2 => sources}/saml/__init__.py | 0 passbook/sources/saml/api.py | 28 + passbook/sources/saml/apps.py | 12 + .../in_saml => sources/saml}/exceptions.py | 0 .../in_saml => sources/saml}/forms.py | 12 +- .../sources/saml/migrations/0001_initial.py | 41 + .../migrations/0002_auto_20191107_1505.py | 22 + .../migrations/0003_auto_20191107_1550.py | 19 + .../migrations/0004_auto_20200217_1526.py | 30 + .../migrations/0005_auto_20200220_1621.py | 26 + .../migrations/0006_auto_20200303_2201.py | 27 + .../saml/migrations}/__init__.py | 0 .../in_saml => sources/saml}/models.py | 18 +- passbook/sources/saml/processors/__init__.py | 0 .../saml}/processors/base.py | 18 +- .../saml}/templates/saml/sp/login.html | 0 .../templates/saml/sp/sso_single_logout.html | 0 .../templates/saml/sp/xml/authn_request.xml | 0 .../saml}/templates/saml/sp/xml/signature.xml | 0 .../templates/saml/sp/xml/signed_info.xml | 0 .../saml/sp/xml/sp_sso_descriptor.xml | 0 .../in_saml => sources/saml}/urls.py | 2 +- passbook/sources/saml/utils.py | 20 + .../in_saml => sources/saml}/views.py | 63 +- .../in_saml => sources/saml}/xml_render.py | 2 +- .../stages/captcha/migrations/0001_initial.py | 2 +- .../stages/dummy/migrations/0001_initial.py | 2 +- .../stages/email/migrations/0001_initial.py | 27 +- .../migrations/0002_auto_20200510_1844.py | 22 + .../migrations/0003_auto_20200515_1242.py | 32 + passbook/stages/email/stage.py | 14 +- passbook/stages/email/tests.py | 4 +- .../identification/migrations/0001_initial.py | 14 +- .../migrations/0002_auto_20200509_1916.py | 18 + .../migrations/0003_auto_20200509_2025.py | 26 + .../migrations/0004_auto_20200510_1648.py | 23 + passbook/stages/identification/stage.py | 12 +- passbook/stages/identification/tests.py | 6 +- .../invitation/migrations/0001_initial.py | 11 +- ...nstage_continue_flow_without_invitation.py | 21 + .../stages/otp/migrations/0001_initial.py | 2 +- .../password/migrations/0001_initial.py | 7 +- ..._remove_passwordstage_password_policies.py | 14 + .../stages/prompt/migrations/0001_initial.py | 6 +- .../user_delete/migrations/0001_initial.py | 4 +- .../user_login/migrations/0001_initial.py | 2 +- .../user_logout/migrations/0001_initial.py | 2 +- .../user_write/migrations/0001_initial.py | 4 +- swagger.yaml | 2660 +++++++++-------- 293 files changed, 4692 insertions(+), 3244 deletions(-) delete mode 100644 passbook/admin/forms/inlet.py create mode 100644 passbook/admin/forms/source.py rename passbook/admin/templates/administration/{outlet => provider}/list.html (100%) rename passbook/admin/templates/administration/{inlet => source}/list.html (100%) rename passbook/admin/views/{policies.py => policy.py} (99%) rename passbook/admin/views/{inlets.py => providers.py} (56%) rename passbook/admin/views/{outlets.py => sources.py} (59%) create mode 100644 passbook/audit/migrations/0002_auto_20191028_0829.py create mode 100644 passbook/audit/migrations/0003_auto_20191205_1407.py create mode 100644 passbook/audit/migrations/0004_auto_20191205_1502.py delete mode 100644 passbook/channels/in_ldap/apps.py delete mode 100644 passbook/channels/in_ldap/tasks.py delete mode 100644 passbook/channels/in_oauth/api.py delete mode 100644 passbook/channels/in_oauth/backends.py delete mode 100644 passbook/channels/in_oauth/migrations/0001_initial.py delete mode 100644 passbook/channels/in_oauth/models.py delete mode 100644 passbook/channels/in_oauth/settings.py delete mode 100644 passbook/channels/in_saml/api.py delete mode 100644 passbook/channels/in_saml/apps.py delete mode 100644 passbook/channels/in_saml/migrations/0001_initial.py delete mode 100644 passbook/channels/in_saml/utils.py delete mode 100644 passbook/channels/out_oauth/api.py delete mode 100644 passbook/channels/out_oauth/apps.py delete mode 100644 passbook/channels/out_oidc/settings.py delete mode 100644 passbook/channels/out_saml/migrations/0001_initial.py delete mode 100644 passbook/channels/out_saml/settings.py delete mode 100644 passbook/channels/out_samlv2/apps.py delete mode 100644 passbook/core/api/inlets.py delete mode 100644 passbook/core/api/outlets.py create mode 100644 passbook/core/api/providers.py create mode 100644 passbook/core/api/sources.py create mode 100644 passbook/core/migrations/0002_auto_20191010_1058.py create mode 100644 passbook/core/migrations/0002_nonce_description.py create mode 100644 passbook/core/migrations/0003_auto_20191011_0914.py create mode 100644 passbook/core/migrations/0003_merge_20191010_1541.py create mode 100644 passbook/core/migrations/0004_remove_policy_action.py create mode 100644 passbook/core/migrations/0005_merge_20191025_2022.py create mode 100644 passbook/core/migrations/0006_propertymapping_template.py create mode 100644 passbook/core/migrations/0007_auto_20200217_1934.py create mode 100644 passbook/core/migrations/0008_auto_20200220_1242.py create mode 100644 passbook/core/migrations/0009_auto_20200221_1410.py create mode 100644 passbook/core/migrations/0010_auto_20200221_2208.py create mode 100644 passbook/core/migrations/0011_auto_20200222_1822.py create mode 100644 passbook/core/migrations/0012_delete_factor.py create mode 100644 passbook/core/migrations/0013_delete_debugpolicy.py create mode 100644 passbook/core/migrations/0014_delete_invitation.py create mode 100644 passbook/flows/migrations/0003_auto_20200509_1258.py create mode 100644 passbook/flows/migrations/0004_auto_20200510_2310.py create mode 100644 passbook/flows/migrations/0005_auto_20200512_1158.py create mode 100644 passbook/policies/migrations/0002_auto_20200508_1230.py create mode 100644 passbook/policies/migrations/0003_auto_20200508_1642.py rename passbook/{channels => providers}/__init__.py (100%) rename passbook/{channels/in_ldap => providers/app_gw}/__init__.py (100%) rename passbook/{channels/out_app_gw => providers/app_gw}/api.py (64%) rename passbook/{channels/out_app_gw => providers/app_gw}/apps.py (58%) rename passbook/{channels/out_app_gw => providers/app_gw}/forms.py (86%) create mode 100644 passbook/providers/app_gw/migrations/0001_initial.py create mode 100644 passbook/providers/app_gw/migrations/0002_auto_20191111_1703.py rename passbook/{channels/out_app_gw/migrations/0001_initial.py => providers/app_gw/migrations/0003_applicationgatewayprovider.py} (65%) create mode 100644 passbook/providers/app_gw/migrations/0004_auto_20200102_1505.py rename passbook/{channels/in_ldap => providers/app_gw}/migrations/__init__.py (100%) rename passbook/{channels/out_app_gw => providers/app_gw}/models.py (69%) rename passbook/{channels/in_oauth => providers/app_gw/provider}/__init__.py (100%) rename passbook/{channels/in_oauth/migrations => providers/app_gw/provider/kubernetes}/__init__.py (100%) rename passbook/{channels/out_app_gw => providers/app_gw}/templates/app_gw/docker-compose.yml (100%) rename passbook/{channels/out_app_gw => providers/app_gw}/templates/app_gw/k8s-manifest.yaml (100%) rename passbook/{channels/out_app_gw => providers/app_gw}/templates/app_gw/setup_modal.html (96%) rename passbook/{channels/out_app_gw => providers/app_gw}/urls.py (74%) rename passbook/{channels/out_app_gw => providers/app_gw}/views.py (79%) rename passbook/{channels/in_oauth/types => providers/oauth}/__init__.py (100%) create mode 100644 passbook/providers/oauth/api.py create mode 100644 passbook/providers/oauth/apps.py rename passbook/{channels/out_oauth => providers/oauth}/forms.py (55%) rename passbook/{channels/out_oauth => providers/oauth}/migrations/0001_initial.py (87%) rename passbook/{channels/in_oauth/views => providers/oauth/migrations}/__init__.py (100%) rename passbook/{channels/out_oauth => providers/oauth}/models.py (70%) rename passbook/{channels/out_oauth => providers/oauth}/settings.py (87%) rename passbook/{channels/out_oauth => providers/oauth}/templates/oauth2_provider/authorize.html (100%) rename passbook/{channels/out_oauth => providers/oauth}/templates/oauth2_provider/base.html (100%) rename passbook/{channels/out_oauth => providers/oauth}/templates/oauth2_provider/setup_url_modal.html (100%) rename passbook/{channels/out_oauth => providers/oauth}/urls.py (95%) rename passbook/{channels/in_saml => providers/oauth/views}/__init__.py (100%) rename passbook/{channels/out_oauth => providers/oauth}/views/github.py (100%) rename passbook/{channels/out_oauth => providers/oauth}/views/oauth2.py (75%) rename passbook/{channels/in_saml/migrations => providers/oidc}/__init__.py (100%) rename passbook/{channels/out_oidc => providers/oidc}/api.py (64%) rename passbook/{channels/out_oidc => providers/oidc}/apps.py (81%) rename passbook/{channels/out_oidc => providers/oidc}/auth.py (79%) rename passbook/{channels/out_oidc => providers/oidc}/claims.py (100%) rename passbook/{channels/out_oidc => providers/oidc}/forms.py (83%) rename passbook/{channels/out_oidc => providers/oidc}/migrations/0001_initial.py (72%) rename passbook/{channels/in_saml/processors => providers/oidc/migrations}/__init__.py (100%) rename passbook/{channels/out_oidc => providers/oidc}/models.py (84%) create mode 100644 passbook/providers/oidc/settings.py rename passbook/{channels/out_oidc => providers/oidc}/signals.py (56%) rename passbook/{channels/out_oidc => providers/oidc}/templates/oidc_provider/authorize.html (100%) rename passbook/{channels/out_oidc => providers/oidc}/templates/oidc_provider/error.html (100%) rename passbook/{channels/out_oidc => providers/oidc}/templates/oidc_provider/setup_url_modal.html (100%) rename passbook/{channels/out_app_gw => providers/saml}/__init__.py (100%) rename passbook/{channels/out_saml => providers/saml}/api.py (72%) rename passbook/{channels/out_saml => providers/saml}/apps.py (79%) rename passbook/{channels/out_saml => providers/saml}/exceptions.py (100%) rename passbook/{channels/out_saml => providers/saml}/forms.py (91%) create mode 100644 passbook/providers/saml/migrations/0001_initial.py create mode 100644 passbook/providers/saml/migrations/0002_auto_20200214_1354.py create mode 100644 passbook/providers/saml/migrations/0003_auto_20200216_1109.py create mode 100644 passbook/providers/saml/migrations/0004_auto_20200217_1526.py create mode 100644 passbook/providers/saml/migrations/0005_remove_samlpropertymapping_values.py create mode 100644 passbook/providers/saml/migrations/0006_auto_20200217_2031.py create mode 100644 passbook/providers/saml/migrations/0007_auto_20200303_2157.py create mode 100644 passbook/providers/saml/migrations/0008_auto_20200305_1606.py create mode 100644 passbook/providers/saml/migrations/0009_auto_20200506_1551.py rename passbook/{channels/out_app_gw => providers/saml}/migrations/__init__.py (100%) rename passbook/{channels/out_saml => providers/saml}/models.py (86%) rename passbook/{channels/out_app_gw/provider => providers/saml/processors}/__init__.py (100%) rename passbook/{channels/out_saml => providers/saml}/processors/base.py (89%) rename passbook/{channels/out_saml => providers/saml}/processors/generic.py (59%) rename passbook/{channels/out_saml => providers/saml}/processors/salesforce.py (71%) rename passbook/{channels/out_saml => providers/saml}/processors/types.py (100%) create mode 100644 passbook/providers/saml/settings.py rename passbook/{channels/out_saml => providers/saml}/templates/saml/idp/admin_metadata_modal.html (100%) rename passbook/{channels/out_saml => providers/saml}/templates/saml/idp/autosubmit_form.html (100%) rename passbook/{channels/out_saml => providers/saml}/templates/saml/idp/logged_out.html (100%) rename passbook/{channels/out_saml => providers/saml}/templates/saml/idp/login.html (100%) rename passbook/{channels/out_saml => providers/saml}/templates/saml/idp/property_mapping_form.html (100%) rename passbook/{channels/out_saml => providers/saml}/templates/saml/xml/assertions/generic.xml (100%) rename passbook/{channels/out_saml => providers/saml}/templates/saml/xml/assertions/google_apps.xml (100%) rename passbook/{channels/out_saml => providers/saml}/templates/saml/xml/assertions/salesforce.xml (100%) rename passbook/{channels/out_saml => providers/saml}/templates/saml/xml/attributes.xml (100%) rename passbook/{channels/out_saml => providers/saml}/templates/saml/xml/metadata.xml (100%) rename passbook/{channels/out_saml => providers/saml}/templates/saml/xml/response.xml (100%) rename passbook/{channels/out_saml => providers/saml}/templates/saml/xml/signature.xml (100%) rename passbook/{channels/out_saml => providers/saml}/templates/saml/xml/subject.xml (100%) rename passbook/{channels/out_app_gw/provider/kubernetes => providers/saml/tests}/__init__.py (100%) rename passbook/{channels/out_saml => providers/saml}/tests/test_utils_time.py (93%) rename passbook/{channels/out_saml => providers/saml}/urls.py (95%) rename passbook/{channels/out_saml => providers/saml}/utils/__init__.py (100%) rename passbook/{channels/out_saml => providers/saml}/utils/encoding.py (100%) rename passbook/{channels/out_saml => providers/saml}/utils/time.py (100%) rename passbook/{channels/out_saml => providers/saml}/utils/xml_render.py (93%) rename passbook/{channels/out_saml => providers/saml}/utils/xml_signing.py (88%) rename passbook/{channels/out_saml => providers/saml}/views.py (90%) rename passbook/{channels/out_oauth => providers/samlv2}/__init__.py (100%) create mode 100644 passbook/providers/samlv2/apps.py rename passbook/{channels/out_samlv2 => providers/samlv2}/models.py (100%) rename passbook/{channels/out_oauth/migrations => providers/samlv2/saml}/__init__.py (100%) rename passbook/{channels/out_samlv2 => providers/samlv2}/saml/constants.py (100%) rename passbook/{channels/out_samlv2 => providers/samlv2}/saml/parser.py (95%) rename passbook/{channels/out_samlv2 => providers/samlv2}/saml/provider.py (100%) rename passbook/{channels/out_samlv2 => providers/samlv2}/saml/utils.py (100%) rename passbook/{channels/out_samlv2 => providers/samlv2}/urls.py (90%) rename passbook/{channels/out_oauth => providers/samlv2}/views/__init__.py (100%) rename passbook/{channels/out_samlv2 => providers/samlv2}/views/authorize.py (100%) rename passbook/{channels/out_samlv2 => providers/samlv2}/views/base.py (88%) rename passbook/{channels/out_samlv2 => providers/samlv2}/views/idp_initiated.py (100%) rename passbook/{channels/out_samlv2 => providers/samlv2}/views/slo.py (100%) rename passbook/{channels/out_samlv2 => providers/samlv2}/views/sso.py (86%) rename passbook/{channels/out_oidc => sources}/__init__.py (100%) rename passbook/{channels/out_oidc/migrations => sources/ldap}/__init__.py (100%) rename passbook/{channels/in_ldap => sources/ldap}/api.py (69%) create mode 100644 passbook/sources/ldap/apps.py rename passbook/{channels/in_ldap => sources/ldap}/auth.py (67%) rename passbook/{channels/in_ldap => sources/ldap}/connector.py (84%) rename passbook/{channels/in_ldap => sources/ldap}/forms.py (86%) rename passbook/{channels/in_ldap => sources/ldap}/migrations/0001_initial.py (53%) create mode 100644 passbook/sources/ldap/migrations/0002_auto_20191011_0825.py create mode 100644 passbook/sources/ldap/migrations/0003_auto_20191011_0825.py create mode 100644 passbook/sources/ldap/migrations/0004_auto_20191011_0839.py create mode 100644 passbook/sources/ldap/migrations/0005_auto_20191011_1059.py create mode 100644 passbook/sources/ldap/migrations/0006_auto_20200216_1116.py create mode 100644 passbook/sources/ldap/migrations/0007_remove_ldappropertymapping_ldap_property.py rename passbook/{channels/out_saml => sources/ldap/migrations}/__init__.py (100%) rename passbook/{channels/in_ldap => sources/ldap}/models.py (85%) rename passbook/{channels/in_ldap => sources/ldap}/settings.py (64%) create mode 100644 passbook/sources/ldap/tasks.py rename passbook/{channels/in_ldap => sources/ldap}/templates/ldap/property_mapping_form.html (100%) rename passbook/{channels/out_saml/migrations => sources/oauth}/__init__.py (100%) create mode 100644 passbook/sources/oauth/api.py rename passbook/{channels/in_oauth => sources/oauth}/apps.py (76%) create mode 100644 passbook/sources/oauth/backends.py rename passbook/{channels/in_oauth => sources/oauth}/clients.py (89%) rename passbook/{channels/in_oauth => sources/oauth}/forms.py (72%) create mode 100644 passbook/sources/oauth/migrations/0001_initial.py create mode 100644 passbook/sources/oauth/migrations/0002_auto_20200217_1526.py rename passbook/{channels/out_saml/processors => sources/oauth/migrations}/__init__.py (100%) create mode 100644 passbook/sources/oauth/models.py create mode 100644 passbook/sources/oauth/settings.py rename passbook/{channels/in_oauth => sources/oauth}/templates/oauth_client/user.html (61%) rename passbook/{channels/out_saml/tests => sources/oauth/types}/__init__.py (100%) rename passbook/{channels/in_oauth => sources/oauth}/types/azure_ad.py (55%) rename passbook/{channels/in_oauth => sources/oauth}/types/discord.py (55%) rename passbook/{channels/in_oauth => sources/oauth}/types/facebook.py (53%) rename passbook/{channels/in_oauth => sources/oauth}/types/github.py (53%) rename passbook/{channels/in_oauth => sources/oauth}/types/google.py (54%) rename passbook/{channels/in_oauth => sources/oauth}/types/manager.py (51%) rename passbook/{channels/in_oauth => sources/oauth}/types/reddit.py (61%) rename passbook/{channels/in_oauth => sources/oauth}/types/twitter.py (54%) rename passbook/{channels/in_oauth => sources/oauth}/urls.py (64%) rename passbook/{channels/in_oauth => sources/oauth}/utils.py (100%) rename passbook/{channels/out_samlv2 => sources/oauth/views}/__init__.py (100%) rename passbook/{channels/in_oauth => sources/oauth}/views/core.py (54%) rename passbook/{channels/in_oauth => sources/oauth}/views/dispatcher.py (55%) rename passbook/{channels/in_oauth => sources/oauth}/views/user.py (60%) rename passbook/{channels/out_samlv2 => sources}/saml/__init__.py (100%) create mode 100644 passbook/sources/saml/api.py create mode 100644 passbook/sources/saml/apps.py rename passbook/{channels/in_saml => sources/saml}/exceptions.py (100%) rename passbook/{channels/in_saml => sources/saml}/forms.py (70%) create mode 100644 passbook/sources/saml/migrations/0001_initial.py create mode 100644 passbook/sources/saml/migrations/0002_auto_20191107_1505.py create mode 100644 passbook/sources/saml/migrations/0003_auto_20191107_1550.py create mode 100644 passbook/sources/saml/migrations/0004_auto_20200217_1526.py create mode 100644 passbook/sources/saml/migrations/0005_auto_20200220_1621.py create mode 100644 passbook/sources/saml/migrations/0006_auto_20200303_2201.py rename passbook/{channels/out_samlv2/views => sources/saml/migrations}/__init__.py (100%) rename passbook/{channels/in_saml => sources/saml}/models.py (75%) create mode 100644 passbook/sources/saml/processors/__init__.py rename passbook/{channels/in_saml => sources/saml}/processors/base.py (87%) rename passbook/{channels/in_saml => sources/saml}/templates/saml/sp/login.html (100%) rename passbook/{channels/in_saml => sources/saml}/templates/saml/sp/sso_single_logout.html (100%) rename passbook/{channels/in_saml => sources/saml}/templates/saml/sp/xml/authn_request.xml (100%) rename passbook/{channels/in_saml => sources/saml}/templates/saml/sp/xml/signature.xml (100%) rename passbook/{channels/in_saml => sources/saml}/templates/saml/sp/xml/signed_info.xml (100%) rename passbook/{channels/in_saml => sources/saml}/templates/saml/sp/xml/sp_sso_descriptor.xml (100%) rename passbook/{channels/in_saml => sources/saml}/urls.py (80%) create mode 100644 passbook/sources/saml/utils.py rename passbook/{channels/in_saml => sources/saml}/views.py (59%) rename passbook/{channels/in_saml => sources/saml}/xml_render.py (89%) create mode 100644 passbook/stages/email/migrations/0002_auto_20200510_1844.py create mode 100644 passbook/stages/email/migrations/0003_auto_20200515_1242.py create mode 100644 passbook/stages/identification/migrations/0002_auto_20200509_1916.py create mode 100644 passbook/stages/identification/migrations/0003_auto_20200509_2025.py create mode 100644 passbook/stages/identification/migrations/0004_auto_20200510_1648.py create mode 100644 passbook/stages/invitation/migrations/0002_invitationstage_continue_flow_without_invitation.py create mode 100644 passbook/stages/password/migrations/0002_remove_passwordstage_password_policies.py diff --git a/passbook/admin/forms/inlet.py b/passbook/admin/forms/inlet.py deleted file mode 100644 index 71e7f1cfe..000000000 --- a/passbook/admin/forms/inlet.py +++ /dev/null @@ -1,4 +0,0 @@ -"""passbook core inlet form fields""" - -INLET_FORM_FIELDS = ["name", "slug", "enabled"] -INLET_SERIALIZER_FIELDS = ["pk", "name", "slug", "enabled"] diff --git a/passbook/admin/forms/source.py b/passbook/admin/forms/source.py new file mode 100644 index 000000000..b18d7157a --- /dev/null +++ b/passbook/admin/forms/source.py @@ -0,0 +1,4 @@ +"""passbook core source form fields""" + +SOURCE_FORM_FIELDS = ["name", "slug", "enabled"] +SOURCE_SERIALIZER_FIELDS = ["pk", "name", "slug", "enabled"] diff --git a/passbook/admin/templates/administration/outlet/list.html b/passbook/admin/templates/administration/provider/list.html similarity index 100% rename from passbook/admin/templates/administration/outlet/list.html rename to passbook/admin/templates/administration/provider/list.html diff --git a/passbook/admin/templates/administration/inlet/list.html b/passbook/admin/templates/administration/source/list.html similarity index 100% rename from passbook/admin/templates/administration/inlet/list.html rename to passbook/admin/templates/administration/source/list.html diff --git a/passbook/admin/urls.py b/passbook/admin/urls.py index 889682789..0f3526713 100644 --- a/passbook/admin/urls.py +++ b/passbook/admin/urls.py @@ -8,12 +8,12 @@ from passbook.admin.views import ( debug, flows, groups, - inlets, invitations, - outlets, overview, - policies, + policy, property_mapping, + providers, + sources, stages, users, ) @@ -39,49 +39,51 @@ urlpatterns = [ applications.ApplicationDeleteView.as_view(), name="application-delete", ), - # Inlets - path("inlets/", inlets.InletListView.as_view(), name="inlets"), - path("inlets/create/", inlets.InletCreateView.as_view(), name="inlet-create"), + # Sources + path("sources/", sources.SourceListView.as_view(), name="sources"), + path("sources/create/", sources.SourceCreateView.as_view(), name="source-create"), path( - "inlets//update/", - inlets.InletUpdateView.as_view(), - name="inlet-update", + "sources//update/", + sources.SourceUpdateView.as_view(), + name="source-update", ), path( - "inlets//delete/", - inlets.InletDeleteView.as_view(), - name="inlet-delete", + "sources//delete/", + sources.SourceDeleteView.as_view(), + name="source-delete", ), # Policies - path("policies/", policies.PolicyListView.as_view(), name="policies"), - path("policies/create/", policies.PolicyCreateView.as_view(), name="policy-create"), + path("policies/", policy.PolicyListView.as_view(), name="policies"), + path("policies/create/", policy.PolicyCreateView.as_view(), name="policy-create"), path( "policies//update/", - policies.PolicyUpdateView.as_view(), + policy.PolicyUpdateView.as_view(), name="policy-update", ), path( "policies//delete/", - policies.PolicyDeleteView.as_view(), + policy.PolicyDeleteView.as_view(), name="policy-delete", ), path( - "policies//test/", - policies.PolicyTestView.as_view(), - name="policy-test", + "policies//test/", policy.PolicyTestView.as_view(), name="policy-test" ), - # Outlets - path("outlets/", outlets.OutletListView.as_view(), name="outlets"), - path("outlets/create/", outlets.OutletCreateView.as_view(), name="outlet-create",), + # Providers + path("providers/", providers.ProviderListView.as_view(), name="providers"), path( - "outlets//update/", - outlets.OutletUpdateView.as_view(), - name="outlet-update", + "providers/create/", + providers.ProviderCreateView.as_view(), + name="provider-create", ), path( - "outlets//delete/", - outlets.OutletDeleteView.as_view(), - name="outlet-delete", + "providers//update/", + providers.ProviderUpdateView.as_view(), + name="provider-update", + ), + path( + "providers//delete/", + providers.ProviderDeleteView.as_view(), + name="provider-delete", ), # Stages path("stages/", stages.StageListView.as_view(), name="stages"), diff --git a/passbook/admin/views/overview.py b/passbook/admin/views/overview.py index cb83aeb59..1b1b0a88b 100644 --- a/passbook/admin/views/overview.py +++ b/passbook/admin/views/overview.py @@ -5,9 +5,8 @@ from django.views.generic import TemplateView from passbook import __version__ from passbook.admin.mixins import AdminRequiredMixin -from passbook.core.models import Application, Inlet, Outlet, User +from passbook.core.models import Application, Policy, Provider, Source, User from passbook.flows.models import Flow, Stage -from passbook.policies.models import Policy from passbook.root.celery import CELERY_APP from passbook.stages.invitation.models import Invitation @@ -28,14 +27,16 @@ class AdministrationOverviewView(AdminRequiredMixin, TemplateView): kwargs["application_count"] = len(Application.objects.all()) kwargs["policy_count"] = len(Policy.objects.all()) kwargs["user_count"] = len(User.objects.all()) - kwargs["outlet_count"] = len(Outlet.objects.all()) - kwargs["inlet_count"] = len(Inlet.objects.all()) + kwargs["provider_count"] = len(Provider.objects.all()) + kwargs["source_count"] = len(Source.objects.all()) kwargs["stage_count"] = len(Stage.objects.all()) kwargs["flow_count"] = len(Flow.objects.all()) kwargs["invitation_count"] = len(Invitation.objects.all()) kwargs["version"] = __version__ kwargs["worker_count"] = len(CELERY_APP.control.ping(timeout=0.5)) - kwargs["outlets_without_application"] = Outlet.objects.filter(application=None) + kwargs["providers_without_application"] = Provider.objects.filter( + application=None + ) kwargs["policies_without_binding"] = len( Policy.objects.filter(policymodel__isnull=True) ) diff --git a/passbook/admin/views/policies.py b/passbook/admin/views/policy.py similarity index 99% rename from passbook/admin/views/policies.py rename to passbook/admin/views/policy.py index 5faa67c5f..7c65c1d5c 100644 --- a/passbook/admin/views/policies.py +++ b/passbook/admin/views/policy.py @@ -13,10 +13,10 @@ from django.views.generic.detail import DetailView from guardian.mixins import PermissionListMixin, PermissionRequiredMixin from passbook.admin.forms.policies import PolicyTestForm +from passbook.core.models import Policy from passbook.lib.utils.reflection import all_subclasses, path_to_class from passbook.lib.views import CreateAssignPermView from passbook.policies.engine import PolicyEngine -from passbook.policies.models import Policy class PolicyListView(LoginRequiredMixin, PermissionListMixin, ListView): diff --git a/passbook/admin/views/inlets.py b/passbook/admin/views/providers.py similarity index 56% rename from passbook/admin/views/inlets.py rename to passbook/admin/views/providers.py index 2a277d53e..f0a1d5892 100644 --- a/passbook/admin/views/inlets.py +++ b/passbook/admin/views/providers.py @@ -1,4 +1,4 @@ -"""passbook Inlet administration""" +"""passbook Provider administration""" from django.contrib import messages from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import ( @@ -11,23 +11,23 @@ from django.utils.translation import ugettext as _ from django.views.generic import DeleteView, ListView, UpdateView from guardian.mixins import PermissionListMixin, PermissionRequiredMixin -from passbook.core.models import Inlet +from passbook.core.models import Provider from passbook.lib.utils.reflection import all_subclasses, path_to_class from passbook.lib.views import CreateAssignPermView -class InletListView(LoginRequiredMixin, PermissionListMixin, ListView): - """Show list of all inlets""" +class ProviderListView(LoginRequiredMixin, PermissionListMixin, ListView): + """Show list of all providers""" - model = Inlet - permission_required = "passbook_core.view_inlet" - ordering = "name" - paginate_by = 40 - template_name = "administration/inlet/list.html" + model = Provider + permission_required = "passbook_core.add_provider" + template_name = "administration/provider/list.html" + paginate_by = 10 + ordering = "id" def get_context_data(self, **kwargs): kwargs["types"] = { - x.__name__: x._meta.verbose_name for x in all_subclasses(Inlet) + x.__name__: x._meta.verbose_name for x in all_subclasses(Provider) } return super().get_context_data(**kwargs) @@ -35,40 +35,40 @@ class InletListView(LoginRequiredMixin, PermissionListMixin, ListView): return super().get_queryset().select_subclasses() -class InletCreateView( +class ProviderCreateView( SuccessMessageMixin, LoginRequiredMixin, DjangoPermissionRequiredMixin, CreateAssignPermView, ): - """Create new Inlet""" + """Create new Provider""" - model = Inlet - permission_required = "passbook_core.add_inlet" + model = Provider + permission_required = "passbook_core.add_provider" template_name = "generic/create.html" - success_url = reverse_lazy("passbook_admin:inlets") - success_message = _("Successfully created Inlet") + success_url = reverse_lazy("passbook_admin:providers") + success_message = _("Successfully created Provider") def get_form_class(self): - inlet_type = self.request.GET.get("type") - model = next(x for x in all_subclasses(Inlet) if x.__name__ == inlet_type) + provider_type = self.request.GET.get("type") + model = next(x for x in all_subclasses(Provider) if x.__name__ == provider_type) if not model: raise Http404 return path_to_class(model.form) -class InletUpdateView( +class ProviderUpdateView( SuccessMessageMixin, LoginRequiredMixin, PermissionRequiredMixin, UpdateView ): - """Update inlet""" + """Update provider""" - model = Inlet - permission_required = "passbook_core.change_inlet" + model = Provider + permission_required = "passbook_core.change_provider" template_name = "generic/update.html" - success_url = reverse_lazy("passbook_admin:inlets") - success_message = _("Successfully updated Inlet") + success_url = reverse_lazy("passbook_admin:providers") + success_message = _("Successfully updated Provider") def get_form_class(self): form_class_path = self.get_object().form @@ -77,25 +77,29 @@ class InletUpdateView( def get_object(self, queryset=None): return ( - Inlet.objects.filter(pk=self.kwargs.get("pk")).select_subclasses().first() + Provider.objects.filter(pk=self.kwargs.get("pk")) + .select_subclasses() + .first() ) -class InletDeleteView( +class ProviderDeleteView( SuccessMessageMixin, LoginRequiredMixin, PermissionRequiredMixin, DeleteView ): - """Delete inlet""" + """Delete provider""" - model = Inlet - permission_required = "passbook_core.delete_inlet" + model = Provider + permission_required = "passbook_core.delete_provider" template_name = "generic/delete.html" - success_url = reverse_lazy("passbook_admin:inlets") - success_message = _("Successfully deleted Inlet") + success_url = reverse_lazy("passbook_admin:providers") + success_message = _("Successfully deleted Provider") def get_object(self, queryset=None): return ( - Inlet.objects.filter(pk=self.kwargs.get("pk")).select_subclasses().first() + Provider.objects.filter(pk=self.kwargs.get("pk")) + .select_subclasses() + .first() ) def delete(self, request, *args, **kwargs): diff --git a/passbook/admin/views/outlets.py b/passbook/admin/views/sources.py similarity index 59% rename from passbook/admin/views/outlets.py rename to passbook/admin/views/sources.py index ac77d5f30..b5d46af2f 100644 --- a/passbook/admin/views/outlets.py +++ b/passbook/admin/views/sources.py @@ -1,4 +1,4 @@ -"""passbook Outlet administration""" +"""passbook Source administration""" from django.contrib import messages from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import ( @@ -11,23 +11,23 @@ from django.utils.translation import ugettext as _ from django.views.generic import DeleteView, ListView, UpdateView from guardian.mixins import PermissionListMixin, PermissionRequiredMixin -from passbook.core.models import Outlet +from passbook.core.models import Source from passbook.lib.utils.reflection import all_subclasses, path_to_class from passbook.lib.views import CreateAssignPermView -class OutletListView(LoginRequiredMixin, PermissionListMixin, ListView): - """Show list of all outlets""" +class SourceListView(LoginRequiredMixin, PermissionListMixin, ListView): + """Show list of all sources""" - model = Outlet - permission_required = "passbook_core.add_outlet" - template_name = "administration/outlet/list.html" - paginate_by = 10 - ordering = "id" + model = Source + permission_required = "passbook_core.view_source" + ordering = "name" + paginate_by = 40 + template_name = "administration/source/list.html" def get_context_data(self, **kwargs): kwargs["types"] = { - x.__name__: x._meta.verbose_name for x in all_subclasses(Outlet) + x.__name__: x._meta.verbose_name for x in all_subclasses(Source) } return super().get_context_data(**kwargs) @@ -35,40 +35,40 @@ class OutletListView(LoginRequiredMixin, PermissionListMixin, ListView): return super().get_queryset().select_subclasses() -class OutletCreateView( +class SourceCreateView( SuccessMessageMixin, LoginRequiredMixin, DjangoPermissionRequiredMixin, CreateAssignPermView, ): - """Create new Outlet""" + """Create new Source""" - model = Outlet - permission_required = "passbook_core.add_outlet" + model = Source + permission_required = "passbook_core.add_source" template_name = "generic/create.html" - success_url = reverse_lazy("passbook_admin:outlets") - success_message = _("Successfully created Outlet") + success_url = reverse_lazy("passbook_admin:sources") + success_message = _("Successfully created Source") def get_form_class(self): - outlet_type = self.request.GET.get("type") - model = next(x for x in all_subclasses(Outlet) if x.__name__ == outlet_type) + source_type = self.request.GET.get("type") + model = next(x for x in all_subclasses(Source) if x.__name__ == source_type) if not model: raise Http404 return path_to_class(model.form) -class OutletUpdateView( +class SourceUpdateView( SuccessMessageMixin, LoginRequiredMixin, PermissionRequiredMixin, UpdateView ): - """Update outlet""" + """Update source""" - model = Outlet - permission_required = "passbook_core.change_outlet" + model = Source + permission_required = "passbook_core.change_source" template_name = "generic/update.html" - success_url = reverse_lazy("passbook_admin:outlets") - success_message = _("Successfully updated Outlet") + success_url = reverse_lazy("passbook_admin:sources") + success_message = _("Successfully updated Source") def get_form_class(self): form_class_path = self.get_object().form @@ -77,25 +77,25 @@ class OutletUpdateView( def get_object(self, queryset=None): return ( - Outlet.objects.filter(pk=self.kwargs.get("pk")).select_subclasses().first() + Source.objects.filter(pk=self.kwargs.get("pk")).select_subclasses().first() ) -class OutletDeleteView( +class SourceDeleteView( SuccessMessageMixin, LoginRequiredMixin, PermissionRequiredMixin, DeleteView ): - """Delete outlet""" + """Delete source""" - model = Outlet - permission_required = "passbook_core.delete_outlet" + model = Source + permission_required = "passbook_core.delete_source" template_name = "generic/delete.html" - success_url = reverse_lazy("passbook_admin:outlets") - success_message = _("Successfully deleted Outlet") + success_url = reverse_lazy("passbook_admin:sources") + success_message = _("Successfully deleted Source") def get_object(self, queryset=None): return ( - Outlet.objects.filter(pk=self.kwargs.get("pk")).select_subclasses().first() + Source.objects.filter(pk=self.kwargs.get("pk")).select_subclasses().first() ) def delete(self, request, *args, **kwargs): diff --git a/passbook/admin/views/users.py b/passbook/admin/views/users.py index 6acca6863..618bbf907 100644 --- a/passbook/admin/views/users.py +++ b/passbook/admin/views/users.py @@ -16,7 +16,7 @@ from guardian.mixins import ( ) from passbook.admin.forms.users import UserForm -from passbook.core.models import Token, User +from passbook.core.models import Nonce, User from passbook.lib.views import CreateAssignPermView @@ -92,12 +92,12 @@ class UserPasswordResetView(LoginRequiredMixin, PermissionRequiredMixin, DetailV permission_required = "passbook_core.reset_user_password" def get(self, request, *args, **kwargs): - """Create token for user and return link""" + """Create nonce for user and return link""" super().get(request, *args, **kwargs) # TODO: create plan for user, get token - token = Token.objects.create(user=self.object) + nonce = Nonce.objects.create(user=self.object) link = request.build_absolute_uri( - reverse("passbook_flows:default-recovery", kwargs={"token": token.uuid}) + reverse("passbook_flows:default-recovery", kwargs={"nonce": nonce.uuid}) ) messages.success( request, _("Password reset link:
%(link)s
" % {"link": link}) diff --git a/passbook/api/permissions.py b/passbook/api/permissions.py index 15fd85d30..90a7a02af 100644 --- a/passbook/api/permissions.py +++ b/passbook/api/permissions.py @@ -1,8 +1,8 @@ """permission classes for django restframework""" from rest_framework.permissions import BasePermission, DjangoObjectPermissions +from passbook.core.models import PolicyModel from passbook.policies.engine import PolicyEngine -from passbook.policies.models import PolicyBindingModel class CustomObjectPermissions(DjangoObjectPermissions): @@ -24,7 +24,8 @@ class PolicyPermissions(BasePermission): policy_engine: PolicyEngine - def has_object_permission(self, request, view, obj: PolicyBindingModel) -> bool: - self.policy_engine = PolicyEngine(obj.policies.all(), request.user, request) + def has_object_permission(self, request, view, obj: PolicyModel) -> bool: + # if not obj.po + self.policy_engine = PolicyEngine(obj.policies, request.user, request) self.policy_engine.request.obj = obj return self.policy_engine.build().passing diff --git a/passbook/api/v2/urls.py b/passbook/api/v2/urls.py index 53d598520..9e5c8604c 100644 --- a/passbook/api/v2/urls.py +++ b/passbook/api/v2/urls.py @@ -9,18 +9,12 @@ from structlog import get_logger from passbook.api.permissions import CustomObjectPermissions from passbook.audit.api import EventViewSet -from passbook.channels.in_ldap.api import LDAPInletViewSet, LDAPPropertyMappingViewSet -from passbook.channels.in_oauth.api import OAuthInletViewSet -from passbook.channels.out_app_gw.api import ApplicationGatewayOutletViewSet -from passbook.channels.out_oauth.api import OAuth2OutletViewSet -from passbook.channels.out_oidc.api import OpenIDOutletViewSet -from passbook.channels.out_saml.api import SAMLOutletViewSet, SAMLPropertyMappingViewSet from passbook.core.api.applications import ApplicationViewSet from passbook.core.api.groups import GroupViewSet -from passbook.core.api.inlets import InletViewSet -from passbook.core.api.outlets import OutletViewSet from passbook.core.api.policies import PolicyViewSet 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.flows.api import FlowStageBindingViewSet, FlowViewSet, StageViewSet from passbook.lib.utils.reflection import get_apps @@ -30,6 +24,12 @@ from passbook.policies.expression.api import ExpressionPolicyViewSet 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.saml.api import SAMLPropertyMappingViewSet, SAMLProviderViewSet +from passbook.sources.ldap.api import LDAPPropertyMappingViewSet, LDAPSourceViewSet +from passbook.sources.oauth.api import OAuthSourceViewSet from passbook.stages.captcha.api import CaptchaStageViewSet from passbook.stages.email.api import EmailStageViewSet from passbook.stages.identification.api import IdentificationStageViewSet @@ -57,15 +57,9 @@ router.register("core/users", UserViewSet) router.register("audit/events", EventViewSet) -router.register("inlets/all", InletViewSet) -router.register("inlets/ldap", LDAPInletViewSet) -router.register("inlets/oauth", OAuthInletViewSet) - -router.register("outlets/all", OutletViewSet) -router.register("outlets/applicationgateway", ApplicationGatewayOutletViewSet) -router.register("outlets/oauth", OAuth2OutletViewSet) -router.register("outlets/openid", OpenIDOutletViewSet) -router.register("outlets/saml", SAMLOutletViewSet) +router.register("sources/all", SourceViewSet) +router.register("sources/ldap", LDAPSourceViewSet) +router.register("sources/oauth", OAuthSourceViewSet) router.register("policies/all", PolicyViewSet) router.register("policies/bindings", PolicyBindingViewSet) @@ -75,6 +69,12 @@ router.register("policies/password", PasswordPolicyViewSet) router.register("policies/passwordexpiry", PasswordExpiryPolicyViewSet) 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/saml", SAMLProviderViewSet) + router.register("propertymappings/all", PropertyMappingViewSet) router.register("propertymappings/ldap", LDAPPropertyMappingViewSet) router.register("propertymappings/saml", SAMLPropertyMappingViewSet) diff --git a/passbook/audit/migrations/0001_initial.py b/passbook/audit/migrations/0001_initial.py index 63bb2fc56..77ade9f0c 100644 --- a/passbook/audit/migrations/0001_initial.py +++ b/passbook/audit/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 3.0.5 on 2020-05-15 19:58 +# Generated by Django 2.2.6 on 2019-10-07 14:07 import uuid @@ -18,7 +18,7 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - name="Event", + name="AuditEntry", fields=[ ( "uuid", @@ -33,16 +33,15 @@ class Migration(migrations.Migration): "action", models.TextField( choices=[ - ("LOGIN", "login"), - ("LOGIN_FAILED", "login_failed"), - ("LOGOUT", "logout"), - ("AUTHORIZE_APPLICATION", "authorize_application"), - ("SUSPICIOUS_REQUEST", "suspicious_request"), - ("SIGN_UP", "sign_up"), - ("PASSWORD_RESET", "password_reset"), - ("INVITE_CREATED", "invitation_created"), - ("INVITE_USED", "invitation_used"), - ("CUSTOM", "custom"), + ("login", "login"), + ("login_failed", "login_failed"), + ("logout", "logout"), + ("authorize_application", "authorize_application"), + ("suspicious_request", "suspicious_request"), + ("sign_up", "sign_up"), + ("password_reset", "password_reset"), + ("invitation_created", "invitation_created"), + ("invitation_used", "invitation_used"), ] ), ), @@ -54,7 +53,7 @@ class Migration(migrations.Migration): blank=True, default=dict ), ), - ("client_ip", models.GenericIPAddressField(null=True)), + ("request_ip", models.GenericIPAddressField()), ("created", models.DateTimeField(auto_now_add=True)), ( "user", @@ -66,8 +65,8 @@ class Migration(migrations.Migration): ), ], options={ - "verbose_name": "Audit Event", - "verbose_name_plural": "Audit Events", + "verbose_name": "Audit Entry", + "verbose_name_plural": "Audit Entries", }, ), ] diff --git a/passbook/audit/migrations/0002_auto_20191028_0829.py b/passbook/audit/migrations/0002_auto_20191028_0829.py new file mode 100644 index 000000000..9a582528c --- /dev/null +++ b/passbook/audit/migrations/0002_auto_20191028_0829.py @@ -0,0 +1,16 @@ +# Generated by Django 2.2.6 on 2019-10-28 08:29 + +from django.conf import settings +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("passbook_audit", "0001_initial"), + ] + + operations = [ + migrations.RenameModel(old_name="AuditEntry", new_name="Event",), + ] diff --git a/passbook/audit/migrations/0003_auto_20191205_1407.py b/passbook/audit/migrations/0003_auto_20191205_1407.py new file mode 100644 index 000000000..61c7a4e77 --- /dev/null +++ b/passbook/audit/migrations/0003_auto_20191205_1407.py @@ -0,0 +1,40 @@ +# Generated by Django 2.2.8 on 2019-12-05 14:07 + +from django.db import migrations, models + +import passbook.audit.models + + +class Migration(migrations.Migration): + + dependencies = [ + ("passbook_audit", "0002_auto_20191028_0829"), + ] + + operations = [ + migrations.AlterModelOptions( + name="event", + options={ + "verbose_name": "Audit Event", + "verbose_name_plural": "Audit Events", + }, + ), + migrations.AlterField( + model_name="event", + name="action", + field=models.TextField( + choices=[ + ("LOGIN", "login"), + ("LOGIN_FAILED", "login_failed"), + ("LOGOUT", "logout"), + ("AUTHORIZE_APPLICATION", "authorize_application"), + ("SUSPICIOUS_REQUEST", "suspicious_request"), + ("SIGN_UP", "sign_up"), + ("PASSWORD_RESET", "password_reset"), + ("INVITE_CREATED", "invitation_created"), + ("INVITE_USED", "invitation_used"), + ("CUSTOM", "custom"), + ] + ), + ), + ] diff --git a/passbook/audit/migrations/0004_auto_20191205_1502.py b/passbook/audit/migrations/0004_auto_20191205_1502.py new file mode 100644 index 000000000..bd45599eb --- /dev/null +++ b/passbook/audit/migrations/0004_auto_20191205_1502.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.8 on 2019-12-05 15:02 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("passbook_audit", "0003_auto_20191205_1407"), + ] + + operations = [ + migrations.RemoveField(model_name="event", name="request_ip",), + migrations.AddField( + model_name="event", + name="client_ip", + field=models.GenericIPAddressField(null=True), + ), + ] diff --git a/passbook/audit/tests/test_event.py b/passbook/audit/tests/test_event.py index 9d7e189f5..5e32b2d09 100644 --- a/passbook/audit/tests/test_event.py +++ b/passbook/audit/tests/test_event.py @@ -5,7 +5,7 @@ from django.test import TestCase from guardian.shortcuts import get_anonymous_user from passbook.audit.models import Event, EventAction -from passbook.policies.models import Policy +from passbook.core.models import Policy class TestAuditEvent(TestCase): diff --git a/passbook/channels/in_ldap/apps.py b/passbook/channels/in_ldap/apps.py deleted file mode 100644 index d49b75197..000000000 --- a/passbook/channels/in_ldap/apps.py +++ /dev/null @@ -1,11 +0,0 @@ -"""Passbook ldap app config""" - -from django.apps import AppConfig - - -class PassbookInletLDAPConfig(AppConfig): - """Passbook ldap app config""" - - name = "passbook.channels.in_ldap" - label = "passbook_channels_in_ldap" - verbose_name = "passbook Inlets.LDAP" diff --git a/passbook/channels/in_ldap/tasks.py b/passbook/channels/in_ldap/tasks.py deleted file mode 100644 index c22889113..000000000 --- a/passbook/channels/in_ldap/tasks.py +++ /dev/null @@ -1,33 +0,0 @@ -"""LDAP Sync tasks""" -from passbook.channels.in_ldap.connector import Connector -from passbook.channels.in_ldap.models import LDAPInlet -from passbook.root.celery import CELERY_APP - - -@CELERY_APP.task() -def sync_groups(inlet_pk: int): - """Sync LDAP Groups on background worker""" - inlet = LDAPInlet.objects.get(pk=inlet_pk) - connector = Connector(inlet) - connector.bind() - connector.sync_groups() - - -@CELERY_APP.task() -def sync_users(inlet_pk: int): - """Sync LDAP Users on background worker""" - inlet = LDAPInlet.objects.get(pk=inlet_pk) - connector = Connector(inlet) - connector.bind() - connector.sync_users() - - -@CELERY_APP.task() -def sync(): - """Sync all inlets""" - for inlet in LDAPInlet.objects.filter(enabled=True): - connector = Connector(inlet) - connector.bind() - connector.sync_users() - connector.sync_groups() - connector.sync_membership() diff --git a/passbook/channels/in_oauth/api.py b/passbook/channels/in_oauth/api.py deleted file mode 100644 index b4c5a6360..000000000 --- a/passbook/channels/in_oauth/api.py +++ /dev/null @@ -1,29 +0,0 @@ -"""OAuth Inlet Serializer""" -from rest_framework.serializers import ModelSerializer -from rest_framework.viewsets import ModelViewSet - -from passbook.admin.forms.inlet import INLET_SERIALIZER_FIELDS -from passbook.channels.in_oauth.models import OAuthInlet - - -class OAuthInletSerializer(ModelSerializer): - """OAuth Inlet Serializer""" - - class Meta: - model = OAuthInlet - fields = INLET_SERIALIZER_FIELDS + [ - "inlet_type", - "request_token_url", - "authorization_url", - "access_token_url", - "profile_url", - "consumer_key", - "consumer_secret", - ] - - -class OAuthInletViewSet(ModelViewSet): - """Inlet Viewset""" - - queryset = OAuthInlet.objects.all() - serializer_class = OAuthInletSerializer diff --git a/passbook/channels/in_oauth/backends.py b/passbook/channels/in_oauth/backends.py deleted file mode 100644 index 6a93b9865..000000000 --- a/passbook/channels/in_oauth/backends.py +++ /dev/null @@ -1,24 +0,0 @@ -"""passbook oauth_client Authorization backend""" - -from django.contrib.auth.backends import ModelBackend -from django.db.models import Q - -from passbook.channels.in_oauth.models import OAuthInlet, UserOAuthInletConnection - - -class AuthorizedServiceBackend(ModelBackend): - "Authentication backend for users registered with remote OAuth provider." - - def authenticate(self, request, inlet=None, identifier=None): - "Fetch user for a given inlet by id." - inlet_q = Q(inlet__name=inlet) - if isinstance(inlet, OAuthInlet): - inlet_q = Q(inlet=inlet) - try: - access = UserOAuthInletConnection.objects.filter( - inlet_q, identifier=identifier - ).select_related("user")[0] - except IndexError: - return None - else: - return access.user diff --git a/passbook/channels/in_oauth/migrations/0001_initial.py b/passbook/channels/in_oauth/migrations/0001_initial.py deleted file mode 100644 index dbe8b5f24..000000000 --- a/passbook/channels/in_oauth/migrations/0001_initial.py +++ /dev/null @@ -1,81 +0,0 @@ -# Generated by Django 3.0.5 on 2020-05-15 19:59 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ("passbook_core", "__first__"), - ] - - operations = [ - migrations.CreateModel( - name="OAuthInlet", - fields=[ - ( - "inlet_ptr", - models.OneToOneField( - auto_created=True, - on_delete=django.db.models.deletion.CASCADE, - parent_link=True, - primary_key=True, - serialize=False, - to="passbook_core.Inlet", - ), - ), - ("inlet_type", models.CharField(max_length=255)), - ( - "request_token_url", - models.CharField( - blank=True, max_length=255, verbose_name="Request Token URL" - ), - ), - ( - "authorization_url", - models.CharField(max_length=255, verbose_name="Authorization URL"), - ), - ( - "access_token_url", - models.CharField(max_length=255, verbose_name="Access Token URL"), - ), - ( - "profile_url", - models.CharField(max_length=255, verbose_name="Profile URL"), - ), - ("consumer_key", models.TextField()), - ("consumer_secret", models.TextField()), - ], - options={ - "verbose_name": "Generic OAuth Inlet", - "verbose_name_plural": "Generic OAuth Inlets", - }, - bases=("passbook_core.inlet",), - ), - migrations.CreateModel( - name="UserOAuthInletConnection", - fields=[ - ( - "userinletconnection_ptr", - models.OneToOneField( - auto_created=True, - on_delete=django.db.models.deletion.CASCADE, - parent_link=True, - primary_key=True, - serialize=False, - to="passbook_core.UserInletConnection", - ), - ), - ("identifier", models.CharField(max_length=255)), - ("access_token", models.TextField(blank=True, default=None, null=True)), - ], - options={ - "verbose_name": "User OAuth Inlet Connection", - "verbose_name_plural": "User OAuth Inlet Connections", - }, - bases=("passbook_core.userinletconnection",), - ), - ] diff --git a/passbook/channels/in_oauth/models.py b/passbook/channels/in_oauth/models.py deleted file mode 100644 index e17ec653f..000000000 --- a/passbook/channels/in_oauth/models.py +++ /dev/null @@ -1,159 +0,0 @@ -"""OAuth Client models""" - -from django.db import models -from django.urls import reverse, reverse_lazy -from django.utils.translation import gettext_lazy as _ - -from passbook.channels.in_oauth.clients import get_client -from passbook.core.models import Inlet, UserInletConnection -from passbook.core.types import UILoginButton, UIUserSettings - - -class OAuthInlet(Inlet): - """Configuration for OAuth inlet.""" - - inlet_type = models.CharField(max_length=255) - request_token_url = models.CharField( - blank=True, max_length=255, verbose_name=_("Request Token URL") - ) - authorization_url = models.CharField( - max_length=255, verbose_name=_("Authorization URL") - ) - access_token_url = models.CharField( - max_length=255, verbose_name=_("Access Token URL") - ) - profile_url = models.CharField(max_length=255, verbose_name=_("Profile URL")) - consumer_key = models.TextField() - consumer_secret = models.TextField() - - form = "passbook.channels.in_oauth.forms.OAuthInletForm" - - @property - def ui_login_button(self) -> UILoginButton: - return UILoginButton( - url=reverse_lazy( - "passbook_channels_in_oauth:oauth-client-login", - kwargs={"inlet_slug": self.slug}, - ), - icon_path=f"passbook/inlets/{self.inlet_type}.svg", - name=self.name, - ) - - @property - def ui_additional_info(self) -> str: - url = reverse_lazy( - "passbook_channels_in_oauth:oauth-client-callback", - kwargs={"inlet_slug": self.slug}, - ) - return f"Callback URL:
{url}
" - - @property - def ui_user_settings(self) -> UIUserSettings: - icon_type = self.inlet_type - if icon_type == "azure ad": - icon_type = "windows" - icon_class = f"fab fa-{icon_type}" - view_name = "passbook_channels_in_oauth:oauth-client-user" - return UIUserSettings( - name=self.name, - icon=icon_class, - view_name=reverse((view_name), kwargs={"inlet_slug": self.slug}), - ) - - class Meta: - - verbose_name = _("Generic OAuth Inlet") - verbose_name_plural = _("Generic OAuth Inlets") - - -class GitHubOAuthInlet(OAuthInlet): - """Abstract subclass of OAuthInlet to specify GitHub Form""" - - form = "passbook.channels.in_oauth.forms.GitHubOAuthInletForm" - - class Meta: - - abstract = True - verbose_name = _("GitHub OAuth Inlet") - verbose_name_plural = _("GitHub OAuth Inlets") - - -class TwitterOAuthInlet(OAuthInlet): - """Abstract subclass of OAuthInlet to specify Twitter Form""" - - form = "passbook.channels.in_oauth.forms.TwitterOAuthInletForm" - - class Meta: - - abstract = True - verbose_name = _("Twitter OAuth Inlet") - verbose_name_plural = _("Twitter OAuth Inlets") - - -class FacebookOAuthInlet(OAuthInlet): - """Abstract subclass of OAuthInlet to specify Facebook Form""" - - form = "passbook.channels.in_oauth.forms.FacebookOAuthInletForm" - - class Meta: - - abstract = True - verbose_name = _("Facebook OAuth Inlet") - verbose_name_plural = _("Facebook OAuth Inlets") - - -class DiscordOAuthInlet(OAuthInlet): - """Abstract subclass of OAuthInlet to specify Discord Form""" - - form = "passbook.channels.in_oauth.forms.DiscordOAuthInletForm" - - class Meta: - - abstract = True - verbose_name = _("Discord OAuth Inlet") - verbose_name_plural = _("Discord OAuth Inlets") - - -class GoogleOAuthInlet(OAuthInlet): - """Abstract subclass of OAuthInlet to specify Google Form""" - - form = "passbook.channels.in_oauth.forms.GoogleOAuthInletForm" - - class Meta: - - abstract = True - verbose_name = _("Google OAuth Inlet") - verbose_name_plural = _("Google OAuth Inlets") - - -class AzureADOAuthInlet(OAuthInlet): - """Abstract subclass of OAuthInlet to specify AzureAD Form""" - - form = "passbook.channels.in_oauth.forms.AzureADOAuthInletForm" - - class Meta: - - abstract = True - verbose_name = _("Azure AD OAuth Inlet") - verbose_name_plural = _("Azure AD OAuth Inlets") - - -class UserOAuthInletConnection(UserInletConnection): - """Authorized remote OAuth inlet.""" - - identifier = models.CharField(max_length=255) - access_token = models.TextField(blank=True, null=True, default=None) - - def save(self, *args, **kwargs): - self.access_token = self.access_token or None - super().save(*args, **kwargs) - - @property - def api_client(self): - """Get API Client""" - return get_client(self.inlet, self.access_token or "") - - class Meta: - - verbose_name = _("User OAuth Inlet Connection") - verbose_name_plural = _("User OAuth Inlet Connections") diff --git a/passbook/channels/in_oauth/settings.py b/passbook/channels/in_oauth/settings.py deleted file mode 100644 index 619d2f89e..000000000 --- a/passbook/channels/in_oauth/settings.py +++ /dev/null @@ -1,15 +0,0 @@ -"""Oauth2 Client Settings""" - -AUTHENTICATION_BACKENDS = [ - "passbook.channels.in_oauth.backends.AuthorizedServiceBackend", -] - -PASSBOOK_SOURCES_OAUTH_TYPES = [ - "passbook.channels.in_oauth.types.discord", - "passbook.channels.in_oauth.types.facebook", - "passbook.channels.in_oauth.types.github", - "passbook.channels.in_oauth.types.google", - "passbook.channels.in_oauth.types.reddit", - "passbook.channels.in_oauth.types.twitter", - "passbook.channels.in_oauth.types.azure_ad", -] diff --git a/passbook/channels/in_saml/api.py b/passbook/channels/in_saml/api.py deleted file mode 100644 index 2bc4286e4..000000000 --- a/passbook/channels/in_saml/api.py +++ /dev/null @@ -1,28 +0,0 @@ -"""SAMLInlet API Views""" -from rest_framework.serializers import ModelSerializer -from rest_framework.viewsets import ModelViewSet - -from passbook.channels.in_saml.models import SAMLInlet - - -class SAMLInletSerializer(ModelSerializer): - """SAMLInlet Serializer""" - - class Meta: - - model = SAMLInlet - fields = [ - "pk", - "issuer", - "idp_url", - "idp_logout_url", - "auto_logout", - "signing_kp", - ] - - -class SAMLInletViewSet(ModelViewSet): - """SAMLInlet Viewset""" - - queryset = SAMLInlet.objects.all() - serializer_class = SAMLInletSerializer diff --git a/passbook/channels/in_saml/apps.py b/passbook/channels/in_saml/apps.py deleted file mode 100644 index b895d9225..000000000 --- a/passbook/channels/in_saml/apps.py +++ /dev/null @@ -1,12 +0,0 @@ -"""Passbook SAML app config""" - -from django.apps import AppConfig - - -class PassbookInletSAMLConfig(AppConfig): - """passbook saml_idp app config""" - - name = "passbook.channels.in_saml" - label = "passbook_channels_in_saml" - verbose_name = "passbook Inlets.SAML" - mountpoint = "source/saml/" diff --git a/passbook/channels/in_saml/migrations/0001_initial.py b/passbook/channels/in_saml/migrations/0001_initial.py deleted file mode 100644 index a1ead667a..000000000 --- a/passbook/channels/in_saml/migrations/0001_initial.py +++ /dev/null @@ -1,68 +0,0 @@ -# Generated by Django 3.0.5 on 2020-05-15 19:59 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ("passbook_crypto", "0001_initial"), - ("passbook_core", "__first__"), - ] - - operations = [ - migrations.CreateModel( - name="SAMLInlet", - fields=[ - ( - "inlet_ptr", - models.OneToOneField( - auto_created=True, - on_delete=django.db.models.deletion.CASCADE, - parent_link=True, - primary_key=True, - serialize=False, - to="passbook_core.Inlet", - ), - ), - ( - "issuer", - models.TextField( - blank=True, - default=None, - help_text="Also known as Entity ID. Defaults the Metadata URL.", - verbose_name="Issuer", - ), - ), - ("idp_url", models.URLField(verbose_name="IDP URL")), - ( - "idp_logout_url", - models.URLField( - blank=True, - default=None, - null=True, - verbose_name="IDP Logout URL", - ), - ), - ("auto_logout", models.BooleanField(default=False)), - ( - "signing_kp", - models.ForeignKey( - default=None, - help_text="Certificate Key Pair of the IdP which Assertions are validated against.", - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to="passbook_crypto.CertificateKeyPair", - ), - ), - ], - options={ - "verbose_name": "SAML Inlet", - "verbose_name_plural": "SAML Inlets", - }, - bases=("passbook_core.inlet",), - ), - ] diff --git a/passbook/channels/in_saml/utils.py b/passbook/channels/in_saml/utils.py deleted file mode 100644 index 1c2fb7eeb..000000000 --- a/passbook/channels/in_saml/utils.py +++ /dev/null @@ -1,20 +0,0 @@ -"""saml sp helpers""" -from django.http import HttpRequest -from django.shortcuts import reverse - -from passbook.channels.in_saml.models import SAMLInlet - - -def get_issuer(request: HttpRequest, inlet: SAMLInlet) -> str: - """Get Inlet's Issuer, falling back to our Metadata URL if none is set""" - issuer = inlet.issuer - if issuer is None: - return build_full_url("metadata", request, inlet) - return issuer - - -def build_full_url(view: str, request: HttpRequest, inlet: SAMLInlet) -> str: - """Build Full ACS URL to be used in IDP""" - return request.build_absolute_uri( - reverse(f"passbook_channels_in_saml:{view}", kwargs={"inlet_slug": inlet.slug}) - ) diff --git a/passbook/channels/out_oauth/api.py b/passbook/channels/out_oauth/api.py deleted file mode 100644 index eea6db83b..000000000 --- a/passbook/channels/out_oauth/api.py +++ /dev/null @@ -1,29 +0,0 @@ -"""OAuth2Outlet API Views""" -from rest_framework.serializers import ModelSerializer -from rest_framework.viewsets import ModelViewSet - -from passbook.channels.out_oauth.models import OAuth2Outlet - - -class OAuth2OutletSerializer(ModelSerializer): - """OAuth2Outlet Serializer""" - - class Meta: - - model = OAuth2Outlet - fields = [ - "pk", - "name", - "redirect_uris", - "client_type", - "authorization_grant_type", - "client_id", - "client_secret", - ] - - -class OAuth2OutletViewSet(ModelViewSet): - """OAuth2Outlet Viewset""" - - queryset = OAuth2Outlet.objects.all() - serializer_class = OAuth2OutletSerializer diff --git a/passbook/channels/out_oauth/apps.py b/passbook/channels/out_oauth/apps.py deleted file mode 100644 index 4b219acd8..000000000 --- a/passbook/channels/out_oauth/apps.py +++ /dev/null @@ -1,12 +0,0 @@ -"""passbook auth oauth provider app config""" - -from django.apps import AppConfig - - -class PassbookOutletOAuthConfig(AppConfig): - """passbook auth oauth provider app config""" - - name = "passbook.channels.out_oauth" - label = "passbook_channels_out_oauth" - verbose_name = "passbook Outlets.OAuth" - mountpoint = "" diff --git a/passbook/channels/out_oidc/settings.py b/passbook/channels/out_oidc/settings.py deleted file mode 100644 index 2a62fe540..000000000 --- a/passbook/channels/out_oidc/settings.py +++ /dev/null @@ -1,9 +0,0 @@ -"""passbook OIDC Provider""" - -INSTALLED_APPS = [ - "oidc_provider", -] - -OIDC_AFTER_USERLOGIN_HOOK = "passbook.channels.out_oidc.auth.check_permissions" -OIDC_IDTOKEN_INCLUDE_CLAIMS = True -OIDC_USERINFO = "passbook.channels.out_oidc.claims.userinfo" diff --git a/passbook/channels/out_saml/migrations/0001_initial.py b/passbook/channels/out_saml/migrations/0001_initial.py deleted file mode 100644 index 9043853b9..000000000 --- a/passbook/channels/out_saml/migrations/0001_initial.py +++ /dev/null @@ -1,140 +0,0 @@ -# Generated by Django 3.0.5 on 2020-05-15 19:59 - -import django.db.models.deletion -from django.db import migrations, models - -import passbook.channels.out_saml.utils.time - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ("passbook_core", "__first__"), - ("passbook_crypto", "0001_initial"), - ] - - operations = [ - migrations.CreateModel( - name="SAMLPropertyMapping", - fields=[ - ( - "propertymapping_ptr", - models.OneToOneField( - auto_created=True, - on_delete=django.db.models.deletion.CASCADE, - parent_link=True, - primary_key=True, - serialize=False, - to="passbook_core.PropertyMapping", - ), - ), - ("saml_name", models.TextField(verbose_name="SAML Name")), - ( - "friendly_name", - models.TextField(blank=True, default=None, null=True), - ), - ], - options={ - "verbose_name": "SAML Property Mapping", - "verbose_name_plural": "SAML Property Mappings", - }, - bases=("passbook_core.propertymapping",), - ), - migrations.CreateModel( - name="SAMLOutlet", - fields=[ - ( - "outlet_ptr", - models.OneToOneField( - auto_created=True, - on_delete=django.db.models.deletion.CASCADE, - parent_link=True, - primary_key=True, - serialize=False, - to="passbook_core.Outlet", - ), - ), - ("name", models.TextField()), - ("processor_path", models.CharField(choices=[], max_length=255)), - ("acs_url", models.URLField(verbose_name="ACS URL")), - ("audience", models.TextField(default="")), - ("issuer", models.TextField(help_text="Also known as EntityID")), - ( - "assertion_valid_not_before", - models.TextField( - default="minutes=-5", - help_text="Assertion valid not before current time + this value (Format: hours=-1;minutes=-2;seconds=-3).", - validators=[ - passbook.channels.out_saml.utils.time.timedelta_string_validator - ], - ), - ), - ( - "assertion_valid_not_on_or_after", - models.TextField( - default="minutes=5", - help_text="Assertion not valid on or after current time + this value (Format: hours=1;minutes=2;seconds=3).", - validators=[ - passbook.channels.out_saml.utils.time.timedelta_string_validator - ], - ), - ), - ( - "session_valid_not_on_or_after", - models.TextField( - default="minutes=86400", - help_text="Session not valid on or after current time + this value (Format: hours=1;minutes=2;seconds=3).", - validators=[ - passbook.channels.out_saml.utils.time.timedelta_string_validator - ], - ), - ), - ( - "digest_algorithm", - models.CharField( - choices=[("sha1", "SHA1"), ("sha256", "SHA256")], - default="sha256", - max_length=50, - ), - ), - ( - "signature_algorithm", - models.CharField( - choices=[ - ("rsa-sha1", "RSA-SHA1"), - ("rsa-sha256", "RSA-SHA256"), - ("ecdsa-sha256", "ECDSA-SHA256"), - ("dsa-sha1", "DSA-SHA1"), - ], - default="rsa-sha256", - max_length=50, - ), - ), - ( - "require_signing", - models.BooleanField( - default=False, - help_text="Require Requests to be signed by an X509 Certificate. Must match the Certificate selected in `Singing Keypair`.", - ), - ), - ( - "signing_kp", - models.ForeignKey( - default=None, - help_text="Singing is enabled upon selection of a Key Pair.", - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to="passbook_crypto.CertificateKeyPair", - verbose_name="Signing Keypair", - ), - ), - ], - options={ - "verbose_name": "SAML Outlet", - "verbose_name_plural": "SAML Outlets", - }, - bases=("passbook_core.outlet",), - ), - ] diff --git a/passbook/channels/out_saml/settings.py b/passbook/channels/out_saml/settings.py deleted file mode 100644 index e9253383a..000000000 --- a/passbook/channels/out_saml/settings.py +++ /dev/null @@ -1,6 +0,0 @@ -"""saml provider settings""" - -PASSBOOK_PROVIDERS_SAML_PROCESSORS = [ - "passbook.channels.out_saml.processors.generic", - "passbook.channels.out_saml.processors.salesforce", -] diff --git a/passbook/channels/out_samlv2/apps.py b/passbook/channels/out_samlv2/apps.py deleted file mode 100644 index d973d5c93..000000000 --- a/passbook/channels/out_samlv2/apps.py +++ /dev/null @@ -1,11 +0,0 @@ -"""passbook saml provider app config""" -from django.apps import AppConfig - - -class PassbookOutletSAMLv2Config(AppConfig): - """passbook samlv2 provider app config""" - - name = "passbook.channels.out_samlv2" - label = "passbook_channels_out_samlv2" - verbose_name = "passbook Outlets.SAMLv2" - mountpoint = "application/samlv2/" diff --git a/passbook/core/api/applications.py b/passbook/core/api/applications.py index fecf5fc78..f0b4c69e2 100644 --- a/passbook/core/api/applications.py +++ b/passbook/core/api/applications.py @@ -16,7 +16,7 @@ class ApplicationSerializer(ModelSerializer): "name", "slug", "skip_authorization", - "outlet", + "provider", "meta_launch_url", "meta_icon_url", "meta_description", diff --git a/passbook/core/api/inlets.py b/passbook/core/api/inlets.py deleted file mode 100644 index 09880d5f9..000000000 --- a/passbook/core/api/inlets.py +++ /dev/null @@ -1,31 +0,0 @@ -"""Inlet API Views""" -from rest_framework.serializers import ModelSerializer, SerializerMethodField -from rest_framework.viewsets import ReadOnlyModelViewSet - -from passbook.admin.forms.inlet import INLET_SERIALIZER_FIELDS -from passbook.core.models import Inlet - - -class InletSerializer(ModelSerializer): - """Inlet Serializer""" - - __type__ = SerializerMethodField(method_name="get_type") - - def get_type(self, obj): - """Get object type so that we know which API Endpoint to use to get the full object""" - return obj._meta.object_name.lower().replace("inlet", "") - - class Meta: - - model = Inlet - fields = INLET_SERIALIZER_FIELDS + ["__type__"] - - -class InletViewSet(ReadOnlyModelViewSet): - """Inlet Viewset""" - - queryset = Inlet.objects.all() - serializer_class = InletSerializer - - def get_queryset(self): - return Inlet.objects.select_subclasses() diff --git a/passbook/core/api/outlets.py b/passbook/core/api/outlets.py deleted file mode 100644 index 6521005e7..000000000 --- a/passbook/core/api/outlets.py +++ /dev/null @@ -1,30 +0,0 @@ -"""Outlet API Views""" -from rest_framework.serializers import ModelSerializer, SerializerMethodField -from rest_framework.viewsets import ReadOnlyModelViewSet - -from passbook.core.models import Outlet - - -class OutletSerializer(ModelSerializer): - """Outlet Serializer""" - - __type__ = SerializerMethodField(method_name="get_type") - - def get_type(self, obj): - """Get object type so that we know which API Endpoint to use to get the full object""" - return obj._meta.object_name.lower().replace("outlet", "") - - class Meta: - - model = Outlet - fields = ["pk", "property_mappings", "__type__"] - - -class OutletViewSet(ReadOnlyModelViewSet): - """Outlet Viewset""" - - queryset = Outlet.objects.all() - serializer_class = OutletSerializer - - def get_queryset(self): - return Outlet.objects.select_subclasses() diff --git a/passbook/core/api/policies.py b/passbook/core/api/policies.py index 13d6d7ad9..bf154d063 100644 --- a/passbook/core/api/policies.py +++ b/passbook/core/api/policies.py @@ -2,8 +2,8 @@ from rest_framework.serializers import ModelSerializer, SerializerMethodField from rest_framework.viewsets import ReadOnlyModelViewSet +from passbook.core.models import Policy from passbook.policies.forms import GENERAL_FIELDS -from passbook.policies.models import Policy class PolicySerializer(ModelSerializer): diff --git a/passbook/core/api/providers.py b/passbook/core/api/providers.py new file mode 100644 index 000000000..2b54a5807 --- /dev/null +++ b/passbook/core/api/providers.py @@ -0,0 +1,30 @@ +"""Provider API Views""" +from rest_framework.serializers import ModelSerializer, SerializerMethodField +from rest_framework.viewsets import ReadOnlyModelViewSet + +from passbook.core.models import Provider + + +class ProviderSerializer(ModelSerializer): + """Provider Serializer""" + + __type__ = SerializerMethodField(method_name="get_type") + + def get_type(self, obj): + """Get object type so that we know which API Endpoint to use to get the full object""" + return obj._meta.object_name.lower().replace("provider", "") + + class Meta: + + model = Provider + fields = ["pk", "property_mappings", "__type__"] + + +class ProviderViewSet(ReadOnlyModelViewSet): + """Provider Viewset""" + + queryset = Provider.objects.all() + serializer_class = ProviderSerializer + + def get_queryset(self): + return Provider.objects.select_subclasses() diff --git a/passbook/core/api/sources.py b/passbook/core/api/sources.py new file mode 100644 index 000000000..0cc49212b --- /dev/null +++ b/passbook/core/api/sources.py @@ -0,0 +1,31 @@ +"""Source API Views""" +from rest_framework.serializers import ModelSerializer, SerializerMethodField +from rest_framework.viewsets import ReadOnlyModelViewSet + +from passbook.admin.forms.source import SOURCE_SERIALIZER_FIELDS +from passbook.core.models import Source + + +class SourceSerializer(ModelSerializer): + """Source Serializer""" + + __type__ = SerializerMethodField(method_name="get_type") + + def get_type(self, obj): + """Get object type so that we know which API Endpoint to use to get the full object""" + return obj._meta.object_name.lower().replace("source", "") + + class Meta: + + model = Source + fields = SOURCE_SERIALIZER_FIELDS + ["__type__"] + + +class SourceViewSet(ReadOnlyModelViewSet): + """Source Viewset""" + + queryset = Source.objects.all() + serializer_class = SourceSerializer + + def get_queryset(self): + return Source.objects.select_subclasses() diff --git a/passbook/core/forms/applications.py b/passbook/core/forms/applications.py index 0a3cb4f98..71df296e1 100644 --- a/passbook/core/forms/applications.py +++ b/passbook/core/forms/applications.py @@ -3,14 +3,14 @@ from django import forms from django.contrib.admin.widgets import FilteredSelectMultiple from django.utils.translation import gettext_lazy as _ -from passbook.core.models import Application, Outlet +from passbook.core.models import Application, Provider class ApplicationForm(forms.ModelForm): """Application Form""" - outlet = forms.ModelChoiceField( - queryset=Outlet.objects.all().order_by("pk").select_subclasses(), + provider = forms.ModelChoiceField( + queryset=Provider.objects.all().order_by("pk").select_subclasses(), required=False, ) @@ -21,7 +21,7 @@ class ApplicationForm(forms.ModelForm): "name", "slug", "skip_authorization", - "outlet", + "provider", "meta_launch_url", "meta_icon_url", "meta_description", diff --git a/passbook/core/migrations/0001_initial.py b/passbook/core/migrations/0001_initial.py index 7d9439b1b..332c900cf 100644 --- a/passbook/core/migrations/0001_initial.py +++ b/passbook/core/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 3.0.5 on 2020-05-15 19:59 +# Generated by Django 2.2.6 on 2019-10-07 14:06 import uuid @@ -7,7 +7,6 @@ import django.contrib.auth.validators import django.contrib.postgres.fields.jsonb import django.db.models.deletion import django.utils.timezone -import guardian.mixins from django.conf import settings from django.db import migrations, models @@ -20,7 +19,6 @@ class Migration(migrations.Migration): dependencies = [ ("auth", "0011_update_proxy_permissions"), - ("passbook_policies", "0001_initial"), ] operations = [ @@ -107,41 +105,63 @@ class Migration(migrations.Migration): ), ), ("uuid", models.UUIDField(default=uuid.uuid4, editable=False)), - ("name", models.TextField(help_text="User's display name.")), + ("name", models.TextField()), ("password_change_date", models.DateTimeField(auto_now_add=True)), - ( - "attributes", - django.contrib.postgres.fields.jsonb.JSONField( - blank=True, default=dict - ), - ), ], - options={"permissions": (("reset_user_password", "Reset Password"),),}, - bases=(guardian.mixins.GuardianUserMixin, models.Model), + options={ + "verbose_name": "user", + "verbose_name_plural": "users", + "abstract": False, + }, managers=[("objects", django.contrib.auth.models.UserManager()),], ), migrations.CreateModel( - name="Inlet", + name="Policy", fields=[ + ("created", models.DateTimeField(auto_now_add=True)), + ("last_updated", models.DateTimeField(auto_now=True)), ( - "policybindingmodel_ptr", - models.OneToOneField( - auto_created=True, - on_delete=django.db.models.deletion.CASCADE, - parent_link=True, + "uuid", + models.UUIDField( + default=uuid.uuid4, + editable=False, primary_key=True, serialize=False, - to="passbook_policies.PolicyBindingModel", ), ), - ("name", models.TextField(help_text="Inlet's display Name.")), + ("name", models.TextField(blank=True, null=True)), ( - "slug", - models.SlugField(help_text="Internal source name, used in URLs."), + "action", + models.CharField( + choices=[("allow", "allow"), ("deny", "deny")], max_length=20 + ), ), - ("enabled", models.BooleanField(default=True)), + ("negate", models.BooleanField(default=False)), + ("order", models.IntegerField(default=0)), + ("timeout", models.IntegerField(default=30)), ], - bases=("passbook_policies.policybindingmodel",), + options={"abstract": False,}, + ), + migrations.CreateModel( + name="PolicyModel", + fields=[ + ("created", models.DateTimeField(auto_now_add=True)), + ("last_updated", models.DateTimeField(auto_now=True)), + ( + "uuid", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ( + "policies", + models.ManyToManyField(blank=True, to="passbook_core.Policy"), + ), + ], + options={"abstract": False,}, ), migrations.CreateModel( name="PropertyMapping", @@ -156,7 +176,6 @@ class Migration(migrations.Migration): ), ), ("name", models.TextField()), - ("expression", models.TextField()), ], options={ "verbose_name": "Property Mapping", @@ -164,38 +183,74 @@ class Migration(migrations.Migration): }, ), migrations.CreateModel( - name="UserInletConnection", + name="DebugPolicy", fields=[ ( - "id", - models.AutoField( + "policy_ptr", + models.OneToOneField( auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, primary_key=True, serialize=False, - verbose_name="ID", - ), - ), - ("created", models.DateTimeField(auto_now_add=True)), - ("last_updated", models.DateTimeField(auto_now=True)), - ( - "inlet", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="passbook_core.Inlet", - ), - ), - ( - "user", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to=settings.AUTH_USER_MODEL, + to="passbook_core.Policy", ), ), + ("result", models.BooleanField(default=False)), + ("wait_min", models.IntegerField(default=5)), + ("wait_max", models.IntegerField(default=30)), ], - options={"unique_together": {("user", "inlet")},}, + options={ + "verbose_name": "Debug Policy", + "verbose_name_plural": "Debug Policies", + }, + bases=("passbook_core.policy",), ), migrations.CreateModel( - name="Outlet", + name="Factor", + fields=[ + ( + "policymodel_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="passbook_core.PolicyModel", + ), + ), + ("name", models.TextField()), + ("slug", models.SlugField(unique=True)), + ("order", models.IntegerField()), + ("enabled", models.BooleanField(default=True)), + ], + options={"abstract": False,}, + bases=("passbook_core.policymodel",), + ), + migrations.CreateModel( + name="Source", + fields=[ + ( + "policymodel_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="passbook_core.PolicyModel", + ), + ), + ("name", models.TextField()), + ("slug", models.SlugField()), + ("enabled", models.BooleanField(default=True)), + ], + options={"abstract": False,}, + bases=("passbook_core.policymodel",), + ), + migrations.CreateModel( + name="Provider", fields=[ ( "id", @@ -215,7 +270,7 @@ class Migration(migrations.Migration): ], ), migrations.CreateModel( - name="Token", + name="Nonce", fields=[ ( "uuid", @@ -229,11 +284,10 @@ class Migration(migrations.Migration): ( "expires", models.DateTimeField( - default=passbook.core.models.default_token_duration + default=passbook.core.models.default_nonce_duration ), ), ("expiring", models.BooleanField(default=True)), - ("description", models.TextField(blank=True, default="")), ( "user", models.ForeignKey( @@ -242,14 +296,36 @@ class Migration(migrations.Migration): ), ), ], - options={"verbose_name": "Token", "verbose_name_plural": "Tokens",}, + options={"verbose_name": "Nonce", "verbose_name_plural": "Nonces",}, ), - migrations.AddField( - model_name="inlet", - name="property_mappings", - field=models.ManyToManyField( - blank=True, default=None, to="passbook_core.PropertyMapping" - ), + migrations.CreateModel( + name="Invitation", + fields=[ + ( + "uuid", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ("expires", models.DateTimeField(blank=True, default=None, null=True)), + ("fixed_username", models.TextField(blank=True, default=None)), + ("fixed_email", models.TextField(blank=True, default=None)), + ("needs_confirmation", models.BooleanField(default=True)), + ( + "created_by", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={ + "verbose_name": "Invitation", + "verbose_name_plural": "Invitations", + }, ), migrations.CreateModel( name="Group", @@ -265,7 +341,7 @@ class Migration(migrations.Migration): ), ("name", models.CharField(max_length=80, verbose_name="name")), ( - "attributes", + "tags", django.contrib.postgres.fields.jsonb.JSONField( blank=True, default=dict ), @@ -283,57 +359,11 @@ class Migration(migrations.Migration): ], options={"unique_together": {("name", "parent")},}, ), - migrations.CreateModel( - name="Application", - fields=[ - ( - "policybindingmodel_ptr", - models.OneToOneField( - auto_created=True, - on_delete=django.db.models.deletion.CASCADE, - parent_link=True, - primary_key=True, - serialize=False, - to="passbook_policies.PolicyBindingModel", - ), - ), - ("name", models.TextField(help_text="Application's display Name.")), - ( - "slug", - models.SlugField( - help_text="Internal application name, used in URLs." - ), - ), - ("skip_authorization", models.BooleanField(default=False)), - ("meta_launch_url", models.URLField(blank=True, default="")), - ("meta_icon_url", models.TextField(blank=True, default="")), - ("meta_description", models.TextField(blank=True, default="")), - ("meta_publisher", models.TextField(blank=True, default="")), - ( - "outlet", - models.OneToOneField( - blank=True, - default=None, - null=True, - on_delete=django.db.models.deletion.SET_DEFAULT, - to="passbook_core.Outlet", - ), - ), - ], - bases=("passbook_policies.policybindingmodel",), - ), migrations.AddField( model_name="user", name="groups", field=models.ManyToManyField(to="passbook_core.Group"), ), - migrations.AddField( - model_name="user", - name="inlets", - field=models.ManyToManyField( - through="passbook_core.UserInletConnection", to="passbook_core.Inlet" - ), - ), migrations.AddField( model_name="user", name="user_permissions", @@ -347,33 +377,74 @@ class Migration(migrations.Migration): ), ), migrations.CreateModel( - name="PropertyMappingBinding", + name="UserSourceConnection", fields=[ ( - "uuid", - models.UUIDField( - default=uuid.uuid4, - editable=False, + "id", + models.AutoField( + auto_created=True, primary_key=True, serialize=False, + verbose_name="ID", ), ), - ("order", models.IntegerField(default=0)), + ("created", models.DateTimeField(auto_now_add=True)), + ("last_updated", models.DateTimeField(auto_now=True)), ( - "outlet", + "user", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, - to="passbook_core.Outlet", + to=settings.AUTH_USER_MODEL, ), ), ( - "property_mapping", + "source", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, - to="passbook_core.PropertyMapping", + to="passbook_core.Source", ), ), ], - options={"unique_together": {("property_mapping", "outlet", "order")},}, + options={"unique_together": {("user", "source")},}, + ), + migrations.CreateModel( + name="Application", + fields=[ + ( + "policymodel_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="passbook_core.PolicyModel", + ), + ), + ("name", models.TextField()), + ("slug", models.SlugField()), + ("launch_url", models.URLField(blank=True, null=True)), + ("icon_url", models.TextField(blank=True, null=True)), + ("skip_authorization", models.BooleanField(default=False)), + ( + "provider", + models.OneToOneField( + blank=True, + default=None, + null=True, + on_delete=django.db.models.deletion.SET_DEFAULT, + to="passbook_core.Provider", + ), + ), + ], + options={"abstract": False,}, + bases=("passbook_core.policymodel",), + ), + migrations.AddField( + model_name="user", + name="sources", + field=models.ManyToManyField( + through="passbook_core.UserSourceConnection", to="passbook_core.Source" + ), ), ] diff --git a/passbook/core/migrations/0002_auto_20191010_1058.py b/passbook/core/migrations/0002_auto_20191010_1058.py new file mode 100644 index 000000000..c87a5000b --- /dev/null +++ b/passbook/core/migrations/0002_auto_20191010_1058.py @@ -0,0 +1,17 @@ +# Generated by Django 2.2.6 on 2019-10-10 10:58 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("passbook_core", "0001_initial"), + ] + + operations = [ + migrations.AlterModelOptions( + name="user", + options={"permissions": (("reset_user_password", "Reset Password"),)}, + ), + ] diff --git a/passbook/core/migrations/0002_nonce_description.py b/passbook/core/migrations/0002_nonce_description.py new file mode 100644 index 000000000..233800827 --- /dev/null +++ b/passbook/core/migrations/0002_nonce_description.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.6 on 2019-10-10 11:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("passbook_core", "0001_initial"), + ] + + operations = [ + migrations.AddField( + model_name="nonce", + name="description", + field=models.TextField(blank=True, default=""), + ), + ] diff --git a/passbook/core/migrations/0003_auto_20191011_0914.py b/passbook/core/migrations/0003_auto_20191011_0914.py new file mode 100644 index 000000000..c39d48198 --- /dev/null +++ b/passbook/core/migrations/0003_auto_20191011_0914.py @@ -0,0 +1,31 @@ +# Generated by Django 2.2.6 on 2019-10-11 09:14 + +import django.contrib.postgres.fields.jsonb +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("passbook_core", "0002_nonce_description"), + ] + + operations = [ + migrations.RenameField( + model_name="group", old_name="tags", new_name="attributes", + ), + migrations.AddField( + model_name="source", + name="property_mappings", + field=models.ManyToManyField( + blank=True, default=None, to="passbook_core.PropertyMapping" + ), + ), + migrations.AddField( + model_name="user", + name="attributes", + field=django.contrib.postgres.fields.jsonb.JSONField( + blank=True, default=dict + ), + ), + ] diff --git a/passbook/core/migrations/0003_merge_20191010_1541.py b/passbook/core/migrations/0003_merge_20191010_1541.py new file mode 100644 index 000000000..26b7a3a69 --- /dev/null +++ b/passbook/core/migrations/0003_merge_20191010_1541.py @@ -0,0 +1,13 @@ +# Generated by Django 2.2.6 on 2019-10-10 15:41 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("passbook_core", "0002_auto_20191010_1058"), + ("passbook_core", "0002_nonce_description"), + ] + + operations = [] diff --git a/passbook/core/migrations/0004_remove_policy_action.py b/passbook/core/migrations/0004_remove_policy_action.py new file mode 100644 index 000000000..9c432fe15 --- /dev/null +++ b/passbook/core/migrations/0004_remove_policy_action.py @@ -0,0 +1,14 @@ +# Generated by Django 2.2.6 on 2019-10-14 11:56 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("passbook_core", "0003_auto_20191011_0914"), + ] + + operations = [ + migrations.RemoveField(model_name="policy", name="action",), + ] diff --git a/passbook/core/migrations/0005_merge_20191025_2022.py b/passbook/core/migrations/0005_merge_20191025_2022.py new file mode 100644 index 000000000..8e6c7965f --- /dev/null +++ b/passbook/core/migrations/0005_merge_20191025_2022.py @@ -0,0 +1,13 @@ +# Generated by Django 2.2.6 on 2019-10-25 20:22 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("passbook_core", "0004_remove_policy_action"), + ("passbook_core", "0003_merge_20191010_1541"), + ] + + operations = [] diff --git a/passbook/core/migrations/0006_propertymapping_template.py b/passbook/core/migrations/0006_propertymapping_template.py new file mode 100644 index 000000000..d842b48ac --- /dev/null +++ b/passbook/core/migrations/0006_propertymapping_template.py @@ -0,0 +1,19 @@ +# Generated by Django 3.0.3 on 2020-02-17 16:15 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("passbook_core", "0005_merge_20191025_2022"), + ] + + operations = [ + migrations.AddField( + model_name="propertymapping", + name="template", + field=models.TextField(default=""), + preserve_default=False, + ), + ] diff --git a/passbook/core/migrations/0007_auto_20200217_1934.py b/passbook/core/migrations/0007_auto_20200217_1934.py new file mode 100644 index 000000000..4fa3282bb --- /dev/null +++ b/passbook/core/migrations/0007_auto_20200217_1934.py @@ -0,0 +1,16 @@ +# Generated by Django 3.0.3 on 2020-02-17 19:34 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("passbook_core", "0006_propertymapping_template"), + ] + + operations = [ + migrations.RenameField( + model_name="propertymapping", old_name="template", new_name="expression", + ), + ] diff --git a/passbook/core/migrations/0008_auto_20200220_1242.py b/passbook/core/migrations/0008_auto_20200220_1242.py new file mode 100644 index 000000000..fe35fffe1 --- /dev/null +++ b/passbook/core/migrations/0008_auto_20200220_1242.py @@ -0,0 +1,29 @@ +# Generated by Django 3.0.3 on 2020-02-20 12:42 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("passbook_core", "0007_auto_20200217_1934"), + ] + + operations = [ + migrations.RenameField( + model_name="application", old_name="icon_url", new_name="meta_icon_url", + ), + migrations.RenameField( + model_name="application", old_name="launch_url", new_name="meta_launch_url", + ), + migrations.AddField( + model_name="application", + name="meta_description", + field=models.TextField(blank=True, null=True), + ), + migrations.AddField( + model_name="application", + name="meta_publisher", + field=models.TextField(blank=True, null=True), + ), + ] diff --git a/passbook/core/migrations/0009_auto_20200221_1410.py b/passbook/core/migrations/0009_auto_20200221_1410.py new file mode 100644 index 000000000..3a1a355d0 --- /dev/null +++ b/passbook/core/migrations/0009_auto_20200221_1410.py @@ -0,0 +1,52 @@ +# Generated by Django 3.0.3 on 2020-02-21 14:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("passbook_core", "0008_auto_20200220_1242"), + ] + + operations = [ + migrations.AlterField( + model_name="application", + name="name", + field=models.TextField(help_text="Application's display Name."), + ), + migrations.AlterField( + model_name="application", + name="slug", + field=models.SlugField( + help_text="Internal application name, used in URLs." + ), + ), + migrations.AlterField( + model_name="factor", + name="name", + field=models.TextField(help_text="Factor's display Name."), + ), + migrations.AlterField( + model_name="factor", + name="slug", + field=models.SlugField( + help_text="Internal factor name, used in URLs.", unique=True + ), + ), + migrations.AlterField( + model_name="source", + name="name", + field=models.TextField(help_text="Source's display Name."), + ), + migrations.AlterField( + model_name="source", + name="slug", + field=models.SlugField(help_text="Internal source name, used in URLs."), + ), + migrations.AlterField( + model_name="user", + name="name", + field=models.TextField(help_text="User's display name."), + ), + ] diff --git a/passbook/core/migrations/0010_auto_20200221_2208.py b/passbook/core/migrations/0010_auto_20200221_2208.py new file mode 100644 index 000000000..bd7dedef9 --- /dev/null +++ b/passbook/core/migrations/0010_auto_20200221_2208.py @@ -0,0 +1,33 @@ +# Generated by Django 3.0.3 on 2020-02-21 22:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("passbook_core", "0009_auto_20200221_1410"), + ] + + operations = [ + migrations.AlterField( + model_name="application", + name="meta_description", + field=models.TextField(blank=True, default=""), + ), + migrations.AlterField( + model_name="application", + name="meta_icon_url", + field=models.TextField(blank=True, default=""), + ), + migrations.AlterField( + model_name="application", + name="meta_launch_url", + field=models.URLField(blank=True, default=""), + ), + migrations.AlterField( + model_name="application", + name="meta_publisher", + field=models.TextField(blank=True, default=""), + ), + ] diff --git a/passbook/core/migrations/0011_auto_20200222_1822.py b/passbook/core/migrations/0011_auto_20200222_1822.py new file mode 100644 index 000000000..fae2af4f1 --- /dev/null +++ b/passbook/core/migrations/0011_auto_20200222_1822.py @@ -0,0 +1,27 @@ +# Generated by Django 3.0.3 on 2020-02-22 18:22 + +from django.db import migrations + + +def fix_application_null(apps, schema_editor): + """Fix Application meta_fields being null""" + Application = apps.get_model("passbook_core", "Application") + for app in Application.objects.all(): + if app.meta_launch_url is None: + app.meta_launch_url = "" + if app.meta_icon_url is None: + app.meta_icon_url = "" + if app.meta_description is None: + app.meta_description = "" + if app.meta_publisher is None: + app.meta_publisher = "" + app.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ("passbook_core", "0010_auto_20200221_2208"), + ] + + operations = [migrations.RunPython(fix_application_null)] diff --git a/passbook/core/migrations/0012_delete_factor.py b/passbook/core/migrations/0012_delete_factor.py new file mode 100644 index 000000000..f8f9c3128 --- /dev/null +++ b/passbook/core/migrations/0012_delete_factor.py @@ -0,0 +1,14 @@ +# Generated by Django 3.0.3 on 2020-05-08 17:58 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("passbook_core", "0011_auto_20200222_1822"), + ] + + operations = [ + migrations.DeleteModel(name="Factor",), + ] diff --git a/passbook/core/migrations/0013_delete_debugpolicy.py b/passbook/core/migrations/0013_delete_debugpolicy.py new file mode 100644 index 000000000..4e658f01f --- /dev/null +++ b/passbook/core/migrations/0013_delete_debugpolicy.py @@ -0,0 +1,16 @@ +# Generated by Django 3.0.5 on 2020-05-10 10:01 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("passbook_policies", "0003_auto_20200508_1642"), + ("passbook_stages_password", "0001_initial"), + ("passbook_core", "0012_delete_factor"), + ] + + operations = [ + migrations.DeleteModel(name="DebugPolicy",), + ] diff --git a/passbook/core/migrations/0014_delete_invitation.py b/passbook/core/migrations/0014_delete_invitation.py new file mode 100644 index 000000000..2f3e67b70 --- /dev/null +++ b/passbook/core/migrations/0014_delete_invitation.py @@ -0,0 +1,14 @@ +# Generated by Django 3.0.5 on 2020-05-11 19:57 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("passbook_core", "0013_delete_debugpolicy"), + ] + + operations = [ + migrations.DeleteModel(name="Invitation",), + ] diff --git a/passbook/core/models.py b/passbook/core/models.py index 69656eda3..6c0a6d5ea 100644 --- a/passbook/core/models.py +++ b/passbook/core/models.py @@ -10,6 +10,7 @@ from django.db import models from django.http import HttpRequest from django.utils.timezone import now from django.utils.translation import gettext_lazy as _ +from django_prometheus.models import ExportModelOperationsMixin from guardian.mixins import GuardianUserMixin from jinja2 import Undefined from jinja2.exceptions import TemplateSyntaxError, UndefinedError @@ -21,18 +22,19 @@ from passbook.core.exceptions import PropertyMappingExpressionException from passbook.core.signals import password_changed from passbook.core.types import UILoginButton, UIUserSettings from passbook.lib.models import CreatedUpdatedModel, UUIDModel -from passbook.policies.models import PolicyBindingModel +from passbook.policies.exceptions import PolicyException +from passbook.policies.types import PolicyRequest, PolicyResult LOGGER = get_logger() NATIVE_ENVIRONMENT = NativeEnvironment() -def default_token_duration(): - """Default duration a Token is valid""" +def default_nonce_duration(): + """Default duration a Nonce is valid""" return now() + timedelta(minutes=30) -class Group(UUIDModel): +class Group(ExportModelOperationsMixin("group"), UUIDModel): """Custom Group model which supports a basic hierarchy""" name = models.CharField(_("name"), max_length=80) @@ -53,13 +55,13 @@ class Group(UUIDModel): unique_together = (("name", "parent",),) -class User(GuardianUserMixin, AbstractUser): +class User(ExportModelOperationsMixin("user"), GuardianUserMixin, AbstractUser): """Custom User model to allow easier adding o f user-based settings""" uuid = models.UUIDField(default=uuid4, editable=False) name = models.TextField(help_text=_("User's display name.")) - inlets = models.ManyToManyField("Inlet", through="UserInletConnection") + sources = models.ManyToManyField("Source", through="UserSourceConnection") groups = models.ManyToManyField("Group") password_change_date = models.DateTimeField(auto_now_add=True) @@ -76,7 +78,29 @@ class User(GuardianUserMixin, AbstractUser): permissions = (("reset_user_password", "Reset Password"),) -class Application(PolicyBindingModel): +class Provider(ExportModelOperationsMixin("provider"), models.Model): + """Application-independent Provider instance. For example SAML2 Remote, OAuth2 Application""" + + property_mappings = models.ManyToManyField( + "PropertyMapping", default=None, blank=True + ) + + objects = InheritanceManager() + + # This class defines no field for easier inheritance + def __str__(self): + if hasattr(self, "name"): + return getattr(self, "name") + return super().__str__() + + +class PolicyModel(UUIDModel, CreatedUpdatedModel): + """Base model which can have policies applied to it""" + + policies = models.ManyToManyField("Policy", blank=True) + + +class Application(ExportModelOperationsMixin("application"), PolicyModel): """Every Application which uses passbook for authentication/identification/authorization needs an Application record. Other authentication types can subclass this Model to add custom fields and other properties""" @@ -84,8 +108,8 @@ class Application(PolicyBindingModel): name = models.TextField(help_text=_("Application's display Name.")) slug = models.SlugField(help_text=_("Internal application name, used in URLs.")) skip_authorization = models.BooleanField(default=False) - outlet = models.OneToOneField( - "Outlet", null=True, blank=True, default=None, on_delete=models.SET_DEFAULT + provider = models.OneToOneField( + "Provider", null=True, blank=True, default=None, on_delete=models.SET_DEFAULT ) meta_launch_url = models.URLField(default="", blank=True) @@ -95,20 +119,20 @@ class Application(PolicyBindingModel): objects = InheritanceManager() - def get_outlet(self) -> Optional["Outlet"]: - """Get casted outlet instance""" - if not self.outlet: + def get_provider(self) -> Optional[Provider]: + """Get casted provider instance""" + if not self.provider: return None - return Outlet.objects.get_subclass(pk=self.outlet.pk) + return Provider.objects.get_subclass(pk=self.provider.pk) def __str__(self): return self.name -class Inlet(PolicyBindingModel): +class Source(ExportModelOperationsMixin("source"), PolicyModel): """Base Authentication source, i.e. an OAuth Provider, SAML Remote or LDAP Server""" - name = models.TextField(help_text=_("Inlet's display Name.")) + name = models.TextField(help_text=_("Source's display Name.")) slug = models.SlugField(help_text=_("Internal source name, used in URLs.")) enabled = models.BooleanField(default=True) @@ -141,69 +165,56 @@ class Inlet(PolicyBindingModel): return self.name -class UserInletConnection(CreatedUpdatedModel): - """Connection between User and Inlet.""" +class UserSourceConnection(CreatedUpdatedModel): + """Connection between User and Source.""" user = models.ForeignKey(User, on_delete=models.CASCADE) - inlet = models.ForeignKey(Inlet, on_delete=models.CASCADE) + source = models.ForeignKey(Source, on_delete=models.CASCADE) class Meta: - unique_together = (("user", "inlet"),) + unique_together = (("user", "source"),) -class Token(UUIDModel): +class Policy(ExportModelOperationsMixin("policy"), UUIDModel, CreatedUpdatedModel): + """Policies which specify if a user is authorized to use an Application. Can be overridden by + other types to add other fields, more logic, etc.""" + + name = models.TextField(blank=True, null=True) + negate = models.BooleanField(default=False) + order = models.IntegerField(default=0) + timeout = models.IntegerField(default=30) + + objects = InheritanceManager() + + def __str__(self): + return f"Policy {self.name}" + + def passes(self, request: PolicyRequest) -> PolicyResult: + """Check if user instance passes this policy""" + raise PolicyException() + + +class Nonce(ExportModelOperationsMixin("nonce"), UUIDModel): """One-time link for password resets/sign-up-confirmations""" - expires = models.DateTimeField(default=default_token_duration) - user = models.ForeignKey("User", on_delete=models.CASCADE, related_name="+") + expires = models.DateTimeField(default=default_nonce_duration) + user = models.ForeignKey("User", on_delete=models.CASCADE) expiring = models.BooleanField(default=True) description = models.TextField(default="", blank=True) @property def is_expired(self) -> bool: - """Check if token is expired yet.""" + """Check if nonce is expired yet.""" return now() > self.expires def __str__(self): - return f"Token f{self.uuid.hex} {self.description} (expires={self.expires})" + return f"Nonce f{self.uuid.hex} {self.description} (expires={self.expires})" class Meta: - verbose_name = _("Token") - verbose_name_plural = _("Tokens") - - -class Outlet(models.Model): - """Application-independent Outlet instance. For example SAML2 Remote, OAuth2 Application""" - - property_mappings = models.ManyToManyField( - "PropertyMapping", default=None, blank=True - ) - - objects = InheritanceManager() - - # This class defines no field for easier inheritance - def __str__(self): - if hasattr(self, "name"): - return getattr(self, "name") - return super().__str__() - - -class PropertyMappingBinding(UUIDModel): - """Binds a PropertyMapping instance to an outlet""" - - property_mapping = models.ForeignKey("PropertyMapping", on_delete=models.CASCADE) - outlet = models.ForeignKey("Outlet", on_delete=models.CASCADE) - - order = models.IntegerField(default=0) - - def __str__(self): - return f"PropertyMapping Binding p={self.property_mapping} outlet={self.outlet}" - - class Meta: - - unique_together = (("property_mapping", "outlet", "order"),) + verbose_name = _("Nonce") + verbose_name_plural = _("Nonces") class PropertyMapping(UUIDModel): diff --git a/passbook/core/signals.py b/passbook/core/signals.py index c3a50b4cc..d450e8bb8 100644 --- a/passbook/core/signals.py +++ b/passbook/core/signals.py @@ -17,7 +17,7 @@ password_changed = Signal(providing_args=["user", "password"]) # pylint: disable=unused-argument def invalidate_policy_cache(sender, instance, **_): """Invalidate Policy cache when policy is updated""" - from passbook.policies.models import Policy + from passbook.core.models import Policy from passbook.policies.process import cache_key if isinstance(instance, Policy): diff --git a/passbook/core/tasks.py b/passbook/core/tasks.py index 4dc560aa8..e0c8898d8 100644 --- a/passbook/core/tasks.py +++ b/passbook/core/tasks.py @@ -2,14 +2,14 @@ from django.utils.timezone import now from structlog import get_logger -from passbook.core.models import Token +from passbook.core.models import Nonce from passbook.root.celery import CELERY_APP LOGGER = get_logger() @CELERY_APP.task() -def clean_tokens(): - """Remove expired tokens""" - amount, _ = Token.objects.filter(expires__lt=now(), expiring=True).delete() - LOGGER.debug("Deleted expired tokens", amount=amount) +def clean_nonces(): + """Remove expired nonces""" + amount, _ = Nonce.objects.filter(expires__lt=now(), expiring=True).delete() + LOGGER.debug("Deleted expired nonces", amount=amount) diff --git a/passbook/core/templates/user/base.html b/passbook/core/templates/user/base.html index 66ad43bb3..4c0c6798b 100644 --- a/passbook/core/templates/user/base.html +++ b/passbook/core/templates/user/base.html @@ -34,17 +34,17 @@ {% endif %} - {% user_inlets as user_inlets_loc %} - {% if user_inlets_loc %} + {% user_sources as user_sources_loc %} + {% if user_sources_loc %}

{% trans 'Sources' %}

    - {% for inlet in user_inlets_loc %} + {% for source in user_sources_loc %}
  • - - - {{ inlet.name }} + + {{ source.name }}
  • {% endfor %} diff --git a/passbook/core/templatetags/passbook_user_settings.py b/passbook/core/templatetags/passbook_user_settings.py index 752684e92..7c0287eec 100644 --- a/passbook/core/templatetags/passbook_user_settings.py +++ b/passbook/core/templatetags/passbook_user_settings.py @@ -4,7 +4,7 @@ from typing import Iterable, List from django import template from django.template.context import RequestContext -from passbook.core.models import Inlet +from passbook.core.models import Source from passbook.core.types import UIUserSettings from passbook.flows.models import Stage from passbook.policies.engine import PolicyEngine @@ -27,14 +27,14 @@ def user_stages(context: RequestContext) -> List[UIUserSettings]: @register.simple_tag(takes_context=True) -def user_inlets(context: RequestContext) -> List[UIUserSettings]: - """Return a list of all inlets which are enabled for the user""" +def user_sources(context: RequestContext) -> List[UIUserSettings]: + """Return a list of all sources which are enabled for the user""" user = context.get("request").user - _all_inlets: Iterable[(Inlet)] = ( - (Inlet).objects.filter(enabled=True).select_subclasses() + _all_sources: Iterable[Source] = ( + Source.objects.filter(enabled=True).select_subclasses() ) - matching_inlets: List[UIUserSettings] = [] - for source in _all_inlets: + matching_sources: List[UIUserSettings] = [] + for source in _all_sources: user_settings = source.ui_user_settings if not user_settings: continue @@ -43,5 +43,5 @@ def user_inlets(context: RequestContext) -> List[UIUserSettings]: ) policy_engine.build() if policy_engine.passing: - matching_inlets.append(user_settings) - return matching_inlets + matching_sources.append(user_settings) + return matching_sources diff --git a/passbook/core/views/access.py b/passbook/core/views/access.py index ab84617fa..ff3888645 100644 --- a/passbook/core/views/access.py +++ b/passbook/core/views/access.py @@ -6,7 +6,7 @@ from django.http import HttpRequest from django.utils.translation import gettext as _ from structlog import get_logger -from passbook.core.models import Application, Outlet, User +from passbook.core.models import Application, Provider, User from passbook.policies.engine import PolicyEngine LOGGER = get_logger() @@ -14,19 +14,22 @@ LOGGER = get_logger() class AccessMixin: """Mixin class for usage in Authorization views. - Outlet functions to check application access, etc""" + Provider functions to check application access, etc""" # request is set by view but since this Mixin has no base class request: HttpRequest = None - def outlet_to_application(self, outlet: Outlet) -> Application: - """Lookup application assigned to outlet, throw error if no application assigned""" + def provider_to_application(self, provider: Provider) -> Application: + """Lookup application assigned to provider, throw error if no application assigned""" try: - return outlet.application + return provider.application except Application.DoesNotExist as exc: messages.error( self.request, - _('Outlet "%(name)s" has no application assigned' % {"name": outlet}), + _( + 'Provider "%(name)s" has no application assigned' + % {"name": provider} + ), ) raise exc diff --git a/passbook/crypto/migrations/0001_initial.py b/passbook/crypto/migrations/0001_initial.py index f802b5a12..9e749f148 100644 --- a/passbook/crypto/migrations/0001_initial.py +++ b/passbook/crypto/migrations/0001_initial.py @@ -1,10 +1,24 @@ -# Generated by Django 3.0.5 on 2020-05-15 19:58 +# Generated by Django 3.0.3 on 2020-03-03 21:45 import uuid from django.db import migrations, models +def create_self_signed(apps, schema_editor): + CertificateKeyPair = apps.get_model("passbook_crypto", "CertificateKeyPair") + db_alias = schema_editor.connection.alias + from passbook.crypto.builder import CertificateBuilder + + builder = CertificateBuilder() + builder.build() + CertificateKeyPair.objects.using(db_alias).create( + name="passbook Self-signed Certificate", + certificate_data=builder.certificate, + key_data=builder.private_key, + ) + + class Migration(migrations.Migration): initial = True @@ -27,22 +41,27 @@ class Migration(migrations.Migration): ), ), ("name", models.TextField()), - ( - "certificate_data", - models.TextField(help_text="PEM-encoded Certificate data"), - ), - ( - "key_data", - models.TextField( - blank=True, - default="", - help_text="Optional Private Key. If this is set, you can use this keypair for encryption.", - ), - ), + ("certificate_data", models.TextField()), + ("key_data", models.TextField(blank=True, default="")), ], options={ "verbose_name": "Certificate-Key Pair", "verbose_name_plural": "Certificate-Key Pairs", }, ), + migrations.RunPython(create_self_signed), + migrations.AlterField( + model_name="certificatekeypair", + name="certificate_data", + field=models.TextField(help_text="PEM-encoded Certificate data"), + ), + migrations.AlterField( + model_name="certificatekeypair", + name="key_data", + field=models.TextField( + blank=True, + default="", + help_text="Optional Private Key. If this is set, you can use this keypair for encryption.", + ), + ), ] diff --git a/passbook/flows/migrations/0001_initial.py b/passbook/flows/migrations/0001_initial.py index 6c7c3e860..df7121778 100644 --- a/passbook/flows/migrations/0001_initial.py +++ b/passbook/flows/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 3.0.5 on 2020-05-15 19:58 +# Generated by Django 3.0.3 on 2020-05-08 18:27 import uuid @@ -11,7 +11,7 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ("passbook_policies", "__first__"), + ("passbook_policies", "0003_auto_20200508_1642"), ] operations = [ @@ -33,12 +33,10 @@ class Migration(migrations.Migration): "designation", models.CharField( choices=[ - ("authentication", "Authentication"), - ("invalidation", "Invalidation"), - ("enrollment", "Enrollment"), - ("unenrollment", "Unrenollment"), - ("recovery", "Recovery"), - ("password_change", "Password Change"), + ("AUTHENTICATION", "authentication"), + ("ENROLLMENT", "enrollment"), + ("RECOVERY", "recovery"), + ("PASSWORD_CHANGE", "password_change"), ], max_length=100, ), diff --git a/passbook/flows/migrations/0003_auto_20200509_1258.py b/passbook/flows/migrations/0003_auto_20200509_1258.py new file mode 100644 index 000000000..574bca294 --- /dev/null +++ b/passbook/flows/migrations/0003_auto_20200509_1258.py @@ -0,0 +1,26 @@ +# Generated by Django 3.0.3 on 2020-05-09 12:58 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("passbook_flows", "0002_default_flows"), + ] + + operations = [ + migrations.AlterField( + model_name="flow", + name="designation", + field=models.CharField( + choices=[ + ("authentication", "Authentication"), + ("enrollment", "Enrollment"), + ("recovery", "Recovery"), + ("password_change", "Password Change"), + ], + max_length=100, + ), + ), + ] diff --git a/passbook/flows/migrations/0004_auto_20200510_2310.py b/passbook/flows/migrations/0004_auto_20200510_2310.py new file mode 100644 index 000000000..61a3cac3a --- /dev/null +++ b/passbook/flows/migrations/0004_auto_20200510_2310.py @@ -0,0 +1,27 @@ +# Generated by Django 3.0.5 on 2020-05-10 23:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("passbook_flows", "0003_auto_20200509_1258"), + ] + + operations = [ + migrations.AlterField( + model_name="flow", + name="designation", + field=models.CharField( + choices=[ + ("authentication", "Authentication"), + ("enrollment", "Enrollment"), + ("recovery", "Recovery"), + ("password_change", "Password Change"), + ("invalidation", "Invalidation"), + ], + max_length=100, + ), + ), + ] diff --git a/passbook/flows/migrations/0005_auto_20200512_1158.py b/passbook/flows/migrations/0005_auto_20200512_1158.py new file mode 100644 index 000000000..92998affc --- /dev/null +++ b/passbook/flows/migrations/0005_auto_20200512_1158.py @@ -0,0 +1,28 @@ +# Generated by Django 3.0.5 on 2020-05-12 11:58 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("passbook_flows", "0004_auto_20200510_2310"), + ] + + operations = [ + migrations.AlterField( + model_name="flow", + name="designation", + field=models.CharField( + choices=[ + ("authentication", "Authentication"), + ("invalidation", "Invalidation"), + ("enrollment", "Enrollment"), + ("unenrollment", "Unrenollment"), + ("recovery", "Recovery"), + ("password_change", "Password Change"), + ], + max_length=100, + ), + ), + ] diff --git a/passbook/policies/dummy/migrations/0001_initial.py b/passbook/policies/dummy/migrations/0001_initial.py index eebc2df68..14e77000e 100644 --- a/passbook/policies/dummy/migrations/0001_initial.py +++ b/passbook/policies/dummy/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 3.0.5 on 2020-05-15 19:58 +# Generated by Django 3.0.5 on 2020-05-10 10:01 import django.db.models.deletion from django.db import migrations, models @@ -9,7 +9,8 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ("passbook_policies", "0001_initial"), + ("passbook_policies", "0003_auto_20200508_1642"), + ("passbook_core", "0013_delete_debugpolicy"), ] operations = [ @@ -24,7 +25,7 @@ class Migration(migrations.Migration): parent_link=True, primary_key=True, serialize=False, - to="passbook_policies.Policy", + to="passbook_core.Policy", ), ), ("result", models.BooleanField(default=False)), @@ -35,6 +36,6 @@ class Migration(migrations.Migration): "verbose_name": "Dummy Policy", "verbose_name_plural": "Dummy Policies", }, - bases=("passbook_policies.policy",), + bases=("passbook_core.policy",), ), ] diff --git a/passbook/policies/dummy/models.py b/passbook/policies/dummy/models.py index 5e7ca8c8b..98d9e22f5 100644 --- a/passbook/policies/dummy/models.py +++ b/passbook/policies/dummy/models.py @@ -6,7 +6,7 @@ from django.db import models from django.utils.translation import gettext_lazy as _ from structlog import get_logger -from passbook.policies.models import Policy +from passbook.core.models import Policy from passbook.policies.types import PolicyRequest, PolicyResult LOGGER = get_logger() diff --git a/passbook/policies/engine.py b/passbook/policies/engine.py index 24aaae59f..62455b0f0 100644 --- a/passbook/policies/engine.py +++ b/passbook/policies/engine.py @@ -7,8 +7,7 @@ from django.core.cache import cache from django.http import HttpRequest from structlog import get_logger -from passbook.core.models import User -from passbook.policies.models import Policy +from passbook.core.models import Policy, User from passbook.policies.process import PolicyProcess, cache_key from passbook.policies.types import PolicyRequest, PolicyResult diff --git a/passbook/policies/expiry/migrations/0001_initial.py b/passbook/policies/expiry/migrations/0001_initial.py index 8f877cc15..a9bf5142b 100644 --- a/passbook/policies/expiry/migrations/0001_initial.py +++ b/passbook/policies/expiry/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 3.0.5 on 2020-05-15 19:58 +# Generated by Django 2.2.6 on 2019-10-07 14:07 import django.db.models.deletion from django.db import migrations, models @@ -9,7 +9,7 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ("passbook_policies", "0001_initial"), + ("passbook_core", "0001_initial"), ] operations = [ @@ -24,7 +24,7 @@ class Migration(migrations.Migration): parent_link=True, primary_key=True, serialize=False, - to="passbook_policies.Policy", + to="passbook_core.Policy", ), ), ("deny_only", models.BooleanField(default=False)), @@ -34,6 +34,6 @@ class Migration(migrations.Migration): "verbose_name": "Password Expiry Policy", "verbose_name_plural": "Password Expiry Policies", }, - bases=("passbook_policies.policy",), + bases=("passbook_core.policy",), ), ] diff --git a/passbook/policies/expiry/models.py b/passbook/policies/expiry/models.py index 34565188b..102360dad 100644 --- a/passbook/policies/expiry/models.py +++ b/passbook/policies/expiry/models.py @@ -6,7 +6,7 @@ from django.utils.timezone import now from django.utils.translation import gettext as _ from structlog import get_logger -from passbook.policies.models import Policy +from passbook.core.models import Policy from passbook.policies.types import PolicyRequest, PolicyResult LOGGER = get_logger() diff --git a/passbook/policies/expression/migrations/0001_initial.py b/passbook/policies/expression/migrations/0001_initial.py index e4a8def10..fa9e907b4 100644 --- a/passbook/policies/expression/migrations/0001_initial.py +++ b/passbook/policies/expression/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 3.0.5 on 2020-05-15 19:59 +# Generated by Django 3.0.3 on 2020-02-18 14:00 import django.db.models.deletion from django.db import migrations, models @@ -9,7 +9,7 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ("passbook_policies", "0001_initial"), + ("passbook_core", "0007_auto_20200217_1934"), ] operations = [ @@ -24,7 +24,7 @@ class Migration(migrations.Migration): parent_link=True, primary_key=True, serialize=False, - to="passbook_policies.Policy", + to="passbook_core.Policy", ), ), ("expression", models.TextField()), @@ -33,6 +33,6 @@ class Migration(migrations.Migration): "verbose_name": "Expression Policy", "verbose_name_plural": "Expression Policies", }, - bases=("passbook_policies.policy",), + bases=("passbook_core.policy",), ), ] diff --git a/passbook/policies/expression/models.py b/passbook/policies/expression/models.py index edf9b629b..2ba3827a6 100644 --- a/passbook/policies/expression/models.py +++ b/passbook/policies/expression/models.py @@ -2,8 +2,8 @@ from django.db import models from django.utils.translation import gettext as _ +from passbook.core.models import Policy from passbook.policies.expression.evaluator import Evaluator -from passbook.policies.models import Policy from passbook.policies.types import PolicyRequest, PolicyResult diff --git a/passbook/policies/hibp/migrations/0001_initial.py b/passbook/policies/hibp/migrations/0001_initial.py index ac6a66992..cb3f04898 100644 --- a/passbook/policies/hibp/migrations/0001_initial.py +++ b/passbook/policies/hibp/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 3.0.5 on 2020-05-15 19:59 +# Generated by Django 2.2.6 on 2019-10-07 14:07 import django.db.models.deletion from django.db import migrations, models @@ -9,7 +9,7 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ("passbook_policies", "0001_initial"), + ("passbook_core", "0001_initial"), ] operations = [ @@ -24,7 +24,7 @@ class Migration(migrations.Migration): parent_link=True, primary_key=True, serialize=False, - to="passbook_policies.Policy", + to="passbook_core.Policy", ), ), ("allowed_count", models.IntegerField(default=0)), @@ -33,6 +33,6 @@ class Migration(migrations.Migration): "verbose_name": "Have I Been Pwned Policy", "verbose_name_plural": "Have I Been Pwned Policies", }, - bases=("passbook_policies.policy",), + bases=("passbook_core.policy",), ), ] diff --git a/passbook/policies/hibp/models.py b/passbook/policies/hibp/models.py index 66fa2e665..5ff10c838 100644 --- a/passbook/policies/hibp/models.py +++ b/passbook/policies/hibp/models.py @@ -6,8 +6,7 @@ from django.utils.translation import gettext as _ from requests import get from structlog import get_logger -from passbook.policies.models import Policy -from passbook.policies.types import PolicyRequest, PolicyResult +from passbook.core.models import Policy, PolicyResult, User LOGGER = get_logger() @@ -20,14 +19,14 @@ class HaveIBeenPwendPolicy(Policy): form = "passbook.policies.hibp.forms.HaveIBeenPwnedPolicyForm" - def passes(self, request: PolicyRequest) -> PolicyResult: + def passes(self, user: User) -> PolicyResult: """Check if password is in HIBP DB. Hashes given Password with SHA1, uses the first 5 characters of Password in request and checks if full hash is in response. Returns 0 if Password is not in result otherwise the count of how many times it was used.""" # Only check if password is being set - if not hasattr(request.user, "__password__"): + if not hasattr(user, "__password__"): return PolicyResult(True) - password = getattr(request.user, "__password__") + password = getattr(user, "__password__") pw_hash = sha1(password.encode("utf-8")).hexdigest() # nosec url = "https://api.pwnedpasswords.com/range/%s" % pw_hash[:5] result = get(url).text diff --git a/passbook/policies/migrations/0001_initial.py b/passbook/policies/migrations/0001_initial.py index d5e0a6947..bc0f6b7ef 100644 --- a/passbook/policies/migrations/0001_initial.py +++ b/passbook/policies/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 3.0.5 on 2020-05-15 19:58 +# Generated by Django 3.0.3 on 2020-05-07 18:35 import uuid @@ -10,30 +10,11 @@ class Migration(migrations.Migration): initial = True - dependencies = [] + dependencies = [ + ("passbook_core", "0011_auto_20200222_1822"), + ] operations = [ - migrations.CreateModel( - name="Policy", - fields=[ - ("created", models.DateTimeField(auto_now_add=True)), - ("last_updated", models.DateTimeField(auto_now=True)), - ( - "uuid", - models.UUIDField( - default=uuid.uuid4, - editable=False, - primary_key=True, - serialize=False, - ), - ), - ("name", models.TextField(blank=True, null=True)), - ("negate", models.BooleanField(default=False)), - ("order", models.IntegerField(default=0)), - ("timeout", models.IntegerField(default=30)), - ], - options={"abstract": False,}, - ), migrations.CreateModel( name="PolicyBinding", fields=[ @@ -53,7 +34,7 @@ class Migration(migrations.Migration): models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, related_name="+", - to="passbook_policies.Policy", + to="passbook_core.Policy", ), ), ], @@ -77,17 +58,12 @@ class Migration(migrations.Migration): ( "policies", models.ManyToManyField( - blank=True, related_name="_policybindingmodel_policies_+", through="passbook_policies.PolicyBinding", - to="passbook_policies.Policy", + to="passbook_core.Policy", ), ), ], - options={ - "verbose_name": "Policy Binding Model", - "verbose_name_plural": "Policy Binding Models", - }, ), migrations.AddField( model_name="policybinding", diff --git a/passbook/policies/migrations/0002_auto_20200508_1230.py b/passbook/policies/migrations/0002_auto_20200508_1230.py new file mode 100644 index 000000000..a575fc02e --- /dev/null +++ b/passbook/policies/migrations/0002_auto_20200508_1230.py @@ -0,0 +1,20 @@ +# Generated by Django 3.0.3 on 2020-05-08 12:30 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("passbook_policies", "0001_initial"), + ] + + operations = [ + migrations.AlterModelOptions( + name="policybindingmodel", + options={ + "verbose_name": "Policy Binding Model", + "verbose_name_plural": "Policy Binding Models", + }, + ), + ] diff --git a/passbook/policies/migrations/0003_auto_20200508_1642.py b/passbook/policies/migrations/0003_auto_20200508_1642.py new file mode 100644 index 000000000..a9e6128ba --- /dev/null +++ b/passbook/policies/migrations/0003_auto_20200508_1642.py @@ -0,0 +1,24 @@ +# Generated by Django 3.0.3 on 2020-05-08 16:42 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("passbook_core", "0011_auto_20200222_1822"), + ("passbook_policies", "0002_auto_20200508_1230"), + ] + + operations = [ + migrations.AlterField( + model_name="policybindingmodel", + name="policies", + field=models.ManyToManyField( + blank=True, + related_name="_policybindingmodel_policies_+", + through="passbook_policies.PolicyBinding", + to="passbook_core.Policy", + ), + ), + ] diff --git a/passbook/policies/models.py b/passbook/policies/models.py index f78d3b4c3..e2c35786b 100644 --- a/passbook/policies/models.py +++ b/passbook/policies/models.py @@ -1,30 +1,9 @@ """Policy base models""" from django.db import models from django.utils.translation import gettext_lazy as _ -from model_utils.managers import InheritanceManager -from passbook.lib.models import CreatedUpdatedModel, UUIDModel -from passbook.policies.exceptions import PolicyException -from passbook.policies.types import PolicyRequest, PolicyResult - - -class Policy(UUIDModel, CreatedUpdatedModel): - """Policies which specify if a user is authorized to use an Application. Can be overridden by - other types to add other fields, more logic, etc.""" - - name = models.TextField(blank=True, null=True) - negate = models.BooleanField(default=False) - order = models.IntegerField(default=0) - timeout = models.IntegerField(default=30) - - objects = InheritanceManager() - - def __str__(self): - return f"Policy {self.name}" - - def passes(self, request: PolicyRequest) -> PolicyResult: - """Check if user instance passes this policy""" - raise PolicyException() +from passbook.core.models import Policy +from passbook.lib.models import UUIDModel class PolicyBindingModel(models.Model): diff --git a/passbook/policies/password/migrations/0001_initial.py b/passbook/policies/password/migrations/0001_initial.py index a89707525..ef73a1871 100644 --- a/passbook/policies/password/migrations/0001_initial.py +++ b/passbook/policies/password/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 3.0.5 on 2020-05-15 19:59 +# Generated by Django 2.2.6 on 2019-10-07 14:07 import django.db.models.deletion from django.db import migrations, models @@ -9,7 +9,7 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ("passbook_policies", "0001_initial"), + ("passbook_core", "0001_initial"), ] operations = [ @@ -24,7 +24,7 @@ class Migration(migrations.Migration): parent_link=True, primary_key=True, serialize=False, - to="passbook_policies.Policy", + to="passbook_core.Policy", ), ), ("amount_uppercase", models.IntegerField(default=0)), @@ -41,6 +41,6 @@ class Migration(migrations.Migration): "verbose_name": "Password Policy", "verbose_name_plural": "Password Policies", }, - bases=("passbook_policies.policy",), + bases=("passbook_core.policy",), ), ] diff --git a/passbook/policies/password/models.py b/passbook/policies/password/models.py index 4f14da98d..03b552a21 100644 --- a/passbook/policies/password/models.py +++ b/passbook/policies/password/models.py @@ -5,7 +5,7 @@ from django.db import models from django.utils.translation import gettext as _ from structlog import get_logger -from passbook.policies.models import Policy +from passbook.core.models import Policy from passbook.policies.types import PolicyRequest, PolicyResult LOGGER = get_logger() diff --git a/passbook/policies/process.py b/passbook/policies/process.py index f6c2a1265..64ccf4962 100644 --- a/passbook/policies/process.py +++ b/passbook/policies/process.py @@ -6,9 +6,8 @@ from typing import Optional from django.core.cache import cache from structlog import get_logger -from passbook.core.models import User +from passbook.core.models import Policy, User from passbook.policies.exceptions import PolicyException -from passbook.policies.models import Policy from passbook.policies.types import PolicyRequest, PolicyResult LOGGER = get_logger() diff --git a/passbook/policies/reputation/migrations/0001_initial.py b/passbook/policies/reputation/migrations/0001_initial.py index 564f0c3fb..7b9dd1c2e 100644 --- a/passbook/policies/reputation/migrations/0001_initial.py +++ b/passbook/policies/reputation/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 3.0.5 on 2020-05-15 19:59 +# Generated by Django 2.2.6 on 2019-10-07 14:07 import django.db.models.deletion from django.conf import settings @@ -10,7 +10,7 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ("passbook_policies", "0001_initial"), + ("passbook_core", "0001_initial"), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] @@ -43,7 +43,7 @@ class Migration(migrations.Migration): parent_link=True, primary_key=True, serialize=False, - to="passbook_policies.Policy", + to="passbook_core.Policy", ), ), ("check_ip", models.BooleanField(default=True)), @@ -54,7 +54,7 @@ class Migration(migrations.Migration): "verbose_name": "Reputation Policy", "verbose_name_plural": "Reputation Policies", }, - bases=("passbook_policies.policy",), + bases=("passbook_core.policy",), ), migrations.CreateModel( name="UserReputation", diff --git a/passbook/policies/reputation/models.py b/passbook/policies/reputation/models.py index a4b22dff9..dfc9014c3 100644 --- a/passbook/policies/reputation/models.py +++ b/passbook/policies/reputation/models.py @@ -2,9 +2,8 @@ from django.db import models from django.utils.translation import gettext as _ -from passbook.core.models import User +from passbook.core.models import Policy, User from passbook.lib.utils.http import get_client_ip -from passbook.policies.models import Policy from passbook.policies.types import PolicyRequest, PolicyResult diff --git a/passbook/policies/tests/test_engine.py b/passbook/policies/tests/test_engine.py index 0f4c63a83..31e4d6855 100644 --- a/passbook/policies/tests/test_engine.py +++ b/passbook/policies/tests/test_engine.py @@ -2,10 +2,9 @@ from django.core.cache import cache from django.test import TestCase -from passbook.core.models import User +from passbook.core.models import Policy, User from passbook.policies.dummy.models import DummyPolicy from passbook.policies.engine import PolicyEngine -from passbook.policies.models import Policy class PolicyTestEngine(TestCase): diff --git a/passbook/channels/__init__.py b/passbook/providers/__init__.py similarity index 100% rename from passbook/channels/__init__.py rename to passbook/providers/__init__.py diff --git a/passbook/channels/in_ldap/__init__.py b/passbook/providers/app_gw/__init__.py similarity index 100% rename from passbook/channels/in_ldap/__init__.py rename to passbook/providers/app_gw/__init__.py diff --git a/passbook/channels/out_app_gw/api.py b/passbook/providers/app_gw/api.py similarity index 64% rename from passbook/channels/out_app_gw/api.py rename to passbook/providers/app_gw/api.py index a80ce629c..c4694f8b9 100644 --- a/passbook/channels/out_app_gw/api.py +++ b/passbook/providers/app_gw/api.py @@ -1,17 +1,17 @@ -"""ApplicationGatewayOutlet API Views""" +"""ApplicationGatewayProvider API Views""" from oauth2_provider.generators import generate_client_id, generate_client_secret from oidc_provider.models import Client from rest_framework.serializers import ModelSerializer from rest_framework.viewsets import ModelViewSet -from passbook.channels.out_app_gw.models import ApplicationGatewayOutlet -from passbook.channels.out_oidc.api import OpenIDOutletSerializer +from passbook.providers.app_gw.models import ApplicationGatewayProvider +from passbook.providers.oidc.api import OpenIDProviderSerializer -class ApplicationGatewayOutletSerializer(ModelSerializer): - """ApplicationGatewayOutlet Serializer""" +class ApplicationGatewayProviderSerializer(ModelSerializer): + """ApplicationGatewayProvider Serializer""" - client = OpenIDOutletSerializer() + client = OpenIDProviderSerializer() def create(self, validated_data): instance = super().create(validated_data) @@ -33,13 +33,13 @@ class ApplicationGatewayOutletSerializer(ModelSerializer): class Meta: - model = ApplicationGatewayOutlet + model = ApplicationGatewayProvider fields = ["pk", "name", "internal_host", "external_host", "client"] read_only_fields = ["client"] -class ApplicationGatewayOutletViewSet(ModelViewSet): - """ApplicationGatewayOutlet Viewset""" +class ApplicationGatewayProviderViewSet(ModelViewSet): + """ApplicationGatewayProvider Viewset""" - queryset = ApplicationGatewayOutlet.objects.all() - serializer_class = ApplicationGatewayOutletSerializer + queryset = ApplicationGatewayProvider.objects.all() + serializer_class = ApplicationGatewayProviderSerializer diff --git a/passbook/channels/out_app_gw/apps.py b/passbook/providers/app_gw/apps.py similarity index 58% rename from passbook/channels/out_app_gw/apps.py rename to passbook/providers/app_gw/apps.py index 0b760da89..a1702dcf9 100644 --- a/passbook/channels/out_app_gw/apps.py +++ b/passbook/providers/app_gw/apps.py @@ -5,7 +5,7 @@ from django.apps import AppConfig class PassbookApplicationApplicationGatewayConfig(AppConfig): """passbook app_gw app""" - name = "passbook.channels.out_app_gw" - label = "passbook_channels_out_app_gw" - verbose_name = "passbook Outlets.Application Security Gateway" + name = "passbook.providers.app_gw" + label = "passbook_providers_app_gw" + verbose_name = "passbook Providers.Application Security Gateway" mountpoint = "application/gateway/" diff --git a/passbook/channels/out_app_gw/forms.py b/passbook/providers/app_gw/forms.py similarity index 86% rename from passbook/channels/out_app_gw/forms.py rename to passbook/providers/app_gw/forms.py index c35db6fe4..ad4c7fc60 100644 --- a/passbook/channels/out_app_gw/forms.py +++ b/passbook/providers/app_gw/forms.py @@ -3,11 +3,11 @@ from django import forms from oauth2_provider.generators import generate_client_id, generate_client_secret from oidc_provider.models import Client, ResponseType -from passbook.channels.out_app_gw.models import ApplicationGatewayOutlet +from passbook.providers.app_gw.models import ApplicationGatewayProvider -class ApplicationGatewayOutletForm(forms.ModelForm): - """Security Gateway Outlet form""" +class ApplicationGatewayProviderForm(forms.ModelForm): + """Security Gateway Provider form""" def save(self, *args, **kwargs): if not self.instance.pk: @@ -31,7 +31,7 @@ class ApplicationGatewayOutletForm(forms.ModelForm): class Meta: - model = ApplicationGatewayOutlet + model = ApplicationGatewayProvider fields = ["name", "internal_host", "external_host"] widgets = { "name": forms.TextInput(), diff --git a/passbook/providers/app_gw/migrations/0001_initial.py b/passbook/providers/app_gw/migrations/0001_initial.py new file mode 100644 index 000000000..4fb55e41c --- /dev/null +++ b/passbook/providers/app_gw/migrations/0001_initial.py @@ -0,0 +1,99 @@ +# Generated by Django 2.2.6 on 2019-10-07 14:07 + +import django.contrib.postgres.fields +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ("passbook_core", "0001_initial"), + ] + + operations = [ + migrations.CreateModel( + name="ApplicationGatewayProvider", + fields=[ + ( + "provider_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="passbook_core.Provider", + ), + ), + ( + "server_name", + django.contrib.postgres.fields.ArrayField( + base_field=models.TextField(), size=None + ), + ), + ( + "upstream", + django.contrib.postgres.fields.ArrayField( + base_field=models.TextField(), size=None + ), + ), + ("enabled", models.BooleanField(default=True)), + ( + "authentication_header", + models.TextField(blank=True, default="X-Remote-User"), + ), + ( + "default_content_type", + models.TextField(default="application/octet-stream"), + ), + ("upstream_ssl_verification", models.BooleanField(default=True)), + ], + options={ + "verbose_name": "Application Gateway Provider", + "verbose_name_plural": "Application Gateway Providers", + }, + bases=("passbook_core.provider",), + ), + migrations.CreateModel( + name="RewriteRule", + fields=[ + ( + "propertymapping_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="passbook_core.PropertyMapping", + ), + ), + ("match", models.TextField()), + ("halt", models.BooleanField(default=False)), + ("replacement", models.TextField()), + ( + "redirect", + models.CharField( + choices=[ + ("internal", "Internal"), + (301, "Moved Permanently"), + (302, "Found"), + ], + max_length=50, + ), + ), + ( + "conditions", + models.ManyToManyField(blank=True, to="passbook_core.Policy"), + ), + ], + options={ + "verbose_name": "Rewrite Rule", + "verbose_name_plural": "Rewrite Rules", + }, + bases=("passbook_core.propertymapping",), + ), + ] diff --git a/passbook/providers/app_gw/migrations/0002_auto_20191111_1703.py b/passbook/providers/app_gw/migrations/0002_auto_20191111_1703.py new file mode 100644 index 000000000..2e2912336 --- /dev/null +++ b/passbook/providers/app_gw/migrations/0002_auto_20191111_1703.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.7 on 2019-11-11 17:03 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("passbook_core", "0005_merge_20191025_2022"), + ("passbook_providers_app_gw", "0001_initial"), + ] + + operations = [ + migrations.RemoveField(model_name="rewriterule", name="conditions",), + migrations.RemoveField(model_name="rewriterule", name="propertymapping_ptr",), + migrations.DeleteModel(name="ApplicationGatewayProvider",), + migrations.DeleteModel(name="RewriteRule",), + ] diff --git a/passbook/channels/out_app_gw/migrations/0001_initial.py b/passbook/providers/app_gw/migrations/0003_applicationgatewayprovider.py similarity index 65% rename from passbook/channels/out_app_gw/migrations/0001_initial.py rename to passbook/providers/app_gw/migrations/0003_applicationgatewayprovider.py index b82637e44..36747a09c 100644 --- a/passbook/channels/out_app_gw/migrations/0001_initial.py +++ b/passbook/providers/app_gw/migrations/0003_applicationgatewayprovider.py @@ -1,4 +1,4 @@ -# Generated by Django 3.0.5 on 2020-05-15 19:59 +# Generated by Django 2.2.7 on 2019-11-11 17:08 import django.db.models.deletion from django.db import migrations, models @@ -9,28 +9,28 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ("passbook_core", "__first__"), + ("passbook_core", "0005_merge_20191025_2022"), ("oidc_provider", "0026_client_multiple_response_types"), + ("passbook_providers_app_gw", "0002_auto_20191111_1703"), ] operations = [ migrations.CreateModel( - name="ApplicationGatewayOutlet", + name="ApplicationGatewayProvider", fields=[ ( - "outlet_ptr", + "provider_ptr", models.OneToOneField( auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, - to="passbook_core.Outlet", + to="passbook_core.Provider", ), ), ("name", models.TextField()), - ("internal_host", models.TextField()), - ("external_host", models.TextField()), + ("host", models.TextField()), ( "client", models.ForeignKey( @@ -40,9 +40,9 @@ class Migration(migrations.Migration): ), ], options={ - "verbose_name": "Application Gateway Outlet", - "verbose_name_plural": "Application Gateway Outlets", + "verbose_name": "Application Gateway Provider", + "verbose_name_plural": "Application Gateway Providers", }, - bases=("passbook_core.outlet",), + bases=("passbook_core.provider",), ), ] diff --git a/passbook/providers/app_gw/migrations/0004_auto_20200102_1505.py b/passbook/providers/app_gw/migrations/0004_auto_20200102_1505.py new file mode 100644 index 000000000..2eb2d959f --- /dev/null +++ b/passbook/providers/app_gw/migrations/0004_auto_20200102_1505.py @@ -0,0 +1,24 @@ +# Generated by Django 2.2.9 on 2020-01-02 15:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("passbook_providers_app_gw", "0003_applicationgatewayprovider"), + ] + + operations = [ + migrations.RenameField( + model_name="applicationgatewayprovider", + old_name="host", + new_name="external_host", + ), + migrations.AddField( + model_name="applicationgatewayprovider", + name="internal_host", + field=models.TextField(default=""), + preserve_default=False, + ), + ] diff --git a/passbook/channels/in_ldap/migrations/__init__.py b/passbook/providers/app_gw/migrations/__init__.py similarity index 100% rename from passbook/channels/in_ldap/migrations/__init__.py rename to passbook/providers/app_gw/migrations/__init__.py diff --git a/passbook/channels/out_app_gw/models.py b/passbook/providers/app_gw/models.py similarity index 69% rename from passbook/channels/out_app_gw/models.py rename to passbook/providers/app_gw/models.py index ff049bfd1..664c75f8b 100644 --- a/passbook/channels/out_app_gw/models.py +++ b/passbook/providers/app_gw/models.py @@ -9,12 +9,12 @@ from django.utils.translation import gettext as _ from oidc_provider.models import Client from passbook import __version__ -from passbook.core.models import Outlet +from passbook.core.models import Provider from passbook.lib.utils.template import render_to_string -class ApplicationGatewayOutlet(Outlet): - """This outlet uses oauth2_proxy with the OIDC Outlet.""" +class ApplicationGatewayProvider(Provider): + """This provider uses oauth2_proxy with the OIDC Provider.""" name = models.TextField() internal_host = models.TextField() @@ -22,7 +22,7 @@ class ApplicationGatewayOutlet(Outlet): client = models.ForeignKey(Client, on_delete=models.CASCADE) - form = "passbook.channels.out_app_gw.forms.ApplicationGatewayOutletForm" + form = "passbook.providers.app_gw.forms.ApplicationGatewayProviderForm" def html_setup_urls(self, request: HttpRequest) -> Optional[str]: """return template and context modal with URLs for authorize, token, openid-config, etc""" @@ -32,7 +32,7 @@ class ApplicationGatewayOutlet(Outlet): ) return render_to_string( "app_gw/setup_modal.html", - {"outlet": self, "cookie_secret": cookie_secret, "version": __version__}, + {"provider": self, "cookie_secret": cookie_secret, "version": __version__}, ) def __str__(self): @@ -40,5 +40,5 @@ class ApplicationGatewayOutlet(Outlet): class Meta: - verbose_name = _("Application Gateway Outlet") - verbose_name_plural = _("Application Gateway Outlets") + verbose_name = _("Application Gateway Provider") + verbose_name_plural = _("Application Gateway Providers") diff --git a/passbook/channels/in_oauth/__init__.py b/passbook/providers/app_gw/provider/__init__.py similarity index 100% rename from passbook/channels/in_oauth/__init__.py rename to passbook/providers/app_gw/provider/__init__.py diff --git a/passbook/channels/in_oauth/migrations/__init__.py b/passbook/providers/app_gw/provider/kubernetes/__init__.py similarity index 100% rename from passbook/channels/in_oauth/migrations/__init__.py rename to passbook/providers/app_gw/provider/kubernetes/__init__.py diff --git a/passbook/channels/out_app_gw/templates/app_gw/docker-compose.yml b/passbook/providers/app_gw/templates/app_gw/docker-compose.yml similarity index 100% rename from passbook/channels/out_app_gw/templates/app_gw/docker-compose.yml rename to passbook/providers/app_gw/templates/app_gw/docker-compose.yml diff --git a/passbook/channels/out_app_gw/templates/app_gw/k8s-manifest.yaml b/passbook/providers/app_gw/templates/app_gw/k8s-manifest.yaml similarity index 100% rename from passbook/channels/out_app_gw/templates/app_gw/k8s-manifest.yaml rename to passbook/providers/app_gw/templates/app_gw/k8s-manifest.yaml diff --git a/passbook/channels/out_app_gw/templates/app_gw/setup_modal.html b/passbook/providers/app_gw/templates/app_gw/setup_modal.html similarity index 96% rename from passbook/channels/out_app_gw/templates/app_gw/setup_modal.html rename to passbook/providers/app_gw/templates/app_gw/setup_modal.html index 4b5605f06..db8000332 100644 --- a/passbook/channels/out_app_gw/templates/app_gw/setup_modal.html +++ b/passbook/providers/app_gw/templates/app_gw/setup_modal.html @@ -42,7 +42,7 @@

    {% trans 'Setup with Kubernetes' %}

    {% trans 'Download the manifest to create the Gatekeeper deployment and service:' %}

    - {% trans 'Here' %} + {% trans 'Here' %}

    {% trans 'Afterwards, add the following annotations to the Ingress you want to secure:' %}