From 55250e88e5050f9b4ba23f91de57c0f33c4b2683 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Sun, 2 May 2021 16:46:13 +0200 Subject: [PATCH] sources/*: rewrite UILoginButton to return challenge instead Signed-off-by: Jens Langhammer --- authentik/core/types.py | 13 +++++-------- authentik/sources/oauth/models.py | 12 +++++++++--- authentik/sources/saml/models.py | 13 ++++++++++--- authentik/stages/identification/stage.py | 4 +++- authentik/stages/identification/tests.py | 12 ++++++++---- web/src/authentik.css | 2 +- web/src/flows/stages/base.ts | 2 ++ .../stages/identification/IdentificationStage.ts | 15 +++++++++++---- 8 files changed, 49 insertions(+), 24 deletions(-) diff --git a/authentik/core/types.py b/authentik/core/types.py index 3901350a3..d8ba7cadf 100644 --- a/authentik/core/types.py +++ b/authentik/core/types.py @@ -1,10 +1,11 @@ """authentik core dataclasses""" from dataclasses import dataclass -from typing import Any, Optional +from typing import Optional from rest_framework.fields import CharField, DictField from authentik.core.api.utils import PassiveSerializer +from authentik.flows.challenge import Challenge @dataclass @@ -14,23 +15,19 @@ class UILoginButton: # Name, ran through i18n name: str - # URL Which Button points to - url: str + # Challenge which is presented to the user when they click the button + challenge: Challenge # Icon URL, used as-is icon_url: Optional[str] = None - # Additional data, optional - additional_data: Any = None - class UILoginButtonSerializer(PassiveSerializer): """Serializer for Login buttons of sources""" name = CharField() - url = CharField() + challenge = DictField() icon_url = CharField(required=False, allow_null=True) - additional_data = DictField(required=False, allow_null=True) class UserSettingSerializer(PassiveSerializer): diff --git a/authentik/sources/oauth/models.py b/authentik/sources/oauth/models.py index 9ba1dc864..b44ff57f1 100644 --- a/authentik/sources/oauth/models.py +++ b/authentik/sources/oauth/models.py @@ -9,6 +9,7 @@ from rest_framework.serializers import Serializer from authentik.core.models import Source, UserSourceConnection from authentik.core.types import UILoginButton, UserSettingSerializer +from authentik.flows.challenge import ChallengeTypes, RedirectChallenge if TYPE_CHECKING: from authentik.sources.oauth.types.manager import SourceType @@ -67,9 +68,14 @@ class OAuthSource(Source): @property def ui_login_button(self) -> UILoginButton: return UILoginButton( - url=reverse( - "authentik_sources_oauth:oauth-client-login", - kwargs={"source_slug": self.slug}, + challenge=RedirectChallenge( + instance={ + "type": ChallengeTypes.REDIRECT.value, + "to": reverse( + "authentik_sources_oauth:oauth-client-login", + kwargs={"source_slug": self.slug}, + ), + } ), icon_url=static(f"authentik/sources/{self.provider_type}.svg"), name=self.name, diff --git a/authentik/sources/saml/models.py b/authentik/sources/saml/models.py index d35685aac..bd7087173 100644 --- a/authentik/sources/saml/models.py +++ b/authentik/sources/saml/models.py @@ -10,6 +10,7 @@ from rest_framework.serializers import Serializer from authentik.core.models import Source from authentik.core.types import UILoginButton from authentik.crypto.models import CertificateKeyPair +from authentik.flows.challenge import ChallengeTypes, RedirectChallenge from authentik.flows.models import Flow from authentik.lib.utils.time import timedelta_string_validator from authentik.sources.saml.processors.constants import ( @@ -169,10 +170,16 @@ class SAMLSource(Source): @property def ui_login_button(self) -> UILoginButton: return UILoginButton( - name=self.name, - url=reverse( - "authentik_sources_saml:login", kwargs={"source_slug": self.slug} + challenge=RedirectChallenge( + instance={ + "type": ChallengeTypes.REDIRECT.value, + "to": reverse( + "authentik_sources_saml:login", + kwargs={"source_slug": self.slug}, + ), + } ), + name=self.name, ) def __str__(self): diff --git a/authentik/stages/identification/stage.py b/authentik/stages/identification/stage.py index f5b3bfc90..625546c0f 100644 --- a/authentik/stages/identification/stage.py +++ b/authentik/stages/identification/stage.py @@ -112,7 +112,9 @@ class IdentificationStageView(ChallengeStageView): for source in sources: ui_login_button = source.ui_login_button if ui_login_button: - ui_sources.append(asdict(ui_login_button)) + button = asdict(ui_login_button) + button["challenge"] = ui_login_button.challenge.data + ui_sources.append(button) challenge.initial_data["sources"] = ui_sources return challenge diff --git a/authentik/stages/identification/tests.py b/authentik/stages/identification/tests.py index bb99ee947..64c051ddc 100644 --- a/authentik/stages/identification/tests.py +++ b/authentik/stages/identification/tests.py @@ -115,10 +115,12 @@ class TestIdentificationStage(TestCase): "title": self.flow.title, "sources": [ { - "additional_data": None, "icon_url": "/static/authentik/sources/.svg", "name": "test", - "url": "/source/oauth/login/test/", + "challenge": { + "to": "/source/oauth/login/test/", + "type": "redirect", + }, } ], }, @@ -159,10 +161,12 @@ class TestIdentificationStage(TestCase): "title": self.flow.title, "sources": [ { - "additional_data": None, + "challenge": { + "to": "/source/oauth/login/test/", + "type": "redirect", + }, "icon_url": "/static/authentik/sources/.svg", "name": "test", - "url": "/source/oauth/login/test/", } ], }, diff --git a/web/src/authentik.css b/web/src/authentik.css index afcebb269..35b0caea0 100644 --- a/web/src/authentik.css +++ b/web/src/authentik.css @@ -272,7 +272,7 @@ body { .pf-c-login__main-header-desc { color: var(--ak-dark-foreground); } - .pf-c-login__main-footer-links-item-link > img { + .pf-c-login__main-footer-links-item img { filter: invert(1); } .pf-c-login__main-footer-band { diff --git a/web/src/flows/stages/base.ts b/web/src/flows/stages/base.ts index 56ef98498..6815d652c 100644 --- a/web/src/flows/stages/base.ts +++ b/web/src/flows/stages/base.ts @@ -1,6 +1,8 @@ +import { Challenge } from "authentik-api"; import { LitElement } from "lit-element"; export interface StageHost { + challenge?: Challenge; submit(formData?: T): Promise; } diff --git a/web/src/flows/stages/identification/IdentificationStage.ts b/web/src/flows/stages/identification/IdentificationStage.ts index 8dc3035a6..a4e7ba371 100644 --- a/web/src/flows/stages/identification/IdentificationStage.ts +++ b/web/src/flows/stages/identification/IdentificationStage.ts @@ -35,7 +35,7 @@ export interface IdentificationChallenge extends Challenge { export interface UILoginButton { name: string; - url: string; + challenge: Challenge; icon_url?: string; } @@ -49,7 +49,11 @@ export class IdentificationStage extends BaseStage { return [PFBase, PFLogin, PFForm, PFFormControl, PFTitle, PFButton, AKGlobal].concat( css` /* login page's icons */ - .pf-c-login__main-footer-links-item-link img { + .pf-c-login__main-footer-links-item button { + background-color: transparent; + border: 0; + } + .pf-c-login__main-footer-links-item img { fill: var(--pf-c-login__main-footer-links-item-link-svg--Fill); width: 100px; max-width: var(--pf-c-login__main-footer-links-item-link-svg--Width); @@ -131,9 +135,12 @@ export class IdentificationStage extends BaseStage { icon = html`${source.name}`; } return html``; }