website/docs: flow context docs (#5243)

* add flow context docs

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* cleanup some redundant things

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* added more section headers

* tweaked new headings

* Apply suggestions from code review

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Jens L. <jens@beryju.org>

* add more keys, use dedicated prefix for internal keys

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* set toc_max_heading_level: 5

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* update datatypes

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* more consistent header

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* more fixes

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* Update website/docs/flow/context/index.md

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

* Update website/docs/flow/context/index.md

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

* Update website/docs/flow/context/index.md

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Signed-off-by: Jens L. <jens@beryju.org>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Tana Berry <tana@goauthentik.io>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
This commit is contained in:
Jens L 2023-04-20 20:31:34 +03:00 committed by GitHub
parent 948b83a2b2
commit e75e2cf324
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 179 additions and 25 deletions

View File

@ -68,7 +68,7 @@ from authentik.stages.consent.stage import (
LOGGER = get_logger() LOGGER = get_logger()
PLAN_CONTEXT_PARAMS = "params" PLAN_CONTEXT_PARAMS = "goauthentik.io/providers/oauth2/params"
SESSION_KEY_LAST_LOGIN_UID = "authentik/providers/oauth2/last_login_uid" SESSION_KEY_LAST_LOGIN_UID = "authentik/providers/oauth2/last_login_uid"
ALLOWED_PROMPT_PARAMS = {PROMPT_NONE, PROMPT_CONSENT, PROMPT_LOGIN} ALLOWED_PROMPT_PARAMS = {PROMPT_NONE, PROMPT_CONSENT, PROMPT_LOGIN}

View File

@ -8,7 +8,7 @@ from authentik.flows.stage import ChallengeStageView
from authentik.flows.views.executor import SESSION_KEY_PLAN from authentik.flows.views.executor import SESSION_KEY_PLAN
from authentik.providers.oauth2.models import DeviceToken from authentik.providers.oauth2.models import DeviceToken
PLAN_CONTEXT_DEVICE = "device" PLAN_CONTEXT_DEVICE = "goauthentik.io/providers/oauth2/device"
class OAuthDeviceCodeFinishChallenge(Challenge): class OAuthDeviceCodeFinishChallenge(Challenge):

View File

@ -29,9 +29,6 @@ from authentik.providers.oauth2.utils import cors_allow
LOGGER = get_logger() LOGGER = get_logger()
PLAN_CONTEXT_PARAMS = "params"
PLAN_CONTEXT_SCOPES = "scopes"
class ProviderInfoView(View): class ProviderInfoView(View):
"""OpenID-compliant Provider Info""" """OpenID-compliant Provider Info"""

View File

@ -40,11 +40,7 @@ from authentik.sources.saml.models import SAMLBindingTypes, SAMLSource
from authentik.sources.saml.processors.metadata import MetadataProcessor from authentik.sources.saml.processors.metadata import MetadataProcessor
from authentik.sources.saml.processors.request import RequestProcessor from authentik.sources.saml.processors.request import RequestProcessor
from authentik.sources.saml.processors.response import ResponseProcessor from authentik.sources.saml.processors.response import ResponseProcessor
from authentik.stages.consent.stage import ( from authentik.stages.consent.stage import PLAN_CONTEXT_CONSENT_HEADER, ConsentStageView
PLAN_CONTEXT_CONSENT_HEADER,
PLAN_CONTEXT_CONSENT_TITLE,
ConsentStageView,
)
LOGGER = get_logger() LOGGER = get_logger()
@ -128,7 +124,6 @@ class InitiateView(View):
injected_stages = [] injected_stages = []
plan_kwargs = { plan_kwargs = {
PLAN_CONTEXT_TITLE: f"Redirecting to {source.name}...", PLAN_CONTEXT_TITLE: f"Redirecting to {source.name}...",
PLAN_CONTEXT_CONSENT_TITLE: f"Redirecting to {source.name}...",
PLAN_CONTEXT_ATTRS: { PLAN_CONTEXT_ATTRS: {
"SAMLRequest": saml_request, "SAMLRequest": saml_request,
"RelayState": relay_state, "RelayState": relay_state,

View File

@ -33,7 +33,6 @@ from authentik.stages.authenticator_validate.models import AuthenticatorValidate
from authentik.stages.authenticator_webauthn.models import UserVerification, WebAuthnDevice from authentik.stages.authenticator_webauthn.models import UserVerification, WebAuthnDevice
from authentik.stages.authenticator_webauthn.stage import SESSION_KEY_WEBAUTHN_CHALLENGE from authentik.stages.authenticator_webauthn.stage import SESSION_KEY_WEBAUTHN_CHALLENGE
from authentik.stages.authenticator_webauthn.utils import get_origin, get_rp_id from authentik.stages.authenticator_webauthn.utils import get_origin, get_rp_id
from authentik.stages.consent.stage import PLAN_CONTEXT_CONSENT_TITLE
LOGGER = get_logger() LOGGER = get_logger()
@ -175,8 +174,6 @@ def validate_challenge_duo(device_pk: int, stage_view: StageView, user: User) ->
pushinfo = { pushinfo = {
__("Domain"): stage_view.request.get_host(), __("Domain"): stage_view.request.get_host(),
} }
if PLAN_CONTEXT_CONSENT_TITLE in stage_view.executor.plan.context:
pushinfo[__("Title")] = stage_view.executor.plan.context[PLAN_CONTEXT_CONSENT_TITLE]
if SESSION_KEY_APPLICATION_PRE in stage_view.request.session: if SESSION_KEY_APPLICATION_PRE in stage_view.request.session:
pushinfo[__("Application")] = stage_view.request.session.get( pushinfo[__("Application")] = stage_view.request.session.get(
SESSION_KEY_APPLICATION_PRE, Application() SESSION_KEY_APPLICATION_PRE, Application()

View File

@ -14,7 +14,6 @@ from rest_framework.serializers import ValidationError
from authentik.core.api.utils import PassiveSerializer from authentik.core.api.utils import PassiveSerializer
from authentik.core.models import User from authentik.core.models import User
from authentik.events.models import Event, EventAction from authentik.events.models import Event, EventAction
from authentik.events.utils import cleanse_dict, sanitize_dict
from authentik.flows.challenge import ChallengeResponse, ChallengeTypes, WithUserInfoChallenge from authentik.flows.challenge import ChallengeResponse, ChallengeTypes, WithUserInfoChallenge
from authentik.flows.exceptions import FlowSkipStageException from authentik.flows.exceptions import FlowSkipStageException
from authentik.flows.models import FlowDesignation, NotConfiguredAction, Stage from authentik.flows.models import FlowDesignation, NotConfiguredAction, Stage
@ -382,13 +381,9 @@ class AuthenticatorValidateStageView(ChallengeStageView):
self.logger.debug("Set user from user-less flow", user=webauthn_device.user) self.logger.debug("Set user from user-less flow", user=webauthn_device.user)
self.executor.plan.context[PLAN_CONTEXT_PENDING_USER] = webauthn_device.user self.executor.plan.context[PLAN_CONTEXT_PENDING_USER] = webauthn_device.user
self.executor.plan.context[PLAN_CONTEXT_METHOD] = "auth_webauthn_pwl" self.executor.plan.context[PLAN_CONTEXT_METHOD] = "auth_webauthn_pwl"
self.executor.plan.context[PLAN_CONTEXT_METHOD_ARGS] = cleanse_dict( self.executor.plan.context[PLAN_CONTEXT_METHOD_ARGS] = {
sanitize_dict(
{
"device": webauthn_device, "device": webauthn_device,
} }
)
)
return self.set_valid_mfa_cookie(response.device) return self.set_valid_mfa_cookie(response.device)
def cleanup(self): def cleanup(self):

View File

@ -19,7 +19,6 @@ from authentik.lib.utils.time import timedelta_from_string
from authentik.stages.consent.models import ConsentMode, ConsentStage, UserConsent from authentik.stages.consent.models import ConsentMode, ConsentStage, UserConsent
PLAN_CONTEXT_CONSENT = "consent" PLAN_CONTEXT_CONSENT = "consent"
PLAN_CONTEXT_CONSENT_TITLE = "consent_title"
PLAN_CONTEXT_CONSENT_HEADER = "consent_header" PLAN_CONTEXT_CONSENT_HEADER = "consent_header"
PLAN_CONTEXT_CONSENT_PERMISSIONS = "consent_permissions" PLAN_CONTEXT_CONSENT_PERMISSIONS = "consent_permissions"
PLAN_CONTEXT_CONSENT_EXTRA_PERMISSIONS = "consent_additional_permissions" PLAN_CONTEXT_CONSENT_EXTRA_PERMISSIONS = "consent_additional_permissions"
@ -59,8 +58,6 @@ class ConsentStageView(ChallengeStageView):
), ),
"token": token, "token": token,
} }
if PLAN_CONTEXT_CONSENT_TITLE in self.executor.plan.context:
data["title"] = self.executor.plan.context[PLAN_CONTEXT_CONSENT_TITLE]
if PLAN_CONTEXT_CONSENT_HEADER in self.executor.plan.context: if PLAN_CONTEXT_CONSENT_HEADER in self.executor.plan.context:
data["header_text"] = self.executor.plan.context[PLAN_CONTEXT_CONSENT_HEADER] data["header_text"] = self.executor.plan.context[PLAN_CONTEXT_CONSENT_HEADER]
challenge = ConsentChallenge(data=data) challenge = ConsentChallenge(data=data)

View File

@ -0,0 +1,172 @@
---
title: Flow Context
toc_max_heading_level: 5
---
Each flow execution has an independent _context_. This context holds all of the arbitrary data about that specific flow, data which can then be used and transformed by stages and policies.
## Managing data in a flow context
You create and manage the data for a context by configuring policies, stages, and bindings. As you plan your flow, and set up the required stages, etc. you are creating the context data for that flow.
For example, in the Identification Stage (part of the default login flow), you can define whether users will be prompted to enter an email address, a username, or both. All such information about the flow's configuration makes up the context.
Any data can be stored in the flow context, however there are some reserved keys in the context dictionary that are used by authentik stages.
## Context dictionary and reserved keys
This section describes the data (the context) that are used in authentik, and provides a list of keys, what they are used for and when they are set.
:::warning
Keys prefixed with `goauthentik.io` are used internally by authentik and are subject to change without notice, and should not be modified in policies in most cases.
:::
### Common keys
#### `pending_user` ([User object](../../user-group/user.md))
`pending_user` is used by multiple stages. In the context of most flow executions, it represents the data of the user that is executing the flow. This value is not set automatically, it is set via the [Identification stage](../stages/identification/).
Stages that require a user, such as the [Password stage](../stages/password/), the [Authenticator validation stage](../stages/authenticator_validate/) and others will use this value if it is set, and fallback to the request's users when possible.
#### `prompt_data` (Dictionary)
`prompt_data` is primarily used by the [Prompt stage](../stages/prompt/). The value of any field within a prompt stage is written to the `prompt_data` dictionary. For example, given a field with the _Field key_ `email` that was submitted with the value `foo@bar.baz` will result in the following context:
```json
{
"prompt_data": {
"email": "foo@bar.baz"
}
}
```
This data can be modified with policies. The data is also used by stages like [User write](../stages/user_write.md), which takes data in `prompt_data` and writes it to `pending_user`.
#### `redirect` (string)
Stores the final redirect URL that the user's browser will be sent to after the flow is finished executing successfully. This is set when an un-authenticated user attempts to access a secured application, and when a user authenticates/enrolls with an external source.
#### Identifications tage
##### `pending_user_identifier` (string)
If _Show matched user_ is disabled, this key will hold the user identifier entered by the user in the identification stage.
Stores the final redirect URL that the user's browser will be sent to after the flow is finished executing successfully. This is set when an un-authenticated user attempts to access a secured application, and when a user authenticates/enrolls with an external source.
#### `application` (Application object)
When an unauthenticated user attempts to access a secured resource, they are redirected to an authentication flow. The application they attempted to access will be stored in the key attached to this object. For example: `application.github`, with `application` being the key and `github` the value.
#### `source` (Source object)
When a user authenticates/enrolls via an external source, this will be set to the source they are using.
### Scenario-specific keys
#### `is_sso` (boolean)
Set to `True` when the flow is executed from an "SSO" context. For example, this is set when a flow is used during the authentication or enrollment via an external source, and if a flow is executed to authorize access to an application.
#### `is_restored` (Token object)
Set when a flow execution is continued from a token. This happens for example when an [Email stage](../stages/email/index.mdx) is used and the user clicks on the link within the email. The token object contains the key that was used to restore the flow execution.
### Stage-specific keys
#### Consent stage
##### `consent_header` (string)
The title of the consent prompt shown. Set automatically when the consent stage is used with a OAuth2, Proxy or SAML provider.
##### `consent_permissions` (List of PermissionDict)
An optional list of all permissions that will be given to the application by granting consent. Not supported with SAML. When used with an OAuth2 or Proxy provider, this will be set based on the configured scopes.
#### Autosubmit stage
The autosubmit stage is an internal stage type that is not configurable via the API/Web interface. It is used in certain situations, where a POST request is sent from the browser, such as with SAML POST bindings. This works by using an HTML form that is submitted automatically.
##### `title` (string)
Optional title of the form shown to the user. Automatically set when this stage is used by the backend.
##### `url` (string)
URL that the form will be submitted to.
##### `attrs` (dictionary)
Key-value pairs of the data that is included in the form and will be submitted to `url`.
#### User write stage
##### `groups` (List of [Group objects](../../user-group/group.md))
See [Group](../../user-group/group.md). If set in the flow context, the `pending_user` will be added to all the groups in this list.
If set, this must be a list of group objects and not group names.
##### `user_path` (string)
Path the `pending_user` will be written to. If not set in the flow, falls back to the value set in the user_write stage, and otherwise to the `users` path.
#### Password stage
##### `user_backend` (string)
Set by the [Password stage](../stages/password/index.md) after successfully authenticating in the user. Contains a dot-notation to the authentication backend that was used to successfully authenticate the user.
##### `auth_method` (string)
Set by the [Password stage](../stages/password/index.md), the [Authenticator validation stage](../stages/authenticator_validate/index.md), the [OAuth2 Provider](../../providers/oauth2/index.md), and the API authentication depending on which method was used to authenticate.
Possible options:
- `password` (Authenticated via the password in authentik's database)
- `token` (Authenticated via API token)
- `ldap` (Authenticated via LDAP bind from an LDAP source)
- `auth_mfa` (Authentication via MFA device without password)
- `auth_webauthn_pwl` (Passwordless authentication via WebAuthn)
- `jwt` ([M2M](../../providers/oauth2/client_credentials.md) authentication via an existing JWT)
##### `auth_method_args` (dictionary)
Additional arguments used during the authentication. Value varies depending on `auth_method`.
Example:
```json
{
// List of the MFA device objects used during authentication
// applies for `auth_method` `auth_mfa`
"mfa_devices": [],
// MFA device used for passwordless authentication, applies to
// `auth_method` `auth_webauthn_pwl`
"device": null,
// the token identifier when `auth_method` `token` was used
"identifier": "",
// JWT information when `auth_method` `jwt` was used
"jwt": {},
"source": null,
"jwk_id": ""
}
```
#### Email stage
##### `email_sent` (boolean)
Boolean set to true after the email form the email stage has been sent.
##### `email` (string)
Optionally override the email address that the email will be sent to. If not set, defaults to the email of `pending_user`.
#### Identifications tage
##### `pending_user_identifier` (string)
If _Show matched user_ is disabled, this key will be set to the user identifier entered by the user in the identification stage.

View File

@ -132,6 +132,7 @@ module.exports = {
items: [ items: [
"flow/layouts", "flow/layouts",
"flow/inspector", "flow/inspector",
"flow/context/index",
{ {
type: "category", type: "category",
label: "Examples", label: "Examples",