flows: update migrations to use update_or_create

This commit is contained in:
Jens Langhammer 2020-06-29 16:19:39 +02:00
parent b8654c06bf
commit ec823aebed
6 changed files with 97 additions and 87 deletions

View file

@ -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,},
)

View file

@ -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}
)

View file

@ -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)]

View file

@ -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,
)

View file

@ -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

View file

@ -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),
}