@azure/msal-angular 3.0.23 → 3.0.25

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.
@@ -7,736 +7,736 @@ import { DOCUMENT, CommonModule } from '@angular/common';
7
7
  import { map, concatMap, catchError, switchMap, take, filter } from 'rxjs/operators';
8
8
  import * as i4 from '@angular/router';
9
9
 
10
- /* eslint-disable header/header */
11
- const name = "@azure/msal-angular";
12
- const version = "3.0.23";
10
+ /* eslint-disable header/header */
11
+ const name = "@azure/msal-angular";
12
+ const version = "3.0.25";
13
13
 
14
- /*
15
- * Copyright (c) Microsoft Corporation. All rights reserved.
16
- * Licensed under the MIT License.
17
- */
18
- const MSAL_INSTANCE = new InjectionToken("MSAL_INSTANCE");
19
- const MSAL_GUARD_CONFIG = new InjectionToken("MSAL_GUARD_CONFIG");
20
- const MSAL_INTERCEPTOR_CONFIG = new InjectionToken("MSAL_INTERCEPTOR_CONFIG");
14
+ /*
15
+ * Copyright (c) Microsoft Corporation. All rights reserved.
16
+ * Licensed under the MIT License.
17
+ */
18
+ const MSAL_INSTANCE = new InjectionToken("MSAL_INSTANCE");
19
+ const MSAL_GUARD_CONFIG = new InjectionToken("MSAL_GUARD_CONFIG");
20
+ const MSAL_INTERCEPTOR_CONFIG = new InjectionToken("MSAL_INTERCEPTOR_CONFIG");
21
21
  const MSAL_BROADCAST_CONFIG = new InjectionToken("MSAL_BROADCAST_CONFIG");
22
22
 
23
- /*
24
- * Copyright (c) Microsoft Corporation. All rights reserved.
25
- * Licensed under the MIT License.
26
- */
27
- class MsalService {
28
- constructor(instance, location) {
29
- this.instance = instance;
30
- this.location = location;
31
- const hash = this.location.path(true).split("#").pop();
32
- if (hash) {
33
- this.redirectHash = `#${hash}`;
34
- }
35
- this.instance.initializeWrapperLibrary(WrapperSKU.Angular, version);
36
- }
37
- initialize() {
38
- return from(this.instance.initialize());
39
- }
40
- acquireTokenPopup(request) {
41
- return from(this.instance.acquireTokenPopup(request));
42
- }
43
- acquireTokenRedirect(request) {
44
- return from(this.instance.acquireTokenRedirect(request));
45
- }
46
- acquireTokenSilent(silentRequest) {
47
- return from(this.instance.acquireTokenSilent(silentRequest));
48
- }
49
- handleRedirectObservable(hash) {
50
- return from(this.instance
51
- .initialize()
52
- .then(() => this.instance.handleRedirectPromise(hash || this.redirectHash)));
53
- }
54
- loginPopup(request) {
55
- return from(this.instance.loginPopup(request));
56
- }
57
- loginRedirect(request) {
58
- return from(this.instance.loginRedirect(request));
59
- }
60
- logout(logoutRequest) {
61
- return from(this.instance.logout(logoutRequest));
62
- }
63
- logoutRedirect(logoutRequest) {
64
- return from(this.instance.logoutRedirect(logoutRequest));
65
- }
66
- logoutPopup(logoutRequest) {
67
- return from(this.instance.logoutPopup(logoutRequest));
68
- }
69
- ssoSilent(request) {
70
- return from(this.instance.ssoSilent(request));
71
- }
72
- /**
73
- * Gets logger for msal-angular.
74
- * If no logger set, returns logger instance created with same options as msal-browser
75
- */
76
- getLogger() {
77
- if (!this.logger) {
78
- this.logger = this.instance.getLogger().clone(name, version);
79
- }
80
- return this.logger;
81
- }
82
- // Create a logger instance for msal-angular with the same options as msal-browser
83
- setLogger(logger) {
84
- this.logger = logger.clone(name, version);
85
- this.instance.setLogger(logger);
86
- }
87
- }
88
- MsalService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalService, deps: [{ token: MSAL_INSTANCE }, { token: i3.Location }], target: i0.ɵɵFactoryTarget.Injectable });
89
- MsalService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalService });
90
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalService, decorators: [{
91
- type: Injectable
92
- }], ctorParameters: function () { return [{ type: undefined, decorators: [{
93
- type: Inject,
94
- args: [MSAL_INSTANCE]
23
+ /*
24
+ * Copyright (c) Microsoft Corporation. All rights reserved.
25
+ * Licensed under the MIT License.
26
+ */
27
+ class MsalService {
28
+ constructor(instance, location) {
29
+ this.instance = instance;
30
+ this.location = location;
31
+ const hash = this.location.path(true).split("#").pop();
32
+ if (hash) {
33
+ this.redirectHash = `#${hash}`;
34
+ }
35
+ this.instance.initializeWrapperLibrary(WrapperSKU.Angular, version);
36
+ }
37
+ initialize() {
38
+ return from(this.instance.initialize());
39
+ }
40
+ acquireTokenPopup(request) {
41
+ return from(this.instance.acquireTokenPopup(request));
42
+ }
43
+ acquireTokenRedirect(request) {
44
+ return from(this.instance.acquireTokenRedirect(request));
45
+ }
46
+ acquireTokenSilent(silentRequest) {
47
+ return from(this.instance.acquireTokenSilent(silentRequest));
48
+ }
49
+ handleRedirectObservable(hash) {
50
+ return from(this.instance
51
+ .initialize()
52
+ .then(() => this.instance.handleRedirectPromise(hash || this.redirectHash)));
53
+ }
54
+ loginPopup(request) {
55
+ return from(this.instance.loginPopup(request));
56
+ }
57
+ loginRedirect(request) {
58
+ return from(this.instance.loginRedirect(request));
59
+ }
60
+ logout(logoutRequest) {
61
+ return from(this.instance.logout(logoutRequest));
62
+ }
63
+ logoutRedirect(logoutRequest) {
64
+ return from(this.instance.logoutRedirect(logoutRequest));
65
+ }
66
+ logoutPopup(logoutRequest) {
67
+ return from(this.instance.logoutPopup(logoutRequest));
68
+ }
69
+ ssoSilent(request) {
70
+ return from(this.instance.ssoSilent(request));
71
+ }
72
+ /**
73
+ * Gets logger for msal-angular.
74
+ * If no logger set, returns logger instance created with same options as msal-browser
75
+ */
76
+ getLogger() {
77
+ if (!this.logger) {
78
+ this.logger = this.instance.getLogger().clone(name, version);
79
+ }
80
+ return this.logger;
81
+ }
82
+ // Create a logger instance for msal-angular with the same options as msal-browser
83
+ setLogger(logger) {
84
+ this.logger = logger.clone(name, version);
85
+ this.instance.setLogger(logger);
86
+ }
87
+ }
88
+ MsalService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalService, deps: [{ token: MSAL_INSTANCE }, { token: i3.Location }], target: i0.ɵɵFactoryTarget.Injectable });
89
+ MsalService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalService });
90
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalService, decorators: [{
91
+ type: Injectable
92
+ }], ctorParameters: function () { return [{ type: undefined, decorators: [{
93
+ type: Inject,
94
+ args: [MSAL_INSTANCE]
95
95
  }] }, { type: i3.Location }]; } });
96
96
 
