core: create FlowToken instead of regular token for generated recovery links (#3193)

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

#2749
This commit is contained in:
Jens L 2022-07-02 14:17:41 +02:00 committed by GitHub
parent a9636b5727
commit c39a5933e1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 150 additions and 59 deletions

View file

@ -63,6 +63,9 @@ from authentik.core.models import (
User,
)
from authentik.events.models import EventAction
from authentik.flows.models import FlowToken
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlanner
from authentik.flows.views.executor import QS_KEY_TOKEN
from authentik.stages.email.models import EmailStage
from authentik.stages.email.tasks import send_mails
from authentik.stages.email.utils import TemplateEmailMessage
@ -294,12 +297,23 @@ class UserViewSet(UsedByMixin, ModelViewSet):
LOGGER.debug("No recovery flow set")
return None, None
user: User = self.get_object()
token, __ = Token.objects.get_or_create(
identifier=f"{user.uid}-password-reset",
user=user,
intent=TokenIntents.INTENT_RECOVERY,
planner = FlowPlanner(flow)
planner.allow_empty_flows = True
plan = planner.plan(
self.request._request,
{
PLAN_CONTEXT_PENDING_USER: user,
},
)
querystring = urlencode({"token": token.key})
token, __ = FlowToken.objects.update_or_create(
identifier=f"{user.uid}-password-reset",
defaults={
"user": user,
"flow": flow,
"_plan": FlowToken.pickle(plan),
},
)
querystring = urlencode({QS_KEY_TOKEN: token.key})
link = self.request.build_absolute_uri(
reverse_lazy("authentik_core:if-flow", kwargs={"flow_slug": flow.slug})
+ f"?{querystring}"

View file

@ -16,6 +16,7 @@ from authentik.core.models import AuthenticatedSession, User
from authentik.events.models import Event, EventAction, Notification
from authentik.events.signals import EventNewThread
from authentik.events.utils import model_to_dict
from authentik.flows.models import FlowToken
from authentik.lib.sentry import before_send
from authentik.lib.utils.errors import exception_to_string
@ -26,6 +27,7 @@ IGNORED_MODELS = [
AuthenticatedSession,
StaticToken,
Session,
FlowToken,
]
if settings.DEBUG:
from silk.models import Request, Response, SQLQuery

View file

@ -27,6 +27,7 @@ def get_attrs(obj: SerializerModel) -> dict[str, Any]:
"promptstage_set",
"policybindingmodel_ptr_id",
"export_url",
"meta_model_name",
)
for to_remove_name in to_remove:
if to_remove_name in data:

View file

@ -138,12 +138,11 @@ class FlowExecutorView(APIView):
message = exc.__doc__ if exc.__doc__ else str(exc)
return self.stage_invalid(error_message=message)
def _check_flow_token(self, get_params: QueryDict):
def _check_flow_token(self, key: str) -> Optional[FlowPlan]:
"""Check if the user is using a flow token to restore a plan"""
tokens = FlowToken.filter_not_expired(key=get_params[QS_KEY_TOKEN])
if not tokens.exists():
return False
token: FlowToken = tokens.first()
token: Optional[FlowToken] = FlowToken.filter_not_expired(key=key).first()
if not token:
return None
try:
plan = token.plan
except (AttributeError, EOFError, ImportError, IndexError) as exc:
@ -164,7 +163,7 @@ class FlowExecutorView(APIView):
span.set_data("authentik Flow", self.flow.slug)
get_params = QueryDict(request.GET.get("query", ""))
if QS_KEY_TOKEN in get_params:
plan = self._check_flow_token(get_params)
plan = self._check_flow_token(get_params[QS_KEY_TOKEN])
if plan:
self.request.session[SESSION_KEY_PLAN] = plan
# Early check if there's an active Plan for the current session

View file

@ -122,6 +122,7 @@ class Migration(migrations.Migration):
default=list,
help_text="Specify which sources should be shown.",
to="authentik_core.Source",
blank=True,
),
),
migrations.RunPython(

View file

@ -87,7 +87,7 @@ class IdentificationStage(Stage):
)
sources = models.ManyToManyField(
Source, default=list, help_text=_("Specify which sources should be shown.")
Source, default=list, help_text=_("Specify which sources should be shown."), blank=True
)
show_source_labels = models.BooleanField(default=False)

