add initial

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens Langhammer 2022-11-14 13:48:29 +01:00 committed by Jens Langhammer
parent 0156249123
commit f28b18805f
No known key found for this signature in database
10 changed files with 252 additions and 2 deletions

View File

@ -42,6 +42,7 @@ class ProviderSerializer(ModelSerializer, MetaNameSerializer):
"name",
"authentication_flow",
"authorization_flow",
"invalidation_flow",
"property_mappings",
"component",
"assigned_application_slug",

View File

@ -0,0 +1,26 @@
# Generated by Django 4.1.7 on 2023-03-22 22:26
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_flows", "0025_alter_flowstagebinding_evaluate_on_plan_and_more"),
("authentik_core", "0027_alter_user_uuid"),
]
operations = [
migrations.AddField(
model_name="provider",
name="invalidation_flow",
field=models.ForeignKey(
default=None,
help_text="Flow used ending the session from a provider.",
null=True,
on_delete=django.db.models.deletion.SET_DEFAULT,
related_name="provider_invalidation",
to="authentik_flows.flow",
),
),
]

View File

@ -299,11 +299,21 @@ class Provider(SerializerModel):
authorization_flow = models.ForeignKey(
"authentik_flows.Flow",
# Set to cascade even though null is allowed, since most providers
# still require an authorization flow set
on_delete=models.CASCADE,
null=True,
help_text=_("Flow used when authorizing this provider."),
related_name="provider_authorization",
)
invalidation_flow = models.ForeignKey(
"authentik_flows.Flow",
on_delete=models.SET_DEFAULT,
default=None,
null=True,
help_text=_("Flow used ending the session from a provider."),
related_name="provider_invalidation",
)
property_mappings = models.ManyToManyField("PropertyMapping", default=None, blank=True)

View File

@ -125,6 +125,12 @@ class AccessDeniedChallenge(WithUserInfoChallenge):
component = CharField(default="ak-stage-access-denied")
class SessionEndChallenge(WithUserInfoChallenge):
"""Challenge for ending a session"""
component = CharField(default="ak-stage-session-end")
class PermissionDict(TypedDict):
"""Consent Permission"""

View File

@ -105,7 +105,9 @@ class Stage(SerializerModel):
def in_memory_stage(view: type["StageView"], **kwargs) -> Stage:
"""Creates an in-memory stage instance, based on a `view` as view."""
"""Creates an in-memory stage instance, based on a `view` as view.
Any key-word arguments are set as attributes on the stage object,
accessible via `self.executor.current_stage`."""
stage = Stage()
# Because we can't pickle a locally generated function,
# we set the view as a separate property and reference a generic function

View File

@ -11,6 +11,7 @@ from authentik.providers.oauth2.api.tokens import (
)
from authentik.providers.oauth2.views.authorize import AuthorizationFlowInitView
from authentik.providers.oauth2.views.device_backchannel import DeviceView
from authentik.providers.oauth2.views.end_session import EndSessionView
from authentik.providers.oauth2.views.introspection import TokenIntrospectionView
from authentik.providers.oauth2.views.jwks import JWKSView
from authentik.providers.oauth2.views.provider import ProviderInfoView
@ -43,7 +44,7 @@ urlpatterns = [
),
path(
"<slug:application_slug>/end-session/",
RedirectView.as_view(pattern_name="authentik_core:if-session-end", query_string=True),
EndSessionView.as_view(),
name="end-session",
),
path("<slug:application_slug>/jwks/", JWKSView.as_view(), name="jwks"),

View File

@ -0,0 +1,39 @@
"""oauth2 provider end_session Views"""
from django.http import Http404, HttpRequest, HttpResponse
from django.shortcuts import get_object_or_404
from authentik.core.models import Application
from authentik.flows.challenge import SessionEndChallenge
from authentik.flows.models import in_memory_stage
from authentik.flows.planner import PLAN_CONTEXT_APPLICATION, FlowPlanner
from authentik.flows.views.executor import SESSION_KEY_PLAN
from authentik.lib.utils.urls import redirect_with_qs
from authentik.policies.views import PolicyAccessView
class EndSessionView(PolicyAccessView):
"""Redirect to application's provider's invalidation flow"""
def resolve_provider_application(self):
self.application = get_object_or_404(Application, slug=self.kwargs["application_slug"])
self.provider = self.application.get_provider()
if not self.provider or not self.provider.invalidation_flow:
raise Http404
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
"""Dispatch the flow planner for the invalidation flow"""
planner = FlowPlanner(self.provider.invalidation_flow)
planner.allow_empty_flows = True
plan = planner.plan(
request,
{
PLAN_CONTEXT_APPLICATION: self.application,
},
)
plan.insert_stage(in_memory_stage(SessionEndChallenge))
request.session[SESSION_KEY_PLAN] = plan
return redirect_with_qs(
"authentik_core:if-flow",
self.request.GET,
flow_slug=self.provider.invalidation_flow.slug,
)