97
- /*
98
- * Copyright (c) Microsoft Corporation. All rights reserved.
99
- * Licensed under the MIT License.
100
- */
101
- class MsalBroadcastService {
102
- constructor(msalInstance, authService, msalBroadcastConfig) {
103
- this.msalInstance = msalInstance;
104
- this.authService = authService;
105
- this.msalBroadcastConfig = msalBroadcastConfig;
106
- // Make _msalSubject a ReplaySubject if configured to replay past events
107
- if (this.msalBroadcastConfig &&
108
- this.msalBroadcastConfig.eventsToReplay > 0) {
109
- this.authService
110
- .getLogger()
111
- .verbose(`BroadcastService - eventsToReplay set on BroadcastConfig, replaying the last ${this.msalBroadcastConfig.eventsToReplay} events`);
112
- this._msalSubject = new ReplaySubject(this.msalBroadcastConfig.eventsToReplay);
113
- }
114
- else {
115
- // Defaults to _msalSubject being a Subject
116
- this._msalSubject = new Subject();
117
- }
118
- this.msalSubject$ = this._msalSubject.asObservable();
119
- // InProgress as BehaviorSubject so most recent inProgress state will be available upon subscription
120
- this._inProgress = new BehaviorSubject(InteractionStatus.Startup);
121
- this.inProgress$ = this._inProgress.asObservable();
122
- this.msalInstance.addEventCallback((message) => {
123
- this._msalSubject.next(message);
124
- const status = EventMessageUtils.getInteractionStatusFromEvent(message, this._inProgress.value);
125
- if (status !== null) {
126
- this.authService
127
- .getLogger()
128
- .verbose(`BroadcastService - ${message.eventType} results in setting inProgress from ${this._inProgress.value} to ${status}`);
129
- this._inProgress.next(status);
130
- }
131
- });
132
- }
133
- }
134
- MsalBroadcastService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalBroadcastService, deps: [{ token: MSAL_INSTANCE }, { token: MsalService }, { token: MSAL_BROADCAST_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
135
- MsalBroadcastService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalBroadcastService });
136
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalBroadcastService, decorators: [{
137
- type: Injectable
138
- }], ctorParameters: function () { return [{ type: undefined, decorators: [{
139
- type: Inject,
140
- args: [MSAL_INSTANCE]
141
- }] }, { type: MsalService }, { type: undefined, decorators: [{
142
- type: Optional
143
- }, {
144
- type: Inject,
145
- args: [MSAL_BROADCAST_CONFIG]
97
+ /*
98
+ * Copyright (c) Microsoft Corporation. All rights reserved.
99
+ * Licensed under the MIT License.
100
+ */
101
+ class MsalBroadcastService {
102
+ constructor(msalInstance, authService, msalBroadcastConfig) {
103
+ this.msalInstance = msalInstance;
104
+ this.authService = authService;
105
+ this.msalBroadcastConfig = msalBroadcastConfig;
106
+ // Make _msalSubject a ReplaySubject if configured to replay past events
107
+ if (this.msalBroadcastConfig &&
108
+ this.msalBroadcastConfig.eventsToReplay > 0) {
109
+ this.authService
110
+ .getLogger()
111
+ .verbose(`BroadcastService - eventsToReplay set on BroadcastConfig, replaying the last ${this.msalBroadcastConfig.eventsToReplay} events`);
112
+ this._msalSubject = new ReplaySubject(this.msalBroadcastConfig.eventsToReplay);
113
+ }
114
+ else {
115
+ // Defaults to _msalSubject being a Subject
116
+ this._msalSubject = new Subject();
117
+ }
118
+ this.msalSubject$ = this._msalSubject.asObservable();
119
+ // InProgress as BehaviorSubject so most recent inProgress state will be available upon subscription
120
+ this._inProgress = new BehaviorSubject(InteractionStatus.Startup);
121
+ this.inProgress$ = this._inProgress.asObservable();
122
+ this.msalInstance.addEventCallback((message) => {
123
+ this._msalSubject.next(message);
124
+ const status = EventMessageUtils.getInteractionStatusFromEvent(message, this._inProgress.value);
125
+ if (status !== null) {
126
+ this.authService
127
+ .getLogger()
128
+ .verbose(`BroadcastService - ${message.eventType} results in setting inProgress from ${this._inProgress.value} to ${status}`);
129
+ this._inProgress.next(status);
130
+ }
131
+ });
132
+ }
133
+ }
134
+ MsalBroadcastService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalBroadcastService, deps: [{ token: MSAL_INSTANCE }, { token: MsalService }, { token: MSAL_BROADCAST_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
135
+ MsalBroadcastService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalBroadcastService });
136
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalBroadcastService, decorators: [{
137
+ type: Injectable
138
+ }], ctorParameters: function () { return [{ type: undefined, decorators: [{
139
+ type: Inject,
140
+ args: [MSAL_INSTANCE]
141
+ }] }, { type: MsalService }, { type: undefined, decorators: [{
142
+ type: Optional
143
+ }, {
144
+ type: Inject,
145
+ args: [MSAL_BROADCAST_CONFIG]
146
146
  }] }]; } });
147
147
 
148
- /*
149
- * Copyright (c) Microsoft Corporation. All rights reserved.
150
- * Licensed under the MIT License.
151
- */
152
- class MsalGuard {
153
- constructor(msalGuardConfig, msalBroadcastService, authService, location, router) {
154
- this.msalGuardConfig = msalGuardConfig;
155
- this.msalBroadcastService = msalBroadcastService;
156
- this.authService = authService;
157
- this.location = location;
158
- this.router = router;
159
- // Subscribing so events in MsalGuard will set inProgress$ observable
160
- this.msalBroadcastService.inProgress$.subscribe();
161
- }
162
- /**
163
- * Parses url string to UrlTree
164
- * @param url
165
- */
166
- parseUrl(url) {
167
- return this.router.parseUrl(url);
168
- }
169
- /**
170
- * Builds the absolute url for the destination page
171
- * @param path Relative path of requested page
172
- * @returns Full destination url
173
- */
174
- getDestinationUrl(path) {
175
- this.authService.getLogger().verbose("Guard - getting destination url");
176
- // Absolute base url for the application (default to origin if base element not present)
177
- const baseElements = document.getElementsByTagName("base");
178
- const baseUrl = this.location.normalize(baseElements.length ? baseElements[0].href : window.location.origin);
179
- // Path of page (including hash, if using hash routing)
180
- const pathUrl = this.location.prepareExternalUrl(path);
181
- // Hash location strategy
182
- if (pathUrl.startsWith("#")) {
183
- this.authService
184
- .getLogger()
185
- .verbose("Guard - destination by hash routing");
186
- return `${baseUrl}/${pathUrl}`;
187
- }
188
- /*
189
- * If using path location strategy, pathUrl will include the relative portion of the base path (e.g. /base/page).
190
- * Since baseUrl also includes /base, can just concatentate baseUrl + path
191
- */
192
- return `${baseUrl}${path}`;
193
- }
194
- /**
195
- * Interactively prompt the user to login
196
- * @param url Path of the requested page
197
- */
198
- loginInteractively(state) {
199
- const authRequest = typeof this.msalGuardConfig.authRequest === "function"
200
- ? this.msalGuardConfig.authRequest(this.authService, state)
201
- : { ...this.msalGuardConfig.authRequest };
202
- if (this.msalGuardConfig.interactionType === InteractionType.Popup) {
203
- this.authService.getLogger().verbose("Guard - logging in by popup");
204
- return this.authService.loginPopup(authRequest).pipe(map((response) => {
205
- this.authService
206
- .getLogger()
207
- .verbose("Guard - login by popup successful, can activate, setting active account");
208
- this.authService.instance.setActiveAccount(response.account);
209
- return true;
210
- }));
211
- }
212
- this.authService.getLogger().verbose("Guard - logging in by redirect");
213
- const redirectStartPage = this.getDestinationUrl(state.url);
214
- return this.authService
215
- .loginRedirect({
216
- redirectStartPage,
217
- ...authRequest,
218
- })
219
- .pipe(map(() => false));
220
- }
221
- /**
222
- * Helper which checks for the correct interaction type, prevents page with Guard to be set as redirect, and calls handleRedirectObservable
223
- * @param state
224
- */
225
- activateHelper(state) {
226
- if (this.msalGuardConfig.interactionType !== InteractionType.Popup &&
227
- this.msalGuardConfig.interactionType !== InteractionType.Redirect) {
228
- throw new BrowserConfigurationAuthError("invalid_interaction_type", "Invalid interaction type provided to MSAL Guard. InteractionType.Popup or InteractionType.Redirect must be provided in the MsalGuardConfiguration");
229
- }
230
- this.authService.getLogger().verbose("MSAL Guard activated");
231
- /*
232
- * If a page with MSAL Guard is set as the redirect for acquireTokenSilent,
233
- * short-circuit to prevent redirecting or popups.
234
- */
235
- if (typeof window !== "undefined") {
236
- if (UrlString.hashContainsKnownProperties(window.location.hash) &&
237
- BrowserUtils.isInIframe() &&
238
- !this.authService.instance.getConfiguration().system
239
- .allowRedirectInIframe) {
240
- this.authService
241
- .getLogger()
242
- .warning("Guard - redirectUri set to page with MSAL Guard. It is recommended to not set redirectUri to a page that requires authentication.");
243
- return of(false);
244
- }
245
- }
246
- else {
247
- this.authService
248
- .getLogger()
249
- .info("Guard - window is undefined, MSAL does not support server-side token acquisition");
250
- return of(true);
251
- }
252
- /**
253
- * If a loginFailedRoute is set in the config, set this as the loginFailedRoute
254
- */
255
- if (this.msalGuardConfig.loginFailedRoute) {
256
- this.loginFailedRoute = this.parseUrl(this.msalGuardConfig.loginFailedRoute);
257
- }
258
- // Capture current path before it gets changed by handleRedirectObservable
259
- const currentPath = this.location.path(true);
260
- return this.authService.initialize().pipe(concatMap(() => {
261
- return this.authService.handleRedirectObservable();
262
- }), concatMap(() => {
263
- if (!this.authService.instance.getAllAccounts().length) {
264
- if (state) {
265
- this.authService
266
- .getLogger()
267
- .verbose("Guard - no accounts retrieved, log in required to activate");
268
- return this.loginInteractively(state);
269
- }
270
- this.authService
271
- .getLogger()
272
- .verbose("Guard - no accounts retrieved, no state, cannot load");
273
- return of(false);
274
- }
275
- this.authService
276
- .getLogger()
277
- .verbose("Guard - at least 1 account exists, can activate or load");
278
- // Prevent navigating the app to /#code= or /code=
279
- if (state) {
280
- /*
281
- * Path routing:
282
- * state.url: /#code=...
283
- * state.root.fragment: code=...
284
- */
285
- /*
286
- * Hash routing:
287
- * state.url: /code
288
- * state.root.fragment: null
289
- */
290
- const urlContainsCode = this.includesCode(state.url);
291
- const fragmentContainsCode = !!state.root &&
292
- !!state.root.fragment &&
293
- this.includesCode(`#${state.root.fragment}`);
294
- const hashRouting = this.location.prepareExternalUrl(state.url).indexOf("#") === 0;
295
- // Ensure code parameter is in fragment (and not in query parameter), or that hash hash routing is used
296
- if (urlContainsCode && (fragmentContainsCode || hashRouting)) {
297
- this.authService
298
- .getLogger()
299
- .info("Guard - Hash contains known code response, stopping navigation.");
300
- // Path routing (navigate to current path without hash)
301
- if (currentPath.indexOf("#") > -1) {
302
- return of(this.parseUrl(this.location.path()));
303
- }
304
- // Hash routing (navigate to root path)
305
- return of(this.parseUrl(""));
306
- }
307
- }
308
- return of(true);
309
- }), catchError((error) => {
310
- this.authService
311
- .getLogger()
312
- .error("Guard - error while logging in, unable to activate");
313
- this.authService
314
- .getLogger()
315
- .errorPii(`Guard - error: ${error.message}`);
316
- /**
317
- * If a loginFailedRoute is set, checks to see if state is passed before returning route
318
- */
319
- if (this.loginFailedRoute && state) {
320
- this.authService
321
- .getLogger()
322
- .verbose("Guard - loginFailedRoute set, redirecting");
323
- return of(this.loginFailedRoute);
324
- }
325
- return of(false);
326
- }));
327
- }
328
- includesCode(path) {
329
- return ((path.lastIndexOf("/code") > -1 &&
330
- path.lastIndexOf("/code") === path.length - "/code".length) || // path.endsWith("/code")
331
- path.indexOf("#code=") > -1 ||
332
- path.indexOf("&code=") > -1);
333
- }
334
- canActivate(route, state) {
335
- this.authService.getLogger().verbose("Guard - canActivate");
336
- return this.activateHelper(state);
337
- }
338
- canActivateChild(route, state) {
339
- this.authService.getLogger().verbose("Guard - canActivateChild");
340
- return this.activateHelper(state);
341
- }
342
- canMatch() {
343
- this.authService.getLogger().verbose("Guard - canLoad");
344
- return this.activateHelper();
345
- }
346
- }
347
- MsalGuard.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalGuard, deps: [{ token: MSAL_GUARD_CONFIG }, { token: MsalBroadcastService }, { token: MsalService }, { token: i3.Location }, { token: i4.Router }], target: i0.ɵɵFactoryTarget.Injectable });
348
- MsalGuard.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalGuard });
349
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalGuard, decorators: [{
350
- type: Injectable
351
- }], ctorParameters: function () { return [{ type: undefined, decorators: [{
352
- type: Inject,
353
- args: [MSAL_GUARD_CONFIG]
148
+ /*
149
+ * Copyright (c) Microsoft Corporation. All rights reserved.
150
+ * Licensed under the MIT License.
151
+ */
152
+ class MsalGuard {
153
+ constructor(msalGuardConfig, msalBroadcastService, authService, location, router) {
154
+ this.msalGuardConfig = msalGuardConfig;
155
+ this.msalBroadcastService = msalBroadcastService;
156
+ this.authService = authService;
157
+ this.location = location;
158
+ this.router = router;
159
+ // Subscribing so events in MsalGuard will set inProgress$ observable
160
+ this.msalBroadcastService.inProgress$.subscribe();
161
+ }
162
+ /**
163
+ * Parses url string to UrlTree
164
+ * @param url
165
+ */
166
+ parseUrl(url) {
167
+ return this.router.parseUrl(url);
168
+ }
169
+ /**
170
+ * Builds the absolute url for the destination page
171
+ * @param path Relative path of requested page
172
+ * @returns Full destination url
173
+ */
174
+ getDestinationUrl(path) {
175
+ this.authService.getLogger().verbose("Guard - getting destination url");
176
+ // Absolute base url for the application (default to origin if base element not present)
177
+ const baseElements = document.getElementsByTagName("base");
178
+ const baseUrl = this.location.normalize(baseElements.length ? baseElements[0].href : window.location.origin);
179
+ // Path of page (including hash, if using hash routing)
180
+ const pathUrl = this.location.prepareExternalUrl(path);
181
+ // Hash location strategy
182
+ if (pathUrl.startsWith("#")) {
183
+ this.authService
184
+ .getLogger()
185
+ .verbose("Guard - destination by hash routing");
186
+ return `${baseUrl}/${pathUrl}`;
187
+ }
188
+ /*
189
+ * If using path location strategy, pathUrl will include the relative portion of the base path (e.g. /base/page).
190
+ * Since baseUrl also includes /base, can just concatentate baseUrl + path
191
+ */
192
+ return `${baseUrl}${path}`;
193
+ }
194
+ /**
195
+ * Interactively prompt the user to login
196
+ * @param url Path of the requested page
197
+ */
198
+ loginInteractively(state) {
199
+ const authRequest = typeof this.msalGuardConfig.authRequest === "function"
200
+ ? this.msalGuardConfig.authRequest(this.authService, state)
201
+ : { ...this.msalGuardConfig.authRequest };
202
+ if (this.msalGuardConfig.interactionType === InteractionType.Popup) {
203
+ this.authService.getLogger().verbose("Guard - logging in by popup");
204
+ return this.authService.loginPopup(authRequest).pipe(map((response) => {
205
+ this.authService
206
+ .getLogger()
207
+ .verbose("Guard - login by popup successful, can activate, setting active account");
208
+ this.authService.instance.setActiveAccount(response.account);
209
+ return true;
210
+ }));
211
+ }
212
+ this.authService.getLogger().verbose("Guard - logging in by redirect");
213
+ const redirectStartPage = this.getDestinationUrl(state.url);
214
+ return this.authService
215
+ .loginRedirect({
216
+ redirectStartPage,
217
+ ...authRequest,
218
+ })
219
+ .pipe(map(() => false));
220
+ }
221
+ /**
222
+ * Helper which checks for the correct interaction type, prevents page with Guard to be set as redirect, and calls handleRedirectObservable
223
+ * @param state
224
+ */
225
+ activateHelper(state) {
226
+ if (this.msalGuardConfig.interactionType !== InteractionType.Popup &&
227
+ this.msalGuardConfig.interactionType !== InteractionType.Redirect) {
228
+ throw new BrowserConfigurationAuthError("invalid_interaction_type", "Invalid interaction type provided to MSAL Guard. InteractionType.Popup or InteractionType.Redirect must be provided in the MsalGuardConfiguration");
229
+ }
230
+ this.authService.getLogger().verbose("MSAL Guard activated");
231
+ /*
232
+ * If a page with MSAL Guard is set as the redirect for acquireTokenSilent,
233
+ * short-circuit to prevent redirecting or popups.
234
+ */
235
+ if (typeof window !== "undefined") {
236
+ if (UrlString.hashContainsKnownProperties(window.location.hash) &&
237
+ BrowserUtils.isInIframe() &&
238
+ !this.authService.instance.getConfiguration().system
239
+ .allowRedirectInIframe) {
240
+ this.authService
241
+ .getLogger()
242
+ .warning("Guard - redirectUri set to page with MSAL Guard. It is recommended to not set redirectUri to a page that requires authentication.");
243
+ return of(false);
244
+ }
245
+ }
246
+ else {
247
+ this.authService
248
+ .getLogger()
249
+ .info("Guard - window is undefined, MSAL does not support server-side token acquisition");
250
+ return of(true);
251
+ }
252
+ /**
253
+ * If a loginFailedRoute is set in the config, set this as the loginFailedRoute
254
+ */
255
+ if (this.msalGuardConfig.loginFailedRoute) {
256
+ this.loginFailedRoute = this.parseUrl(this.msalGuardConfig.loginFailedRoute);
257
+ }
258
+ // Capture current path before it gets changed by handleRedirectObservable
259
+ const currentPath = this.location.path(true);
260
+ return this.authService.initialize().pipe(concatMap(() => {
261
+ return this.authService.handleRedirectObservable();
262
+ }), concatMap(() => {
263
+ if (!this.authService.instance.getAllAccounts().length) {
264
+ if (state) {
265
+ this.authService
266
+ .getLogger()
267
+ .verbose("Guard - no accounts retrieved, log in required to activate");
268
+ return this.loginInteractively(state);
269
+ }
270
+ this.authService
271
+ .getLogger()
272
+ .verbose("Guard - no accounts retrieved, no state, cannot load");
273
+ return of(false);
274
+ }
275
+ this.authService
276
+ .getLogger()
277
+ .verbose("Guard - at least 1 account exists, can activate or load");
278
+ // Prevent navigating the app to /#code= or /code=
279
+ if (state) {
280
+ /*
281
+ * Path routing:
282
+ * state.url: /#code=...
283
+ * state.root.fragment: code=...
284
+ */
285
+ /*
286
+ * Hash routing:
287
+ * state.url: /code
288
+ * state.root.fragment: null
289
+ */
290
+ const urlContainsCode = this.includesCode(state.url);
291
+ const fragmentContainsCode = !!state.root &&
292
+ !!state.root.fragment &&
293
+ this.includesCode(`#${state.root.fragment}`);
294
+ const hashRouting = this.location.prepareExternalUrl(state.url).indexOf("#") === 0;
295
+ // Ensure code parameter is in fragment (and not in query parameter), or that hash hash routing is used
296
+ if (urlContainsCode && (fragmentContainsCode || hashRouting)) {
297
+ this.authService
298
+ .getLogger()
299
+ .info("Guard - Hash contains known code response, stopping navigation.");
300
+ // Path routing (navigate to current path without hash)
301
+ if (currentPath.indexOf("#") > -1) {
302
+ return of(this.parseUrl(this.location.path()));
303
+ }
304
+ // Hash routing (navigate to root path)
305
+ return of(this.parseUrl(""));
306
+ }
307
+ }
308
+ return of(true);
309
+ }), catchError((error) => {
310
+ this.authService
311
+ .getLogger()
312
+ .error("Guard - error while logging in, unable to activate");
313
+ this.authService
314
+ .getLogger()
315
+ .errorPii(`Guard - error: ${error.message}`);
316
+ /**
317
+ * If a loginFailedRoute is set, checks to see if state is passed before returning route
318
+ */
319
+ if (this.loginFailedRoute && state) {
320
+ this.authService
321
+ .getLogger()
322
+ .verbose("Guard - loginFailedRoute set, redirecting");
323
+ return of(this.loginFailedRoute);
324
+ }
325
+ return of(false);
326
+ }));
327
+ }
328
+ includesCode(path) {
329
+ return ((path.lastIndexOf("/code") > -1 &&
330
+ path.lastIndexOf("/code") === path.length - "/code".length) || // path.endsWith("/code")
331
+ path.indexOf("#code=") > -1 ||
332
+ path.indexOf("&code=") > -1);
333
+ }
334
+ canActivate(route, state) {
335
+ this.authService.getLogger().verbose("Guard - canActivate");
336
+ return this.activateHelper(state);
337
+ }
338
+ canActivateChild(route, state) {
339
+ this.authService.getLogger().verbose("Guard - canActivateChild");
340
+ return this.activateHelper(state);
341
+ }
342
+ canMatch() {
343
+ this.authService.getLogger().verbose("Guard - canLoad");
344
+ return this.activateHelper();
345
+ }
346
+ }
347
+ MsalGuard.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalGuard, deps: [{ token: MSAL_GUARD_CONFIG }, { token: MsalBroadcastService }, { token: MsalService }, { token: i3.Location }, { token: i4.Router }], target: i0.ɵɵFactoryTarget.Injectable });
348
+ MsalGuard.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalGuard });
349
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalGuard, decorators: [{
350
+ type: Injectable
351
+ }], ctorParameters: function () { return [{ type: undefined, decorators: [{
352
+ type: Inject,
353
+ args: [MSAL_GUARD_CONFIG]
354
354
  }] }, { type: MsalBroadcastService }, { type: MsalService }, { type: i3.Location }, { type: i4.Router }]; } });