View file

@ -10,21 +10,11 @@
"attrs": {
"name": "Default recovery flow",
"title": "Reset your password",
"designation": "recovery"
}
},
{
"identifiers": {
"pk": "1ff91927-e33d-4615-95b0-c258e5f0df62"
},
"model": "authentik_stages_prompt.prompt",
"attrs": {
"field_key": "email",
"label": "Email",
"type": "email",
"required": true,
"placeholder": "Email",
"order": 1
"designation": "recovery",
"cache_count": 0,
"policy_engine_mode": "any",
"compatibility_mode": false,
"layout": "stacked"
}
},
{
@ -38,7 +28,9 @@
"type": "password",
"required": true,
"placeholder": "Password",
"order": 0
"order": 0,
"sub_text": "",
"placeholder_expression": false
}
},
{
@ -52,33 +44,38 @@
"type": "password",
"required": true,
"placeholder": "Password (repeat)",
"order": 1
"order": 1,
"sub_text": "",
"placeholder_expression": false
}
},
{
"identifiers": {
"pk": "e54045a7-6ecb-4ad9-ad37-28e72d8e565e",
"name": "default-recovery-identification"
"pk": "1c5709ae-1b3e-413a-a117-260ab509bf5c"
},
"model": "authentik_stages_identification.identificationstage",
"model": "authentik_policies_expression.expressionpolicy",
"attrs": {
"user_fields": ["email", "username"],
"template": "stages/identification/recovery.html",
"enrollment_flow": null,
"recovery_flow": null
"name": "default-recovery-skip-if-restored",
"execution_logging": false,
"bound_to": 2,
"expression": "return request.context.get('is_restored', False)"
}
},
{
"identifiers": {
"pk": "3909fd60-b013-4668-8806-12e9507dab97",
"name": "default-recovery-user-write"
"pk": "1c5709ae-1b3e-413a-a117-260ab509bf5c"
},
"model": "authentik_stages_user_write.userwritestage",
"attrs": {}
"model": "authentik_policies_expression.expressionpolicy",
"attrs": {
"name": "default-recovery-skip-if-restored",
"execution_logging": false,
"bound_to": 2,
"expression": "return request.context.get('is_restored', False)"
}
},
{
"identifiers": {
"pk": "66f948dc-3f74-42b2-b26b-b8b9df109efb",
"pk": "4ac5719f-32c0-441c-8a7e-33c5ea0db7da",
"name": "default-recovery-email"
},
"model": "authentik_stages_email.emailstage",
@ -99,20 +96,40 @@
},
{
"identifiers": {
"pk": "975d5502-1e22-4d10-b560-fbc5bd70ff4d",
"name": "Change your password"
"pk": "68b25ad5-318a-496e-95a7-cf4d94247f0d",
"name": "default-recovery-user-write"
},
"model": "authentik_stages_prompt.promptstage",
"model": "authentik_stages_user_write.userwritestage",
"attrs": {
"fields": [
"7db91ee8-4290-4e08-8d39-63f132402515",
"d30b5eb4-7787-4072-b1ba-65b46e928920"
]
"create_users_as_inactive": false,
"create_users_group": null,
"user_path_template": ""
}
},
{
"identifiers": {
"pk": "fcdd4206-0d35-4ad2-a59f-5a72422936bb",
"pk": "94843ef6-28fe-4939-bd61-cd46bb34f1de",
"name": "default-recovery-identification"
},
"model": "authentik_stages_identification.identificationstage",
"attrs": {
"user_fields": [
"email",
"username"
],
"password_stage": null,
"case_insensitive_matching": true,
"show_matched_user": true,
"enrollment_flow": null,
"recovery_flow": null,
"passwordless_flow": null,
"sources": [],
"show_source_labels": false
}
},
{
"identifiers": {
"pk": "e74230b2-82bc-4843-8b18-2c3a66a62d57",
"name": "default-recovery-user-login"
},
"model": "authentik_stages_user_login.userloginstage",
@ -120,64 +137,121 @@
"session_duration": "seconds=0"
}
},
{
"identifiers": {
"pk": "fa2d8d65-1809-4dcc-bdc0-56266e0f7971",
"name": "Change your password"
},
"model": "authentik_stages_prompt.promptstage",
"attrs": {
"fields": [
"7db91ee8-4290-4e08-8d39-63f132402515",
"d30b5eb4-7787-4072-b1ba-65b46e928920"
],
"validation_policies": []
}
},
{
"identifiers": {
"pk": "7af7558e-2196-4b9f-a08e-d38420b7cfbb",
"target": "a5993183-89c0-43d2-a7f4-ddffb17baba7",
"stage": "e54045a7-6ecb-4ad9-ad37-28e72d8e565e",
"stage": "94843ef6-28fe-4939-bd61-cd46bb34f1de",
"order": 10
},
"model": "authentik_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
"evaluate_on_plan": true,
"re_evaluate_policies": true,
"policy_engine_mode": "any",
"invalid_response_action": "retry"
}
},
{
"identifiers": {
"pk": "29446fd6-dd93-4e92-9830-2d81debad5ae",
"target": "a5993183-89c0-43d2-a7f4-ddffb17baba7",
"stage": "66f948dc-3f74-42b2-b26b-b8b9df109efb",
"stage": "4ac5719f-32c0-441c-8a7e-33c5ea0db7da",
"order": 20
},
"model": "authentik_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
"evaluate_on_plan": true,
"re_evaluate_policies": true,
"policy_engine_mode": "any",
"invalid_response_action": "retry"
}
},
{
"identifiers": {
"pk": "1219d06e-2c06-4c5b-a162-78e3959c6cf0",
"target": "a5993183-89c0-43d2-a7f4-ddffb17baba7",
"stage": "975d5502-1e22-4d10-b560-fbc5bd70ff4d",
"stage": "fa2d8d65-1809-4dcc-bdc0-56266e0f7971",
"order": 30
},
"model": "authentik_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
"evaluate_on_plan": true,
"re_evaluate_policies": false,
"policy_engine_mode": "any",
"invalid_response_action": "retry"
}
},
{
"identifiers": {
"pk": "66de86ba-0707-46a0-8475-ff2e260d6935",
"target": "a5993183-89c0-43d2-a7f4-ddffb17baba7",
"stage": "3909fd60-b013-4668-8806-12e9507dab97",
"stage": "68b25ad5-318a-496e-95a7-cf4d94247f0d",
"order": 40
},
"model": "authentik_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
"evaluate_on_plan": true,
"re_evaluate_policies": false,
"policy_engine_mode": "any",
"invalid_response_action": "retry"
}
},
{
"identifiers": {
"pk": "9cec2334-d4a2-4895-a2b2-bc5ae4e9639a",
"target": "a5993183-89c0-43d2-a7f4-ddffb17baba7",
"stage": "fcdd4206-0d35-4ad2-a59f-5a72422936bb",
"stage": "e74230b2-82bc-4843-8b18-2c3a66a62d57",
"order": 100
},
"model": "authentik_flows.flowstagebinding",
"attrs": {
"re_evaluate_policies": false
"evaluate_on_plan": true,
"re_evaluate_policies": false,
"policy_engine_mode": "any",
"invalid_response_action": "retry"
}
},
{
"identifiers": {
"pk": "95aad215-8729-4177-953d-41ffbe86239e",
"policy": "1c5709ae-1b3e-413a-a117-260ab509bf5c",
"target": "7af7558e-2196-4b9f-a08e-d38420b7cfbb",
"order": 0
},
"model": "authentik_policies.policybinding",
"attrs": {
"negate": false,
"enabled": true,
"timeout": 30
}
},
{
"identifiers": {
"pk": "a5454cbc-d2e4-403a-84af-6af999990b12",
"policy": "1c5709ae-1b3e-413a-a117-260ab509bf5c",
"target": "29446fd6-dd93-4e92-9830-2d81debad5ae",
"order": 0
},
"model": "authentik_policies.policybinding",
"attrs": {
"negate": false,
"enabled": true,
"timeout": 30
}
}
]