{"version":3,"sources":["../../../packages/core/security/authorization-manager.ts"],"names":[],"mappings":"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","file":"authorization-manager.d.ts","sourcesContent":["import { Observable, of, Subject, throwError } from 'rxjs';\r\nimport { AjaxError, AjaxRequest } from 'rxjs/ajax';\r\nimport { map, mergeMap, take } from 'rxjs/operators';\r\nimport { CimStreamOptions, CimStreamResponse } from '../data/cim-stream';\r\nimport { Crypto } from '../data/crypto';\r\nimport { headerConstants, HttpStatusCode } from '../data/http-constants';\r\nimport { Net } from '../data/net';\r\nimport { PowerShellStreamResponse } from '../data/powershell-stream';\r\nimport { Logging } from '../diagnostics/logging';\r\nimport { Strings } from '../generated/strings';\r\nimport { RpcForwardResponse } from '../rpc/forward/rpc-forward-model';\r\nimport { Rpc } from '../rpc/rpc';\r\nimport { RpcRelationshipType } from '../rpc/rpc-base';\r\nimport { RpcForwarder, RpcServiceForwarder } from '../rpc/rpc-forwarder';\r\nimport { SignedHttpRequestToken, SignOnManager, SignOnTokenRefresh, SignOnTokenResponse } from './sign-on-manager';\r\n\r\n/**\r\n * Defines the response from an Authorization Handler\r\n */\r\nexport interface AuthorizationCredentials {\r\n    username: string;\r\n    password: string;\r\n    applyToAllNodes?: boolean;\r\n    useLaps?: boolean;\r\n    lapsLocalAdminName?: string;\r\n}\r\n\r\n/**\r\n * Defines the response the AuthorizationManager returns from getToken\r\n */\r\nexport interface AuthorizationTokenResponse {\r\n    token: AuthorizationToken;\r\n    appliesTo?: string | string[];\r\n}\r\n\r\n/**\r\n * Defines an authorizationToken\r\n */\r\nexport interface AuthorizationToken {\r\n    value: string;\r\n    username: string;\r\n    useLaps: boolean;\r\n    lapsLocalAdminName: string;\r\n}\r\n\r\n/**\r\n * The create authorization token options\r\n */\r\nexport interface CreateAuthorizationTokenOptions {\r\n    password?: string;\r\n    username?: string;\r\n    useLaps?: boolean;\r\n    lapsLocalAdminName?: string;\r\n}\r\n\r\n/**\r\n * The extra error data of original cause.\r\n */\r\nexport interface NodeAuthorizationErrorData {\r\n    statusCode: HttpStatusCode;\r\n    errorCode: string;\r\n    errorMessage: string;\r\n}\r\n\r\n/**\r\n * Defines a handler that takes a nodeName and returns authorization credentials\r\n */\r\nexport type NodeAuthorizationHandler =\r\n    (nodeName?: string | string[], errorData?: NodeAuthorizationErrorData) => Observable<AuthorizationCredentials>;\r\n\r\n/**\r\n * Defines properties that will be provided to child instances on a forward init request\r\n */\r\nexport interface AuthorizationManagerInitProperties {\r\n    manageAsToken: AuthorizationToken;\r\n    nodeTokens: MsftSme.StringMap<AuthorizationToken>;\r\n    nodePowershellEndpoints: MsftSme.StringMap<string>;\r\n    signOnToken: SignedHttpRequestToken;\r\n}\r\n\r\n/**\r\n * Representation of authorization cache data structure\r\n */\r\ninterface AuthorizationCacheData {\r\n    jwk?: string;\r\n    nodeTokens?: MsftSme.StringMap<AuthorizationToken>;\r\n    manageAsToken?: AuthorizationToken;\r\n    nodePowershellEndpoints?: MsftSme.StringMap<string>;\r\n    logOnUser?: string;\r\n}\r\n\r\n/**\r\n * Authorization Manager class. Handles SME authentication for service requests.\r\n */\r\nexport class AuthorizationManager extends RpcServiceForwarder {\r\n\r\n    /**\r\n     * Cache key for session storage of authorization cache\r\n     */\r\n    private static cacheKey = 'AuthorizationManager.cache.v1';\r\n\r\n    /**\r\n     * If no laps local admin name is defined, it will default to 'administrator'\r\n     */\r\n    public static defaultLapsLocalAdminName = 'administrator';\r\n\r\n    private static rpcCommands = {\r\n        setNodeToken: 'setNodeToken',\r\n        setNodeTokens: 'setNodeTokens',\r\n        manageAsToken: 'manageAsToken',\r\n        setNodeTokenError: 'setNodeTokenError',\r\n        setJeaContext: 'setJeaContext',\r\n        clearNodeTokens: 'clearNodeTokens',\r\n        getNewToken: 'getNewToken',\r\n        secureToken: 'secureToken',\r\n        encrypt: 'encrypt',\r\n        getSignOnToken: 'getSignOnToken',\r\n        setSignOnToken: 'setSignOnToken',\r\n        setSignOnTokenError: 'setSignOnTokenError'\r\n    };\r\n\r\n    /**\r\n     * Create a map of nodeNames to token objects to hold node specific tokens.\r\n     */\r\n    public nodeTokens: MsftSme.StringMap<AuthorizationToken>;\r\n\r\n    /**\r\n     * The sign on operation manager.\r\n     */\r\n    public signOnManager: SignOnManager;\r\n\r\n    /**\r\n     * The backing store fro the manageAsToken\r\n     */\r\n    private token: AuthorizationToken;\r\n\r\n    /**\r\n     * The JSON Web Key. Single string with JSON.stringify format.\r\n     */\r\n    private jwk: string;\r\n\r\n    /**\r\n     * Credentials expiration time, used to determine the lifetime of new tokens. Value in milliseconds.\r\n     */\r\n    private credentialsExpirationTimeInMs: number;\r\n\r\n    /**\r\n     * Underlying implementation subject for credentialExpiration observable\r\n     */\r\n    private credentialExpirationChangedSubject: Subject<number>;\r\n\r\n    /**\r\n     * Observable that emits whenever the credentials expiration has changed\r\n     */\r\n    public credentialExpirationChanged: Observable<number>;\r\n\r\n    /**\r\n     * Set the admin configured expiration time in milliseconds\r\n     * If this is not set it will be defaulted to 365 days.\r\n     */\r\n    public set authExpirationInMs(expirationTimeInMs: number) {\r\n        this.credentialsExpirationTimeInMs = expirationTimeInMs;\r\n        this.credentialExpirationChangedSubject.next(expirationTimeInMs);\r\n    }\r\n\r\n    /**\r\n     * The logon user returned by gateway's api/user\r\n     */\r\n    private logOnUser: string;\r\n\r\n    /**\r\n     * Sets logon user and caches the value\r\n     */\r\n    public set shellLogOnUser(username: string) {\r\n        this.logOnUser = username;\r\n        this.updateCache();\r\n    }\r\n\r\n    /**\r\n     * The mapping of connections to PowershellEndpoints\r\n     */\r\n    private nodePowershellEndpoints: MsftSme.StringMap<string>;\r\n\r\n    /**\r\n     * The token awaiter subject.\r\n     */\r\n    private tokenAwaiter: Subject<AuthorizationTokenResponse>;\r\n\r\n    /**\r\n     * The subject observable of sign on token awaiter.\r\n     */\r\n    private signOnTokenAwaiter: Subject<SignOnTokenResponse>;\r\n\r\n    /**\r\n     * Sets the current manage as token\r\n     * If running with an Rpc child, notify of the change\r\n     */\r\n    public set manageAsToken(token: AuthorizationToken) {\r\n        this.token = token;\r\n        this.nodePowershellEndpoints = {};\r\n        this.forwardNotify(RpcRelationshipType.Child, AuthorizationManager.rpcCommands.manageAsToken, token);\r\n        this.updateCache();\r\n    }\r\n\r\n    /**\r\n     * Gets the current manage as token\r\n     */\r\n    public get manageAsToken(): AuthorizationToken {\r\n        return this.token;\r\n    }\r\n\r\n    /**\r\n     * Sets the gateway encryption certificate JWK.\r\n     * If this is not set by Shell/Add-Connection, it will send clear text password.\r\n     */\r\n    public set gatewayJwk(jwk: string) {\r\n        if (this.jwk !== jwk) {\r\n            this.resetAllTokens();\r\n        }\r\n        this.jwk = jwk;\r\n        this.gatewayJwkChangedSubject.next(jwk);\r\n        this.updateCache();\r\n    }\r\n\r\n    /**\r\n     * Observable that emits whenever the gateways Jwk has changed\r\n     */\r\n    public readonly gatewayJwkChanged: Observable<string>;\r\n\r\n    /**\r\n     * Underlying implementation subject for gatewayJwkChanged observable\r\n     */\r\n    private gatewayJwkChangedSubject: Subject<string>;\r\n\r\n    /**\r\n     * Gets the gateway encryption certificate JWK.\r\n     */\r\n    public get gatewayJwk() {\r\n        return this.jwk;\r\n    }\r\n\r\n    /**\r\n     * Gets an observable the emits when the authorization token is ready\r\n     */\r\n    public get authAwaiter() {\r\n        if (this.tokenAwaiter && !this.tokenAwaiter.closed) {\r\n            // return the global token\r\n            return this.tokenAwaiter;\r\n        }\r\n\r\n        // return the global token\r\n        return of(<AuthorizationTokenResponse>{ appliesTo: null, token: this.manageAsToken });\r\n    }\r\n\r\n    /**\r\n     * Initializes a new instance of the Authorization Manager class\r\n     * @param authorize An AuthorizationHandler with which to retrieve user credentials\r\n     * @param rpc The rpc to forward auth requests to a parent window\r\n     */\r\n    constructor(private authorize: NodeAuthorizationHandler, rpc: Rpc) {\r\n        super('authorization-manager', rpc);\r\n        this.gatewayJwkChangedSubject = new Subject<string>();\r\n        this.gatewayJwkChanged = this.gatewayJwkChangedSubject.asObservable();\r\n\r\n        this.credentialExpirationChangedSubject = new Subject<number>();\r\n        this.credentialExpirationChanged = this.credentialExpirationChangedSubject.asObservable();\r\n\r\n        this.nodeTokens = {};\r\n        this.nodePowershellEndpoints = {};\r\n        if (MsftSme.isShell()) {\r\n            // attempt to restore from storage if this is a shell instance\r\n            const cachedDataString = MsftSme.SessionStorageHandler.getItem(AuthorizationManager.cacheKey);\r\n\r\n            if (!MsftSme.isNullOrWhiteSpace(cachedDataString)) {\r\n                try {\r\n                    const cachedData: AuthorizationCacheData = JSON.parse(cachedDataString);\r\n                    // verify data and set properties\r\n                    this.jwk = cachedData.jwk || null;\r\n                    this.manageAsToken = cachedData.manageAsToken || null;\r\n                    this.nodeTokens = cachedData.nodeTokens || {};\r\n                    this.nodePowershellEndpoints = cachedData.nodePowershellEndpoints || {};\r\n                    this.logOnUser = cachedData.logOnUser;\r\n                } catch (error) {\r\n                    MsftSme.SessionStorageHandler.removeItem(AuthorizationManager.cacheKey);\r\n                }\r\n            }\r\n        }\r\n\r\n        this.signOnManager = new SignOnManager(() => this.refreshSignOnToken());\r\n    }\r\n\r\n    /**\r\n     * defines the conditions under which the AuthorizationManager can handle an ajax error\r\n     */\r\n    public canHandleAjaxFailure(code: HttpStatusCode, error: AjaxError) {\r\n        // we can handle ajax errors if we have a getter defined, and the code is Unauthorized (401) or we get a cim authorization failure\r\n        return this.authorize && Net.isUnauthorized(error);\r\n    }\r\n\r\n    /**\r\n     * When canHandle returns true for an ajax error, this method can be called to handle that error.\r\n     */\r\n    public handleAjaxFailure(\r\n        code: HttpStatusCode,\r\n        request: AjaxRequest,\r\n        error: AjaxError,\r\n        nodeName?: string): Observable<AjaxRequest> {\r\n        const errorData = this.getErrorData(code, error);\r\n\r\n        return this.getNewToken(nodeName, errorData)\r\n            .pipe(mergeMap(response => {\r\n                // There may be multiple nodes requesting authentication, but we can only ask the user for one.\r\n                // check if the result if for our node, otherwise try again.\r\n                // It looks for inside of array only for first name.\r\n                const names = response.appliesTo;\r\n                const isTokenForNode = !names || names === nodeName || (Array.isArray(names) && names[0] === nodeName);\r\n                if (isTokenForNode) {\r\n                    // this token applies to our node, so continue\r\n                    this.addAuthorizationRequestHeader(request, nodeName);\r\n                    return of(request);\r\n                } else {\r\n                    // this token did not apply to our node. Ask again.\r\n                    return this.handleAjaxFailure(code, request, error, nodeName);\r\n                }\r\n            }));\r\n    }\r\n\r\n    /**\r\n     * Check if it can handle the error.\r\n     *\r\n     * @param response the response of CIM stream query.\r\n     */\r\n    public canHandleStreamFailure(response: CimStreamResponse): boolean {\r\n        // access denied case.\r\n        return response && response.response && response.response.statusCode === HttpStatusCode.Unauthorized;\r\n    }\r\n\r\n    /**\r\n     * When canHandle returns true for an ajax error, this method can be called to handle that error.\r\n     */\r\n    public handleStreamFailure(\r\n        nodeName: string,\r\n        options: CimStreamOptions,\r\n        response: CimStreamResponse | PowerShellStreamResponse): Observable<CimStreamOptions> {\r\n        let message = response.response.error && response.response.error.message;\r\n        if (!message) {\r\n            const errors = response.response.errors;\r\n            if (errors && errors.length > 0) {\r\n                message = errors[0].message;\r\n            }\r\n        }\r\n        const errorData: NodeAuthorizationErrorData = {\r\n            statusCode: response.response.statusCode,\r\n            errorCode: 'Unauthorized',\r\n            errorMessage: message\r\n        };\r\n        return this.getNewToken(nodeName, errorData)\r\n            .pipe(mergeMap(result => {\r\n                const names = result.appliesTo;\r\n                const isTokenForNode = !names || names === nodeName || (Array.isArray(names) && names[0] === nodeName);\r\n                if (isTokenForNode) {\r\n                    const token = this.getSavedNodeToken(nodeName);\r\n                    if (token) {\r\n                        if (options) {\r\n                            options.authToken = token;\r\n                        } else {\r\n                            options = { authToken: token };\r\n                        }\r\n                    }\r\n\r\n                    return of(options);\r\n                } else {\r\n                    return this.handleStreamFailure(nodeName, options, response);\r\n                }\r\n            }));\r\n    }\r\n\r\n    public saveJeaContext(nodeName: string, endpoint: string) {\r\n        Logging.trace({\r\n            view: 'sme-ui-control',\r\n            instance: 'saveJeaContext',\r\n            action: 'command-click',\r\n            data: { message: 'Establishing session using JEA endpoint' }\r\n        });\r\n        this.setJeaEndpoint(nodeName, endpoint);\r\n\r\n        this.forwardNotify(\r\n            RpcRelationshipType.Child,\r\n            AuthorizationManager.rpcCommands.setJeaContext,\r\n            { nodeName: nodeName, endpoint: endpoint });\r\n    }\r\n\r\n    public getJeaEndpoint(nodeName: string): string {\r\n        return this.nodePowershellEndpoints[nodeName.toLocaleLowerCase()];\r\n    }\r\n\r\n    /**\r\n     * Associates a node to use a specified JEA endpoint\r\n     */\r\n    public setJeaEndpoint(nodeName: string, endpoint: string): void {\r\n        this.nodePowershellEndpoints[nodeName.toLocaleLowerCase()] = endpoint;\r\n        this.updateCache();\r\n    }\r\n\r\n    /**\r\n     * Calls the authorize method and gets a new token.\r\n     * If running as a child, the token comes from the parent windows service\r\n     */\r\n    public getNewToken(nodeName: string): Observable<AuthorizationTokenResponse>;\r\n    public getNewToken(nodeNames: string[]): Observable<AuthorizationTokenResponse>;\r\n    public getNewToken(nodeName: string, errorData: NodeAuthorizationErrorData): Observable<AuthorizationTokenResponse>;\r\n    public getNewToken(nodeNames: string[], errorData: NodeAuthorizationErrorData): Observable<AuthorizationTokenResponse>;\r\n\r\n    public getNewToken(nodeNames?: string | string[], errorData?: NodeAuthorizationErrorData): Observable<AuthorizationTokenResponse> {\r\n        // if we are already awaiting a token, then hook into the current request and try using that token\r\n        if (this.tokenAwaiter && !this.tokenAwaiter.closed) {\r\n            return this.tokenAwaiter;\r\n        }\r\n\r\n        // ensure input is an array only if not null.\r\n        if (nodeNames && !Array.isArray(nodeNames)) {\r\n            nodeNames = [nodeNames];\r\n        }\r\n\r\n        // define a new subject for multiple requests to wait on\r\n        this.tokenAwaiter = new Subject<AuthorizationTokenResponse>();\r\n\r\n        // try to forward execute getNewToken from our parent\r\n        const parentExecuter = this.forwardExecute<void>(\r\n            RpcRelationshipType.Parent,\r\n            AuthorizationManager.rpcCommands.getNewToken,\r\n            [nodeNames, errorData]);\r\n\r\n        if (parentExecuter) {\r\n            return this.tokenAwaiter;\r\n        }\r\n\r\n        // Need to clear the endpoints before we acquire a new token,\r\n        // because we must try new credentials in an admin context before any fallback happens.\r\n        if (nodeNames) {\r\n            for (const node of <string[]>nodeNames) {\r\n                this.setJeaEndpoint(node, null);\r\n            }\r\n        }\r\n\r\n        // since we could not forward the request We must ask for the auth token ourselves\r\n        this.authorize(nodeNames, errorData)\r\n            .pipe(\r\n                mergeMap(credentials => {\r\n                    if (credentials.applyToAllNodes) {\r\n                        this.nodeTokens = {};\r\n                        this.updateCache();\r\n                        const forward = this.forwardExecute(\r\n                            RpcRelationshipType.Child, AuthorizationManager.rpcCommands.clearNodeTokens, []);\r\n                        if (forward) {\r\n                            return forward.pipe(map(() => credentials));\r\n                        }\r\n                    }\r\n\r\n                    return of(credentials);\r\n                }),\r\n                mergeMap(credentials => {\r\n                    const appliesTo = credentials.applyToAllNodes ? null : nodeNames || null;\r\n                    return this.createSecureToken({\r\n                        username: credentials.username,\r\n                        password: credentials.password,\r\n                        useLaps: credentials.useLaps,\r\n                        lapsLocalAdminName: credentials.lapsLocalAdminName\r\n                    }).pipe(\r\n                        map(token => {\r\n                            return <AuthorizationTokenResponse>{\r\n                                token: token,\r\n                                appliesTo: appliesTo\r\n                            };\r\n                        }));\r\n                }),\r\n                // take the next 1 result and use it for our token.\r\n                // We can now notify anyone waiting for auth and save the token\r\n                take(1))\r\n            .subscribe({\r\n                next: result => {\r\n                    this.completeTokenAwaiter(result);\r\n                    this.forwardNotify(RpcRelationshipType.Child, AuthorizationManager.rpcCommands.setNodeToken, result);\r\n                },\r\n                error: error => {\r\n                    this.completeTokenAwaiter(null, error);\r\n                    this.forwardNotify(\r\n                        RpcRelationshipType.Child,\r\n                        AuthorizationManager.rpcCommands.setNodeTokenError,\r\n                        RpcForwarder.ensureSerializable(error));\r\n                }\r\n            });\r\n\r\n        return this.tokenAwaiter;\r\n    }\r\n\r\n    public refreshSignOnToken(): Observable<SignOnTokenResponse> {\r\n        // if we are already awaiting a token, then hook into the current request and try using that token\r\n        if (this.signOnTokenAwaiter) {\r\n            return this.signOnTokenAwaiter;\r\n        }\r\n\r\n        // define a new subject for multiple requests to wait on\r\n        this.signOnTokenAwaiter = new Subject<SignOnTokenResponse>();\r\n\r\n        // try to forward execute getSignOnToken from our parent.\r\n        const now = Date.now();\r\n        const parentExecuter = this.forwardExecute<SignOnTokenRefresh>(\r\n            RpcRelationshipType.Parent,\r\n            AuthorizationManager.rpcCommands.getSignOnToken,\r\n            [now]);\r\n\r\n        if (parentExecuter) {\r\n            return this.signOnTokenAwaiter;\r\n        }\r\n\r\n        // since we could not forward the request We must ask for the signon token ourselves\r\n        this.signOnManager.requestSignOnRefresh()\r\n            .subscribe({\r\n                next: response => {\r\n                    this.completeSignOnTokenAwaiter(response);\r\n                    this.forwardNotify(\r\n                        RpcRelationshipType.Child,\r\n                        AuthorizationManager.rpcCommands.setSignOnToken,\r\n                        RpcForwarder.ensureSerializable(response));\r\n                },\r\n                error: error => {\r\n                    this.completeSignOnTokenAwaiter(null, error);\r\n                    this.forwardNotify(\r\n                        RpcRelationshipType.Child,\r\n                        AuthorizationManager.rpcCommands.setSignOnTokenError,\r\n                        RpcForwarder.ensureSerializable(error));\r\n                }\r\n            });\r\n\r\n        return this.signOnTokenAwaiter;\r\n    }\r\n\r\n    /**\r\n     * Forward Sign On Token to child frame.\r\n     */\r\n    public forwardSignOnToken(): void {\r\n        const data: SignOnTokenResponse = { time: Date.now(),  token: this.signOnManager.signedHttpRequestToken };\r\n        this.forwardNotify(RpcRelationshipType.Child, AuthorizationManager.rpcCommands.setSignOnToken, data);\r\n    }\r\n\r\n    /**\r\n     * @deprecated use createSecureToken() after configured gatewayJwk property.\r\n     *\r\n     * Creates a token from the given options that may be used for node authentication\r\n     * @param options The token creation options\r\n     */\r\n    public createToken(options: CreateAuthorizationTokenOptions, passwordEncryptedWith: string = null): AuthorizationToken {\r\n        // ensure a valid value for laps local admin name\r\n        if (MsftSme.isNullOrWhiteSpace(options.lapsLocalAdminName)) {\r\n            options.lapsLocalAdminName = AuthorizationManager.defaultLapsLocalAdminName;\r\n        }\r\n        // ensure username has a valid value\r\n        if (MsftSme.isNullOrWhiteSpace(options.username)) {\r\n            options.username = null;\r\n        }\r\n        if (options.useLaps || !options.username) {\r\n            return {\r\n                value: null,\r\n                username: null,\r\n                useLaps: options.useLaps,\r\n                lapsLocalAdminName: options.lapsLocalAdminName\r\n            };\r\n        }\r\n\r\n        // ensure password has a valid value\r\n        if (MsftSme.isNullOrWhiteSpace(options.password)) {\r\n            options.password = null;\r\n        }\r\n\r\n        let username: string[];\r\n        if (options.username.indexOf('@') >= 0) {\r\n            // domain is empty if UPN is used.\r\n            username = [\"\", options.username];\r\n        } else {\r\n            username = options.username.split('\\\\');\r\n        }\r\n\r\n        const token = Net.createEncodedAuthenticationHeader(username, options.password, passwordEncryptedWith);\r\n        return {\r\n            value: token,\r\n            username: options.username,\r\n            useLaps: false, // UseLaps must be false when user provides explicit username and password.,\r\n            lapsLocalAdminName: null\r\n        };\r\n    }\r\n\r\n    /**\r\n     * Creates a secure token from the given options that may be used for node authentication\r\n     *\r\n     * @param options The token creation options\r\n     */\r\n    public createSecureToken(options: CreateAuthorizationTokenOptions): Observable<AuthorizationToken> {\r\n        const forward = this.forwardExecute<AuthorizationToken>(\r\n            RpcRelationshipType.Parent,\r\n            AuthorizationManager.rpcCommands.secureToken,\r\n            [options]);\r\n        if (forward) {\r\n            return forward;\r\n        } else {\r\n            return this.secureToken(options);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Get the saved Auth token for a node.\r\n     *\r\n     * @param nodeName The nodeName to get token for.\r\n     */\r\n    public getSavedNodeToken(nodeName: string): AuthorizationToken {\r\n        if (nodeName && this.nodeTokens[nodeName.toLocaleLowerCase()]) {\r\n            return this.nodeTokens[nodeName.toLocaleLowerCase()];\r\n        }\r\n\r\n        return this.manageAsToken;\r\n    }\r\n\r\n    /**\r\n     * Sets a token on the given nodes\r\n     * @param token The token to use for the given nodes\r\n     * @param nodeName The names of the nodes to set the token for. If empty or null, the token will be used as the global manageAs token\r\n     * @returns an Observable indicating that the token has been set.\r\n     */\r\n    public setNodeTokens(token: AuthorizationToken, nodeNames?: string[]): Observable<void> {\r\n        // if we have a parent instance, just forward it and return the result\r\n        const forward = this.forwardExecute<void>(\r\n            RpcRelationshipType.Parent,\r\n            AuthorizationManager.rpcCommands.setNodeTokens,\r\n            [token, nodeNames]\r\n        );\r\n        if (forward) {\r\n            return forward;\r\n        }\r\n\r\n        // otherwise process the token\r\n        const childSetTokenResponse: AuthorizationTokenResponse = { token: token };\r\n        if (!nodeNames || !Array.isArray(nodeNames) || nodeNames.length === 0) {\r\n            this.manageAsToken = token;\r\n        } else {\r\n            childSetTokenResponse.appliesTo = nodeNames;\r\n            nodeNames.forEach(nodeName => this.nodeTokens[nodeName.toLocaleLowerCase()] = token);\r\n        }\r\n        this.updateCache();\r\n\r\n        // notify all child instances of the token change.\r\n        this.forwardNotify(RpcRelationshipType.Child, AuthorizationManager.rpcCommands.setNodeToken, childSetTokenResponse, true);\r\n\r\n        // return a null observable, indicating we are done.\r\n        return of(null);\r\n    }\r\n\r\n    /**\r\n     * Adds a authorization header to a request given a node with a manageAsToken\r\n     * @param request The request to add headers to\r\n     * @param nodeName optional. The node to add headers for if not provided, the global token will be used\r\n     * @param token optional. The token to use for the headers. if provided, the nodeName is not used.\r\n     */\r\n    public addAuthorizationRequestHeader(request: AjaxRequest, nodeName?: string, token?: AuthorizationToken) {\r\n        if (!token) {\r\n            token = this.getSavedNodeToken(nodeName);\r\n        }\r\n\r\n        if (token) {\r\n            if (token.value) {\r\n\r\n                // If username and password are explicitly provided, we only add the Authorization header.\r\n                (<any>request).headers[headerConstants.SME_AUTHORIZATION] = token.value;\r\n            } else {\r\n\r\n                // If not, we add useLaps header.\r\n                (<any>request).headers[headerConstants.USE_LAPS] = token.useLaps;\r\n                (<any>request).headers[headerConstants.LAPS_LOCALADMINNAME] = token.lapsLocalAdminName;\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Create token headers.\r\n     *\r\n     * @param nodeName the node name.\r\n     * @param token the token to override current setting (optional).\r\n     */\r\n    public createTokenHeaders(nodeName: string, token?: AuthorizationToken): MsftSme.StringMap<string> {\r\n        const headers: MsftSme.StringMap<string> = {};\r\n        token = token || this.getSavedNodeToken(nodeName);\r\n        if (token) {\r\n            if (token.value) {\r\n                // If username and password are explicitly provided, we only add the Authorization header.\r\n                headers[headerConstants.SME_AUTHORIZATION] = token.value;\r\n            } else {\r\n\r\n                // If not, we add useLaps header.\r\n                headers[headerConstants.USE_LAPS] = token.useLaps ? 'true' : 'false';\r\n                headers[headerConstants.LAPS_LOCALADMINNAME] = token.lapsLocalAdminName;\r\n            }\r\n        }\r\n\r\n        return headers;\r\n    }\r\n\r\n    /**\r\n     * Adds a authorization header to a request given a node with a manageAsToken\r\n     */\r\n    public addAuthorizationTokensToMultiPartBody(body: string[], nodeName?: string, token?: AuthorizationToken) {\r\n        if (!token) {\r\n            token = this.getSavedNodeToken(nodeName);\r\n        }\r\n\r\n        if (token) {\r\n            if (token.value) {\r\n                // If username and password are explicitly provided, we only add the Authorization header.\r\n                body.push(headerConstants.SME_AUTHORIZATION + ': ' + token.value);\r\n            } else {\r\n                // If not, we add useLaps header.\r\n                body.push(headerConstants.USE_LAPS + ': ' + token.useLaps);\r\n                body.push(headerConstants.LAPS_LOCALADMINNAME + ': ' + token.lapsLocalAdminName);\r\n            }\r\n        }\r\n    }\r\n\r\n    public resetAllTokens(): void {\r\n        this.manageAsToken = null;\r\n        this.nodePowershellEndpoints = {};\r\n        this.nodeTokens = {};\r\n        this.forwardNotify(RpcRelationshipType.Child, AuthorizationManager.rpcCommands.manageAsToken, null);\r\n        this.forwardNotify(RpcRelationshipType.Child, AuthorizationManager.rpcCommands.clearNodeTokens, []);\r\n        this.updateCache();\r\n    }\r\n\r\n    /**\r\n     * Encrypts a string value using the jwk from the gateway\r\n     */\r\n    public encrypt(value: string): Observable<string> {\r\n        const forward = this.forwardExecute<string>(RpcRelationshipType.Parent, AuthorizationManager.rpcCommands.encrypt, [value]);\r\n        if (forward) {\r\n            return forward;\r\n        }\r\n\r\n        return Crypto.encryptRsaSha1(this.jwk, value);\r\n    }\r\n\r\n    /**\r\n     * Called on a child service instance when onForwardInit returns from the parent\r\n     * @param data The response from the forwardInit call\r\n     */\r\n    protected onForwardInitResponse(data: RpcForwardResponse<AuthorizationManagerInitProperties>): void {\r\n        if (data && data.error) {\r\n            // if there is an error, we cannot continue, so throw it\r\n            throw data.error;\r\n        }\r\n\r\n        this.manageAsToken = data.result.manageAsToken;\r\n        this.nodeTokens = data.result.nodeTokens;\r\n        this.nodePowershellEndpoints = data.result.nodePowershellEndpoints;\r\n        this.signOnManager.signedHttpRequestToken = data.result.signOnToken;\r\n    }\r\n\r\n    /**\r\n     * Called when a new instance of the service in another window is initialized and needs to synchronize with its parent\r\n     * @param from The RpcRelationshipType that this request is from\r\n     * @returns an observable for the all the values needed to initialize the service\r\n     */\r\n    protected onForwardInit(): Observable<AuthorizationManagerInitProperties> {\r\n        // authorization manager doesn't pass any properties to child services at this time.\r\n        return of(<AuthorizationManagerInitProperties>{\r\n            manageAsToken: this.manageAsToken,\r\n            nodeTokens: this.nodeTokens,\r\n            nodePowershellEndpoints: this.nodePowershellEndpoints,\r\n            signOnToken: this.signOnManager.signedHttpRequestToken\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Called when the forwarded services counterpart wants to get data from the parent\r\n     * @param from The RpcRelationshipType that this request is from\r\n     * @param name The name of the method to forward to\r\n     * @param args The arguments of the method\r\n     * @returns an observable for the result of the method call\r\n     */\r\n    protected onForwardExecute(from: RpcRelationshipType, name: string, args: any[]): Observable<any> {\r\n        // command comes from child\r\n        if (from === RpcRelationshipType.Child) {\r\n            switch (name) {\r\n                case AuthorizationManager.rpcCommands.getNewToken: {\r\n                    // start getting the new token, but return immediately to avoid timeout\r\n                    const subscription = this.getNewToken(args ? args[0] : null, args ? args[1] : null)\r\n                        .subscribe({\r\n                            next: () => subscription.unsubscribe(),\r\n                            error: error => {\r\n                                subscription.unsubscribe();\r\n                                this.forwardNotify(\r\n                                    RpcRelationshipType.Child,\r\n                                    AuthorizationManager.rpcCommands.setNodeTokenError,\r\n                                    RpcForwarder.ensureSerializable(error));\r\n                            }\r\n                        });\r\n                    return of(null);\r\n                }\r\n                case AuthorizationManager.rpcCommands.secureToken: {\r\n                    const options = args && args[0];\r\n                    if (!options) {\r\n                        return of(null);\r\n                    }\r\n\r\n                    return this.secureToken(options);\r\n                }\r\n                case AuthorizationManager.rpcCommands.encrypt: {\r\n                    const options = args && args[0];\r\n                    if (!options) {\r\n                        return of(null);\r\n                    }\r\n\r\n                    return this.encrypt(options);\r\n                }\r\n                case AuthorizationManager.rpcCommands.setNodeTokens: {\r\n                    const token = args && args[0];\r\n                    const nodes = args && args[1];\r\n                    if (!token) {\r\n                        return of(null);\r\n                    }\r\n\r\n                    return this.setNodeTokens(token, nodes);\r\n                }\r\n                case AuthorizationManager.rpcCommands.getSignOnToken: {\r\n                    const subscription = this.refreshSignOnToken()\r\n                        .subscribe({\r\n                            next: () => subscription.unsubscribe(),\r\n                            error: error => {\r\n                                subscription.unsubscribe(),\r\n                                this.forwardNotify(\r\n                                    RpcRelationshipType.Child,\r\n                                    AuthorizationManager.rpcCommands.setSignOnTokenError,\r\n                                    RpcForwarder.ensureSerializable(error)\r\n                                );\r\n                            }\r\n                        });\r\n                    return of(null);\r\n                }\r\n            }\r\n        }\r\n\r\n        // command comes from parent\r\n        if (from === RpcRelationshipType.Parent) {\r\n            if (name === AuthorizationManager.rpcCommands.clearNodeTokens) {\r\n                this.nodeTokens = {};\r\n                this.nodePowershellEndpoints = {};\r\n                // if we also have children, forward the request on\r\n                const forward = this.forwardExecute(RpcRelationshipType.Child, AuthorizationManager.rpcCommands.clearNodeTokens, args);\r\n                return forward || of(null);\r\n            }\r\n        }\r\n\r\n        // command not implemented\r\n        return this.nameNotFound(name);\r\n    }\r\n\r\n    /**\r\n     * Called when the forwarded services counterpart sends a notify message\r\n     * @param from The RpcRelationshipType that this request is from\r\n     * @param name The name of the property to change\r\n     * @param value The new value of the property\r\n     * @returns an observable that completes when the property has been changed.\r\n     */\r\n    protected onForwardNotify(from: RpcRelationshipType, name: string, value: any): Observable<void> {\r\n        // allow our parent to give us a new token.\r\n        if (from === RpcRelationshipType.Parent) {\r\n            if (name === AuthorizationManager.rpcCommands.manageAsToken) {\r\n                this.manageAsToken = value;\r\n                // if we also have children, forward the notification on\r\n                const forward = this.forwardNotify(RpcRelationshipType.Child, AuthorizationManager.rpcCommands.manageAsToken, value);\r\n                return forward || of(null);\r\n            }\r\n\r\n            if (name === AuthorizationManager.rpcCommands.setNodeToken) {\r\n                if (!value) {\r\n                    const message = MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.InvalidValue.message;\r\n                    return throwError(() => message.format(AuthorizationManager.rpcCommands.setNodeToken));\r\n                }\r\n\r\n                this.completeTokenAwaiter(value);\r\n                const forward = this.forwardNotify(RpcRelationshipType.Child, AuthorizationManager.rpcCommands.setNodeToken, value);\r\n                return forward || of(null);\r\n            }\r\n\r\n            if (name === AuthorizationManager.rpcCommands.setNodeTokenError) {\r\n                if (!value) {\r\n                    const message = MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.InvalidValue.message;\r\n                    return throwError(() => message.format(AuthorizationManager.rpcCommands.setNodeTokenError));\r\n                }\r\n\r\n                this.completeTokenAwaiter(null, value);\r\n                const forward = this.forwardNotify(RpcRelationshipType.Child, AuthorizationManager.rpcCommands.setNodeTokenError, value);\r\n                return forward || of(null);\r\n            }\r\n\r\n            if (name === AuthorizationManager.rpcCommands.setJeaContext) {\r\n                if (!value) {\r\n                    const message = MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.InvalidValue.message;\r\n                    return throwError(() => message.format(AuthorizationManager.rpcCommands.setJeaContext));\r\n                }\r\n\r\n                this.saveJeaContext(value.nodeName, value.endpoint);\r\n                const forward = this.forwardNotify(RpcRelationshipType.Child, AuthorizationManager.rpcCommands.setJeaContext, value);\r\n                return forward || of(null);\r\n            }\r\n\r\n            if (name === AuthorizationManager.rpcCommands.setSignOnToken) {\r\n                if (!value) {\r\n                    const message = MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.InvalidValue.message;\r\n                    return throwError(() => message.format(AuthorizationManager.rpcCommands.setNodeToken));\r\n                }\r\n\r\n                this.completeSignOnTokenAwaiter(value);\r\n                const forward = this.forwardNotify(RpcRelationshipType.Child, AuthorizationManager.rpcCommands.setSignOnToken, value);\r\n                return forward || of(null);\r\n            }\r\n\r\n            if (name === AuthorizationManager.rpcCommands.setSignOnTokenError) {\r\n                if (!value) {\r\n                    const message = MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.InvalidValue.message;\r\n                    return throwError(() => message.format(AuthorizationManager.rpcCommands.setNodeTokenError));\r\n                }\r\n\r\n                this.completeSignOnTokenAwaiter(null, value);\r\n                const forward = this.forwardNotify(RpcRelationshipType.Child, AuthorizationManager.rpcCommands.setSignOnTokenError, value);\r\n                return forward || of(null);\r\n            }\r\n        }\r\n\r\n        return this.nameNotFound(name);\r\n    }\r\n\r\n    /**\r\n     * Creates a secure token from the given options that may be used for node authentication\r\n     *\r\n     * @param options The token creation options\r\n     */\r\n    private secureToken(options: CreateAuthorizationTokenOptions): Observable<AuthorizationToken> {\r\n        // ensure a valid value for laps local admin name\r\n        if (MsftSme.isNullOrWhiteSpace(options.lapsLocalAdminName)) {\r\n            options.lapsLocalAdminName = AuthorizationManager.defaultLapsLocalAdminName;\r\n        }\r\n\r\n        // ensure username has a valid value\r\n        if (MsftSme.isNullOrWhiteSpace(options.username)) {\r\n            options.username = null;\r\n        }\r\n\r\n        if (options.useLaps || !options.username) {\r\n            return of({\r\n                value: null,\r\n                username: null,\r\n                useLaps: options.useLaps,\r\n                lapsLocalAdminName: options.lapsLocalAdminName\r\n            });\r\n        }\r\n\r\n        // ensure password has a valid value\r\n        if (MsftSme.isNullOrWhiteSpace(options.password)) {\r\n            options.password = null;\r\n        }\r\n\r\n        let username: string[];\r\n        if (options.username.indexOf('@') >= 0) {\r\n            // domain is empty if UPN is used.\r\n            username = [\"\", options.username];\r\n        } else {\r\n            username = options.username.split('\\\\');\r\n        }\r\n\r\n        const tokenData = {\r\n            value: undefined,\r\n            username: options.username,\r\n            useLaps: false, // UseLaps must be false when user provides explicit username and password.,\r\n            lapsLocalAdminName: null\r\n        };\r\n\r\n        if (this.jwk) {\r\n            return Net.createEncryptedAuthenticationHeader(\r\n                this.jwk,\r\n                username,\r\n                options.password,\r\n                this.logOnUser,\r\n                this.credentialsExpirationTimeInMs)\r\n            .pipe(map(newToken => {\r\n                tokenData.value = newToken;\r\n                return tokenData;\r\n            }));\r\n        }\r\n\r\n        tokenData.value = Net.createEncodedAuthenticationHeader(username, options.password);\r\n        return of(tokenData);\r\n    }\r\n\r\n    /**\r\n     * Completes the token awaiter\r\n     */\r\n    private completeTokenAwaiter(result: AuthorizationTokenResponse, error?: any) {\r\n        if (error) {\r\n            if (this.tokenAwaiter) {\r\n                const awaiter = this.tokenAwaiter;\r\n                this.tokenAwaiter = null;\r\n                awaiter.error(error);\r\n            }\r\n        } else {\r\n            if (!result.appliesTo) {\r\n                this.manageAsToken = result.token;\r\n            } else if (Array.isArray(result.appliesTo)) {\r\n                result.appliesTo.forEach(nodeName => {\r\n                    this.nodeTokens[nodeName.toLocaleLowerCase()] = result.token;\r\n                });\r\n                this.updateCache();\r\n            } else {\r\n                this.nodeTokens[result.appliesTo.toLocaleLowerCase()] = result.token;\r\n                this.updateCache();\r\n            }\r\n\r\n            if (this.tokenAwaiter) {\r\n                const awaiter = this.tokenAwaiter;\r\n                this.tokenAwaiter = null;\r\n                awaiter.next(result);\r\n                awaiter.complete();\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Completes the sign on token awaiter\r\n     */\r\n     private completeSignOnTokenAwaiter(result: SignOnTokenResponse, error?: any) {\r\n        const awaiter = this.signOnTokenAwaiter;\r\n        if (awaiter) {\r\n            this.signOnTokenAwaiter = null;\r\n        }\r\n\r\n        if (error) {\r\n            if (awaiter) {\r\n                awaiter.error(error);\r\n            }\r\n\r\n            return;\r\n        }\r\n\r\n        if (result.token) {\r\n            this.signOnManager.signedHttpRequestToken = result.token;\r\n        } else {\r\n            Logging.logError('Shell.AuthorizationManager', 'Null token was passed.');\r\n        }\r\n\r\n        if (awaiter) {\r\n            awaiter.next(result);\r\n            awaiter.complete();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Gets the error data.\r\n     * @param code the http status code.\r\n     * @param error the AJAX error object.\r\n     */\r\n    private getErrorData(code: HttpStatusCode, error: AjaxError): NodeAuthorizationErrorData {\r\n        return {\r\n            statusCode: code,\r\n            errorCode: error && error.xhr && error.xhr.response && error.xhr.response.error && error.xhr.response.error.code,\r\n            errorMessage: Net.getErrorMessage(error)\r\n        };\r\n    }\r\n\r\n    /**\r\n     * Updates the authorization cache. Does nothing if we are not running in shell\r\n     */\r\n    private updateCache(): void {\r\n        if (!MsftSme.isShell()) {\r\n            // ignore if not shell\r\n            return;\r\n        }\r\n        // update cached data\r\n        const cacheData: AuthorizationCacheData = {\r\n            jwk: this.jwk,\r\n            manageAsToken: this.manageAsToken,\r\n            nodePowershellEndpoints: this.nodePowershellEndpoints,\r\n            nodeTokens: this.nodeTokens\r\n        };\r\n\r\n        MsftSme.SessionStorageHandler.setItem(AuthorizationManager.cacheKey, JSON.stringify(cacheData));\r\n    }\r\n}\r\n"]}