355
355
 
356
- /*
357
- * Copyright (c) Microsoft Corporation. All rights reserved.
358
- * Licensed under the MIT License.
359
- */
360
- class MsalInterceptor {
361
- constructor(msalInterceptorConfig, authService, location, msalBroadcastService,
362
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
363
- document) {
364
- this.msalInterceptorConfig = msalInterceptorConfig;
365
- this.authService = authService;
366
- this.location = location;
367
- this.msalBroadcastService = msalBroadcastService;
368
- this._document = document;
369
- }
370
- intercept(req, // eslint-disable-line @typescript-eslint/no-explicit-any
371
- next
372
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
373
- ) {
374
- if (this.msalInterceptorConfig.interactionType !== InteractionType.Popup &&
375
- this.msalInterceptorConfig.interactionType !== InteractionType.Redirect) {
376
- throw new BrowserConfigurationAuthError("invalid_interaction_type", "Invalid interaction type provided to MSAL Interceptor. InteractionType.Popup, InteractionType.Redirect must be provided in the msalInterceptorConfiguration");
377
- }
378
- this.authService.getLogger().verbose("MSAL Interceptor activated");
379
- const scopes = this.getScopesForEndpoint(req.url, req.method);
380
- // If no scopes for endpoint, does not acquire token
381
- if (!scopes || scopes.length === 0) {
382
- this.authService
383
- .getLogger()
384
- .verbose("Interceptor - no scopes for endpoint");
385
- return next.handle(req);
386
- }
387
- // Sets account as active account or first account
388
- let account;
389
- if (!!this.authService.instance.getActiveAccount()) {
390
- this.authService
391
- .getLogger()
392
- .verbose("Interceptor - active account selected");
393
- account = this.authService.instance.getActiveAccount();
394
- }
395
- else {
396
- this.authService
397
- .getLogger()
398
- .verbose("Interceptor - no active account, fallback to first account");
399
- account = this.authService.instance.getAllAccounts()[0];
400
- }
401
- const authRequest = typeof this.msalInterceptorConfig.authRequest === "function"
402
- ? this.msalInterceptorConfig.authRequest(this.authService, req, {
403
- account: account,
404
- })
405
- : { ...this.msalInterceptorConfig.authRequest, account };
406
- this.authService
407
- .getLogger()
408
- .info(`Interceptor - ${scopes.length} scopes found for endpoint`);
409
- this.authService
410
- .getLogger()
411
- .infoPii(`Interceptor - [${scopes}] scopes found for ${req.url}`);
412
- return this.acquireToken(authRequest, scopes, account).pipe(switchMap((result) => {
413
- this.authService
414
- .getLogger()
415
- .verbose("Interceptor - setting authorization headers");
416
- const headers = req.headers.set("Authorization", `Bearer ${result.accessToken}`);
417
- const requestClone = req.clone({ headers });
418
- return next.handle(requestClone);
419
- }));
420
- }
421
- /**
422
- * Try to acquire token silently. Invoke interaction if acquireTokenSilent rejected with error or resolved with null access token
423
- * @param authRequest Request
424
- * @param scopes Array of scopes for the request
425
- * @param account Account
426
- * @returns Authentication result
427
- */
428
- acquireToken(authRequest, scopes, account) {
429
- // Note: For MSA accounts, include openid scope when calling acquireTokenSilent to return idToken
430
- return this.authService
431
- .acquireTokenSilent({ ...authRequest, scopes, account })
432
- .pipe(catchError(() => {
433
- this.authService
434
- .getLogger()
435
- .error("Interceptor - acquireTokenSilent rejected with error. Invoking interaction to resolve.");
436
- return this.msalBroadcastService.inProgress$.pipe(take(1), switchMap((status) => {
437
- if (status === InteractionStatus.None) {
438
- return this.acquireTokenInteractively(authRequest, scopes);
439
- }
440
- return this.msalBroadcastService.inProgress$.pipe(filter((status) => status === InteractionStatus.None), take(1), switchMap(() => this.acquireToken(authRequest, scopes, account)));
441
- }));
442
- }), switchMap((result) => {
443
- if (!result.accessToken) {
444
- this.authService
445
- .getLogger()
446
- .error("Interceptor - acquireTokenSilent resolved with null access token. Known issue with B2C tenants, invoking interaction to resolve.");
447
- return this.msalBroadcastService.inProgress$.pipe(filter((status) => status === InteractionStatus.None), take(1), switchMap(() => this.acquireTokenInteractively(authRequest, scopes)));
448
- }
449
- return of(result);
450
- }));
451
- }
452
- /**
453
- * Invoke interaction for the given set of scopes
454
- * @param authRequest Request
455
- * @param scopes Array of scopes for the request
456
- * @returns Result from the interactive request
457
- */
458
- acquireTokenInteractively(authRequest, scopes) {
459
- if (this.msalInterceptorConfig.interactionType === InteractionType.Popup) {
460
- this.authService
461
- .getLogger()
462
- .verbose("Interceptor - error acquiring token silently, acquiring by popup");
463
- return this.authService.acquireTokenPopup({ ...authRequest, scopes });
464
- }
465
- this.authService
466
- .getLogger()
467
- .verbose("Interceptor - error acquiring token silently, acquiring by redirect");
468
- const redirectStartPage = window.location.href;
469
- this.authService.acquireTokenRedirect({
470
- ...authRequest,
471
- scopes,
472
- redirectStartPage,
473
- });
474
- return EMPTY;
475
- }
476
- /**
477
- * Looks up the scopes for the given endpoint from the protectedResourceMap
478
- * @param endpoint Url of the request
479
- * @param httpMethod Http method of the request
480
- * @returns Array of scopes, or null if not found
481
- *
482
- */
483
- getScopesForEndpoint(endpoint, httpMethod) {
484
- this.authService
485
- .getLogger()
486
- .verbose("Interceptor - getting scopes for endpoint");
487
- // Ensures endpoints and protected resources compared are normalized
488
- const normalizedEndpoint = this.location.normalize(endpoint);
489
- const protectedResourcesArray = Array.from(this.msalInterceptorConfig.protectedResourceMap.keys());
490
- const matchingProtectedResources = this.matchResourcesToEndpoint(protectedResourcesArray, normalizedEndpoint);
491
- if (matchingProtectedResources.length > 0) {
492
- return this.matchScopesToEndpoint(this.msalInterceptorConfig.protectedResourceMap, matchingProtectedResources, httpMethod);
493
- }
494
- return null;
495
- }
496
- /**
497
- * Finds resource endpoints that match request endpoint
498
- * @param protectedResourcesEndpoints
499
- * @param endpoint
500
- * @returns
501
- */
502
- matchResourcesToEndpoint(protectedResourcesEndpoints, endpoint) {
503
- const matchingResources = [];
504
- protectedResourcesEndpoints.forEach((key) => {
505
- const normalizedKey = this.location.normalize(key);
506
- // Get url components
507
- const absoluteKey = this.getAbsoluteUrl(normalizedKey);
508
- const keyComponents = new URL(absoluteKey);
509
- const absoluteEndpoint = this.getAbsoluteUrl(endpoint);
510
- const endpointComponents = new URL(absoluteEndpoint);
511
- if (this.checkUrlComponents(keyComponents, endpointComponents)) {
512
- matchingResources.push(key);
513
- }
514
- });
515
- return matchingResources;
516
- }
517
- /**
518
- * Compares URL segments between key and endpoint
519
- * @param key
520
- * @param endpoint
521
- * @returns
522
- */
523
- checkUrlComponents(keyComponents, endpointComponents) {
524
- // URL properties from https://developer.mozilla.org/en-US/docs/Web/API/URL
525
- const urlProperties = ["protocol", "host", "pathname", "search", "hash"];
526
- for (const property of urlProperties) {
527
- if (keyComponents[property]) {
528
- const decodedInput = decodeURIComponent(keyComponents[property]);
529
- if (!StringUtils.matchPattern(decodedInput, endpointComponents[property])) {
530
- return false;
531
- }
532
- }
533
- }
534
- return true;
535
- }
536
- /**
537
- * Transforms relative urls to absolute urls
538
- * @param url
539
- * @returns
540
- */
541
- getAbsoluteUrl(url) {
542
- const link = this._document.createElement("a");
543
- link.href = url;
544
- return link.href;
545
- }
546
- /**
547
- * Finds scopes from first matching endpoint with HTTP method that matches request
548
- * @param protectedResourceMap Protected resource map
549
- * @param endpointArray Array of resources that match request endpoint
550
- * @param httpMethod Http method of the request
551
- * @returns
552
- */
553
- matchScopesToEndpoint(protectedResourceMap, endpointArray, httpMethod) {
554
- const allMatchedScopes = [];
555
- // Check each matched endpoint for matching HttpMethod and scopes
556
- endpointArray.forEach((matchedEndpoint) => {
557
- const scopesForEndpoint = [];
558
- const methodAndScopesArray = protectedResourceMap.get(matchedEndpoint);
559
- // Return if resource is unprotected
560
- if (methodAndScopesArray === null) {
561
- allMatchedScopes.push(null);
562
- return;
563
- }
564
- methodAndScopesArray.forEach((entry) => {
565
- // Entry is either array of scopes or ProtectedResourceScopes object
566
- if (typeof entry === "string") {
567
- scopesForEndpoint.push(entry);
568
- }
569
- else {
570
- // Ensure methods being compared are normalized
571
- const normalizedRequestMethod = httpMethod.toLowerCase();
572
- const normalizedResourceMethod = entry.httpMethod.toLowerCase();
573
- // Method in protectedResourceMap matches request http method
574
- if (normalizedResourceMethod === normalizedRequestMethod) {
575
- // Validate if scopes comes null to unprotect the resource in a certain http method
576
- if (entry.scopes === null) {
577
- allMatchedScopes.push(null);
578
- }
579
- else {
580
- entry.scopes.forEach((scope) => {
581
- scopesForEndpoint.push(scope);
582
- });
583
- }
584
- }
585
- }
586
- });
587
- // Only add to all scopes if scopes for endpoint and method is found
588
- if (scopesForEndpoint.length > 0) {
589
- allMatchedScopes.push(scopesForEndpoint);
590
- }
591
- });
592
- if (allMatchedScopes.length > 0) {
593
- if (allMatchedScopes.length > 1) {
594
- this.authService
595
- .getLogger()
596
- .warning("Interceptor - More than 1 matching scopes for endpoint found.");
597
- }
598
- // Returns scopes for first matching endpoint
599
- return allMatchedScopes[0];
600
- }
601
- return null;
602
- }
603
- }
604
- MsalInterceptor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalInterceptor, deps: [{ token: MSAL_INTERCEPTOR_CONFIG }, { token: MsalService }, { token: i3.Location }, { token: MsalBroadcastService }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Injectable });
605
- MsalInterceptor.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalInterceptor });
606
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalInterceptor, decorators: [{
607
- type: Injectable
608
- }], ctorParameters: function () { return [{ type: undefined, decorators: [{
609
- type: Inject,
610
- args: [MSAL_INTERCEPTOR_CONFIG]
611
- }] }, { type: MsalService }, { type: i3.Location }, { type: MsalBroadcastService }, { type: undefined, decorators: [{
612
- type: Inject,
613
- args: [DOCUMENT]
356
+ /*
357
+ * Copyright (c) Microsoft Corporation. All rights reserved.
358
+ * Licensed under the MIT License.
359
+ */
360
+ class MsalInterceptor {
361
+ constructor(msalInterceptorConfig, authService, location, msalBroadcastService,
362
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
363
+ document) {
364
+ this.msalInterceptorConfig = msalInterceptorConfig;
365
+ this.authService = authService;
366
+ this.location = location;
367
+ this.msalBroadcastService = msalBroadcastService;
368
+ this._document = document;
369
+ }
370
+ intercept(req, // eslint-disable-line @typescript-eslint/no-explicit-any
371
+ next
372
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
373
+ ) {
374
+ if (this.msalInterceptorConfig.interactionType !== InteractionType.Popup &&
375
+ this.msalInterceptorConfig.interactionType !== InteractionType.Redirect) {
376
+ throw new BrowserConfigurationAuthError("invalid_interaction_type", "Invalid interaction type provided to MSAL Interceptor. InteractionType.Popup, InteractionType.Redirect must be provided in the msalInterceptorConfiguration");
377
+ }
378
+ this.authService.getLogger().verbose("MSAL Interceptor activated");
379
+ const scopes = this.getScopesForEndpoint(req.url, req.method);
380
+ // If no scopes for endpoint, does not acquire token
381
+ if (!scopes || scopes.length === 0) {
382
+ this.authService
383
+ .getLogger()
384
+ .verbose("Interceptor - no scopes for endpoint");
385
+ return next.handle(req);
386
+ }
387
+ // Sets account as active account or first account
388
+ let account;
389
+ if (!!this.authService.instance.getActiveAccount()) {
390
+ this.authService
391
+ .getLogger()
392
+ .verbose("Interceptor - active account selected");
393
+ account = this.authService.instance.getActiveAccount();
394
+ }
395
+ else {
396
+ this.authService
397
+ .getLogger()
398
+ .verbose("Interceptor - no active account, fallback to first account");
399
+ account = this.authService.instance.getAllAccounts()[0];
400
+ }
401
+ const authRequest = typeof this.msalInterceptorConfig.authRequest === "function"
402
+ ? this.msalInterceptorConfig.authRequest(this.authService, req, {
403
+ account: account,
404
+ })
405
+ : { ...this.msalInterceptorConfig.authRequest, account };
406
+ this.authService
407
+ .getLogger()
408
+ .info(`Interceptor - ${scopes.length} scopes found for endpoint`);
409
+ this.authService
410
+ .getLogger()
411
+ .infoPii(`Interceptor - [${scopes}] scopes found for ${req.url}`);
412
+ return this.acquireToken(authRequest, scopes, account).pipe(switchMap((result) => {
413
+ this.authService
414
+ .getLogger()
415
+ .verbose("Interceptor - setting authorization headers");
416
+ const headers = req.headers.set("Authorization", `Bearer ${result.accessToken}`);
417
+ const requestClone = req.clone({ headers });
418
+ return next.handle(requestClone);
419
+ }));
420
+ }
421
+ /**
422
+ * Try to acquire token silently. Invoke interaction if acquireTokenSilent rejected with error or resolved with null access token
423
+ * @param authRequest Request
424
+ * @param scopes Array of scopes for the request
425
+ * @param account Account
426
+ * @returns Authentication result
427
+ */
428
+ acquireToken(authRequest, scopes, account) {
429
+ // Note: For MSA accounts, include openid scope when calling acquireTokenSilent to return idToken
430
+ return this.authService
431
+ .acquireTokenSilent({ ...authRequest, scopes, account })
432
+ .pipe(catchError(() => {
433
+ this.authService
434
+ .getLogger()
435
+ .error("Interceptor - acquireTokenSilent rejected with error. Invoking interaction to resolve.");
436
+ return this.msalBroadcastService.inProgress$.pipe(take(1), switchMap((status) => {
437
+ if (status === InteractionStatus.None) {
438
+ return this.acquireTokenInteractively(authRequest, scopes);
439
+ }
440
+ return this.msalBroadcastService.inProgress$.pipe(filter((status) => status === InteractionStatus.None), take(1), switchMap(() => this.acquireToken(authRequest, scopes, account)));
441
+ }));
442
+ }), switchMap((result) => {
443
+ if (!result.accessToken) {
444
+ this.authService
445
+ .getLogger()
446
+ .error("Interceptor - acquireTokenSilent resolved with null access token. Known issue with B2C tenants, invoking interaction to resolve.");
447
+ return this.msalBroadcastService.inProgress$.pipe(filter((status) => status === InteractionStatus.None), take(1), switchMap(() => this.acquireTokenInteractively(authRequest, scopes)));
448
+ }
449
+ return of(result);
450
+ }));
451
+ }
452
+ /**
453
+ * Invoke interaction for the given set of scopes
454
+ * @param authRequest Request
455
+ * @param scopes Array of scopes for the request
456
+ * @returns Result from the interactive request
457
+ */
458
+ acquireTokenInteractively(authRequest, scopes) {
459
+ if (this.msalInterceptorConfig.interactionType === InteractionType.Popup) {
460
+ this.authService
461
+ .getLogger()
462
+ .verbose("Interceptor - error acquiring token silently, acquiring by popup");
463
+ return this.authService.acquireTokenPopup({ ...authRequest, scopes });
464
+ }
465
+ this.authService
466
+ .getLogger()
467
+ .verbose("Interceptor - error acquiring token silently, acquiring by redirect");
468
+ const redirectStartPage = window.location.href;
469
+ this.authService.acquireTokenRedirect({
470
+ ...authRequest,
471
+ scopes,
472
+ redirectStartPage,
473
+ });
474
+ return EMPTY;
475
+ }
476
+ /**
477
+ * Looks up the scopes for the given endpoint from the protectedResourceMap
478
+ * @param endpoint Url of the request
479
+ * @param httpMethod Http method of the request
480
+ * @returns Array of scopes, or null if not found
481
+ *
482
+ */
483
+ getScopesForEndpoint(endpoint, httpMethod) {
484
+ this.authService
485
+ .getLogger()
486
+ .verbose("Interceptor - getting scopes for endpoint");
487
+ // Ensures endpoints and protected resources compared are normalized
488
+ const normalizedEndpoint = this.location.normalize(endpoint);
489
+ const protectedResourcesArray = Array.from(this.msalInterceptorConfig.protectedResourceMap.keys());
490
+ const matchingProtectedResources = this.matchResourcesToEndpoint(protectedResourcesArray, normalizedEndpoint);
491
+ if (matchingProtectedResources.length > 0) {
492
+ return this.matchScopesToEndpoint(this.msalInterceptorConfig.protectedResourceMap, matchingProtectedResources, httpMethod);
493
+ }
494
+ return null;
495
+ }
496
+ /**
497
+ * Finds resource endpoints that match request endpoint
498
+ * @param protectedResourcesEndpoints
499
+ * @param endpoint
500
+ * @returns
501
+ */
502
+ matchResourcesToEndpoint(protectedResourcesEndpoints, endpoint) {
503
+ const matchingResources = [];
504
+ protectedResourcesEndpoints.forEach((key) => {
505
+ const normalizedKey = this.location.normalize(key);
506
+ // Get url components
507
+ const absoluteKey = this.getAbsoluteUrl(normalizedKey);
508
+ const keyComponents = new URL(absoluteKey);
509
+ const absoluteEndpoint = this.getAbsoluteUrl(endpoint);
510
+ const endpointComponents = new URL(absoluteEndpoint);
511
+ if (this.checkUrlComponents(keyComponents, endpointComponents)) {
512
+ matchingResources.push(key);
513
+ }
514
+ });
515
+ return matchingResources;
516
+ }
517
+ /**
518
+ * Compares URL segments between key and endpoint
519
+ * @param key
520
+ * @param endpoint
521
+ * @returns
522
+ */
523
+ checkUrlComponents(keyComponents, endpointComponents) {
524
+ // URL properties from https://developer.mozilla.org/en-US/docs/Web/API/URL
525
+ const urlProperties = ["protocol", "host", "pathname", "search", "hash"];
526
+ for (const property of urlProperties) {
527
+ if (keyComponents[property]) {
528
+ const decodedInput = decodeURIComponent(keyComponents[property]);
529
+ if (!StringUtils.matchPattern(decodedInput, endpointComponents[property])) {
530
+ return false;
531
+ }
532
+ }
533
+ }
534
+ return true;
535
+ }
536
+ /**
537
+ * Transforms relative urls to absolute urls
538
+ * @param url
539
+ * @returns
540
+ */
541
+ getAbsoluteUrl(url) {
542
+ const link = this._document.createElement("a");
543
+ link.href = url;
544
+ return link.href;
545
+ }
546
+ /**
547
+ * Finds scopes from first matching endpoint with HTTP method that matches request
548
+ * @param protectedResourceMap Protected resource map
549
+ * @param endpointArray Array of resources that match request endpoint
550
+ * @param httpMethod Http method of the request
551
+ * @returns
552
+ */
553
+ matchScopesToEndpoint(protectedResourceMap, endpointArray, httpMethod) {
554
+ const allMatchedScopes = [];
555
+ // Check each matched endpoint for matching HttpMethod and scopes
556
+ endpointArray.forEach((matchedEndpoint) => {
557
+ const scopesForEndpoint = [];
558
+ const methodAndScopesArray = protectedResourceMap.get(matchedEndpoint);
559
+ // Return if resource is unprotected
560
+ if (methodAndScopesArray === null) {
561
+ allMatchedScopes.push(null);
562
+ return;
563
+ }
564
+ methodAndScopesArray.forEach((entry) => {
565
+ // Entry is either array of scopes or ProtectedResourceScopes object
566
+ if (typeof entry === "string") {
567
+ scopesForEndpoint.push(entry);
568
+ }
569
+ else {
570
+ // Ensure methods being compared are normalized
571
+ const normalizedRequestMethod = httpMethod.toLowerCase();
572
+ const normalizedResourceMethod = entry.httpMethod.toLowerCase();
573
+ // Method in protectedResourceMap matches request http method
574
+ if (normalizedResourceMethod === normalizedRequestMethod) {
575
+ // Validate if scopes comes null to unprotect the resource in a certain http method
576
+ if (entry.scopes === null) {
577
+ allMatchedScopes.push(null);
578
+ }
579
+ else {
580
+ entry.scopes.forEach((scope) => {
581
+ scopesForEndpoint.push(scope);
582
+ });
583
+ }
584
+ }
585
+ }
586
+ });
587
+ // Only add to all scopes if scopes for endpoint and method is found
588
+ if (scopesForEndpoint.length > 0) {
589
+ allMatchedScopes.push(scopesForEndpoint);
590
+ }
591
+ });
592
+ if (allMatchedScopes.length > 0) {
593
+ if (allMatchedScopes.length > 1) {
594
+ this.authService
595
+ .getLogger()
596
+ .warning("Interceptor - More than 1 matching scopes for endpoint found.");
597
+ }
598
+ // Returns scopes for first matching endpoint
599
+ return allMatchedScopes[0];
600
+ }
601
+ return null;
602
+ }
603
+ }
604
+ MsalInterceptor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalInterceptor, deps: [{ token: MSAL_INTERCEPTOR_CONFIG }, { token: MsalService }, { token: i3.Location }, { token: MsalBroadcastService }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Injectable });
605
+ MsalInterceptor.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalInterceptor });
606
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalInterceptor, decorators: [{
607
+ type: Injectable
608
+ }], ctorParameters: function () { return [{ type: undefined, decorators: [{
609
+ type: Inject,
610
+ args: [MSAL_INTERCEPTOR_CONFIG]
611
+ }] }, { type: MsalService }, { type: i3.Location }, { type: MsalBroadcastService }, { type: undefined, decorators: [{
612
+ type: Inject,
613
+ args: [DOCUMENT]
614
614
  }] }]; } });
