Compare commits

...

12 Commits

Author SHA1 Message Date
a68f5deed9 Merge remote-tracking branch 'refs/remotes/origin/web/use-oauth' into web/use-oauth-by-jens
* refs/remotes/origin/web/use-oauth:
  fix missing mappings
  add blueprints for apps
  store user data in memory
  web: use OAuth
2024-07-08 10:34:47 -07:00
441e4c48e9 Merge branch 'main' into web/use-oauth-by-jens
* main: (179 commits)
  website/integrations: add offline_access scope to DokuWiki (#10208)
  api: use custom json renderer for speed (#9977)
  core: bump github.com/sethvargo/go-envconfig from 1.0.3 to 1.1.0 (#10405)
  core: bump goauthentik.io/api/v3 from 3.2024060.5 to 3.2024060.6 (#10404)
  web: bump glob from 10.4.2 to 10.4.3 in /web (#10407)
  web: bump @swc/core from 1.6.7 to 1.6.13 in /web/sfe (#10408)
  core: bump ruff from 0.5.0 to 0.5.1 (#10390)
  web: bump @swc/cli from 0.3.14 to 0.4.0 in /web/sfe (#10394)
  core: bump certifi from 2024.2.2 to 2024.7.4 (#10398)
  web: bump @swc/core from 1.6.6 to 1.6.7 in /web/sfe (#10395)
  web: bump @sentry/browser from 8.14.0 to 8.15.0 in /web in the sentry group across 1 directory (#10388)
  website/integrations: aws: cleanup (#10355)
  web: bump API Client version (#10389)
  web/flows: Simplified flow executor (#10296)
  website/docs: sources: ldap: remove extra example (#10387)
  website/docs: add new content from old PR #9524 (#10158)
  stages/authenticator_validate: fix friendly_name being required (#10382)
  core: bump go api client (#10383)
  web: bump API Client version (#10381)
  outposts: make refresh interval configurable (#10138)
  ...
2024-07-08 10:30:26 -07:00
d4a6874a45 fix missing mappings
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2024-06-28 13:03:22 +02:00
40c5cb12fd add blueprints for apps
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2024-06-28 12:30:15 +02:00
89b7b735b4 store user data in memory
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2024-06-28 12:30:15 +02:00
6d82e568ae web: use OAuth
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2024-06-28 12:26:54 +02:00
696175f6f7 Another lost-in-the-merge thing. 2024-06-18 09:11:24 -07:00
ad3dbaa9c4 Lost in the merge. 2024-06-18 09:06:28 -07:00
033617c5d2 Merge branch 'main' into web/use-oauth-by-jens
* main: (1457 commits)
  root: use custom model serializer that saves m2m without bulk (#10139)
  core: bump urllib3 from 2.2.1 to 2.2.2 (#10143)
  ci: bump docker/build-push-action from 5 to 6 (#10144)
  web: bump the storybook group in /web with 7 updates (#10147)
  web: bump ws from 8.16.0 to 8.17.1 in /web (#10149)
  web: fix needed because recent upgrade to task breaks spinner button (#10142)
  core: include version in built JS files (#9558)
  website/integations/services: Slack integration docs (#9933)
  web: fix early modal stack depletion (#10068)
  website: bump react-tooltip from 5.26.4 to 5.27.0 in /website (#10129)
  web: bump @patternfly/elements from 3.0.1 to 3.0.2 in /web (#10132)
  core: bump github.com/gorilla/sessions from 1.2.2 to 1.3.0 (#10135)
  web: bump chromedriver from 126.0.0 to 126.0.1 in /tests/wdio (#10136)
  core: bump github.com/spf13/cobra from 1.8.0 to 1.8.1 (#10133)
  core, web: update translations (#10127)
  core: bump ruff from 0.4.8 to 0.4.9 (#10128)
  core: bump goauthentik.io/api/v3 from 3.2024042.11 to 3.2024042.13 (#10134)
  core, web: update translations (#10118)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#10121)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#10120)
  ...
2024-06-18 09:05:52 -07:00
0ce250dcd1 add blueprints for apps
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-12-18 16:54:40 +01:00
f9eed9f065 store user data in memory
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-12-18 16:54:33 +01:00
c0bb1f7347 web: use OAuth
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-12-18 16:12:18 +01:00
27 changed files with 886 additions and 834 deletions

View File

@ -16,6 +16,7 @@ from django.views.decorators.clickjacking import xframe_options_sameorigin
from django.views.generic import View
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, PolymorphicProxySerializer, extend_schema
from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import AllowAny
from rest_framework.views import APIView
from sentry_sdk import capture_exception
@ -23,6 +24,7 @@ from sentry_sdk.api import set_tag
from sentry_sdk.hub import Hub
from structlog.stdlib import BoundLogger, get_logger
from authentik.api.authentication import TokenAuthentication
from authentik.brands.models import Brand
from authentik.core.models import Application
from authentik.events.models import Event, EventAction, cleanse_dict
@ -104,6 +106,10 @@ class FlowExecutorView(APIView):
"""Flow executor, passing requests to Stage Views"""
permission_classes = [AllowAny]
authentication_classes = [
TokenAuthentication,
SessionAuthentication,
]
flow: Flow

View File

@ -180,10 +180,7 @@ REST_FRAMEWORK = {
"rest_framework.filters.SearchFilter",
],
"DEFAULT_PERMISSION_CLASSES": ("authentik.rbac.permissions.ObjectPermissions",),
"DEFAULT_AUTHENTICATION_CLASSES": (
"authentik.api.authentication.TokenAuthentication",
"rest_framework.authentication.SessionAuthentication",
),
"DEFAULT_AUTHENTICATION_CLASSES": ("authentik.api.authentication.TokenAuthentication",),
"DEFAULT_RENDERER_CLASSES": [
"drf_orjson_renderer.renderers.ORJSONRenderer",
],

View File

@ -0,0 +1,45 @@
version: 1
metadata:
name: Default - authentik Admin Interface
entries:
- model: authentik_providers_oauth2.oauth2provider
id: provider
identifiers:
name: authentik-admin-interface
attrs:
authorization_flow:
!Find [
authentik_flows.flow,
[slug, default-provider-authorization-implicit-consent],
]
client_type: public
client_id: authentik-admin-interface
property_mappings:
- !Find [
authentik_providers_oauth2.scopemapping,
[managed, goauthentik.io/providers/oauth2/scope-openid],
]
- !Find [
authentik_providers_oauth2.scopemapping,
[managed, goauthentik.io/providers/oauth2/scope-email],
]
- !Find [
authentik_providers_oauth2.scopemapping,
[managed, goauthentik.io/providers/oauth2/scope-profile],
]
- !Find [
authentik_providers_oauth2.scopemapping,
[managed, goauthentik.io/providers/oauth2/scope-authentik_api],
]
signing_key:
!Find [
authentik_crypto.certificatekeypair,
[name, authentik Self-signed Certificate],
]
- model: authentik_core.application
identifiers:
slug: authentik-admin-interface
attrs:
name: authentik Admin interface
icon: https://goauthentik.io/img/icon.png
provider: !KeyOf provider

View File

@ -0,0 +1,45 @@
version: 1
metadata:
name: Default - authentik User Interface
entries:
- model: authentik_providers_oauth2.oauth2provider
id: provider
identifiers:
name: authentik-user-interface
attrs:
authorization_flow:
!Find [
authentik_flows.flow,
[slug, default-provider-authorization-implicit-consent],
]
client_type: public
client_id: authentik-user-interface
property_mappings:
- !Find [
authentik_providers_oauth2.scopemapping,
[managed, goauthentik.io/providers/oauth2/scope-openid],
]
- !Find [
authentik_providers_oauth2.scopemapping,
[managed, goauthentik.io/providers/oauth2/scope-email],
]
- !Find [
authentik_providers_oauth2.scopemapping,
[managed, goauthentik.io/providers/oauth2/scope-profile],
]
- !Find [
authentik_providers_oauth2.scopemapping,
[managed, goauthentik.io/providers/oauth2/scope-authentik_api],
]
signing_key:
!Find [
authentik_crypto.certificatekeypair,
[name, authentik Self-signed Certificate],
]
- model: authentik_core.application
identifiers:
slug: authentik-user-interface
attrs:
name: authentik User interface
icon: https://goauthentik.io/img/icon.png
provider: !KeyOf provider

1256
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -65,6 +65,7 @@
"lit": "^3.1.4",
"md-front-matter": "^1.0.4",
"mermaid": "^10.9.1",
"oidc-client-ts": "^2.4.0",
"rapidoc": "^9.3.4",
"showdown": "^2.1.0",
"style-mod": "^4.1.2",

View File

@ -4,9 +4,12 @@ import {
EVENT_API_DRAWER_TOGGLE,
EVENT_NOTIFICATION_DRAWER_TOGGLE,
} from "@goauthentik/common/constants";
import { WithOAuth } from "@goauthentik/common/oauth/interface";
import { configureSentry } from "@goauthentik/common/sentry";
import { me } from "@goauthentik/common/users";
import { WebsocketClient } from "@goauthentik/common/ws";
import { OAuthLoginController } from "@goauthentik/components/oauth/controller";
import { adminSettings } from "@goauthentik/components/oauth/settings";
import { EnterpriseAwareInterface } from "@goauthentik/elements/Interface";
import "@goauthentik/elements/ak-locale-context";
import "@goauthentik/elements/enterprise/EnterpriseStatusBanner";
@ -33,7 +36,7 @@ import { AdminApi, SessionUser, UiThemeEnum, Version } from "@goauthentik/api";
import "./AdminSidebar";
@customElement("ak-interface-admin")
export class AdminInterface extends EnterpriseAwareInterface {
export class AdminInterface extends WithOAuth(EnterpriseAwareInterface, adminSettings) {
@property({ type: Boolean })
notificationDrawerOpen = getURLParam("notificationDrawerOpen", false);
@ -48,6 +51,8 @@ export class AdminInterface extends EnterpriseAwareInterface {
@state()
user?: SessionUser;
oauthController: OAuthLoginController;
static get styles(): CSSResult[] {
return [
PFBase,
@ -78,6 +83,7 @@ export class AdminInterface extends EnterpriseAwareInterface {
constructor() {
super();
this.ws = new WebsocketClient();
this.oauthController = new OAuthLoginController(this, adminSettings);
window.addEventListener(EVENT_NOTIFICATION_DRAWER_TOGGLE, () => {
this.notificationDrawerOpen = !this.notificationDrawerOpen;
updateURLParams({
@ -92,7 +98,8 @@ export class AdminInterface extends EnterpriseAwareInterface {
});
}
async firstUpdated(): Promise<void> {
async firstUpdated(_changedProperties: Map<PropertyKey, unknown>): Promise<void> {
super.firstUpdated(_changedProperties);
configureSentry(true);
this.version = await new AdminApi(DEFAULT_CONFIG).adminVersionRetrieve();
this.user = await me();

View File

@ -1,4 +1,7 @@
import "@goauthentik/admin/admin-overview/AdminOverviewPage";
import "@goauthentik/components/oauth/callback";
import { adminSettings } from "@goauthentik/components/oauth/settings";
import "@goauthentik/components/oauth/signout";
import { ID_REGEX, Route, SLUG_REGEX, UUID_REGEX } from "@goauthentik/elements/router/Route";
import { html } from "lit";
@ -8,6 +11,15 @@ export const ROUTES: Route[] = [
new Route(new RegExp("^/$")).redirect("/administration/overview"),
new Route(new RegExp("^#.*")).redirect("/administration/overview"),
new Route(new RegExp("^/library$")).redirect("/if/user/", true),
new Route(new RegExp("^/oauth-callback/(?<rest>.*)$"), async (args) => {
return html`<ak-oauth-callback
.settings=${adminSettings}
params=${args.rest}
></ak-oauth-callback>`;
}),
new Route(new RegExp("^/oauth-signout$"), async () => {
return html`<ak-oauth-signout .settings=${adminSettings}></ak-oauth-signout>`;
}),
// statically imported since this is the default route
new Route(new RegExp("^/administration/overview$"), async () => {
return html`<ak-admin-overview></ak-admin-overview>`;

View File

@ -5,6 +5,7 @@ import {
} from "@goauthentik/common/api/middleware";
import { EVENT_LOCALE_REQUEST, VERSION } from "@goauthentik/common/constants";
import { globalAK } from "@goauthentik/common/global";
import { TokenMiddleware } from "@goauthentik/common/oauth-middleware.js";
import { Config, Configuration, CoreApi, CurrentBrand, RootApi } from "@goauthentik/api";
@ -73,6 +74,7 @@ export const DEFAULT_CONFIG = new Configuration({
"sentry-trace": getMetaContent("sentry-trace"),
},
middleware: [
new TokenMiddleware(),
new CSRFMiddleware(),
new EventMiddleware(),
new LoggingMiddleware(globalAK().brand),

View File

@ -0,0 +1,15 @@
import { adminSettings } from "@goauthentik/components/oauth/settings";
import { UserManager } from "oidc-client-ts";
import { FetchParams, Middleware, RequestContext } from "@goauthentik/api";
export class TokenMiddleware implements Middleware {
async pre?(context: RequestContext): Promise<FetchParams | void> {
const user = await new UserManager(adminSettings).getUser();
if (user !== null) {
// @ts-ignore
context.init.headers["Authorization"] = `Bearer ${user.access_token}`;
}
return Promise.resolve(context);
}
}

View File

@ -0,0 +1,24 @@
import { state } from "@goauthentik/common/oauth/constants";
import { refreshMe } from "@goauthentik/common/users";
import { User, UserManager, UserManagerSettings } from "oidc-client-ts";
import { LitElement } from "lit";
import { customElement, property } from "lit/decorators.js";
@customElement("ak-oauth-callback")
export class OAuthCallback extends LitElement {
@property()
params?: string;
@property({ attribute: false })
settings?: UserManagerSettings;
async firstUpdated(): Promise<void> {
if (!this.settings) {
return;
}
const client = new UserManager(this.settings);
const user = (await client.signinCallback(`#${this.params}`)) as User;
const st = user.state as state;
window.location.assign(st.url);
refreshMe();
}
}

View File

@ -0,0 +1,7 @@
export class state {
url: string;
constructor() {
this.url = window.location.href;
}
}

View File

@ -0,0 +1,34 @@
import { state } from "@goauthentik/common/oauth/constants";
import { AbstractConstructor } from "@goauthentik/elements/types";
import { UserManager, UserManagerSettings } from "oidc-client-ts";
import type { LitElement } from "lit";
export function WithOAuth<T extends AbstractConstructor<LitElement>>(
superclass: T,
settings: UserManagerSettings,
) {
abstract class OAuthInterface extends superclass {
private async ensureLoggedIn() {
const client = new UserManager(settings);
const user = await client.getUser();
if (user !== null) {
return;
}
if (window.location.href.startsWith(settings.redirect_uri)) {
return;
}
const s = new state();
await client.signinRedirect({
state: s,
});
}
async firstUpdated(_changedProperties: Map<PropertyKey, unknown>): Promise<void> {
await this.ensureLoggedIn();
await super.firstUpdated(_changedProperties);
}
}
return OAuthInterface;
}

View File

@ -0,0 +1,15 @@
import { adminSettings } from "@goauthentik/common/oauth/settings";
import { UserManager } from "oidc-client-ts";
import { FetchParams, Middleware, RequestContext } from "@goauthentik/api";
export class TokenMiddleware implements Middleware {
async pre?(context: RequestContext): Promise<FetchParams | void> {
const user = await new UserManager(adminSettings).getUser();
if (user !== null) {
// @ts-ignore
context.init.headers["Authorization"] = `Bearer ${user.access_token}`;
}
return Promise.resolve(context);
}
}

View File

@ -0,0 +1,25 @@
import { MemoryStore } from "@goauthentik/common/oauth/storage";
import { Log, OidcClientSettings, UserManagerSettings } from "oidc-client-ts";
Log.setLogger(console);
Log.setLevel(Log.DEBUG);
export const userSettings: OidcClientSettings & UserManagerSettings = {
authority: `${window.location.origin}/application/o/authentik-user-interface/`,
redirect_uri: `${window.location.origin}/if/user/#/oauth-callback/`,
client_id: "authentik-user-interface",
scope: "openid profile email goauthentik.io/api",
response_mode: "fragment",
automaticSilentRenew: true,
userStore: new MemoryStore(),
};
export const adminSettings: OidcClientSettings & UserManagerSettings = {
authority: `${window.location.origin}/application/o/authentik-admin-interface/`,
redirect_uri: `${window.location.origin}/if/admin/#/oauth-callback/`,
client_id: "authentik-admin-interface",
scope: "openid profile email goauthentik.io/api",
response_mode: "fragment",
automaticSilentRenew: true,
userStore: new MemoryStore(),
};

View File

@ -0,0 +1,17 @@
import { UserManager, UserManagerSettings } from "oidc-client-ts";
import { LitElement } from "lit";
import { customElement, property } from "lit/decorators.js";
@customElement("ak-oauth-signout")
export class OAuthSignout extends LitElement {
@property({ attribute: false })
settings?: UserManagerSettings;
async firstUpdated(): Promise<void> {
if (!this.settings) {
return;
}
const client = new UserManager(this.settings);
await client.signoutRedirect();
}
}

View File

@ -0,0 +1,20 @@
import { WebStorageStateStore } from "oidc-client-ts";
export class MemoryStore extends WebStorageStateStore {
private map: Map<string, string> = new Map();
async set(key: string, value: string): Promise<void> {
this.map.set(key, value);
}
async get(key: string): Promise<string | null> {
const value = this.map.get(key);
return value ? value : null;
}
async remove(key: string): Promise<string | null> {
const value = await this.get(key);
this.map.delete(key);
return value;
}
async getAllKeys(): Promise<string[]> {
return Array.from(this.map.keys());
}
}

View File

@ -1,7 +1,7 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { EVENT_LOCALE_REQUEST } from "@goauthentik/common/constants";
import { CoreApi, ResponseError, SessionUser } from "@goauthentik/api";
import { CoreApi, SessionUser } from "@goauthentik/api";
let globalMePromise: Promise<SessionUser> | undefined;
@ -33,7 +33,7 @@ export function me(): Promise<SessionUser> {
}
return user;
})
.catch((ex: ResponseError) => {
.catch(() => {
const defaultUser: SessionUser = {
user: {
pk: -1,
@ -48,14 +48,6 @@ export function me(): Promise<SessionUser> {
systemPermissions: [],
},
};
if (ex.response?.status === 401 || ex.response?.status === 403) {
const relativeUrl = window.location
.toString()
.substring(window.location.origin.length);
window.location.assign(
`/flows/-/default/authentication/?next=${encodeURIComponent(relativeUrl)}`,
);
}
return defaultUser;
});
}

View File

@ -0,0 +1,24 @@
import { refreshMe } from "@goauthentik/common/users";
import { state } from "@goauthentik/components/oauth/constants";
import { User, UserManager, UserManagerSettings } from "oidc-client-ts";
import { LitElement } from "lit";
import { customElement, property } from "lit/decorators.js";
@customElement("ak-oauth-callback")
export class OAuthCallback extends LitElement {
@property()
params?: string;
@property({ attribute: false })
settings?: UserManagerSettings;
async firstUpdated(): Promise<void> {
if (!this.settings) {
return;
}
const client = new UserManager(this.settings);
const user = (await client.signinCallback(`#${this.params}`)) as User;
const st = user.state as state;
window.location.assign(st.url);
refreshMe();
}
}

View File

@ -0,0 +1,7 @@
export class state {
url: string;
constructor() {
this.url = window.location.href;
}
}

View File

@ -0,0 +1,41 @@
import { state } from "@goauthentik/components/oauth/constants";
import { Interface } from "@goauthentik/elements/Interface/index.js";
import { UserManager, UserManagerSettings } from "oidc-client-ts";
import { ReactiveController, ReactiveControllerHost } from "lit";
type ReactiveInterfaceHost = Partial<ReactiveControllerHost> & Interface;
export class OAuthLoginController implements ReactiveController {
checked = false;
constructor(
private host: ReactiveInterfaceHost,
private settings: UserManagerSettings,
) {
this.host.addController(this);
}
hostUpdated() {
if (this.checked) {
return;
}
this.checked = true;
this.ensureLoggedIn();
}
private async ensureLoggedIn() {
const client = new UserManager(this.settings);
const user = await client.getUser();
if (user !== null) {
return;
}
if (window.location.href.startsWith(this.settings.redirect_uri)) {
return;
}
const s = new state();
await client.signinRedirect({
state: s,
});
}
}

View File

@ -0,0 +1,25 @@
import { MemoryStore } from "@goauthentik/components/oauth/storage";
import { Log, OidcClientSettings, UserManagerSettings } from "oidc-client-ts";
Log.setLogger(console);
Log.setLevel(Log.DEBUG);
export const userSettings: OidcClientSettings & UserManagerSettings = {
authority: `${window.location.origin}/application/o/authentik-user-interface/`,
redirect_uri: `${window.location.origin}/if/user/#/oauth-callback/`,
client_id: "authentik-user-interface",
scope: "openid profile email goauthentik.io/api",
response_mode: "fragment",
automaticSilentRenew: true,
userStore: new MemoryStore(),
};
export const adminSettings: OidcClientSettings & UserManagerSettings = {
authority: `${window.location.origin}/application/o/authentik-admin-interface/`,
redirect_uri: `${window.location.origin}/if/admin/#/oauth-callback/`,
client_id: "authentik-admin-interface",
scope: "openid profile email goauthentik.io/api",
response_mode: "fragment",
automaticSilentRenew: true,
userStore: new MemoryStore(),
};

View File

@ -0,0 +1,17 @@
import { UserManager, UserManagerSettings } from "oidc-client-ts";
import { LitElement } from "lit";
import { customElement, property } from "lit/decorators.js";
@customElement("ak-oauth-signout")
export class OAuthSignout extends LitElement {
@property({ attribute: false })
settings?: UserManagerSettings;
async firstUpdated(): Promise<void> {
if (!this.settings) {
return;
}
const client = new UserManager(this.settings);
await client.signoutRedirect();
}
}

View File

@ -0,0 +1,20 @@
import { WebStorageStateStore } from "oidc-client-ts";
export class MemoryStore extends WebStorageStateStore {
private map: Map<string, string> = new Map();
async set(key: string, value: string): Promise<void> {
this.map.set(key, value);
}
async get(key: string): Promise<string | null> {
const value = this.map.get(key);
return value ? value : null;
}
async remove(key: string): Promise<string | null> {
const value = await this.get(key);
this.map.delete(key);
return value;
}
async getAllKeys(): Promise<string[]> {
return Array.from(this.map.keys());
}
}

View File

@ -47,7 +47,7 @@ export class SidebarUser extends AKElement {
html``,
)}
</a>
<a href="/flows/-/default/invalidation/" class="pf-c-nav__link user-logout" id="logout">
<a href="#/oauth-signout" class="pf-c-nav__link user-logout" id="logout">
<i class="fas fa-sign-out-alt" aria-hidden="true"></i>
</a>
`;

View File

@ -1,3 +1,6 @@
import "@goauthentik/components/oauth/callback";
import { userSettings } from "@goauthentik/components/oauth/settings";
import "@goauthentik/components/oauth/signout";
import { Route } from "@goauthentik/elements/router/Route";
import "@goauthentik/user/LibraryPage/ak-library.js";
@ -7,6 +10,15 @@ export const ROUTES: Route[] = [
// Prevent infinite Shell loops
new Route(new RegExp("^/$")).redirect("/library"),
new Route(new RegExp("^#.*")).redirect("/library"),
new Route(new RegExp("^/oauth-callback/(?<rest>.*)$"), async (args) => {
return html`<ak-oauth-callback
.settings=${userSettings}
params=${args.rest}
></ak-oauth-callback>`;
}),
new Route(new RegExp("^/oauth-signout$"), async () => {
return html`<ak-oauth-signout .settings=${userSettings}></ak-oauth-signout>`;
}),
new Route(new RegExp("^/library$"), async () => html`<ak-library></ak-library>`),
new Route(new RegExp("^/settings$"), async () => {
await import("@goauthentik/user/user-settings/UserSettingsPage");

View File

@ -4,14 +4,18 @@ import {
EVENT_NOTIFICATION_DRAWER_TOGGLE,
EVENT_WS_MESSAGE,
} from "@goauthentik/common/constants";
import { WithOAuth } from "@goauthentik/common/oauth/interface";
import { configureSentry } from "@goauthentik/common/sentry";
import { UIConfig, UserDisplay } from "@goauthentik/common/ui/config";
import { me } from "@goauthentik/common/users";
import { WebsocketClient } from "@goauthentik/common/ws";
import { OAuthLoginController } from "@goauthentik/components/oauth/controller.js";
import { userSettings } from "@goauthentik/components/oauth/settings";
import { AKElement } from "@goauthentik/elements/Base";
import { EnterpriseAwareInterface } from "@goauthentik/elements/Interface";
import "@goauthentik/elements/ak-locale-context";
import "@goauthentik/elements/buttons/ActionButton";
import { bound } from "@goauthentik/elements/decorators/bound.js";
import "@goauthentik/elements/enterprise/EnterpriseStatusBanner";
import "@goauthentik/elements/messages/MessageContainer";
import "@goauthentik/elements/notifications/APIDrawer";
@ -206,10 +210,7 @@ class UserInterfacePresentation extends AKElement {
<!-- -->
${this.renderSettings()}
<div class="pf-c-page__header-tools-item">
<a
href="/flows/-/default/invalidation/"
class="pf-c-button pf-m-plain"
>
<a href="#/oauth-signout" class="pf-c-button pf-m-plain">
<pf-tooltip position="top" content=${msg("Sign out")}>
<i class="fas fa-sign-out-alt" aria-hidden="true"></i>
</pf-tooltip>
@ -384,7 +385,7 @@ class UserInterfacePresentation extends AKElement {
//
//
@customElement("ak-interface-user")
export class UserInterface extends EnterpriseAwareInterface {
export class UserInterface extends WithOAuth(EnterpriseAwareInterface, userSettings) {
@property({ type: Boolean })
notificationDrawerOpen = getURLParam("notificationDrawerOpen", false);
@ -399,14 +400,14 @@ export class UserInterface extends EnterpriseAwareInterface {
@state()
me?: SessionUser;
oauthController: OAuthLoginController;
constructor() {
super();
this.ws = new WebsocketClient();
this.fetchConfigurationDetails();
configureSentry(true);
this.toggleNotificationDrawer = this.toggleNotificationDrawer.bind(this);
this.toggleApiDrawer = this.toggleApiDrawer.bind(this);
this.fetchConfigurationDetails = this.fetchConfigurationDetails.bind(this);
this.oauthController = new OAuthLoginController(this, userSettings);
}
connectedCallback() {
@ -423,6 +424,7 @@ export class UserInterface extends EnterpriseAwareInterface {
super.disconnectedCallback();
}
@bound
toggleNotificationDrawer() {
this.notificationDrawerOpen = !this.notificationDrawerOpen;
updateURLParams({
@ -430,6 +432,7 @@ export class UserInterface extends EnterpriseAwareInterface {
});
}
@bound
toggleApiDrawer() {
this.apiDrawerOpen = !this.apiDrawerOpen;
updateURLParams({
@ -437,6 +440,7 @@ export class UserInterface extends EnterpriseAwareInterface {
});
}
@bound
fetchConfigurationDetails() {
me().then((me: SessionUser) => {
this.me = me;