View File

@ -0,0 +1,13 @@
version: 1
metadata:
name: Default - Provider invalidation flow
entries:
- attrs:
designation: invalidation
name: Logout
title: You've logged out of %(app)s.
authentication: none
identifiers:
slug: default-provider-invalidation-flow
model: authentik_flows.flow
id: flow

View File

@ -16394,6 +16394,11 @@ paths:
name: is_backchannel
schema:
type: boolean
- in: query
name: invalidation_flow
schema:
type: string
format: uuid
- in: query
name: issuer
schema:
@ -29557,6 +29562,7 @@ components:
- $ref: '#/components/schemas/PlexAuthenticationChallenge'
- $ref: '#/components/schemas/PromptChallenge'
- $ref: '#/components/schemas/RedirectChallenge'
- $ref: '#/components/schemas/SessionEndChallenge'
- $ref: '#/components/schemas/ShellChallenge'
- $ref: '#/components/schemas/UserLoginChallenge'
discriminator:
@ -29583,6 +29589,7 @@ components:
ak-source-plex: '#/components/schemas/PlexAuthenticationChallenge'
ak-stage-prompt: '#/components/schemas/PromptChallenge'
xak-flow-redirect: '#/components/schemas/RedirectChallenge'
ak-stage-session-end: '#/components/schemas/SessionEndChallenge'
xak-flow-shell: '#/components/schemas/ShellChallenge'
ak-stage-user-login: '#/components/schemas/UserLoginChallenge'
ClientTypeEnum:
@ -32592,6 +32599,11 @@ components:
type: string
format: uuid
description: Flow used when authorizing this provider.
invalidation_flow:
type: string
format: uuid
nullable: true
description: Flow used ending the session from a provider.
property_mappings:
type: array
items:
@ -32705,6 +32717,11 @@ components:
type: string
format: uuid
description: Flow used when authorizing this provider.
invalidation_flow:
type: string
format: uuid
nullable: true
description: Flow used ending the session from a provider.
property_mappings:
type: array
items:
@ -33627,6 +33644,11 @@ components:
type: string
format: uuid
description: Flow used when authorizing this provider.
invalidation_flow:
type: string
format: uuid
nullable: true
description: Flow used ending the session from a provider.
property_mappings:
type: array
items:
@ -33760,6 +33782,11 @@ components:
type: string
format: uuid
description: Flow used when authorizing this provider.
invalidation_flow:
type: string
format: uuid
nullable: true
description: Flow used ending the session from a provider.
property_mappings:
type: array
items:
@ -36728,6 +36755,11 @@ components:
type: string
format: uuid
description: Flow used when authorizing this provider.
invalidation_flow:
type: string
format: uuid
nullable: true
description: Flow used ending the session from a provider.
property_mappings:
type: array
items:
@ -36986,6 +37018,11 @@ components:
type: string
format: uuid
description: Flow used when authorizing this provider.
invalidation_flow:
type: string
format: uuid
nullable: true
description: Flow used ending the session from a provider.
property_mappings:
type: array
items:
@ -37478,6 +37515,11 @@ components:
type: string
format: uuid
description: Flow used when authorizing this provider.
invalidation_flow:
type: string
format: uuid
nullable: true
description: Flow used ending the session from a provider.
property_mappings:
type: array
items:
@ -37566,6 +37608,11 @@ components:
type: string
format: uuid
description: Flow used when authorizing this provider.
invalidation_flow:
type: string
format: uuid
nullable: true
description: Flow used ending the session from a provider.
property_mappings:
type: array
items:
@ -37657,6 +37704,11 @@ components:
type: string
format: uuid
description: Flow used when authorizing this provider.
invalidation_flow:
type: string
format: uuid
nullable: true
description: Flow used ending the session from a provider.
property_mappings:
type: array
items:
@ -38984,6 +39036,11 @@ components:
type: string
format: uuid
description: Flow used when authorizing this provider.
invalidation_flow:
type: string
format: uuid
nullable: true
description: Flow used ending the session from a provider.
property_mappings:
type: array
items:
@ -39074,6 +39131,11 @@ components:
type: string
format: uuid
description: Flow used when authorizing this provider.
invalidation_flow:
type: string
format: uuid
nullable: true
description: Flow used ending the session from a provider.
property_mappings:
type: array
items:
@ -39242,6 +39304,11 @@ components:
type: string
format: uuid
description: Flow used when authorizing this provider.
invalidation_flow:
type: string
format: uuid
nullable: true
description: Flow used ending the session from a provider.
property_mappings:
type: array
items:
@ -39386,6 +39453,11 @@ components:
type: string
format: uuid
description: Flow used when authorizing this provider.
invalidation_flow:
type: string
format: uuid
nullable: true
description: Flow used ending the session from a provider.
property_mappings:
type: array
items:
@ -39515,6 +39587,11 @@ components:
type: string
format: uuid
description: Flow used when authorizing this provider.
invalidation_flow:
type: string
format: uuid
nullable: true
description: Flow used ending the session from a provider.
property_mappings:
type: array
items:
@ -39602,6 +39679,11 @@ components:
type: string
format: uuid
description: Flow used when authorizing this provider.
invalidation_flow:
type: string
format: uuid
nullable: true
description: Flow used ending the session from a provider.
property_mappings:
type: array
items:
@ -39944,6 +40026,11 @@ components:
type: string
format: uuid
description: Flow used when authorizing this provider.
invalidation_flow:
type: string
format: uuid
nullable: true
description: Flow used ending the session from a provider.
property_mappings:
type: array
items:
@ -40118,6 +40205,11 @@ components:
type: string
format: uuid
description: Flow used when authorizing this provider.
invalidation_flow:
type: string
format: uuid
nullable: true
description: Flow used ending the session from a provider.
property_mappings:
type: array
items:
@ -40814,6 +40906,31 @@ components:
required:
- healthy
- version
SessionEndChallenge:
type: object
description: Challenge for ending a session
properties:
type:
$ref: '#/components/schemas/ChallengeChoices'
flow_info:
$ref: '#/components/schemas/ContextualFlowInfo'
component:
type: string
default: ak-stage-session-end
response_errors:
type: object
additionalProperties:
type: array
items:
$ref: '#/components/schemas/ErrorDetail'
pending_user:
type: string
pending_user_avatar:
type: string
required:
- pending_user
- pending_user_avatar
- type
SessionUser:
type: object
description: |-