615
615
 
616
- /*
617
- * Copyright (c) Microsoft Corporation. All rights reserved.
618
- * Licensed under the MIT License.
619
- */
620
- /**
621
- * This is a dedicated redirect component to be added to Angular apps to
622
- * handle redirects when using @azure/msal-angular.
623
- * Import this component to use redirects in your app.
624
- */
625
- class MsalRedirectComponent {
626
- constructor(authService) {
627
- this.authService = authService;
628
- }
629
- ngOnInit() {
630
- this.authService.getLogger().verbose("MsalRedirectComponent activated");
631
- this.authService.handleRedirectObservable().subscribe();
632
- }
633
- }
634
- MsalRedirectComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalRedirectComponent, deps: [{ token: MsalService }], target: i0.ɵɵFactoryTarget.Component });
635
- MsalRedirectComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: MsalRedirectComponent, selector: "app-redirect", ngImport: i0, template: "", isInline: true });
636
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalRedirectComponent, decorators: [{
637
- type: Component,
638
- args: [{
639
- selector: "app-redirect",
640
- template: "",
641
- }]
616
+ /*
617
+ * Copyright (c) Microsoft Corporation. All rights reserved.
618
+ * Licensed under the MIT License.
619
+ */
620
+ /**
621
+ * This is a dedicated redirect component to be added to Angular apps to
622
+ * handle redirects when using @azure/msal-angular.
623
+ * Import this component to use redirects in your app.
624
+ */
625
+ class MsalRedirectComponent {
626
+ constructor(authService) {
627
+ this.authService = authService;
628
+ }
629
+ ngOnInit() {
630
+ this.authService.getLogger().verbose("MsalRedirectComponent activated");
631
+ this.authService.handleRedirectObservable().subscribe();
632
+ }
633
+ }
634
+ MsalRedirectComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalRedirectComponent, deps: [{ token: MsalService }], target: i0.ɵɵFactoryTarget.Component });
635
+ MsalRedirectComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: MsalRedirectComponent, selector: "app-redirect", ngImport: i0, template: "", isInline: true });
636
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalRedirectComponent, decorators: [{
637
+ type: Component,
638
+ args: [{
639
+ selector: "app-redirect",
640
+ template: "",
641
+ }]
642
642
  }], ctorParameters: function () { return [{ type: MsalService }]; } });
