{ "version": 3, "sources": ["src/app/core/auth/extended-msal.guard.ts"], "sourcesContent": ["import {Location} from '@angular/common';\nimport {Inject, Injectable, VERSION} from '@angular/core';\nimport {ActivatedRouteSnapshot, Router, RouterStateSnapshot, UrlTree} from '@angular/router';\nimport {\n MSAL_GUARD_CONFIG,\n MsalBroadcastService,\n MsalGuardConfiguration,\n MsalService,\n} from '@azure/msal-angular';\nimport {\n AuthenticationResult,\n BrowserConfigurationAuthError,\n BrowserUtils,\n InteractionType,\n PopupRequest,\n RedirectRequest,\n UrlString,\n} from '@azure/msal-browser';\nimport {catchError, concatMap, map, Observable, of} from 'rxjs';\n\n@Injectable()\nexport class ExtendedMsalGuard {\n private loginFailedRoute?: UrlTree;\n\n constructor(\n @Inject(MSAL_GUARD_CONFIG) private msalGuardConfig: MsalGuardConfiguration,\n private msalBroadcastService: MsalBroadcastService,\n private authService: MsalService,\n private location: Location,\n private router: Router,\n ) {\n // Subscribing so events in MsalGuard will set inProgress$ observable\n this.msalBroadcastService.inProgress$.subscribe();\n }\n\n /**\n * Parses url string to UrlTree\n * @param url\n */\n public parseUrl(url: string): UrlTree {\n return this.router.parseUrl(url);\n }\n\n /**\n * Builds the absolute url for the destination page\n * @param path Relative path of requested page\n * @returns Full destination url\n */\n public getDestinationUrl(path: string): string {\n this.authService.getLogger().verbose('Guard - getting destination url');\n // Absolute base url for the application (default to origin if base element not present)\n const baseElements = document.getElementsByTagName('base');\n const baseUrl = this.location.normalize(\n baseElements.length ? baseElements[0].href : window.location.origin,\n );\n\n // Path of page (including hash, if using hash routing)\n const pathUrl = this.location.prepareExternalUrl(path);\n\n // Hash location strategy\n if (pathUrl.startsWith('#')) {\n this.authService.getLogger().verbose('Guard - destination by hash routing');\n return `${baseUrl}/${pathUrl}`;\n }\n\n /*\n * If using path location strategy, pathUrl will include the relative portion of the base path (e.g. /base/page).\n * Since baseUrl also includes /base, can just concatentate baseUrl + path\n */\n return `${baseUrl}${path}`;\n }\n\n /**\n * Interactively prompt the user to login\n * @param url Path of the requested page\n */\n private loginInteractively(state: RouterStateSnapshot): Observable {\n const authRequest =\n typeof this.msalGuardConfig.authRequest === 'function'\n ? this.msalGuardConfig.authRequest(this.authService, state)\n : {...this.msalGuardConfig.authRequest};\n if (this.msalGuardConfig.interactionType === InteractionType.Popup) {\n this.authService.getLogger().verbose('Guard - logging in by popup');\n return this.authService.loginPopup(authRequest as PopupRequest).pipe(\n map((response: AuthenticationResult) => {\n this.authService\n .getLogger()\n .verbose(\n 'Guard - login by popup successful, can activate, setting active account',\n );\n this.authService.instance.setActiveAccount(response.account);\n return true;\n }),\n );\n }\n\n this.authService.getLogger().verbose('Guard - logging in by redirect');\n const redirectStartPage = this.getDestinationUrl(state.url);\n return this.authService\n .loginRedirect({\n redirectStartPage,\n ...authRequest,\n } as RedirectRequest)\n .pipe(map(() => false));\n }\n\n /**\n * Helper which checks for the correct interaction type, prevents page with Guard to be set as reidrect, and calls handleRedirectObservable\n * @param state\n */\n private activateHelper(state?: RouterStateSnapshot): Observable {\n if (\n this.msalGuardConfig.interactionType !== InteractionType.Popup &&\n this.msalGuardConfig.interactionType !== InteractionType.Redirect\n ) {\n throw new BrowserConfigurationAuthError(\n 'invalid_interaction_type',\n 'Invalid interaction type provided to MSAL Guard. InteractionType.Popup or InteractionType.Redirect must be provided in the MsalGuardConfiguration',\n );\n }\n this.authService.getLogger().verbose('MSAL Guard activated');\n\n /*\n * If a page with MSAL Guard is set as the redirect for acquireTokenSilent,\n * short-circuit to prevent redirecting or popups.\n */\n if (typeof window !== 'undefined') {\n if (\n UrlString.hashContainsKnownProperties(window.location.hash) &&\n BrowserUtils.isInIframe() &&\n !this.authService.instance.getConfiguration().system.allowRedirectInIframe\n ) {\n this.authService\n .getLogger()\n .warning(\n 'Guard - redirectUri set to page with MSAL Guard. It is recommended to not set redirectUri to a page that requires authentication.',\n );\n return of(false);\n }\n } else {\n this.authService\n .getLogger()\n .info(\n 'Guard - window is undefined, MSAL does not support server-side token acquisition',\n );\n return of(true);\n }\n\n /**\n * If a loginFailedRoute is set in the config, set this as the loginFailedRoute\n */\n if (this.msalGuardConfig.loginFailedRoute) {\n this.loginFailedRoute = this.parseUrl(this.msalGuardConfig.loginFailedRoute);\n }\n\n // Capture current path before it gets changed by handleRedirectObservable\n const currentPath = this.location.path(true);\n\n return this.authService.handleRedirectObservable().pipe(\n concatMap(() => {\n if (!this.authService.instance.getAllAccounts().length) {\n if (state) {\n this.authService\n .getLogger()\n .verbose('Guard - no accounts retrieved, log in required to activate');\n\n // prevent redirect to the B2C login page\n // and show landing with OTP flow\n let url = '/';\n if (state.url.includes('(payment:payment-success)')) {\n url = '/(payment:payment-success)';\n } else if (state.url.includes('(payment:payment-error)')) {\n url = '/(payment:payment-error)';\n }\n return of(this.router.parseUrl(url));\n // return this.loginInteractively(state);\n }\n this.authService\n .getLogger()\n .verbose('Guard - no accounts retrieved, no state, cannot load');\n return of(false);\n }\n\n this.authService\n .getLogger()\n .verbose('Guard - at least 1 account exists, can activate or load');\n\n // Prevent navigating the app to /#code= or /code=\n if (state) {\n /*\n * Path routing:\n * state.url: /#code=...\n * state.root.fragment: code=...\n */\n\n /*\n * Hash routing:\n * state.url: /code\n * state.root.fragment: null\n */\n const urlContainsCode: boolean = this.includesCode(state.url);\n const fragmentContainsCode: boolean =\n !!state.root &&\n !!state.root.fragment &&\n this.includesCode(`#${state.root.fragment}`);\n const hashRouting: boolean =\n this.location.prepareExternalUrl(state.url).indexOf('#') === 0;\n\n // Ensure code parameter is in fragment (and not in query parameter), or that hash hash routing is used\n if (urlContainsCode && (fragmentContainsCode || hashRouting)) {\n this.authService\n .getLogger()\n .info(\n 'Guard - Hash contains known code response, stopping navigation.',\n );\n\n // Path routing (navigate to current path without hash)\n if (currentPath.indexOf('#') > -1) {\n return of(this.parseUrl(this.location.path()));\n }\n\n // Hash routing (navigate to root path)\n return of(this.parseUrl(''));\n }\n }\n\n return of(true);\n }),\n catchError((error: Error) => {\n // Allow to activate route in the case of canceling password change or similar flows\n // AADB2C90091: The user has cancelled entering self-asserted information\n if (error.message.indexOf('AADB2C90091') > -1) {\n return of(true);\n }\n\n // TODO: it is workaround and we just checking if the user is loggedIn in the app, if yes then we just allow to activate route\n // based on the answer in the thread\n // https://github.com/AzureAD/microsoft-authentication-library-for-js/issues/4378#issuecomment-1268770149\n const isLoggedIn = this.authService.instance.getAllAccounts().length > 0;\n if (isLoggedIn) {\n return of(true);\n }\n\n this.authService\n .getLogger()\n .error('Guard - error while logging in, unable to activate');\n this.authService.getLogger().errorPii(`Guard - error: ${error.message}`);\n /**\n * If a loginFailedRoute is set, checks to see if Angular 10+ is used and state is passed in before returning route\n * Apps using Angular 9 will receive of(false) in canLoad interface, as it does not support UrlTree return types\n */\n if (this.loginFailedRoute && parseInt(VERSION.major, 10) > 9 && state) {\n this.authService\n .getLogger()\n .verbose('Guard - loginFailedRoute set, redirecting');\n return of(this.loginFailedRoute);\n }\n return of(false);\n }),\n );\n }\n\n public includesCode(path: string): boolean {\n return (\n (path.lastIndexOf('/code') > -1 &&\n path.lastIndexOf('/code') === path.length - '/code'.length) || // path.endsWith(\"/code\")\n path.indexOf('#code=') > -1 ||\n path.indexOf('&code=') > -1\n );\n }\n\n public canActivate(\n route: ActivatedRouteSnapshot,\n state: RouterStateSnapshot,\n ): Observable {\n this.authService.getLogger().verbose('Guard - canActivate');\n return this.activateHelper(state);\n }\n\n public canActivateChild(\n route: ActivatedRouteSnapshot,\n state: RouterStateSnapshot,\n ): Observable {\n this.authService.getLogger().verbose('Guard - canActivateChild');\n return this.activateHelper(state);\n }\n\n public canLoad(): Observable {\n this.authService.getLogger().verbose('Guard - canLoad');\n // @ts-ignore\n return this.activateHelper();\n }\n}\n"], "mappings": "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", "names": ["ExtendedMsalGuard", "constructor", "msalGuardConfig", "msalBroadcastService", "authService", "location", "router", "inProgress$", "subscribe", "parseUrl", "url", "getDestinationUrl", "path", "getLogger", "verbose", "baseElements", "document", "getElementsByTagName", "baseUrl", "normalize", "length", "href", "window", "origin", "pathUrl", "prepareExternalUrl", "startsWith", "loginInteractively", "state", "authRequest", "__spreadValues", "interactionType", "InteractionType", "Popup", "loginPopup", "pipe", "map", "response", "instance", "setActiveAccount", "account", "redirectStartPage", "loginRedirect", "activateHelper", "Redirect", "BrowserConfigurationAuthError", "UrlString", "hashContainsKnownProperties", "hash", "BrowserUtils", "isInIframe", "getConfiguration", "system", "allowRedirectInIframe", "warning", "of", "info", "loginFailedRoute", "currentPath", "handleRedirectObservable", "concatMap", "getAllAccounts", "includes", "urlContainsCode", "includesCode", "fragmentContainsCode", "root", "fragment", "hashRouting", "indexOf", "catchError", "error", "message", "errorPii", "parseInt", "VERSION", "major", "lastIndexOf", "canActivate", "route", "canActivateChild", "canLoad", "\u0275\u0275inject", "MSAL_GUARD_CONFIG", "MsalBroadcastService", "MsalService", "Location", "Router", "factory", "\u0275fac", "_ExtendedMsalGuard"] }