UNPKG

@microsoft/windows-admin-center-sdk

Version:

Microsoft - Windows Admin Center Shell

1 lines 50.5 kB
{"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