643
643
 
644
- /*
645
- * Copyright (c) Microsoft Corporation. All rights reserved.
646
- * Licensed under the MIT License.
647
- */
648
- class MsalModule {
649
- static forRoot(msalInstance, guardConfig, interceptorConfig) {
650
- return {
651
- ngModule: MsalModule,
652
- providers: [
653
- {
654
- provide: MSAL_INSTANCE,
655
- useValue: msalInstance,
656
- },
657
- {
658
- provide: MSAL_GUARD_CONFIG,
659
- useValue: guardConfig,
660
- },
661
- {
662
- provide: MSAL_INTERCEPTOR_CONFIG,
663
- useValue: interceptorConfig,
664
- },
665
- MsalService,
666
- ],
667
- };
668
- }
669
- }
670
- MsalModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
671
- MsalModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: MsalModule, declarations: [MsalRedirectComponent], imports: [CommonModule] });
672
- MsalModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalModule, providers: [MsalGuard, MsalBroadcastService], imports: [CommonModule] });
673
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalModule, decorators: [{
674
- type: NgModule,
675
- args: [{
676
- declarations: [MsalRedirectComponent],
677
- imports: [CommonModule],
678
- providers: [MsalGuard, MsalBroadcastService],
679
- }]
644
+ /*
645
+ * Copyright (c) Microsoft Corporation. All rights reserved.
646
+ * Licensed under the MIT License.
647
+ */
648
+ class MsalModule {
649
+ static forRoot(msalInstance, guardConfig, interceptorConfig) {
650
+ return {
651
+ ngModule: MsalModule,
652
+ providers: [
653
+ {
654
+ provide: MSAL_INSTANCE,
655
+ useValue: msalInstance,
656
+ },
657
+ {
658
+ provide: MSAL_GUARD_CONFIG,
659
+ useValue: guardConfig,
660
+ },
661
+ {
662
+ provide: MSAL_INTERCEPTOR_CONFIG,
663
+ useValue: interceptorConfig,
664
+ },
665
+ MsalService,
666
+ ],
667
+ };
668
+ }
669
+ }
670
+ MsalModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
671
+ MsalModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: MsalModule, declarations: [MsalRedirectComponent], imports: [CommonModule] });
672
+ MsalModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalModule, providers: [MsalGuard, MsalBroadcastService], imports: [CommonModule] });
673
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalModule, decorators: [{
674
+ type: NgModule,
675
+ args: [{
676
+ declarations: [MsalRedirectComponent],
677
+ imports: [CommonModule],
678
+ providers: [MsalGuard, MsalBroadcastService],
679
+ }]
680
680
  }] });