View File

@ -193,6 +193,41 @@ export class OAuth2ProviderFormPage extends BaseProviderForm<OAuth2Provider> {
${msg("Flow used when authorizing this provider.")}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${t`Invalidation flow`}
?required=${true}
name="invalidationFlow"
>
<ak-search-select
.fetchObjects=${async (query?: string): Promise<Flow[]> => {
const args: FlowsInstancesListRequest = {
ordering: "slug",
designation: FlowsInstancesListDesignationEnum.Invalidation,
};
if (query !== undefined) {
args.search = query;
}
const flows = await new FlowsApi(DEFAULT_CONFIG).flowsInstancesList(args);
return flows.results;
}}
.renderElement=${(flow: Flow): string => {
return RenderFlowOption(flow);
}}
.renderDescription=${(flow: Flow): TemplateResult => {
return html`${flow.name}`;
}}
.value=${(flow: Flow | undefined): string | undefined => {
return flow?.pk;
}}
.selected=${(flow: Flow): boolean => {
return flow.pk === this.instance?.invalidationFlow;
}}
>
</ak-search-select>
<p class="pf-c-form__helper-text">
${t`Flow used when authorizing this provider.`}
</p>
</ak-form-element-horizontal>
<ak-form-group .expanded=${true}>
<span slot="header"> ${msg("Protocol settings")} </span>