flows: update migrations to use update_or_create
This commit is contained in:
		| @ -20,42 +20,38 @@ def create_default_authentication_flow( | ||||
|     ) | ||||
|     db_alias = schema_editor.connection.alias | ||||
|  | ||||
|     if ( | ||||
|         Flow.objects.using(db_alias) | ||||
|         .filter(designation=FlowDesignation.AUTHENTICATION) | ||||
|         .exists() | ||||
|     ): | ||||
|         # Only create default flow when none exist | ||||
|         return | ||||
|     identification_stage, _ = IdentificationStage.objects.using( | ||||
|         db_alias | ||||
|     ).update_or_create( | ||||
|         name="default-authentication-identification", | ||||
|         defaults={ | ||||
|             "user_fields": [UserFields.E_MAIL, UserFields.USERNAME], | ||||
|             "template": Templates.DEFAULT_LOGIN, | ||||
|         }, | ||||
|     ) | ||||
|  | ||||
|     if not IdentificationStage.objects.using(db_alias).exists(): | ||||
|         IdentificationStage.objects.using(db_alias).create( | ||||
|             name="identification", | ||||
|             user_fields=[UserFields.E_MAIL, UserFields.USERNAME], | ||||
|             template=Templates.DEFAULT_LOGIN, | ||||
|         ) | ||||
|     password_stage, _ = PasswordStage.objects.using(db_alias).update_or_create( | ||||
|         name="default-authentication-password", | ||||
|         defaults={"backends": ["django.contrib.auth.backends.ModelBackend"]}, | ||||
|     ) | ||||
|  | ||||
|     if not PasswordStage.objects.using(db_alias).exists(): | ||||
|         PasswordStage.objects.using(db_alias).create( | ||||
|             name="password", backends=["django.contrib.auth.backends.ModelBackend"], | ||||
|         ) | ||||
|     login_stage, _ = UserLoginStage.objects.using(db_alias).update_or_create( | ||||
|         name="default-authentication-login" | ||||
|     ) | ||||
|  | ||||
|     if not UserLoginStage.objects.using(db_alias).exists(): | ||||
|         UserLoginStage.objects.using(db_alias).create(name="authentication") | ||||
|  | ||||
|     flow = Flow.objects.using(db_alias).create( | ||||
|         name="Welcome to passbook!", | ||||
|     flow, _ = Flow.objects.using(db_alias).update_or_create( | ||||
|         slug="default-authentication-flow", | ||||
|         designation=FlowDesignation.AUTHENTICATION, | ||||
|         defaults={"name": "Welcome to passbook!",}, | ||||
|     ) | ||||
|     FlowStageBinding.objects.using(db_alias).create( | ||||
|         flow=flow, stage=IdentificationStage.objects.using(db_alias).first(), order=0, | ||||
|     FlowStageBinding.objects.using(db_alias).update_or_create( | ||||
|         flow=flow, stage=identification_stage, defaults={"order": 0,}, | ||||
|     ) | ||||
|     FlowStageBinding.objects.using(db_alias).create( | ||||
|         flow=flow, stage=PasswordStage.objects.using(db_alias).first(), order=1, | ||||
|     FlowStageBinding.objects.using(db_alias).update_or_create( | ||||
|         flow=flow, stage=password_stage, defaults={"order": 1,}, | ||||
|     ) | ||||
|     FlowStageBinding.objects.using(db_alias).create( | ||||
|         flow=flow, stage=UserLoginStage.objects.using(db_alias).first(), order=2, | ||||
|     FlowStageBinding.objects.using(db_alias).update_or_create( | ||||
|         flow=flow, stage=login_stage, defaults={"order": 2,}, | ||||
|     ) | ||||
|  | ||||
|  | ||||
| @ -67,24 +63,19 @@ def create_default_invalidation_flow( | ||||
|     UserLogoutStage = apps.get_model("passbook_stages_user_logout", "UserLogoutStage") | ||||
|     db_alias = schema_editor.connection.alias | ||||
|  | ||||
|     if ( | ||||
|         Flow.objects.using(db_alias) | ||||
|         .filter(designation=FlowDesignation.INVALIDATION) | ||||
|         .exists() | ||||
|     ): | ||||
|         # Only create default flow when none exist | ||||
|         return | ||||
|     UserLogoutStage.objects.using(db_alias).update_or_create( | ||||
|         name="default-invalidation-logout" | ||||
|     ) | ||||
|  | ||||
|     if not UserLogoutStage.objects.using(db_alias).exists(): | ||||
|         UserLogoutStage.objects.using(db_alias).create(name="logout") | ||||
|  | ||||
|     flow = Flow.objects.using(db_alias).create( | ||||
|         name="default-invalidation-flow", | ||||
|     flow, _ = Flow.objects.using(db_alias).update_or_create( | ||||
|         slug="default-invalidation-flow", | ||||
|         designation=FlowDesignation.INVALIDATION, | ||||
|         defaults={"name": "Logout",}, | ||||
|     ) | ||||
|     FlowStageBinding.objects.using(db_alias).create( | ||||
|         flow=flow, stage=UserLogoutStage.objects.using(db_alias).first(), order=0, | ||||
|     FlowStageBinding.objects.using(db_alias).update_or_create( | ||||
|         flow=flow, | ||||
|         stage=UserLogoutStage.objects.using(db_alias).first(), | ||||
|         defaults={"order": 0,}, | ||||
|     ) | ||||
|  | ||||
|  | ||||
|  | ||||
| @ -34,60 +34,63 @@ def create_default_source_enrollment_flow( | ||||
|     db_alias = schema_editor.connection.alias | ||||
|  | ||||
|     # Create a policy that only allows this flow when doing an SSO Request | ||||
|     flow_policy = ExpressionPolicy.objects.using(db_alias).create( | ||||
|         name="default-source-enrollment-if-sso", expression=FLOW_POLICY_EXPRESSION | ||||
|     flow_policy, _ = ExpressionPolicy.objects.using(db_alias).update_or_create( | ||||
|         name="default-source-enrollment-if-sso", | ||||
|         defaults={"expression": FLOW_POLICY_EXPRESSION}, | ||||
|     ) | ||||
|  | ||||
|     # This creates a Flow used by sources to enroll users | ||||
|     # It makes sure that a username is set, and if not, prompts the user for a Username | ||||
|     flow = Flow.objects.using(db_alias).create( | ||||
|         name="default-source-enrollment", | ||||
|     flow, _ = Flow.objects.using(db_alias).update_or_create( | ||||
|         slug="default-source-enrollment", | ||||
|         designation=FlowDesignation.ENROLLMENT, | ||||
|         defaults={"name": "Welcome to passbook!",}, | ||||
|     ) | ||||
|     PolicyBinding.objects.using(db_alias).create( | ||||
|         policy=flow_policy, target=flow, order=0 | ||||
|     PolicyBinding.objects.using(db_alias).update_or_create( | ||||
|         policy=flow_policy, target=flow, defaults={"order": 0} | ||||
|     ) | ||||
|  | ||||
|     # PromptStage to ask user for their username | ||||
|     prompt_stage = PromptStage.objects.using(db_alias).create( | ||||
|     prompt_stage, _ = PromptStage.objects.using(db_alias).update_or_create( | ||||
|         name="default-source-enrollment-username-prompt", | ||||
|     ) | ||||
|     prompt_stage.fields.add( | ||||
|         Prompt.objects.using(db_alias).create( | ||||
|             field_key="username", | ||||
|             label="Username", | ||||
|             type=FieldTypes.TEXT, | ||||
|             required=True, | ||||
|             placeholder="Username", | ||||
|         ) | ||||
|     prompt, _ = Prompt.objects.using(db_alias).update_or_create( | ||||
|         field_key="username", | ||||
|         defaults={ | ||||
|             "label": "Username", | ||||
|             "type": FieldTypes.TEXT, | ||||
|             "required": True, | ||||
|             "placeholder": "Username", | ||||
|         }, | ||||
|     ) | ||||
|     prompt_stage.fields.add(prompt) | ||||
|  | ||||
|     # Policy to only trigger prompt when no username is given | ||||
|     prompt_policy = ExpressionPolicy.objects.using(db_alias).create( | ||||
|     prompt_policy, _ = ExpressionPolicy.objects.using(db_alias).update_or_create( | ||||
|         name="default-source-enrollment-if-username", | ||||
|         expression=PROMPT_POLICY_EXPRESSION, | ||||
|         defaults={"expression": PROMPT_POLICY_EXPRESSION}, | ||||
|     ) | ||||
|  | ||||
|     # UserWrite stage to create the user, and login stage to log user in | ||||
|     user_write = UserWriteStage.objects.using(db_alias).create( | ||||
|     user_write, _ = UserWriteStage.objects.using(db_alias).update_or_create( | ||||
|         name="default-source-enrollment-write" | ||||
|     ) | ||||
|     user_login = UserLoginStage.objects.using(db_alias).create( | ||||
|     user_login, _ = UserLoginStage.objects.using(db_alias).update_or_create( | ||||
|         name="default-source-enrollment-login" | ||||
|     ) | ||||
|  | ||||
|     binding = FlowStageBinding.objects.using(db_alias).create( | ||||
|         flow=flow, stage=prompt_stage, order=0 | ||||
|     binding, _ = FlowStageBinding.objects.using(db_alias).update_or_create( | ||||
|         flow=flow, stage=prompt_stage, defaults={"order": 0} | ||||
|     ) | ||||
|     PolicyBinding.objects.using(db_alias).create( | ||||
|         policy=prompt_policy, target=binding, order=0 | ||||
|     PolicyBinding.objects.using(db_alias).update_or_create( | ||||
|         policy=prompt_policy, target=binding, defaults={"order": 0} | ||||
|     ) | ||||
|  | ||||
|     FlowStageBinding.objects.using(db_alias).create( | ||||
|         flow=flow, stage=user_write, order=1 | ||||
|     FlowStageBinding.objects.using(db_alias).update_or_create( | ||||
|         flow=flow, stage=user_write, defaults={"order": 1} | ||||
|     ) | ||||
|     FlowStageBinding.objects.using(db_alias).create( | ||||
|         flow=flow, stage=user_login, order=2 | ||||
|     FlowStageBinding.objects.using(db_alias).update_or_create( | ||||
|         flow=flow, stage=user_login, defaults={"order": 2} | ||||
|     ) | ||||
|  | ||||
|  | ||||
| @ -107,25 +110,26 @@ def create_default_source_authentication_flow( | ||||
|     db_alias = schema_editor.connection.alias | ||||
|  | ||||
|     # Create a policy that only allows this flow when doing an SSO Request | ||||
|     flow_policy = ExpressionPolicy.objects.using(db_alias).create( | ||||
|         name="default-source-authentication-if-sso", expression=FLOW_POLICY_EXPRESSION | ||||
|     flow_policy, _ = ExpressionPolicy.objects.using(db_alias).update_or_create( | ||||
|         name="default-source-authentication-if-sso", | ||||
|         defaults={"expression": FLOW_POLICY_EXPRESSION,}, | ||||
|     ) | ||||
|  | ||||
|     # This creates a Flow used by sources to authenticate users | ||||
|     flow = Flow.objects.using(db_alias).create( | ||||
|         name="default-source-authentication", | ||||
|     flow, _ = Flow.objects.using(db_alias).update_or_create( | ||||
|         slug="default-source-authentication", | ||||
|         designation=FlowDesignation.AUTHENTICATION, | ||||
|         defaults={"name": "Welcome to passbook!",}, | ||||
|     ) | ||||
|     PolicyBinding.objects.using(db_alias).create( | ||||
|         policy=flow_policy, target=flow, order=0 | ||||
|     PolicyBinding.objects.using(db_alias).update_or_create( | ||||
|         policy=flow_policy, target=flow, defaults={"order": 0} | ||||
|     ) | ||||
|  | ||||
|     user_login = UserLoginStage.objects.using(db_alias).create( | ||||
|     user_login, _ = UserLoginStage.objects.using(db_alias).update_or_create( | ||||
|         name="default-source-authentication-login" | ||||
|     ) | ||||
|     FlowStageBinding.objects.using(db_alias).create( | ||||
|         flow=flow, stage=user_login, order=0 | ||||
|     FlowStageBinding.objects.using(db_alias).update_or_create( | ||||
|         flow=flow, stage=user_login, defaults={"order": 0} | ||||
|     ) | ||||
|  | ||||
|  | ||||
|  | ||||
| @ -7,7 +7,7 @@ from django.db.backends.base.schema import BaseDatabaseSchemaEditor | ||||
| from passbook.flows.models import FlowDesignation | ||||
|  | ||||
|  | ||||
| def create_default_provider_authz_flow( | ||||
| def create_default_provider_authorization_flow( | ||||
|     apps: Apps, schema_editor: BaseDatabaseSchemaEditor | ||||
| ): | ||||
|     Flow = apps.get_model("passbook_flows", "Flow") | ||||
| @ -18,22 +18,24 @@ def create_default_provider_authz_flow( | ||||
|     db_alias = schema_editor.connection.alias | ||||
|  | ||||
|     # Empty flow for providers where consent is implicitly given | ||||
|     Flow.objects.using(db_alias).create( | ||||
|         name="Authorize Application", | ||||
|     Flow.objects.using(db_alias).update_or_create( | ||||
|         slug="default-provider-authorization-implicit-consent", | ||||
|         designation=FlowDesignation.AUTHORIZATION, | ||||
|         defaults={"name": "Authorize Application"}, | ||||
|     ) | ||||
|  | ||||
|     # Flow with consent form to obtain explicit user consent | ||||
|     flow = Flow.objects.using(db_alias).create( | ||||
|         name="Authorize Application", | ||||
|     flow, _ = Flow.objects.using(db_alias).update_or_create( | ||||
|         slug="default-provider-authorization-explicit-consent", | ||||
|         designation=FlowDesignation.AUTHORIZATION, | ||||
|         defaults={"name": "Authorize Application"}, | ||||
|     ) | ||||
|     stage = ConsentStage.objects.using(db_alias).create( | ||||
|     stage, _ = ConsentStage.objects.using(db_alias).update_or_create( | ||||
|         name="default-provider-authorization-consent" | ||||
|     ) | ||||
|     FlowStageBinding.objects.using(db_alias).create(flow=flow, stage=stage, order=0) | ||||
|     FlowStageBinding.objects.using(db_alias).update_or_create( | ||||
|         flow=flow, stage=stage, defaults={"order": 0} | ||||
|     ) | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
| @ -43,4 +45,4 @@ class Migration(migrations.Migration): | ||||
|         ("passbook_stages_consent", "0001_initial"), | ||||
|     ] | ||||
|  | ||||
|     operations = [migrations.RunPython(create_default_provider_authz_flow)] | ||||
|     operations = [migrations.RunPython(create_default_provider_authorization_flow)] | ||||
|  | ||||
| @ -153,7 +153,7 @@ class Processor: | ||||
|         self, request: HttpRequest, flow: Flow, **kwargs | ||||
|     ) -> HttpResponse: | ||||
|         kwargs[PLAN_CONTEXT_SSO] = True | ||||
|         request.session[SESSION_KEY_PLAN] = FlowPlanner(flow).plan(request, kwargs,) | ||||
|         request.session[SESSION_KEY_PLAN] = FlowPlanner(flow).plan(request, kwargs) | ||||
|         return redirect_with_qs( | ||||
|             "passbook_flows:flow-executor-shell", request.GET, flow_slug=flow.slug, | ||||
|         ) | ||||
|  | ||||
| @ -5,6 +5,7 @@ from django.core.validators import validate_email | ||||
| from django.utils.translation import gettext_lazy as _ | ||||
| from structlog import get_logger | ||||
|  | ||||
| from passbook.flows.models import Flow, FlowDesignation | ||||
| from passbook.lib.utils.ui import human_list | ||||
| from passbook.stages.identification.models import IdentificationStage, UserFields | ||||
|  | ||||
| @ -14,6 +15,15 @@ LOGGER = get_logger() | ||||
| class IdentificationStageForm(forms.ModelForm): | ||||
|     """Form to create/edit IdentificationStage instances""" | ||||
|  | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         super().__init__(*args, **kwargs) | ||||
|         self.fields["enrollment_flow"].queryset = Flow.objects.filter( | ||||
|             designation=FlowDesignation.ENROLLMENT | ||||
|         ) | ||||
|         self.fields["recovery_flow"].queryset = Flow.objects.filter( | ||||
|             designation=FlowDesignation.RECOVERY | ||||
|         ) | ||||
|  | ||||
|     class Meta: | ||||
|  | ||||
|         model = IdentificationStage | ||||
|  | ||||
| @ -1,5 +1,7 @@ | ||||
| """Prompt forms""" | ||||
| from django import forms | ||||
| from django.contrib.admin.widgets import FilteredSelectMultiple | ||||
| from django.utils.translation import gettext_lazy as _ | ||||
| from guardian.shortcuts import get_anonymous_user | ||||
|  | ||||
| from passbook.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlan | ||||
| @ -16,6 +18,7 @@ class PromptStageForm(forms.ModelForm): | ||||
|         fields = ["name", "fields"] | ||||
|         widgets = { | ||||
|             "name": forms.TextInput(), | ||||
|             "fields": FilteredSelectMultiple(_("prompts"), False), | ||||
|         } | ||||
|  | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Jens Langhammer
					Jens Langhammer