@odx/auth 1.0.3 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -1
- package/esm2020/index.mjs +2 -1
- package/esm2020/lib/auth.component.mjs +6 -5
- package/esm2020/lib/auth.config.mjs +20 -4
- package/esm2020/lib/auth.directive.mjs +2 -2
- package/esm2020/lib/auth.guard.mjs +17 -6
- package/esm2020/lib/auth.providers.mjs +7 -2
- package/esm2020/lib/auth.service.mjs +29 -15
- package/esm2020/lib/auth.typings.mjs +1 -1
- package/esm2020/lib/directives/auth-action.directive.mjs +24 -0
- package/esm2020/lib/directives/index.mjs +2 -1
- package/esm2020/lib/directives/sign-in.directive.mjs +10 -15
- package/esm2020/lib/directives/sign-out.directive.mjs +10 -15
- package/esm2020/lib/helpers/create-inititals.mjs +3 -3
- package/esm2020/lib/helpers/index.mjs +3 -2
- package/esm2020/lib/helpers/resolve-email.mjs +14 -0
- package/esm2020/lib/helpers/resolve-username.mjs +14 -0
- package/esm2020/lib/models/auth-http-cache.mjs +34 -0
- package/esm2020/lib/models/auth-plugin-manager.mjs +29 -0
- package/esm2020/lib/models/authorized-handler.mjs +1 -1
- package/esm2020/lib/models/index.mjs +3 -1
- package/esm2020/lib/plugins/core-identity.plugin.mjs +13 -0
- package/esm2020/lib/plugins/index.mjs +2 -0
- package/esm2020/plugins/service-connect/index.mjs +8 -0
- package/esm2020/plugins/service-connect/lib/dtos/get-service-connect-rights-response.dto.mjs +2 -0
- package/esm2020/plugins/service-connect/lib/dtos/index.mjs +2 -0
- package/esm2020/plugins/service-connect/lib/helpers/build-service-connect-url.mjs +9 -0
- package/esm2020/plugins/service-connect/lib/helpers/has-roles-or-rights-handler.mjs +5 -0
- package/esm2020/plugins/service-connect/lib/helpers/has-roles-or-rights.mjs +5 -0
- package/esm2020/plugins/service-connect/lib/helpers/index.mjs +4 -0
- package/esm2020/plugins/service-connect/lib/service-connect-rights.directive.mjs +32 -0
- package/esm2020/plugins/service-connect/lib/service-connect-rights.guard.mjs +7 -0
- package/esm2020/plugins/service-connect/lib/service-connect-rights.plugin.mjs +29 -0
- package/esm2020/plugins/service-connect/lib/service-connect.config.mjs +14 -0
- package/esm2020/plugins/service-connect/lib/service-connect.typings.mjs +2 -0
- package/esm2020/plugins/service-connect/odx-auth-plugins-service-connect.mjs +5 -0
- package/fesm2015/odx-auth-plugins-service-connect.mjs +99 -0
- package/fesm2015/odx-auth-plugins-service-connect.mjs.map +1 -0
- package/fesm2015/odx-auth.mjs +208 -72
- package/fesm2015/odx-auth.mjs.map +1 -1
- package/fesm2020/odx-auth-plugins-service-connect.mjs +97 -0
- package/fesm2020/odx-auth-plugins-service-connect.mjs.map +1 -0
- package/fesm2020/odx-auth.mjs +201 -71
- package/fesm2020/odx-auth.mjs.map +1 -1
- package/index.d.ts +1 -0
- package/lib/auth.component.d.ts +1 -1
- package/lib/auth.config.d.ts +12 -3
- package/lib/auth.guard.d.ts +2 -2
- package/lib/auth.service.d.ts +11 -8
- package/lib/auth.typings.d.ts +9 -1
- package/lib/directives/auth-action.directive.d.ts +12 -0
- package/lib/directives/index.d.ts +1 -0
- package/lib/directives/sign-in.directive.d.ts +4 -6
- package/lib/directives/sign-out.directive.d.ts +4 -6
- package/lib/helpers/create-inititals.d.ts +1 -1
- package/lib/helpers/index.d.ts +2 -1
- package/lib/helpers/resolve-email.d.ts +1 -0
- package/lib/helpers/resolve-username.d.ts +1 -0
- package/lib/models/auth-http-cache.d.ts +11 -0
- package/lib/models/auth-plugin-manager.d.ts +15 -0
- package/lib/models/authorized-handler.d.ts +1 -2
- package/lib/models/index.d.ts +2 -0
- package/lib/plugins/core-identity.plugin.d.ts +11 -0
- package/lib/plugins/index.d.ts +1 -0
- package/package.json +11 -2
- package/plugins/service-connect/README.md +3 -0
- package/plugins/service-connect/index.d.ts +7 -0
- package/plugins/service-connect/lib/dtos/get-service-connect-rights-response.dto.d.ts +3 -0
- package/plugins/service-connect/lib/dtos/index.d.ts +1 -0
- package/plugins/service-connect/lib/helpers/build-service-connect-url.d.ts +3 -0
- package/plugins/service-connect/lib/helpers/has-roles-or-rights-handler.d.ts +3 -0
- package/plugins/service-connect/lib/helpers/has-roles-or-rights.d.ts +5 -0
- package/plugins/service-connect/lib/helpers/index.d.ts +3 -0
- package/plugins/service-connect/lib/service-connect-rights.directive.d.ts +9 -0
- package/plugins/service-connect/lib/service-connect-rights.guard.d.ts +3 -0
- package/plugins/service-connect/lib/service-connect-rights.plugin.d.ts +7 -0
- package/plugins/service-connect/lib/service-connect.config.d.ts +11 -0
- package/plugins/service-connect/lib/service-connect.typings.d.ts +9 -0
- package/esm2020/lib/helpers/parse-identity-claims.mjs +0 -13
- package/lib/helpers/parse-identity-claims.d.ts +0 -2
package/fesm2020/odx-auth.mjs
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, Injectable,
|
|
2
|
+
import { InjectionToken, inject, Injectable, Directive, EventEmitter, Output, HostListener, Component, ChangeDetectionStrategy, ViewEncapsulation, Input, NgModule, EnvironmentInjector, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, APP_INITIALIZER } from '@angular/core';
|
|
3
3
|
import { WindowRef, CoreModule } from '@odx/angular';
|
|
4
4
|
import * as i3 from '@odx/angular/components/area-header';
|
|
5
5
|
import { AreaHeaderModule } from '@odx/angular/components/area-header';
|
|
6
6
|
import * as i8 from '@odx/angular/components/dropdown';
|
|
7
7
|
import { DropdownModule } from '@odx/angular/components/dropdown';
|
|
8
|
-
import * as i9 from '@odx/angular/components/header';
|
|
9
8
|
import { HeaderModule } from '@odx/angular/components/header';
|
|
9
|
+
import * as i1 from '@odx/angular/components/loading-spinner';
|
|
10
|
+
import { LoadingSpinnerDirective, LoadingSpinnerModule } from '@odx/angular/components/loading-spinner';
|
|
10
11
|
import { LogoDirective } from '@odx/angular/components/logo';
|
|
11
|
-
import {
|
|
12
|
+
import { isString, createConfigTokens, untilDestroyed, Position, buildUrl } from '@odx/angular/utils';
|
|
12
13
|
import { HttpErrorResponse } from '@angular/common/http';
|
|
13
14
|
import { Router } from '@angular/router';
|
|
15
|
+
import { fromEvents } from '@odx/angular/rxjs';
|
|
14
16
|
import { OAuthService, OAuthErrorEvent, provideOAuthClient, OAuthModuleConfig, OAuthStorage } from 'angular-oauth2-oidc';
|
|
15
|
-
import {
|
|
16
|
-
import
|
|
17
|
-
import {
|
|
17
|
+
import { deepmerge } from 'deepmerge-ts';
|
|
18
|
+
import jwtDecode from 'jwt-decode';
|
|
19
|
+
import { BehaviorSubject, filter, map, distinctUntilChanged, share, of, switchMap, combineLatest, tap, take, fromEvent, startWith, shareReplay, merge } from 'rxjs';
|
|
18
20
|
import * as i1$1 from '@angular/common';
|
|
19
21
|
import { NgIf } from '@angular/common';
|
|
20
22
|
import * as i2 from '@ngrx/component';
|
|
@@ -23,12 +25,62 @@ import * as i5 from '@odx/angular/components/action-group';
|
|
|
23
25
|
import * as i6 from '@odx/angular/components/button';
|
|
24
26
|
import * as i7 from '@odx/angular/components/icon';
|
|
25
27
|
|
|
28
|
+
function createInitials(value) {
|
|
29
|
+
if (!value)
|
|
30
|
+
return '';
|
|
31
|
+
const parts = value.trim().split(' ');
|
|
32
|
+
return parts.reduce((initials, curr, index) => {
|
|
33
|
+
if (index === 0 || index === parts.length - 1) {
|
|
34
|
+
initials += curr[0].toUpperCase();
|
|
35
|
+
}
|
|
36
|
+
return initials;
|
|
37
|
+
}, '');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function resolveEmail(claims) {
|
|
41
|
+
if (isString(claims['email'])) {
|
|
42
|
+
return claims['email'];
|
|
43
|
+
}
|
|
44
|
+
if (isString(claims['email_address'])) {
|
|
45
|
+
return claims['email_address'];
|
|
46
|
+
}
|
|
47
|
+
if (Array.isArray(claims['emails']) && isString(claims['emails'][0])) {
|
|
48
|
+
return claims['emails'][0];
|
|
49
|
+
}
|
|
50
|
+
return '';
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function resolveUsername(claims) {
|
|
54
|
+
if (isString(claims['firstname']) && isString(claims['lastname'])) {
|
|
55
|
+
return `${claims['firstname']} ${claims['lastname']}`;
|
|
56
|
+
}
|
|
57
|
+
if (isString(claims['displayname'])) {
|
|
58
|
+
return claims['displayname'];
|
|
59
|
+
}
|
|
60
|
+
if (isString(claims['name'])) {
|
|
61
|
+
return claims['name'];
|
|
62
|
+
}
|
|
63
|
+
return '';
|
|
64
|
+
}
|
|
65
|
+
|
|
26
66
|
const DEFAULT_AUTH_SCOPES = ['openid', 'profile', 'email', 'offline_access'];
|
|
27
67
|
const DEFAULT_ISSUERS = {
|
|
28
68
|
dev: 'https://dev.login.draeger.com/oauth2/default',
|
|
29
69
|
stage: 'https://test.login.draeger.com/oauth2/default',
|
|
30
70
|
prod: 'https://login.draeger.com/oauth2/default',
|
|
31
71
|
};
|
|
72
|
+
const ODX_AUTH_CORE_PLUGINS = new InjectionToken('@odx/auth::CorePlugins', {
|
|
73
|
+
providedIn: 'root',
|
|
74
|
+
factory: () => [],
|
|
75
|
+
});
|
|
76
|
+
const ODX_AUTH_PLUGINS = new InjectionToken('@odx/auth::Plugins', {
|
|
77
|
+
providedIn: 'root',
|
|
78
|
+
factory: () => {
|
|
79
|
+
const { plugins } = injectAuthConfig();
|
|
80
|
+
const corePlugins = inject(ODX_AUTH_CORE_PLUGINS);
|
|
81
|
+
return [...corePlugins, ...plugins].map((pluginFactory) => pluginFactory());
|
|
82
|
+
},
|
|
83
|
+
});
|
|
32
84
|
const { AuthDefaultConfig, AuthConfig, injectAuthConfig, provideAuthConfig } = createConfigTokens('Auth', '@odx/auth', {
|
|
33
85
|
environment: 'prod',
|
|
34
86
|
redirectPath: 'login/callback',
|
|
@@ -39,60 +91,93 @@ const { AuthDefaultConfig, AuthConfig, injectAuthConfig, provideAuthConfig } = c
|
|
|
39
91
|
errorHandler: (error) => {
|
|
40
92
|
throw error;
|
|
41
93
|
},
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
94
|
+
createInitials,
|
|
95
|
+
resolveEmail,
|
|
96
|
+
resolveUsername,
|
|
97
|
+
showRedirectOverlay: false,
|
|
98
|
+
plugins: [],
|
|
45
99
|
});
|
|
46
100
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
101
|
+
const ODX_AUTH_HTTP_CACHE_STORAGE = new InjectionToken('@odx/auth::AuthHttpCacheStorage', {
|
|
102
|
+
providedIn: 'root',
|
|
103
|
+
factory: () => inject(WindowRef).nativeWindow.caches,
|
|
104
|
+
});
|
|
105
|
+
class AuthHttpCache {
|
|
106
|
+
constructor() {
|
|
107
|
+
this.cacheStorage = inject(ODX_AUTH_HTTP_CACHE_STORAGE);
|
|
108
|
+
}
|
|
109
|
+
async delete(request) {
|
|
110
|
+
const cache = await this.cacheStorage.open(AuthHttpCache.CACHE_KEY);
|
|
111
|
+
return cache.delete(request);
|
|
112
|
+
}
|
|
113
|
+
async request(request) {
|
|
114
|
+
const cache = await this.cacheStorage.open(AuthHttpCache.CACHE_KEY);
|
|
115
|
+
try {
|
|
116
|
+
await cache.add(request);
|
|
54
117
|
}
|
|
55
|
-
|
|
56
|
-
|
|
118
|
+
catch {
|
|
119
|
+
// ignore request errors
|
|
120
|
+
}
|
|
121
|
+
return cache.match(request, { ignoreVary: true, ignoreSearch: true }).then((res) => res?.json() ?? null);
|
|
122
|
+
}
|
|
57
123
|
}
|
|
124
|
+
AuthHttpCache.CACHE_KEY = '@odx/auth/http-cache';
|
|
125
|
+
AuthHttpCache.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: AuthHttpCache, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
126
|
+
AuthHttpCache.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: AuthHttpCache, providedIn: 'root' });
|
|
127
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: AuthHttpCache, decorators: [{
|
|
128
|
+
type: Injectable,
|
|
129
|
+
args: [{ providedIn: 'root' }]
|
|
130
|
+
}] });
|
|
58
131
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
132
|
+
class AuthPluginManager {
|
|
133
|
+
constructor() {
|
|
134
|
+
this.plugins = inject(ODX_AUTH_PLUGINS);
|
|
135
|
+
this.result$$ = new BehaviorSubject(null);
|
|
136
|
+
this.pluginsReady$ = this.result$$.pipe(filter(Boolean), map(Boolean), distinctUntilChanged(), share());
|
|
137
|
+
this.pluginsLoading$ = this.result$$.pipe(map((result) => !result), distinctUntilChanged(), share());
|
|
138
|
+
}
|
|
139
|
+
runPlugins(authService) {
|
|
140
|
+
if (this.plugins.length < 1) {
|
|
141
|
+
return of({});
|
|
142
|
+
}
|
|
143
|
+
return authService.isInitialized$.pipe(switchMap(() => combineLatest(this.plugins.map((plugin) => plugin(authService)))), map((results) => deepmerge(...results)), tap((result) => this.result$$.next(result)), take(1));
|
|
144
|
+
}
|
|
145
|
+
getResult() {
|
|
146
|
+
return this.result$$.getValue() ?? {};
|
|
147
|
+
}
|
|
69
148
|
}
|
|
149
|
+
AuthPluginManager.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: AuthPluginManager, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
150
|
+
AuthPluginManager.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: AuthPluginManager, providedIn: 'root' });
|
|
151
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: AuthPluginManager, decorators: [{
|
|
152
|
+
type: Injectable,
|
|
153
|
+
args: [{ providedIn: 'root' }]
|
|
154
|
+
}] });
|
|
70
155
|
|
|
71
156
|
class AuthService {
|
|
72
157
|
constructor() {
|
|
73
158
|
this.authConfig = injectAuthConfig();
|
|
159
|
+
this.authPluginManager = inject(AuthPluginManager);
|
|
74
160
|
this.oauthService = inject(OAuthService);
|
|
75
161
|
this.router = inject(Router);
|
|
76
162
|
this.windowRef = inject(WindowRef);
|
|
77
163
|
this.isInitialized$$ = new BehaviorSubject(false);
|
|
78
164
|
this.onAccessTokenUpdate$ = fromEvent(this.windowRef.nativeWindow, 'storage').pipe(filter(({ key }) => key === 'access_token' || key === null), startWith(null), share());
|
|
79
165
|
this.onAuthStateChange$ = combineLatest([this.oauthService.events.pipe(startWith(null)), this.windowRef.isOnline$, this.onAccessTokenUpdate$]);
|
|
80
|
-
this.
|
|
166
|
+
this.isInitialized$ = this.isInitialized$$.pipe(filter(Boolean), distinctUntilChanged());
|
|
167
|
+
this.isAuthenticated$ = this.isInitialized$.pipe(switchMap(() => this.authPluginManager.pluginsReady$), switchMap(() => this.onAuthStateChange$), map(() => this.isAuthenticated()), shareReplay({ refCount: true }));
|
|
81
168
|
this.identityClaims$ = this.isAuthenticated$.pipe(map(() => this.getIdentityClaims()), shareReplay({ refCount: true }));
|
|
82
169
|
this.errors$ = this.oauthService.events.pipe(filter((event) => event instanceof OAuthErrorEvent), share());
|
|
83
|
-
this.
|
|
84
|
-
|
|
170
|
+
this.isRedirecting$ = fromEvents(this.windowRef.nativeWindow, 'beforeunload').pipe(map(Boolean), distinctUntilChanged(), share());
|
|
171
|
+
this.isLoading$ = merge(this.isRedirecting$, this.authPluginManager.pluginsLoading$).pipe(distinctUntilChanged());
|
|
172
|
+
this.windowRef.isOnline$.subscribe((isOnline) => {
|
|
85
173
|
if (isOnline) {
|
|
86
174
|
this.oauthService.setupAutomaticSilentRefresh();
|
|
87
175
|
}
|
|
88
176
|
else {
|
|
89
177
|
this.oauthService.stopAutomaticRefresh();
|
|
90
178
|
}
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
ngOnDestroy() {
|
|
95
|
-
this.subscription.unsubscribe();
|
|
179
|
+
});
|
|
180
|
+
this.authPluginManager.runPlugins(this).subscribe();
|
|
96
181
|
}
|
|
97
182
|
async initialize(config) {
|
|
98
183
|
this.oauthService.configure(config);
|
|
@@ -144,6 +229,10 @@ class AuthService {
|
|
|
144
229
|
getAccessToken() {
|
|
145
230
|
return this.oauthService.getAccessToken() ?? null;
|
|
146
231
|
}
|
|
232
|
+
getAccessTokenPayload() {
|
|
233
|
+
const token = this.getAccessToken();
|
|
234
|
+
return token ? jwtDecode(token) : null;
|
|
235
|
+
}
|
|
147
236
|
getRefreshToken() {
|
|
148
237
|
return this.oauthService.getRefreshToken() ?? null;
|
|
149
238
|
}
|
|
@@ -151,7 +240,14 @@ class AuthService {
|
|
|
151
240
|
return this.oauthService.getIdToken() ?? null;
|
|
152
241
|
}
|
|
153
242
|
getIdentityClaims() {
|
|
154
|
-
|
|
243
|
+
if (!this.getIdToken())
|
|
244
|
+
return null;
|
|
245
|
+
return deepmerge(this.oauthService.getIdentityClaims(), this.authPluginManager.getResult());
|
|
246
|
+
}
|
|
247
|
+
getRawIdentityClaims() {
|
|
248
|
+
if (!this.getIdToken())
|
|
249
|
+
return null;
|
|
250
|
+
return this.oauthService.getIdentityClaims();
|
|
155
251
|
}
|
|
156
252
|
isAuthenticated() {
|
|
157
253
|
if (this.windowRef.isOnline()) {
|
|
@@ -163,9 +259,9 @@ class AuthService {
|
|
|
163
259
|
return this.isAuthenticated() && (authorizedHandler?.(this.getIdentityClaims(), this) ?? true);
|
|
164
260
|
}
|
|
165
261
|
async routeToRequestedUrl() {
|
|
166
|
-
if (this.oauthService.state)
|
|
167
|
-
|
|
168
|
-
|
|
262
|
+
if (!this.oauthService.state)
|
|
263
|
+
return;
|
|
264
|
+
await this.router.navigateByUrl(decodeURIComponent(this.oauthService.state));
|
|
169
265
|
}
|
|
170
266
|
hasValidOfflineToken() {
|
|
171
267
|
const issuedAt = this.getIdentityClaims()?.iat ?? 0;
|
|
@@ -179,24 +275,38 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImpor
|
|
|
179
275
|
args: [{ providedIn: 'root' }]
|
|
180
276
|
}], ctorParameters: function () { return []; } });
|
|
181
277
|
|
|
182
|
-
class
|
|
278
|
+
class AuthActionDirective {
|
|
183
279
|
constructor() {
|
|
184
|
-
this.
|
|
280
|
+
this.takeUntilDestroyed = untilDestroyed();
|
|
185
281
|
this.loadingSpinnerDirective = inject(LoadingSpinnerDirective, { self: true });
|
|
186
|
-
|
|
187
|
-
this.afterSignIn = new EventEmitter();
|
|
282
|
+
this.authService = inject(AuthService);
|
|
188
283
|
}
|
|
189
284
|
ngAfterViewInit() {
|
|
190
285
|
this.loadingSpinnerDirective.autoColor = true;
|
|
286
|
+
this.authService.isRedirecting$.pipe(this.takeUntilDestroyed()).subscribe(() => {
|
|
287
|
+
this.loadingSpinnerDirective.isLoading = true;
|
|
288
|
+
});
|
|
191
289
|
}
|
|
192
|
-
|
|
193
|
-
|
|
290
|
+
}
|
|
291
|
+
AuthActionDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: AuthActionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
292
|
+
AuthActionDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.9", type: AuthActionDirective, ngImport: i0 });
|
|
293
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: AuthActionDirective, decorators: [{
|
|
294
|
+
type: Directive
|
|
295
|
+
}] });
|
|
296
|
+
|
|
297
|
+
class SignInDirective extends AuthActionDirective {
|
|
298
|
+
constructor() {
|
|
299
|
+
super(...arguments);
|
|
300
|
+
// eslint-disable-next-line @angular-eslint/no-output-rename
|
|
301
|
+
this.afterSignIn = new EventEmitter();
|
|
302
|
+
}
|
|
303
|
+
handleClick() {
|
|
194
304
|
this.authService.signIn();
|
|
195
|
-
this.afterSignIn.
|
|
305
|
+
this.afterSignIn.next();
|
|
196
306
|
}
|
|
197
307
|
}
|
|
198
|
-
SignInDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: SignInDirective, deps:
|
|
199
|
-
SignInDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.9", type: SignInDirective, isStandalone: true, selector: "[odxButton][odxAuthSignIn]", outputs: { afterSignIn: "odxAuthSignIn" }, host: { listeners: { "click": "
|
|
308
|
+
SignInDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: SignInDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
309
|
+
SignInDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.9", type: SignInDirective, isStandalone: true, selector: "[odxButton][odxAuthSignIn]", outputs: { afterSignIn: "odxAuthSignIn" }, host: { listeners: { "click": "handleClick()" } }, usesInheritance: true, hostDirectives: [{ directive: i1.LoadingSpinnerDirective }], ngImport: i0 });
|
|
200
310
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: SignInDirective, decorators: [{
|
|
201
311
|
type: Directive,
|
|
202
312
|
args: [{
|
|
@@ -207,29 +317,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImpor
|
|
|
207
317
|
}], propDecorators: { afterSignIn: [{
|
|
208
318
|
type: Output,
|
|
209
319
|
args: ['odxAuthSignIn']
|
|
210
|
-
}],
|
|
320
|
+
}], handleClick: [{
|
|
211
321
|
type: HostListener,
|
|
212
322
|
args: ['click']
|
|
213
323
|
}] } });
|
|
214
324
|
|
|
215
|
-
class SignOutDirective {
|
|
325
|
+
class SignOutDirective extends AuthActionDirective {
|
|
216
326
|
constructor() {
|
|
217
|
-
|
|
218
|
-
this.loadingSpinnerDirective = inject(LoadingSpinnerDirective, { self: true });
|
|
327
|
+
super(...arguments);
|
|
219
328
|
// eslint-disable-next-line @angular-eslint/no-output-rename
|
|
220
329
|
this.afterSignOut = new EventEmitter();
|
|
221
330
|
}
|
|
222
|
-
|
|
223
|
-
this.loadingSpinnerDirective.autoColor = true;
|
|
224
|
-
}
|
|
225
|
-
async signIn() {
|
|
226
|
-
this.loadingSpinnerDirective.isLoading = true;
|
|
331
|
+
handleClick() {
|
|
227
332
|
this.authService.signOut();
|
|
228
|
-
this.afterSignOut.
|
|
333
|
+
this.afterSignOut.next();
|
|
229
334
|
}
|
|
230
335
|
}
|
|
231
|
-
SignOutDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: SignOutDirective, deps:
|
|
232
|
-
SignOutDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.9", type: SignOutDirective, isStandalone: true, selector: "[odxButton][odxAuthSignOut]", outputs: { afterSignOut: "odxAuthSignOut" }, host: { listeners: { "click": "
|
|
336
|
+
SignOutDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: SignOutDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
337
|
+
SignOutDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.9", type: SignOutDirective, isStandalone: true, selector: "[odxButton][odxAuthSignOut]", outputs: { afterSignOut: "odxAuthSignOut" }, host: { listeners: { "click": "handleClick()" } }, usesInheritance: true, hostDirectives: [{ directive: i1.LoadingSpinnerDirective }], ngImport: i0 });
|
|
233
338
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: SignOutDirective, decorators: [{
|
|
234
339
|
type: Directive,
|
|
235
340
|
args: [{
|
|
@@ -240,15 +345,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImpor
|
|
|
240
345
|
}], propDecorators: { afterSignOut: [{
|
|
241
346
|
type: Output,
|
|
242
347
|
args: ['odxAuthSignOut']
|
|
243
|
-
}],
|
|
348
|
+
}], handleClick: [{
|
|
244
349
|
type: HostListener,
|
|
245
350
|
args: ['click']
|
|
246
351
|
}] } });
|
|
247
352
|
|
|
248
353
|
class AuthComponent {
|
|
249
354
|
constructor() {
|
|
250
|
-
this.authService = inject(AuthService);
|
|
251
355
|
this.authConfig = injectAuthConfig();
|
|
356
|
+
this.authService = inject(AuthService);
|
|
252
357
|
this.dropdownOptions = {
|
|
253
358
|
position: Position.BOTTOM_END,
|
|
254
359
|
enableFallback: false,
|
|
@@ -259,10 +364,10 @@ class AuthComponent {
|
|
|
259
364
|
}
|
|
260
365
|
}
|
|
261
366
|
AuthComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: AuthComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
262
|
-
AuthComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: AuthComponent, isStandalone: true, selector: "odx-auth", inputs: { signInButtonText: "signInButtonText", signOutButtonText: "signOutButtonText" }, ngImport: i0, template: "<odx-action-group
|
|
367
|
+
AuthComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: AuthComponent, isStandalone: true, selector: "odx-auth", inputs: { signInButtonText: "signInButtonText", signOutButtonText: "signOutButtonText" }, ngImport: i0, template: "<odx-action-group>\n <ng-template [ngrxLet]=\"{ idClaims: authService.identityClaims$, isAuthenticated: authService.isAuthenticated$ }\" let-vm>\n <ng-template [ngIf]=\"vm.isAuthenticated\" [ngIfElse]=\"notAuthenticated\">\n <button odxButton [odxDropdown]=\"userProfileMenu\" [odxDropdownOptions]=\"dropdownOptions\" data-testid=\"odx-auth-user-profile-button\">\n <ng-template [ngTemplateOutlet]=\"userAvatar\"></ng-template>\n </button>\n <ng-template #userProfileMenu>\n <odx-area-header class=\"odx-padding-x-12\" size=\"small\">\n <ng-template [ngTemplateOutlet]=\"userAvatar\" ngProjectAs=\"odx-avatar\"></ng-template>\n {{ vm.idClaims?.username }}\n <odx-area-header-subtitle>\n {{ vm.idClaims?.email }}\n </odx-area-header-subtitle>\n </odx-area-header>\n <ng-content></ng-content>\n <div class=\"odx-margin-top-12\" odxLayout=\"flex vertical-center\">\n <odx-logo odxLayout=\"auto\" class=\"odx-margin-left-12 odx-margin-right-auto\"></odx-logo>\n <button odxButton odxAuthSignOut variant=\"ghost\" data-testid=\"odx-auth-sign-out-button\">\n {{ signOutButtonText }}\n <odx-icon name=\"arrow-right\" alignRight></odx-icon>\n </button>\n </div>\n </ng-template>\n </ng-template>\n <ng-template #notAuthenticated>\n <button class=\"odx-auth-sign-in\" odxButton odxAuthSignIn variant=\"secondary\" data-testid=\"odx-auth-sign-in-button\">\n <odx-icon name=\"user\" alignLeft></odx-icon>\n {{ signInButtonText }}\n </button>\n </ng-template>\n <ng-template #userAvatar>\n <odx-avatar class=\"odx-auth-user-avatar\">\n {{ vm.idClaims?.initials ?? '' }}\n </odx-avatar>\n </ng-template>\n </ng-template>\n <ng-template [ngIf]=\"authConfig.showRedirectOverlay\">\n <div class=\"odx-auth-overlay\" [odxLoadingSpinner]=\"true\" *ngIf=\"authService.isLoading$ | async\"></div>\n </ng-template>\n</odx-action-group>\n", styles: [".odx-auth-user-profile .odx-dropdown__inner>.odx-area-header{max-width:max(360px,25vw);min-width:296px}.odx-auth-overlay{position:fixed;z-index:var(--odx-v-layer-5);inset:0}\n"], dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "directive", type: i2.LetDirective, selector: "[ngrxLet]", inputs: ["ngrxLet", "ngrxLetSuspenseTpl"] }, { kind: "ngmodule", type: AreaHeaderModule }, { kind: "component", type: i3.AreaHeaderComponent, selector: "odx-area-header", inputs: ["size"] }, { kind: "directive", type: i3.AreaHeaderSubtitleDirective, selector: "odx-area-header-subtitle" }, { kind: "component", type: i4.AvatarComponent, selector: "odx-avatar", inputs: ["size", "variant"] }, { kind: "component", type: i5.ActionGroupComponent, selector: "odx-action-group", inputs: ["reverse"] }, { kind: "component", type: i6.ButtonComponent, selector: "button[odxButton], a[odxButton]", inputs: ["variant", "size"] }, { kind: "component", type: i7.IconComponent, selector: "odx-icon", inputs: ["inline", "size", "name", "iconSet"] }, { kind: "ngmodule", type: DropdownModule }, { kind: "directive", type: i8.DropdownDirective, selector: "[odxDropdown]", inputs: ["odxDropdown", "odxDropdownDisabled", "odxDropdownShowLoader", "odxDropdownClickOutsideActive", "odxDropdownOptions", "odxDropdownReferenceElement", "odxDropdownTriggerElement", "odxDropdownHost", "odxDropdownOpenTrigger", "odxDropdownCloseTrigger"], outputs: ["odxDropdownBeforeOpen", "odxDropdownAfterOpen", "odxDropdownBeforeClose", "odxDropdownAfterClose"], exportAs: ["odxDropdown"] }, { kind: "ngmodule", type: HeaderModule }, { kind: "directive", type: LogoDirective, selector: "odx-logo", inputs: ["size", "variant"] }, { kind: "directive", type: SignInDirective, selector: "[odxButton][odxAuthSignIn]", outputs: ["odxAuthSignIn"] }, { kind: "directive", type: SignOutDirective, selector: "[odxButton][odxAuthSignOut]", outputs: ["odxAuthSignOut"] }, { kind: "ngmodule", type: LoadingSpinnerModule }, { kind: "directive", type: i1.LoadingSpinnerDirective, selector: "[odxLoadingSpinner]", inputs: ["odxLoadingSpinnerAutoColor", "odxLoadingSpinner", "odxLoadingSpinnerMinHeight"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
263
368
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: AuthComponent, decorators: [{
|
|
264
369
|
type: Component,
|
|
265
|
-
args: [{ standalone: true, selector: 'odx-auth', imports: [CoreModule, AreaHeaderModule, DropdownModule, HeaderModule, LogoDirective, SignInDirective, SignOutDirective], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<odx-action-group
|
|
370
|
+
args: [{ standalone: true, selector: 'odx-auth', imports: [CoreModule, AreaHeaderModule, DropdownModule, HeaderModule, LogoDirective, SignInDirective, SignOutDirective, LoadingSpinnerModule], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<odx-action-group>\n <ng-template [ngrxLet]=\"{ idClaims: authService.identityClaims$, isAuthenticated: authService.isAuthenticated$ }\" let-vm>\n <ng-template [ngIf]=\"vm.isAuthenticated\" [ngIfElse]=\"notAuthenticated\">\n <button odxButton [odxDropdown]=\"userProfileMenu\" [odxDropdownOptions]=\"dropdownOptions\" data-testid=\"odx-auth-user-profile-button\">\n <ng-template [ngTemplateOutlet]=\"userAvatar\"></ng-template>\n </button>\n <ng-template #userProfileMenu>\n <odx-area-header class=\"odx-padding-x-12\" size=\"small\">\n <ng-template [ngTemplateOutlet]=\"userAvatar\" ngProjectAs=\"odx-avatar\"></ng-template>\n {{ vm.idClaims?.username }}\n <odx-area-header-subtitle>\n {{ vm.idClaims?.email }}\n </odx-area-header-subtitle>\n </odx-area-header>\n <ng-content></ng-content>\n <div class=\"odx-margin-top-12\" odxLayout=\"flex vertical-center\">\n <odx-logo odxLayout=\"auto\" class=\"odx-margin-left-12 odx-margin-right-auto\"></odx-logo>\n <button odxButton odxAuthSignOut variant=\"ghost\" data-testid=\"odx-auth-sign-out-button\">\n {{ signOutButtonText }}\n <odx-icon name=\"arrow-right\" alignRight></odx-icon>\n </button>\n </div>\n </ng-template>\n </ng-template>\n <ng-template #notAuthenticated>\n <button class=\"odx-auth-sign-in\" odxButton odxAuthSignIn variant=\"secondary\" data-testid=\"odx-auth-sign-in-button\">\n <odx-icon name=\"user\" alignLeft></odx-icon>\n {{ signInButtonText }}\n </button>\n </ng-template>\n <ng-template #userAvatar>\n <odx-avatar class=\"odx-auth-user-avatar\">\n {{ vm.idClaims?.initials ?? '' }}\n </odx-avatar>\n </ng-template>\n </ng-template>\n <ng-template [ngIf]=\"authConfig.showRedirectOverlay\">\n <div class=\"odx-auth-overlay\" [odxLoadingSpinner]=\"true\" *ngIf=\"authService.isLoading$ | async\"></div>\n </ng-template>\n</odx-action-group>\n", styles: [".odx-auth-user-profile .odx-dropdown__inner>.odx-area-header{max-width:max(360px,25vw);min-width:296px}.odx-auth-overlay{position:fixed;z-index:var(--odx-v-layer-5);inset:0}\n"] }]
|
|
266
371
|
}], propDecorators: { signInButtonText: [{
|
|
267
372
|
type: Input
|
|
268
373
|
}], signOutButtonText: [{
|
|
@@ -281,7 +386,7 @@ class AuthDirective {
|
|
|
281
386
|
this.ngIfDirective.ngIfElse = value;
|
|
282
387
|
}
|
|
283
388
|
ngAfterViewInit() {
|
|
284
|
-
this.authService.
|
|
389
|
+
this.authService.identityClaims$.pipe(this.takeUntilDestroyed()).subscribe(() => {
|
|
285
390
|
const handler = isString(this.authorizationHandler) ? null : this.authorizationHandler;
|
|
286
391
|
this.ngIfDirective.ngIf = this.authService.isAuthorized(handler);
|
|
287
392
|
});
|
|
@@ -304,16 +409,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImpor
|
|
|
304
409
|
args: ['odxAuthElse']
|
|
305
410
|
}] } });
|
|
306
411
|
|
|
307
|
-
|
|
412
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
413
|
+
function authGuard(authorizedHandler, redirectTo) {
|
|
308
414
|
return (_, state) => {
|
|
309
415
|
const authService = inject(AuthService);
|
|
310
|
-
const router = inject(Router);
|
|
311
|
-
const isAuthorized = () => authorizedHandler?.(authService.getIdentityClaims(), router, authService);
|
|
416
|
+
const router = inject(Router, { optional: true });
|
|
312
417
|
return authService.isAuthenticated$.pipe(map((isAuthenticated) => {
|
|
313
418
|
if (!isAuthenticated) {
|
|
314
419
|
authService.signIn(state.url);
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
return authorizedHandler?.(authService.getIdentityClaims(), authService, router) ?? isAuthenticated;
|
|
423
|
+
}), tap((isAuthorized) => {
|
|
424
|
+
if (isAuthorized || !router)
|
|
425
|
+
return;
|
|
426
|
+
if (isString(redirectTo)) {
|
|
427
|
+
router.navigateByUrl(redirectTo);
|
|
428
|
+
}
|
|
429
|
+
else if (Array.isArray(redirectTo)) {
|
|
430
|
+
router.navigate(redirectTo);
|
|
315
431
|
}
|
|
316
|
-
return isAuthorized() ?? isAuthenticated;
|
|
317
432
|
}), take(1));
|
|
318
433
|
};
|
|
319
434
|
}
|
|
@@ -332,6 +447,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImpor
|
|
|
332
447
|
}]
|
|
333
448
|
}] });
|
|
334
449
|
|
|
450
|
+
const coreIdentityPlugin = () => {
|
|
451
|
+
const { resolveEmail, resolveUsername, createInitials } = injectAuthConfig();
|
|
452
|
+
return (authService) => {
|
|
453
|
+
const claims = authService.getRawIdentityClaims();
|
|
454
|
+
if (!claims)
|
|
455
|
+
return of({});
|
|
456
|
+
const username = resolveUsername(claims);
|
|
457
|
+
return of({ email: resolveEmail(claims), username, initials: createInitials(username) });
|
|
458
|
+
};
|
|
459
|
+
};
|
|
460
|
+
|
|
335
461
|
function configureInterceptor() {
|
|
336
462
|
const { allowedUrls } = injectAuthConfig();
|
|
337
463
|
return {
|
|
@@ -387,6 +513,10 @@ function provideAuth(config) {
|
|
|
387
513
|
provide: OAuthStorage,
|
|
388
514
|
useFactory: () => inject(AuthConfig).storage ?? inject(WindowRef).nativeWindow.localStorage,
|
|
389
515
|
},
|
|
516
|
+
{
|
|
517
|
+
provide: ODX_AUTH_CORE_PLUGINS,
|
|
518
|
+
useValue: [coreIdentityPlugin],
|
|
519
|
+
},
|
|
390
520
|
]);
|
|
391
521
|
}
|
|
392
522
|
|
|
@@ -394,5 +524,5 @@ function provideAuth(config) {
|
|
|
394
524
|
* Generated bundle index. Do not edit.
|
|
395
525
|
*/
|
|
396
526
|
|
|
397
|
-
export { AuthComponent, AuthConfig, AuthDefaultConfig, AuthDirective, AuthModule, AuthService, DEFAULT_AUTH_SCOPES, DEFAULT_ISSUERS, SignInDirective, SignOutDirective, authGuard, configureInterceptor,
|
|
527
|
+
export { AuthActionDirective, AuthComponent, AuthConfig, AuthDefaultConfig, AuthDirective, AuthHttpCache, AuthModule, AuthPluginManager, AuthService, DEFAULT_AUTH_SCOPES, DEFAULT_ISSUERS, ODX_AUTH_CORE_PLUGINS, ODX_AUTH_HTTP_CACHE_STORAGE, ODX_AUTH_PLUGINS, SignInDirective, SignOutDirective, authGuard, configureInterceptor, coreIdentityPlugin, createInitials, initalizeAuthConfig, initializeAuthErrorHandler, injectAuthConfig, provideAuth, provideAuthConfig, resolveEmail, resolveUsername };
|
|
398
528
|
//# sourceMappingURL=odx-auth.mjs.map
|