681
681
 
682
- /*
683
- * Copyright (c) Microsoft Corporation. All rights reserved.
684
- * Licensed under the MIT License.
685
- */
686
- /**
687
- * Custom navigation used for Angular client-side navigation.
688
- * See performance doc for details:
689
- * https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/lib/msal-angular/docs/performance.md
690
- */
691
- class MsalCustomNavigationClient extends NavigationClient {
692
- constructor(authService, router, location) {
693
- super();
694
- this.authService = authService;
695
- this.router = router;
696
- this.location = location;
697
- }
698
- async navigateInternal(url, options) {
699
- this.authService.getLogger().trace("MsalCustomNavigationClient called");
700
- this.authService
701
- .getLogger()
702
- .verbose("MsalCustomNavigationClient - navigating");
703
- this.authService
704
- .getLogger()
705
- .verbosePii(`MsalCustomNavigationClient - navigating to url: ${url}`);
706
- // Prevent hash clearing from causing an issue with Client-side navigation after redirect is handled
707
- if (options.noHistory) {
708
- return super.navigateInternal(url, options);
709
- }
710
- else {
711
- // Normalizing newUrl if no query string
712
- const urlComponents = new UrlString(url).getUrlComponents();
713
- const newUrl = urlComponents.QueryString
714
- ? `${urlComponents.AbsolutePath}?${urlComponents.QueryString}`
715
- : this.location.normalize(urlComponents.AbsolutePath);
716
- await this.router.navigateByUrl(newUrl, {
717
- replaceUrl: options.noHistory,
718
- });
719
- }
720
- return Promise.resolve(options.noHistory);
721
- }
722
- }
723
- MsalCustomNavigationClient.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalCustomNavigationClient, deps: [{ token: MsalService }, { token: i4.Router }, { token: i3.Location }], target: i0.ɵɵFactoryTarget.Injectable });
724
- MsalCustomNavigationClient.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalCustomNavigationClient });
725
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalCustomNavigationClient, decorators: [{
726
- type: Injectable
682
+ /*
683
+ * Copyright (c) Microsoft Corporation. All rights reserved.
684
+ * Licensed under the MIT License.
685
+ */
686
+ /**
687
+ * Custom navigation used for Angular client-side navigation.
688
+ * See performance doc for details:
689
+ * https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/lib/msal-angular/docs/performance.md
690
+ */
691
+ class MsalCustomNavigationClient extends NavigationClient {
692
+ constructor(authService, router, location) {
693
+ super();
694
+ this.authService = authService;
695
+ this.router = router;
696
+ this.location = location;
697
+ }
698
+ async navigateInternal(url, options) {
699
+ this.authService.getLogger().trace("MsalCustomNavigationClient called");
700
+ this.authService
701
+ .getLogger()
702
+ .verbose("MsalCustomNavigationClient - navigating");
703
+ this.authService
704
+ .getLogger()
705
+ .verbosePii(`MsalCustomNavigationClient - navigating to url: ${url}`);
706
+ // Prevent hash clearing from causing an issue with Client-side navigation after redirect is handled
707
+ if (options.noHistory) {
708
+ return super.navigateInternal(url, options);
709
+ }
710
+ else {
711
+ // Normalizing newUrl if no query string
712
+ const urlComponents = new UrlString(url).getUrlComponents();
713
+ const newUrl = urlComponents.QueryString
714
+ ? `${urlComponents.AbsolutePath}?${urlComponents.QueryString}`
715
+ : this.location.normalize(urlComponents.AbsolutePath);
716
+ await this.router.navigateByUrl(newUrl, {
717
+ replaceUrl: options.noHistory,
718
+ });
719
+ }
720
+ return Promise.resolve(options.noHistory);
721
+ }
722
+ }
723
+ MsalCustomNavigationClient.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalCustomNavigationClient, deps: [{ token: MsalService }, { token: i4.Router }, { token: i3.Location }], target: i0.ɵɵFactoryTarget.Injectable });
724
+ MsalCustomNavigationClient.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalCustomNavigationClient });
725
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalCustomNavigationClient, decorators: [{
726
+ type: Injectable
727
727
  }], ctorParameters: function () { return [{ type: MsalService }, { type: i4.Router }, { type: i3.Location }]; } });
728
728
 
729
- /*
730
- * Copyright (c) Microsoft Corporation. All rights reserved.
731
- * Licensed under the MIT License.
732
- */
733
- /**
734
- * @packageDocumentation
735
- * @module @azure/msal-angular
729
+ /*
730
+ * Copyright (c) Microsoft Corporation. All rights reserved.
731
+ * Licensed under the MIT License.
732
+ */
733
+ /**
734
+ * @packageDocumentation
735
+ * @module @azure/msal-angular
736
736
  */
737
737
 
738
- /**
739
- * Generated bundle index. Do not edit.
738
+ /**
739
+ * Generated bundle index. Do not edit.
740
740
  */
741
741
 
742
742
  export { MSAL_BROADCAST_CONFIG, MSAL_GUARD_CONFIG, MSAL_INSTANCE, MSAL_INTERCEPTOR_CONFIG, MsalBroadcastService, MsalCustomNavigationClient, MsalGuard, MsalInterceptor, MsalModule, MsalRedirectComponent, MsalService, version };