@masterteam/gateway-auth 0.0.16 → 0.0.18
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.
|
@@ -1,11 +1,11 @@
|
|
|
1
|
+
import { firstValueFrom, EMPTY, of, defer, from, isObservable, map, tap as tap$1, shareReplay, finalize, catchError as catchError$1, throwError, switchMap as switchMap$1 } from 'rxjs';
|
|
1
2
|
import { HttpClient, HttpContextToken, HttpBackend } from '@angular/common/http';
|
|
2
3
|
import * as i0 from '@angular/core';
|
|
3
4
|
import { InjectionToken, inject, Injectable, computed, input, ChangeDetectionStrategy, Component, signal, effect } from '@angular/core';
|
|
4
|
-
import { EMPTY, of, isObservable, from, firstValueFrom, map, tap as tap$1, shareReplay, finalize, switchMap, catchError as catchError$1, throwError } from 'rxjs';
|
|
5
5
|
import { Action, Selector, State, Store, select } from '@ngxs/store';
|
|
6
6
|
import { Router, ActivatedRoute } from '@angular/router';
|
|
7
7
|
import { ModalService } from '@masterteam/components/modal';
|
|
8
|
-
import { mergeMap, catchError, tap } from 'rxjs/operators';
|
|
8
|
+
import { switchMap, mergeMap, catchError, tap } from 'rxjs/operators';
|
|
9
9
|
import * as i2 from '@angular/common';
|
|
10
10
|
import { NgTemplateOutlet, CommonModule } from '@angular/common';
|
|
11
11
|
import * as i1 from '@angular/forms';
|
|
@@ -28,9 +28,12 @@ const GATEWAY_AUTH_ENDPOINTS = {
|
|
|
28
28
|
resendMfa: 'auth/2fa/resend',
|
|
29
29
|
refresh: 'auth/refresh',
|
|
30
30
|
logout: 'auth/logout',
|
|
31
|
+
meApplications: 'auth/me/applications',
|
|
32
|
+
applicationContext: 'public/application-context',
|
|
31
33
|
ssoProviders: 'auth/sso/providers',
|
|
32
34
|
ssoExchange: 'auth/sso/exchange',
|
|
33
35
|
ssoTokenExchange: 'auth/sso/token-exchange',
|
|
36
|
+
applicationLaunch: (applicationCode) => `applications/${encodeURIComponent(applicationCode)}/launch`,
|
|
34
37
|
nafathStart: (providerKey) => `auth/sso/nafath/${encodeURIComponent(providerKey)}/start`,
|
|
35
38
|
nafathStatus: (providerKey) => `auth/sso/nafath/${encodeURIComponent(providerKey)}/status`,
|
|
36
39
|
ssoStart: (providerKey) => `auth/sso/${encodeURIComponent(providerKey)}/start`,
|
|
@@ -58,6 +61,53 @@ function resolveAccessTokenRefreshSkewMs(skewMs) {
|
|
|
58
61
|
? skewMs
|
|
59
62
|
: GATEWAY_AUTH_ACCESS_TOKEN_REFRESH_SKEW_MS;
|
|
60
63
|
}
|
|
64
|
+
function resolveApplicationCodeOption(applicationCode) {
|
|
65
|
+
const value = typeof applicationCode === 'function' ? applicationCode() : applicationCode;
|
|
66
|
+
const normalized = value?.trim();
|
|
67
|
+
return normalized ? normalized : null;
|
|
68
|
+
}
|
|
69
|
+
const applicationContextCache = new Map();
|
|
70
|
+
function buildApplicationContextUrl(applicationApiBaseUrl) {
|
|
71
|
+
if (!applicationApiBaseUrl) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
const base = normalizeGatewayBase(applicationApiBaseUrl);
|
|
75
|
+
if (!base) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
const path = GATEWAY_AUTH_ENDPOINTS.applicationContext;
|
|
79
|
+
if (/\/api\/?$/i.test(base)) {
|
|
80
|
+
return `${base.replace(/\/+$/, '')}/${path}`;
|
|
81
|
+
}
|
|
82
|
+
return `${base}/api/${path}`;
|
|
83
|
+
}
|
|
84
|
+
function clearApplicationContextCache(applicationApiBaseUrl) {
|
|
85
|
+
if (applicationApiBaseUrl) {
|
|
86
|
+
applicationContextCache.delete(applicationApiBaseUrl);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
applicationContextCache.clear();
|
|
90
|
+
}
|
|
91
|
+
async function fetchApplicationContextCode(http, applicationApiBaseUrl) {
|
|
92
|
+
const url = buildApplicationContextUrl(applicationApiBaseUrl);
|
|
93
|
+
if (!url || !applicationApiBaseUrl) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
const cacheKey = applicationApiBaseUrl;
|
|
97
|
+
const cached = applicationContextCache.get(cacheKey);
|
|
98
|
+
if (cached) {
|
|
99
|
+
return cached;
|
|
100
|
+
}
|
|
101
|
+
const promise = firstValueFrom(http.get(url))
|
|
102
|
+
.then((response) => response?.data?.applicationCode?.trim() || null)
|
|
103
|
+
.catch(() => null);
|
|
104
|
+
applicationContextCache.set(cacheKey, promise);
|
|
105
|
+
const code = await promise;
|
|
106
|
+
if (!code) {
|
|
107
|
+
applicationContextCache.delete(cacheKey);
|
|
108
|
+
}
|
|
109
|
+
return code;
|
|
110
|
+
}
|
|
61
111
|
function resolveGatewayDeviceToken(deviceToken) {
|
|
62
112
|
const configuredToken = typeof deviceToken === 'function' ? deviceToken() : deviceToken;
|
|
63
113
|
const normalizedConfiguredToken = configuredToken?.trim();
|
|
@@ -310,6 +360,53 @@ class SetRateLimit {
|
|
|
310
360
|
class ClearRateLimit {
|
|
311
361
|
static type = '[Auth] Clear Rate Limit';
|
|
312
362
|
}
|
|
363
|
+
class LoadApplications {
|
|
364
|
+
static type = '[Auth] Load Applications';
|
|
365
|
+
}
|
|
366
|
+
class SetApplications {
|
|
367
|
+
applications;
|
|
368
|
+
static type = '[Auth] Set Applications';
|
|
369
|
+
constructor(applications) {
|
|
370
|
+
this.applications = applications;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
class LaunchApplication {
|
|
374
|
+
applicationCode;
|
|
375
|
+
returnUrl;
|
|
376
|
+
navigate;
|
|
377
|
+
static type = '[Auth] Launch Application';
|
|
378
|
+
constructor(applicationCode, returnUrl, navigate = false) {
|
|
379
|
+
this.applicationCode = applicationCode;
|
|
380
|
+
this.returnUrl = returnUrl;
|
|
381
|
+
this.navigate = navigate;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
class SetAppSession {
|
|
385
|
+
session;
|
|
386
|
+
static type = '[Auth] Set App Session';
|
|
387
|
+
constructor(session) {
|
|
388
|
+
this.session = session;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
class UpdateAppTokens {
|
|
392
|
+
applicationCode;
|
|
393
|
+
tokens;
|
|
394
|
+
static type = '[Auth] Update App Tokens';
|
|
395
|
+
constructor(applicationCode, tokens) {
|
|
396
|
+
this.applicationCode = applicationCode;
|
|
397
|
+
this.tokens = tokens;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
class ClearAppSession {
|
|
401
|
+
applicationCode;
|
|
402
|
+
static type = '[Auth] Clear App Session';
|
|
403
|
+
constructor(applicationCode) {
|
|
404
|
+
this.applicationCode = applicationCode;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
class ClearAllAppSessions {
|
|
408
|
+
static type = '[Auth] Clear All App Sessions';
|
|
409
|
+
}
|
|
313
410
|
|
|
314
411
|
const GATEWAY_AUTH_OPTIONS = new InjectionToken('GATEWAY_AUTH_OPTIONS', {
|
|
315
412
|
factory: () => ({
|
|
@@ -321,6 +418,7 @@ const GATEWAY_AUTH_OPTIONS = new InjectionToken('GATEWAY_AUTH_OPTIONS', {
|
|
|
321
418
|
ssoCallbackPath: '/auth/sso/callback',
|
|
322
419
|
defaultAuthenticatedRoute: '/',
|
|
323
420
|
preserveSsoProvidersOnLogout: true,
|
|
421
|
+
autoLaunchApplicationOnLogin: false,
|
|
324
422
|
loginPage: {
|
|
325
423
|
imageBasePath: '/Settings/login-image/',
|
|
326
424
|
translationPrefix: 'login',
|
|
@@ -378,6 +476,10 @@ const AUTH_STATE_DEFAULTS = {
|
|
|
378
476
|
pendingMfa: null,
|
|
379
477
|
ssoProviders: [],
|
|
380
478
|
rateLimit: null,
|
|
479
|
+
applications: [],
|
|
480
|
+
applicationsLoading: false,
|
|
481
|
+
appSessions: {},
|
|
482
|
+
appLaunchLoading: {},
|
|
381
483
|
};
|
|
382
484
|
function pruneRateLimit(rateLimit) {
|
|
383
485
|
if (!rateLimit) {
|
|
@@ -389,6 +491,22 @@ function pruneRateLimit(rateLimit) {
|
|
|
389
491
|
}
|
|
390
492
|
return rateLimit;
|
|
391
493
|
}
|
|
494
|
+
function pruneAppSessions(appSessions) {
|
|
495
|
+
if (!appSessions || typeof appSessions !== 'object') {
|
|
496
|
+
return {};
|
|
497
|
+
}
|
|
498
|
+
const pruned = {};
|
|
499
|
+
for (const [code, session] of Object.entries(appSessions)) {
|
|
500
|
+
if (!session || typeof session !== 'object') {
|
|
501
|
+
continue;
|
|
502
|
+
}
|
|
503
|
+
if (!session.accessToken || !session.refreshToken) {
|
|
504
|
+
continue;
|
|
505
|
+
}
|
|
506
|
+
pruned[code] = session;
|
|
507
|
+
}
|
|
508
|
+
return pruned;
|
|
509
|
+
}
|
|
392
510
|
function sanitizePersistedAuthState(obj) {
|
|
393
511
|
return {
|
|
394
512
|
...AUTH_STATE_DEFAULTS,
|
|
@@ -402,6 +520,10 @@ function sanitizePersistedAuthState(obj) {
|
|
|
402
520
|
pendingMfa: null,
|
|
403
521
|
ssoProviders: [],
|
|
404
522
|
rateLimit: pruneRateLimit(obj?.rateLimit ?? null),
|
|
523
|
+
applications: obj?.applications ?? [],
|
|
524
|
+
applicationsLoading: false,
|
|
525
|
+
appSessions: pruneAppSessions(obj?.appSessions ?? null),
|
|
526
|
+
appLaunchLoading: {},
|
|
405
527
|
};
|
|
406
528
|
}
|
|
407
529
|
|
|
@@ -465,6 +587,18 @@ let GatewayAuthState = class GatewayAuthState {
|
|
|
465
587
|
static userDetails(state) {
|
|
466
588
|
return state.user?.user || null;
|
|
467
589
|
}
|
|
590
|
+
static applications(state) {
|
|
591
|
+
return state.applications;
|
|
592
|
+
}
|
|
593
|
+
static applicationsLoading(state) {
|
|
594
|
+
return state.applicationsLoading;
|
|
595
|
+
}
|
|
596
|
+
static appSessions(state) {
|
|
597
|
+
return state.appSessions;
|
|
598
|
+
}
|
|
599
|
+
static appLaunchLoading(state) {
|
|
600
|
+
return state.appLaunchLoading;
|
|
601
|
+
}
|
|
468
602
|
login(ctx, action) {
|
|
469
603
|
if (this.isRateLimitActive(ctx, 'login')) {
|
|
470
604
|
return EMPTY;
|
|
@@ -475,22 +609,37 @@ let GatewayAuthState = class GatewayAuthState {
|
|
|
475
609
|
pendingMfa: null,
|
|
476
610
|
twoFactorRequired: false,
|
|
477
611
|
});
|
|
478
|
-
return this.http
|
|
612
|
+
return this.resolveApplicationCode$(action.payload.applicationCode).pipe(switchMap((applicationCode) => this.http
|
|
479
613
|
.post(this.gatewayAuthMutationUrl(GATEWAY_AUTH_ENDPOINTS.login), {
|
|
480
614
|
userName: action.payload.userName,
|
|
481
615
|
password: action.payload.password,
|
|
616
|
+
applicationCode: applicationCode ?? undefined,
|
|
482
617
|
isEncrypted: action.payload.isEncrypted ?? false,
|
|
483
618
|
deviceToken: action.payload.deviceToken || this.deviceToken,
|
|
484
619
|
recaptchaToken: action.payload.recaptchaToken,
|
|
485
620
|
recaptchaAction: action.payload.recaptchaAction,
|
|
486
621
|
})
|
|
487
|
-
.pipe(mergeMap((response) => this.handleLoginResponse(ctx, response.data)), catchError((error) => {
|
|
622
|
+
.pipe(mergeMap((response) => this.handleLoginResponse(ctx, response.data, applicationCode)), catchError((error) => {
|
|
488
623
|
if (this.handleRateLimit(ctx, error, 'login')) {
|
|
489
624
|
return of(null);
|
|
490
625
|
}
|
|
491
626
|
ctx.dispatch(new LoginFailure(getGatewayErrorMessage(error, 'Login failed')));
|
|
492
627
|
return of(null);
|
|
493
|
-
}));
|
|
628
|
+
}))));
|
|
629
|
+
}
|
|
630
|
+
resolveApplicationCode$(explicitCode) {
|
|
631
|
+
if (explicitCode) {
|
|
632
|
+
return of(explicitCode);
|
|
633
|
+
}
|
|
634
|
+
const configured = resolveApplicationCodeOption(this.options.applicationCode);
|
|
635
|
+
if (configured) {
|
|
636
|
+
return of(configured);
|
|
637
|
+
}
|
|
638
|
+
const applicationApiBaseUrl = this.options.getApplicationApiBaseUrl?.();
|
|
639
|
+
if (!applicationApiBaseUrl) {
|
|
640
|
+
return of(null);
|
|
641
|
+
}
|
|
642
|
+
return defer(() => from(fetchApplicationContextCode(this.http, applicationApiBaseUrl)));
|
|
494
643
|
}
|
|
495
644
|
verifyMfa(ctx, action) {
|
|
496
645
|
const pendingMfa = ctx.getState().pendingMfa;
|
|
@@ -637,6 +786,9 @@ let GatewayAuthState = class GatewayAuthState {
|
|
|
637
786
|
refreshTokenExpiresAt: null,
|
|
638
787
|
pendingMfa: null,
|
|
639
788
|
twoFactorRequired: false,
|
|
789
|
+
applications: [],
|
|
790
|
+
appSessions: {},
|
|
791
|
+
appLaunchLoading: {},
|
|
640
792
|
});
|
|
641
793
|
}
|
|
642
794
|
logout(ctx, action) {
|
|
@@ -710,6 +862,125 @@ let GatewayAuthState = class GatewayAuthState {
|
|
|
710
862
|
clearRateLimit(ctx) {
|
|
711
863
|
ctx.patchState({ rateLimit: null });
|
|
712
864
|
}
|
|
865
|
+
loadApplications(ctx) {
|
|
866
|
+
ctx.patchState({ applicationsLoading: true });
|
|
867
|
+
return this.http
|
|
868
|
+
.get(this.gatewayUrl(GATEWAY_AUTH_ENDPOINTS.meApplications))
|
|
869
|
+
.pipe(tap((response) => {
|
|
870
|
+
ctx.patchState({
|
|
871
|
+
applications: response.data?.applications ?? [],
|
|
872
|
+
applicationsLoading: false,
|
|
873
|
+
});
|
|
874
|
+
}), catchError((error) => {
|
|
875
|
+
ctx.patchState({
|
|
876
|
+
applicationsLoading: false,
|
|
877
|
+
error: getGatewayErrorMessage(error, 'Failed to load applications'),
|
|
878
|
+
});
|
|
879
|
+
return of(null);
|
|
880
|
+
}));
|
|
881
|
+
}
|
|
882
|
+
setApplications(ctx, action) {
|
|
883
|
+
ctx.patchState({ applications: action.applications });
|
|
884
|
+
}
|
|
885
|
+
launchApplication(ctx, action) {
|
|
886
|
+
const code = action.applicationCode;
|
|
887
|
+
ctx.patchState({
|
|
888
|
+
appLaunchLoading: {
|
|
889
|
+
...ctx.getState().appLaunchLoading,
|
|
890
|
+
[code]: true,
|
|
891
|
+
},
|
|
892
|
+
});
|
|
893
|
+
const params = {};
|
|
894
|
+
if (action.returnUrl) {
|
|
895
|
+
params['returnUrl'] = action.returnUrl;
|
|
896
|
+
}
|
|
897
|
+
const deviceToken = this.deviceToken;
|
|
898
|
+
if (deviceToken) {
|
|
899
|
+
params['deviceToken'] = deviceToken;
|
|
900
|
+
}
|
|
901
|
+
return this.http
|
|
902
|
+
.get(this.gatewayUrl(GATEWAY_AUTH_ENDPOINTS.applicationLaunch(code)), { params })
|
|
903
|
+
.pipe(tap((response) => {
|
|
904
|
+
const data = response.data;
|
|
905
|
+
if (!data || !hasGatewayTokens(data.tokens)) {
|
|
906
|
+
ctx.patchState({
|
|
907
|
+
appLaunchLoading: this.removeLoadingFlag(ctx, code),
|
|
908
|
+
});
|
|
909
|
+
return;
|
|
910
|
+
}
|
|
911
|
+
const mapped = mapGatewayTokens(data.tokens);
|
|
912
|
+
const session = {
|
|
913
|
+
applicationCode: data.applicationCode,
|
|
914
|
+
applicationName: data.applicationName,
|
|
915
|
+
launchUrl: data.launchUrl,
|
|
916
|
+
accessToken: mapped.accessToken,
|
|
917
|
+
refreshToken: mapped.refreshToken,
|
|
918
|
+
accessTokenExpiresAt: mapped.accessTokenExpiresAt,
|
|
919
|
+
refreshTokenExpiresAt: mapped.refreshTokenExpiresAt,
|
|
920
|
+
};
|
|
921
|
+
ctx.patchState({
|
|
922
|
+
appSessions: {
|
|
923
|
+
...ctx.getState().appSessions,
|
|
924
|
+
[data.applicationCode]: session,
|
|
925
|
+
},
|
|
926
|
+
appLaunchLoading: this.removeLoadingFlag(ctx, code),
|
|
927
|
+
});
|
|
928
|
+
if (action.navigate && session.launchUrl) {
|
|
929
|
+
try {
|
|
930
|
+
window.location.assign(session.launchUrl);
|
|
931
|
+
}
|
|
932
|
+
catch {
|
|
933
|
+
// ignore navigation errors in non-browser env
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
}), catchError((error) => {
|
|
937
|
+
ctx.patchState({
|
|
938
|
+
appLaunchLoading: this.removeLoadingFlag(ctx, code),
|
|
939
|
+
error: getGatewayErrorMessage(error, 'Failed to launch application'),
|
|
940
|
+
});
|
|
941
|
+
return of(null);
|
|
942
|
+
}));
|
|
943
|
+
}
|
|
944
|
+
setAppSession(ctx, action) {
|
|
945
|
+
ctx.patchState({
|
|
946
|
+
appSessions: {
|
|
947
|
+
...ctx.getState().appSessions,
|
|
948
|
+
[action.session.applicationCode]: action.session,
|
|
949
|
+
},
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
updateAppTokens(ctx, action) {
|
|
953
|
+
const existing = ctx.getState().appSessions[action.applicationCode];
|
|
954
|
+
if (!existing) {
|
|
955
|
+
return;
|
|
956
|
+
}
|
|
957
|
+
const mapped = mapGatewayTokens(action.tokens);
|
|
958
|
+
ctx.patchState({
|
|
959
|
+
appSessions: {
|
|
960
|
+
...ctx.getState().appSessions,
|
|
961
|
+
[action.applicationCode]: {
|
|
962
|
+
...existing,
|
|
963
|
+
accessToken: mapped.accessToken,
|
|
964
|
+
refreshToken: mapped.refreshToken,
|
|
965
|
+
accessTokenExpiresAt: mapped.accessTokenExpiresAt,
|
|
966
|
+
refreshTokenExpiresAt: mapped.refreshTokenExpiresAt,
|
|
967
|
+
},
|
|
968
|
+
},
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
clearAppSession(ctx, action) {
|
|
972
|
+
const sessions = { ...ctx.getState().appSessions };
|
|
973
|
+
delete sessions[action.applicationCode];
|
|
974
|
+
ctx.patchState({ appSessions: sessions });
|
|
975
|
+
}
|
|
976
|
+
clearAllAppSessions(ctx) {
|
|
977
|
+
ctx.patchState({ appSessions: {}, applications: [] });
|
|
978
|
+
}
|
|
979
|
+
removeLoadingFlag(ctx, code) {
|
|
980
|
+
const next = { ...ctx.getState().appLaunchLoading };
|
|
981
|
+
delete next[code];
|
|
982
|
+
return next;
|
|
983
|
+
}
|
|
713
984
|
isRateLimitActive(ctx, scope) {
|
|
714
985
|
const lock = ctx.getState().rateLimit;
|
|
715
986
|
if (!lock || lock.scope !== scope) {
|
|
@@ -737,7 +1008,7 @@ let GatewayAuthState = class GatewayAuthState {
|
|
|
737
1008
|
}));
|
|
738
1009
|
return true;
|
|
739
1010
|
}
|
|
740
|
-
handleLoginResponse(ctx, session) {
|
|
1011
|
+
handleLoginResponse(ctx, session, resolvedApplicationCode) {
|
|
741
1012
|
if (session.requiresTwoFactor) {
|
|
742
1013
|
ctx.patchState({
|
|
743
1014
|
user: null,
|
|
@@ -773,13 +1044,26 @@ let GatewayAuthState = class GatewayAuthState {
|
|
|
773
1044
|
error: null,
|
|
774
1045
|
pendingMfa: null,
|
|
775
1046
|
twoFactorRequired: false,
|
|
1047
|
+
appSessions: {},
|
|
1048
|
+
appLaunchLoading: {},
|
|
776
1049
|
});
|
|
777
|
-
return this.toObservable(this.options.afterLogin?.(session, ctx)).pipe(tap(() => {
|
|
1050
|
+
return this.toObservable(this.options.afterLogin?.(session, ctx)).pipe(mergeMap(() => this.maybeAutoLaunchApplication(ctx, resolvedApplicationCode)), tap(() => {
|
|
778
1051
|
this.router.navigateByUrl(this.resolveAuthenticatedRoute(), {
|
|
779
1052
|
replaceUrl: true,
|
|
780
1053
|
});
|
|
781
1054
|
}));
|
|
782
1055
|
}
|
|
1056
|
+
maybeAutoLaunchApplication(ctx, resolvedApplicationCode) {
|
|
1057
|
+
if (!this.options.autoLaunchApplicationOnLogin) {
|
|
1058
|
+
return of(null);
|
|
1059
|
+
}
|
|
1060
|
+
const code = resolvedApplicationCode ??
|
|
1061
|
+
resolveApplicationCodeOption(this.options.applicationCode);
|
|
1062
|
+
if (!code) {
|
|
1063
|
+
return of(null);
|
|
1064
|
+
}
|
|
1065
|
+
return ctx.dispatch(new LaunchApplication(code));
|
|
1066
|
+
}
|
|
783
1067
|
get deviceToken() {
|
|
784
1068
|
return resolveGatewayDeviceToken(this.options.deviceToken);
|
|
785
1069
|
}
|
|
@@ -874,6 +1158,27 @@ __decorate([
|
|
|
874
1158
|
__decorate([
|
|
875
1159
|
Action(ClearRateLimit)
|
|
876
1160
|
], GatewayAuthState.prototype, "clearRateLimit", null);
|
|
1161
|
+
__decorate([
|
|
1162
|
+
Action(LoadApplications)
|
|
1163
|
+
], GatewayAuthState.prototype, "loadApplications", null);
|
|
1164
|
+
__decorate([
|
|
1165
|
+
Action(SetApplications)
|
|
1166
|
+
], GatewayAuthState.prototype, "setApplications", null);
|
|
1167
|
+
__decorate([
|
|
1168
|
+
Action(LaunchApplication)
|
|
1169
|
+
], GatewayAuthState.prototype, "launchApplication", null);
|
|
1170
|
+
__decorate([
|
|
1171
|
+
Action(SetAppSession)
|
|
1172
|
+
], GatewayAuthState.prototype, "setAppSession", null);
|
|
1173
|
+
__decorate([
|
|
1174
|
+
Action(UpdateAppTokens)
|
|
1175
|
+
], GatewayAuthState.prototype, "updateAppTokens", null);
|
|
1176
|
+
__decorate([
|
|
1177
|
+
Action(ClearAppSession)
|
|
1178
|
+
], GatewayAuthState.prototype, "clearAppSession", null);
|
|
1179
|
+
__decorate([
|
|
1180
|
+
Action(ClearAllAppSessions)
|
|
1181
|
+
], GatewayAuthState.prototype, "clearAllAppSessions", null);
|
|
877
1182
|
__decorate([
|
|
878
1183
|
Selector()
|
|
879
1184
|
], GatewayAuthState, "user", null);
|
|
@@ -922,6 +1227,18 @@ __decorate([
|
|
|
922
1227
|
__decorate([
|
|
923
1228
|
Selector()
|
|
924
1229
|
], GatewayAuthState, "userDetails", null);
|
|
1230
|
+
__decorate([
|
|
1231
|
+
Selector()
|
|
1232
|
+
], GatewayAuthState, "applications", null);
|
|
1233
|
+
__decorate([
|
|
1234
|
+
Selector()
|
|
1235
|
+
], GatewayAuthState, "applicationsLoading", null);
|
|
1236
|
+
__decorate([
|
|
1237
|
+
Selector()
|
|
1238
|
+
], GatewayAuthState, "appSessions", null);
|
|
1239
|
+
__decorate([
|
|
1240
|
+
Selector()
|
|
1241
|
+
], GatewayAuthState, "appLaunchLoading", null);
|
|
925
1242
|
GatewayAuthState = __decorate([
|
|
926
1243
|
State({
|
|
927
1244
|
name: 'auth',
|
|
@@ -930,7 +1247,7 @@ GatewayAuthState = __decorate([
|
|
|
930
1247
|
], GatewayAuthState);
|
|
931
1248
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: GatewayAuthState, decorators: [{
|
|
932
1249
|
type: Injectable
|
|
933
|
-
}], propDecorators: { login: [], verifyMfa: [], resendMfa: [], loadSsoProviders: [], startSso: [], exchangeSsoCode: [], loginSuccess: [], loginFailure: [], logout: [], updateUserData: [], updateTokens: [], clearError: [], clearPendingMfa: [], setRateLimit: [], clearRateLimit: [] } });
|
|
1250
|
+
}], propDecorators: { login: [], verifyMfa: [], resendMfa: [], loadSsoProviders: [], startSso: [], exchangeSsoCode: [], loginSuccess: [], loginFailure: [], logout: [], updateUserData: [], updateTokens: [], clearError: [], clearPendingMfa: [], setRateLimit: [], clearRateLimit: [], loadApplications: [], setApplications: [], launchApplication: [], setAppSession: [], updateAppTokens: [], clearAppSession: [], clearAllAppSessions: [] } });
|
|
934
1251
|
|
|
935
1252
|
class GatewayAuthFacade {
|
|
936
1253
|
store = inject(Store);
|
|
@@ -950,6 +1267,10 @@ class GatewayAuthFacade {
|
|
|
950
1267
|
rateLimit = select(GatewayAuthState.rateLimit);
|
|
951
1268
|
isAdmin = select(GatewayAuthState.isAdmin);
|
|
952
1269
|
userDetails = select(GatewayAuthState.userDetails);
|
|
1270
|
+
applications = select(GatewayAuthState.applications);
|
|
1271
|
+
applicationsLoading = select(GatewayAuthState.applicationsLoading);
|
|
1272
|
+
appSessions = select(GatewayAuthState.appSessions);
|
|
1273
|
+
appLaunchLoading = select(GatewayAuthState.appLaunchLoading);
|
|
953
1274
|
hasError = computed(() => this.error() !== null, ...(ngDevMode ? [{ debugName: "hasError" }] : /* istanbul ignore next */ []));
|
|
954
1275
|
isReady = computed(() => !this.loading() && this.error() === null, ...(ngDevMode ? [{ debugName: "isReady" }] : /* istanbul ignore next */ []));
|
|
955
1276
|
userDisplayName = computed(() => this.user()?.user?.displayName || '', ...(ngDevMode ? [{ debugName: "userDisplayName" }] : /* istanbul ignore next */ []));
|
|
@@ -993,6 +1314,34 @@ class GatewayAuthFacade {
|
|
|
993
1314
|
updateTokens(tokens) {
|
|
994
1315
|
this.store.dispatch(new UpdateTokens(tokens));
|
|
995
1316
|
}
|
|
1317
|
+
loadApplications() {
|
|
1318
|
+
this.store.dispatch(new LoadApplications());
|
|
1319
|
+
}
|
|
1320
|
+
setApplications(applications) {
|
|
1321
|
+
this.store.dispatch(new SetApplications(applications));
|
|
1322
|
+
}
|
|
1323
|
+
launchApplication(applicationCode, returnUrl, navigate = false) {
|
|
1324
|
+
this.store.dispatch(new LaunchApplication(applicationCode, returnUrl, navigate));
|
|
1325
|
+
}
|
|
1326
|
+
setAppSession(session) {
|
|
1327
|
+
this.store.dispatch(new SetAppSession(session));
|
|
1328
|
+
}
|
|
1329
|
+
updateAppTokens(applicationCode, tokens) {
|
|
1330
|
+
this.store.dispatch(new UpdateAppTokens(applicationCode, tokens));
|
|
1331
|
+
}
|
|
1332
|
+
clearAppSession(applicationCode) {
|
|
1333
|
+
this.store.dispatch(new ClearAppSession(applicationCode));
|
|
1334
|
+
}
|
|
1335
|
+
clearAllAppSessions() {
|
|
1336
|
+
this.store.dispatch(new ClearAllAppSessions());
|
|
1337
|
+
}
|
|
1338
|
+
getAppSession(applicationCode) {
|
|
1339
|
+
return this.appSessions()?.[applicationCode] ?? null;
|
|
1340
|
+
}
|
|
1341
|
+
getAppToken(applicationCode) {
|
|
1342
|
+
const session = this.getAppSession(applicationCode);
|
|
1343
|
+
return session?.accessToken ?? null;
|
|
1344
|
+
}
|
|
996
1345
|
clearError() {
|
|
997
1346
|
this.store.dispatch(new ClearError());
|
|
998
1347
|
}
|
|
@@ -1064,7 +1413,6 @@ function isGatewayAuthRequestUrl(url, gatewayApiBaseUrl) {
|
|
|
1064
1413
|
return (GATEWAY_AUTH_ENDPOINT_PATHS.has(path) ||
|
|
1065
1414
|
GATEWAY_AUTH_ENDPOINT_PREFIXES.some((prefix) => path.startsWith(prefix)));
|
|
1066
1415
|
}
|
|
1067
|
-
let inflightRefresh$ = null;
|
|
1068
1416
|
const getBrowserRefreshLock = () => {
|
|
1069
1417
|
if (typeof navigator === 'undefined') {
|
|
1070
1418
|
return null;
|
|
@@ -1072,12 +1420,12 @@ const getBrowserRefreshLock = () => {
|
|
|
1072
1420
|
const locks = navigator.locks;
|
|
1073
1421
|
return typeof locks?.request === 'function' ? locks : null;
|
|
1074
1422
|
};
|
|
1075
|
-
const runWithRefreshLock = (operation) => {
|
|
1423
|
+
const runWithRefreshLock = (scopeKey, operation) => {
|
|
1076
1424
|
const locks = getBrowserRefreshLock();
|
|
1077
|
-
return locks
|
|
1078
|
-
? locks.request('masterteam-gateway-auth-refresh', operation)
|
|
1079
|
-
: operation();
|
|
1425
|
+
return locks ? locks.request(scopeKey, operation) : operation();
|
|
1080
1426
|
};
|
|
1427
|
+
const GATEWAY_REFRESH_SCOPE = 'gateway';
|
|
1428
|
+
const inflightRefreshByScope = new Map();
|
|
1081
1429
|
const getCurrentAuthTokens = (auth) => {
|
|
1082
1430
|
const accessToken = auth.token();
|
|
1083
1431
|
const refreshToken = auth.refreshToken();
|
|
@@ -1099,7 +1447,7 @@ const tokenHasUsableAccessToken = (tokens, refreshSkewMs) => !!tokens.accessToke
|
|
|
1099
1447
|
!isExpired(resolveApiDateValue(tokens.accessTokenExpiresAt), refreshSkewMs);
|
|
1100
1448
|
const tokenHasUsableRefreshToken = (tokens) => !!tokens.refreshToken &&
|
|
1101
1449
|
!isExpired(resolveApiDateValue(tokens.refreshTokenExpiresAt));
|
|
1102
|
-
const
|
|
1450
|
+
const getSynchronizedGatewayTokens = (auth, staleRefreshToken, refreshSkewMs) => {
|
|
1103
1451
|
const candidates = [
|
|
1104
1452
|
getCurrentAuthTokens(auth),
|
|
1105
1453
|
readPersistedGatewayAuthTokens(),
|
|
@@ -1108,7 +1456,7 @@ const getSynchronizedTokens = (auth, staleRefreshToken, refreshSkewMs) => {
|
|
|
1108
1456
|
tokens.refreshToken !== staleRefreshToken &&
|
|
1109
1457
|
tokenHasUsableAccessToken(tokens, refreshSkewMs)) ?? null);
|
|
1110
1458
|
};
|
|
1111
|
-
const
|
|
1459
|
+
const getLatestGatewayRefreshToken = (auth, fallbackRefreshToken) => {
|
|
1112
1460
|
const candidates = [
|
|
1113
1461
|
getCurrentAuthTokens(auth),
|
|
1114
1462
|
readPersistedGatewayAuthTokens(),
|
|
@@ -1118,33 +1466,95 @@ const getLatestRefreshToken = (auth, fallbackRefreshToken) => {
|
|
|
1118
1466
|
tokenHasUsableRefreshToken(tokens));
|
|
1119
1467
|
return latestTokens?.refreshToken ?? fallbackRefreshToken;
|
|
1120
1468
|
};
|
|
1121
|
-
const
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
}
|
|
1127
|
-
const latestRefreshToken = getLatestRefreshToken(auth, refreshToken);
|
|
1128
|
-
const url = buildGatewayUrl(gatewayApiBaseUrl, GATEWAY_AUTH_ENDPOINTS.refresh);
|
|
1129
|
-
return firstValueFrom(http
|
|
1130
|
-
.post(url, {
|
|
1131
|
-
refreshToken: latestRefreshToken,
|
|
1132
|
-
deviceToken,
|
|
1133
|
-
})
|
|
1134
|
-
.pipe(map((response) => response.data), map((tokens) => {
|
|
1135
|
-
if (!tokens?.accessToken || !tokens.refreshToken) {
|
|
1136
|
-
throw new Error('Invalid refresh response');
|
|
1137
|
-
}
|
|
1138
|
-
return tokens;
|
|
1139
|
-
}), tap$1((tokens) => auth.updateTokens(tokens))));
|
|
1469
|
+
const sessionAsTokens = (session) => ({
|
|
1470
|
+
accessToken: session.accessToken,
|
|
1471
|
+
accessTokenExpiresAt: { actualValue: session.accessTokenExpiresAt ?? '' },
|
|
1472
|
+
refreshToken: session.refreshToken,
|
|
1473
|
+
refreshTokenExpiresAt: { actualValue: session.refreshTokenExpiresAt ?? '' },
|
|
1140
1474
|
});
|
|
1141
|
-
const
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1475
|
+
const getSynchronizedAppTokens = (auth, applicationCode, staleRefreshToken, refreshSkewMs) => {
|
|
1476
|
+
const session = auth.getAppSession(applicationCode);
|
|
1477
|
+
if (!session) {
|
|
1478
|
+
return null;
|
|
1479
|
+
}
|
|
1480
|
+
const tokens = sessionAsTokens(session);
|
|
1481
|
+
if (tokens.refreshToken !== staleRefreshToken &&
|
|
1482
|
+
tokenHasUsableAccessToken(tokens, refreshSkewMs)) {
|
|
1483
|
+
return tokens;
|
|
1146
1484
|
}
|
|
1147
|
-
return
|
|
1485
|
+
return null;
|
|
1486
|
+
};
|
|
1487
|
+
const getLatestAppRefreshToken = (auth, applicationCode, fallbackRefreshToken) => {
|
|
1488
|
+
const session = auth.getAppSession(applicationCode);
|
|
1489
|
+
if (!session) {
|
|
1490
|
+
return fallbackRefreshToken;
|
|
1491
|
+
}
|
|
1492
|
+
if (session.refreshToken &&
|
|
1493
|
+
session.refreshToken !== fallbackRefreshToken &&
|
|
1494
|
+
!isExpired(session.refreshTokenExpiresAt)) {
|
|
1495
|
+
return session.refreshToken;
|
|
1496
|
+
}
|
|
1497
|
+
return fallbackRefreshToken;
|
|
1498
|
+
};
|
|
1499
|
+
const executeRefresh = (context, refreshToken) => {
|
|
1500
|
+
const { http, gatewayApiBaseUrl, auth, deviceToken, refreshSkewMs, scope, applicationCode, } = context;
|
|
1501
|
+
const lockKey = scope === 'gateway'
|
|
1502
|
+
? 'masterteam-gateway-auth-refresh:gateway'
|
|
1503
|
+
: `masterteam-gateway-auth-refresh:app:${applicationCode ?? ''}`;
|
|
1504
|
+
return runWithRefreshLock(lockKey, async () => {
|
|
1505
|
+
if (scope === 'gateway') {
|
|
1506
|
+
const synchronizedTokens = getSynchronizedGatewayTokens(auth, refreshToken, refreshSkewMs);
|
|
1507
|
+
if (synchronizedTokens) {
|
|
1508
|
+
auth.updateTokens(synchronizedTokens);
|
|
1509
|
+
return synchronizedTokens;
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
else if (applicationCode) {
|
|
1513
|
+
const synchronizedTokens = getSynchronizedAppTokens(auth, applicationCode, refreshToken, refreshSkewMs);
|
|
1514
|
+
if (synchronizedTokens) {
|
|
1515
|
+
auth.updateAppTokens(applicationCode, synchronizedTokens);
|
|
1516
|
+
return synchronizedTokens;
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
const latestRefreshToken = scope === 'gateway'
|
|
1520
|
+
? getLatestGatewayRefreshToken(auth, refreshToken)
|
|
1521
|
+
: applicationCode
|
|
1522
|
+
? getLatestAppRefreshToken(auth, applicationCode, refreshToken)
|
|
1523
|
+
: refreshToken;
|
|
1524
|
+
const url = buildGatewayUrl(gatewayApiBaseUrl, GATEWAY_AUTH_ENDPOINTS.refresh);
|
|
1525
|
+
return firstValueFrom(http
|
|
1526
|
+
.post(url, {
|
|
1527
|
+
refreshToken: latestRefreshToken,
|
|
1528
|
+
deviceToken,
|
|
1529
|
+
})
|
|
1530
|
+
.pipe(map((response) => response.data), map((tokens) => {
|
|
1531
|
+
if (!tokens?.accessToken || !tokens.refreshToken) {
|
|
1532
|
+
throw new Error('Invalid refresh response');
|
|
1533
|
+
}
|
|
1534
|
+
return tokens;
|
|
1535
|
+
}), tap$1((tokens) => {
|
|
1536
|
+
if (scope === 'gateway') {
|
|
1537
|
+
auth.updateTokens(tokens);
|
|
1538
|
+
}
|
|
1539
|
+
else if (applicationCode) {
|
|
1540
|
+
auth.updateAppTokens(applicationCode, tokens);
|
|
1541
|
+
}
|
|
1542
|
+
})));
|
|
1543
|
+
});
|
|
1544
|
+
};
|
|
1545
|
+
const refreshTokens$ = (context, refreshToken) => {
|
|
1546
|
+
const scopeKey = context.scope === 'gateway'
|
|
1547
|
+
? GATEWAY_REFRESH_SCOPE
|
|
1548
|
+
: `application:${context.applicationCode ?? ''}`;
|
|
1549
|
+
const existing = inflightRefreshByScope.get(scopeKey);
|
|
1550
|
+
if (existing) {
|
|
1551
|
+
return existing;
|
|
1552
|
+
}
|
|
1553
|
+
const observable = from(executeRefresh(context, refreshToken)).pipe(shareReplay({ bufferSize: 1, refCount: true }), finalize(() => {
|
|
1554
|
+
inflightRefreshByScope.delete(scopeKey);
|
|
1555
|
+
}));
|
|
1556
|
+
inflightRefreshByScope.set(scopeKey, observable);
|
|
1557
|
+
return observable;
|
|
1148
1558
|
};
|
|
1149
1559
|
const prepareRequest = (req, token, markRetried, baseUrl) => {
|
|
1150
1560
|
let modifiedReq = req;
|
|
@@ -1167,6 +1577,35 @@ const prepareRequest = (req, token, markRetried, baseUrl) => {
|
|
|
1167
1577
|
}
|
|
1168
1578
|
return modifiedReq;
|
|
1169
1579
|
};
|
|
1580
|
+
const resolveRequestScope = (req, options, auth) => {
|
|
1581
|
+
const useGatewayBaseUrl = options.shouldUseGatewayApiBaseUrl?.(req) ?? false;
|
|
1582
|
+
const explicitCode = options.resolveApplicationCodeForRequest?.(req);
|
|
1583
|
+
if (explicitCode) {
|
|
1584
|
+
const session = auth.getAppSession(explicitCode);
|
|
1585
|
+
return {
|
|
1586
|
+
scope: 'application',
|
|
1587
|
+
applicationCode: explicitCode,
|
|
1588
|
+
session,
|
|
1589
|
+
useGatewayBaseUrl,
|
|
1590
|
+
};
|
|
1591
|
+
}
|
|
1592
|
+
if (useGatewayBaseUrl) {
|
|
1593
|
+
return { scope: 'gateway', useGatewayBaseUrl: true };
|
|
1594
|
+
}
|
|
1595
|
+
const defaultCode = resolveApplicationCodeOption(options.applicationCode);
|
|
1596
|
+
if (defaultCode) {
|
|
1597
|
+
const session = auth.getAppSession(defaultCode);
|
|
1598
|
+
if (session) {
|
|
1599
|
+
return {
|
|
1600
|
+
scope: 'application',
|
|
1601
|
+
applicationCode: defaultCode,
|
|
1602
|
+
session,
|
|
1603
|
+
useGatewayBaseUrl,
|
|
1604
|
+
};
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
return { scope: 'gateway', useGatewayBaseUrl };
|
|
1608
|
+
};
|
|
1170
1609
|
const gatewayAuthInterceptor = (req, next) => {
|
|
1171
1610
|
if (isAssetRequest(req.url)) {
|
|
1172
1611
|
return next(req);
|
|
@@ -1176,41 +1615,86 @@ const gatewayAuthInterceptor = (req, next) => {
|
|
|
1176
1615
|
const http = new HttpClient(inject(HttpBackend));
|
|
1177
1616
|
const gatewayApiBaseUrl = options.getGatewayApiBaseUrl();
|
|
1178
1617
|
const appApiBaseUrl = options.getApplicationApiBaseUrl?.();
|
|
1179
|
-
const useGatewayBaseUrl = options.shouldUseGatewayApiBaseUrl?.(req) ?? false;
|
|
1180
|
-
const baseUrl = useGatewayBaseUrl ? gatewayApiBaseUrl : appApiBaseUrl;
|
|
1181
1618
|
const deviceToken = resolveGatewayDeviceToken(options.deviceToken);
|
|
1182
1619
|
const refreshSkewMs = resolveAccessTokenRefreshSkewMs(options.accessTokenRefreshSkewMs);
|
|
1183
|
-
const
|
|
1184
|
-
const
|
|
1185
|
-
const
|
|
1186
|
-
const
|
|
1620
|
+
const isAuthRequest = isGatewayAuthRequestUrl(req.url, gatewayApiBaseUrl);
|
|
1621
|
+
const alreadyRetried = req.context.get(GATEWAY_AUTH_RETRY_CONTEXT);
|
|
1622
|
+
const resolved = resolveRequestScope(req, options, auth);
|
|
1623
|
+
const baseUrl = resolved.useGatewayBaseUrl
|
|
1624
|
+
? gatewayApiBaseUrl
|
|
1625
|
+
: appApiBaseUrl;
|
|
1626
|
+
const gatewayAccessToken = auth.token();
|
|
1627
|
+
const gatewayRefreshToken = auth.refreshToken();
|
|
1628
|
+
const gatewayAccessTokenExpiresAt = auth.accessTokenExpiresAt();
|
|
1629
|
+
const gatewayRefreshTokenExpiresAt = auth.refreshTokenExpiresAt();
|
|
1630
|
+
const session = resolved.session ?? null;
|
|
1631
|
+
const accessToken = resolved.scope === 'application' && session
|
|
1632
|
+
? session.accessToken
|
|
1633
|
+
: gatewayAccessToken;
|
|
1634
|
+
const accessTokenExpiresAt = resolved.scope === 'application' && session
|
|
1635
|
+
? session.accessTokenExpiresAt
|
|
1636
|
+
: gatewayAccessTokenExpiresAt;
|
|
1637
|
+
const refreshToken = resolved.scope === 'application' && session
|
|
1638
|
+
? session.refreshToken
|
|
1639
|
+
: gatewayRefreshToken;
|
|
1640
|
+
const refreshTokenExpiresAt = resolved.scope === 'application' && session
|
|
1641
|
+
? session.refreshTokenExpiresAt
|
|
1642
|
+
: gatewayRefreshTokenExpiresAt;
|
|
1187
1643
|
const accessTokenValid = !!accessToken && !isExpired(accessTokenExpiresAt, refreshSkewMs);
|
|
1188
1644
|
const canRefresh = !!refreshToken && !isExpired(refreshTokenExpiresAt);
|
|
1189
|
-
const alreadyRetried = req.context.get(GATEWAY_AUTH_RETRY_CONTEXT);
|
|
1190
|
-
const isAuthRequest = isGatewayAuthRequestUrl(req.url, gatewayApiBaseUrl);
|
|
1191
1645
|
const tokenToAttach = !isAuthRequest && accessTokenValid ? accessToken : null;
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1646
|
+
const buildRefreshContext = (scopeOverride, appCodeOverride) => ({
|
|
1647
|
+
http,
|
|
1648
|
+
gatewayApiBaseUrl,
|
|
1649
|
+
auth,
|
|
1650
|
+
deviceToken,
|
|
1651
|
+
refreshSkewMs,
|
|
1652
|
+
scope: scopeOverride ?? resolved.scope,
|
|
1653
|
+
applicationCode: appCodeOverride ?? resolved.applicationCode,
|
|
1654
|
+
});
|
|
1655
|
+
if (!isAuthRequest && !accessTokenValid && canRefresh && refreshToken) {
|
|
1656
|
+
return refreshTokens$(buildRefreshContext(), refreshToken).pipe(catchError$1((refreshError) => {
|
|
1657
|
+
if (resolved.scope === 'application' && resolved.applicationCode) {
|
|
1658
|
+
auth.clearAppSession(resolved.applicationCode);
|
|
1659
|
+
}
|
|
1660
|
+
else {
|
|
1661
|
+
auth.logout();
|
|
1662
|
+
}
|
|
1663
|
+
return throwError(() => refreshError);
|
|
1664
|
+
}), switchMap$1((tokens) => next(prepareRequest(req, tokens.accessToken, true, baseUrl))));
|
|
1197
1665
|
}
|
|
1198
1666
|
return next(prepareRequest(req, tokenToAttach, false, baseUrl)).pipe(catchError$1((error) => {
|
|
1199
|
-
if (error?.status
|
|
1200
|
-
|
|
1201
|
-
const latestRefreshTokenExpiresAt = auth.refreshTokenExpiresAt();
|
|
1202
|
-
const canRefreshNow = !!latestRefreshToken && !isExpired(latestRefreshTokenExpiresAt);
|
|
1203
|
-
if (canRefreshNow) {
|
|
1204
|
-
return refreshTokens$(http, gatewayApiBaseUrl, latestRefreshToken, auth, deviceToken, refreshSkewMs).pipe(switchMap((tokens) => next(prepareRequest(req, tokens.accessToken, true, baseUrl))), catchError$1((refreshError) => {
|
|
1205
|
-
auth.logout();
|
|
1206
|
-
return throwError(() => refreshError);
|
|
1207
|
-
}));
|
|
1208
|
-
}
|
|
1667
|
+
if (error?.status !== 401 || isAuthRequest || alreadyRetried) {
|
|
1668
|
+
return throwError(() => error);
|
|
1209
1669
|
}
|
|
1210
|
-
|
|
1211
|
-
auth.
|
|
1670
|
+
const latestAppSession = resolved.scope === 'application' && resolved.applicationCode
|
|
1671
|
+
? auth.getAppSession(resolved.applicationCode)
|
|
1672
|
+
: null;
|
|
1673
|
+
const latestRefreshToken = resolved.scope === 'application' && resolved.applicationCode
|
|
1674
|
+
? (latestAppSession?.refreshToken ?? null)
|
|
1675
|
+
: auth.refreshToken();
|
|
1676
|
+
const latestRefreshTokenExpiresAt = resolved.scope === 'application' && resolved.applicationCode
|
|
1677
|
+
? (latestAppSession?.refreshTokenExpiresAt ?? null)
|
|
1678
|
+
: auth.refreshTokenExpiresAt();
|
|
1679
|
+
const canRefreshNow = !!latestRefreshToken && !isExpired(latestRefreshTokenExpiresAt);
|
|
1680
|
+
if (!canRefreshNow || !latestRefreshToken) {
|
|
1681
|
+
if (resolved.scope === 'application' && resolved.applicationCode) {
|
|
1682
|
+
auth.clearAppSession(resolved.applicationCode);
|
|
1683
|
+
}
|
|
1684
|
+
else {
|
|
1685
|
+
auth.logout();
|
|
1686
|
+
}
|
|
1687
|
+
return throwError(() => error);
|
|
1212
1688
|
}
|
|
1213
|
-
return
|
|
1689
|
+
return refreshTokens$(buildRefreshContext(), latestRefreshToken).pipe(catchError$1((refreshError) => {
|
|
1690
|
+
if (resolved.scope === 'application' && resolved.applicationCode) {
|
|
1691
|
+
auth.clearAppSession(resolved.applicationCode);
|
|
1692
|
+
}
|
|
1693
|
+
else {
|
|
1694
|
+
auth.logout();
|
|
1695
|
+
}
|
|
1696
|
+
return throwError(() => refreshError);
|
|
1697
|
+
}), switchMap$1((tokens) => next(prepareRequest(req, tokens.accessToken, true, baseUrl))));
|
|
1214
1698
|
}));
|
|
1215
1699
|
};
|
|
1216
1700
|
|
|
@@ -1415,9 +1899,11 @@ class GatewayLoginPage {
|
|
|
1415
1899
|
return;
|
|
1416
1900
|
}
|
|
1417
1901
|
const { username, password } = this.loginForm.getRawValue();
|
|
1902
|
+
const applicationCode = resolveApplicationCodeOption(this.options.applicationCode);
|
|
1418
1903
|
this.authFacade.login({
|
|
1419
1904
|
userName: username,
|
|
1420
1905
|
password,
|
|
1906
|
+
applicationCode: applicationCode ?? undefined,
|
|
1421
1907
|
isEncrypted: false,
|
|
1422
1908
|
deviceToken: resolveGatewayDeviceToken(this.options.deviceToken),
|
|
1423
1909
|
});
|
|
@@ -1557,5 +2043,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
1557
2043
|
* Generated bundle index. Do not edit.
|
|
1558
2044
|
*/
|
|
1559
2045
|
|
|
1560
|
-
export { AUTH_STATE_DEFAULTS, ClearError, ClearPendingMfa, ClearRateLimit, ExchangeSsoCode, GATEWAY_AUTH_ACCESS_TOKEN_REFRESH_SKEW_MS, GATEWAY_AUTH_DEVICE_TOKEN, GATEWAY_AUTH_DEVICE_TOKEN_STORAGE_KEY, GATEWAY_AUTH_ENDPOINTS, GATEWAY_AUTH_NGSW_BYPASS_PARAM, GATEWAY_AUTH_OPTIONS, GATEWAY_AUTH_RETRY_CONTEXT, GATEWAY_RATE_LIMIT_ERROR_CODE, GATEWAY_RATE_LIMIT_STATUS, GatewayAuthFacade, GatewayAuthState, GatewayLoginPage, GatewayMfa, GatewaySsoButtons, GatewaySsoCallback, GatewaySsoSession, LoadSsoProviders, Login, LoginFailure, LoginSuccess, Logout, ResendMfa, SetRateLimit, StartSso, UpdateTokens, UpdateUserData, VerifyMfa, buildGatewayUrl, buildSsoStartUrl, createSecureClientState, extractGatewayRateLimitInfo, gatewayAuthInterceptor, getGatewayErrorMessage, hasGatewayTokens, isExpired, isGatewayAuthRequestUrl, mapGatewayTokens, mapGatewayUser, normalizeGatewayBase, readPersistedGatewayAuthTokens, resolveAccessTokenRefreshSkewMs, resolveApiDateValue, resolveGatewayAuthPath, resolveGatewayDeviceToken, sanitizePersistedAuthState, withGatewayAuthNgswBypass };
|
|
2046
|
+
export { AUTH_STATE_DEFAULTS, ClearAllAppSessions, ClearAppSession, ClearError, ClearPendingMfa, ClearRateLimit, ExchangeSsoCode, GATEWAY_AUTH_ACCESS_TOKEN_REFRESH_SKEW_MS, GATEWAY_AUTH_DEVICE_TOKEN, GATEWAY_AUTH_DEVICE_TOKEN_STORAGE_KEY, GATEWAY_AUTH_ENDPOINTS, GATEWAY_AUTH_NGSW_BYPASS_PARAM, GATEWAY_AUTH_OPTIONS, GATEWAY_AUTH_RETRY_CONTEXT, GATEWAY_RATE_LIMIT_ERROR_CODE, GATEWAY_RATE_LIMIT_STATUS, GatewayAuthFacade, GatewayAuthState, GatewayLoginPage, GatewayMfa, GatewaySsoButtons, GatewaySsoCallback, GatewaySsoSession, LaunchApplication, LoadApplications, LoadSsoProviders, Login, LoginFailure, LoginSuccess, Logout, ResendMfa, SetAppSession, SetApplications, SetRateLimit, StartSso, UpdateAppTokens, UpdateTokens, UpdateUserData, VerifyMfa, buildApplicationContextUrl, buildGatewayUrl, buildSsoStartUrl, clearApplicationContextCache, createSecureClientState, extractGatewayRateLimitInfo, fetchApplicationContextCode, gatewayAuthInterceptor, getGatewayErrorMessage, hasGatewayTokens, isExpired, isGatewayAuthRequestUrl, mapGatewayTokens, mapGatewayUser, normalizeGatewayBase, readPersistedGatewayAuthTokens, resolveAccessTokenRefreshSkewMs, resolveApiDateValue, resolveApplicationCodeOption, resolveGatewayAuthPath, resolveGatewayDeviceToken, sanitizePersistedAuthState, withGatewayAuthNgswBypass };
|
|
1561
2047
|
//# sourceMappingURL=masterteam-gateway-auth.mjs.map
|