UNPKG

@azure/msal-common

Version:
231 lines (216 loc) 7.77 kB
/* * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ import { CcsCredential, CcsCredentialType } from "../account/CcsCredential.js"; import { buildClientInfoFromHomeAccountId } from "../account/ClientInfo.js"; import { Logger } from "../logger/Logger.js"; import { BaseAuthRequest } from "../request/BaseAuthRequest.js"; import { HeaderNames, URL_FORM_CONTENT_TYPE } from "../utils/Constants.js"; import * as RequestParameterBuilder from "../request/RequestParameterBuilder.js"; import * as UrlUtils from "../utils/UrlUtils.js"; import { IPerformanceClient } from "../exports-browser-only.js"; import { ServerAuthorizationTokenResponse } from "../response/ServerAuthorizationTokenResponse.js"; import { RequestThumbprint } from "../network/RequestThumbprint.js"; import { INetworkModule, NetworkRequestOptions, } from "../network/INetworkModule.js"; import { NetworkResponse } from "../network/NetworkResponse.js"; import { ThrottlingUtils } from "../network/ThrottlingUtils.js"; import { NetworkError } from "../error/NetworkError.js"; import { AuthError } from "../error/AuthError.js"; import { ClientAuthErrorCodes, createClientAuthError, } from "../error/ClientAuthError.js"; import { invokeAsync } from "../utils/FunctionWrappers.js"; import * as PerformanceEvents from "../telemetry/performance/PerformanceEvents.js"; import { CacheManager } from "../cache/CacheManager.js"; import { ServerTelemetryManager } from "../telemetry/server/ServerTelemetryManager.js"; /** * Creates default headers for requests to token endpoint */ export function createTokenRequestHeaders( logger: Logger, preventCorsPreflight: boolean, ccsCred?: CcsCredential ): Record<string, string> { const headers: Record<string, string> = {}; headers[HeaderNames.CONTENT_TYPE] = URL_FORM_CONTENT_TYPE; if (!preventCorsPreflight && ccsCred) { switch (ccsCred.type) { case CcsCredentialType.HOME_ACCOUNT_ID: try { const clientInfo = buildClientInfoFromHomeAccountId( ccsCred.credential ); headers[ HeaderNames.CCS_HEADER ] = `Oid:${clientInfo.uid}@${clientInfo.utid}`; } catch (e) { logger.verbose( `Could not parse home account ID for CCS Header: '${e}'`, "" ); } break; case CcsCredentialType.UPN: headers[HeaderNames.CCS_HEADER] = `UPN: ${ccsCred.credential}`; break; } } return headers; } /** * Creates query string for the /token request * @param request */ export function createTokenQueryParameters( request: BaseAuthRequest, clientId: string, redirectUri: string, performanceClient: IPerformanceClient ): string { const parameters = new Map<string, string>(); if (request.embeddedClientId) { RequestParameterBuilder.addBrokerParameters( parameters, clientId, redirectUri ); } if (request.extraQueryParameters) { RequestParameterBuilder.addExtraParameters( parameters, request.extraQueryParameters ); } RequestParameterBuilder.addCorrelationId(parameters, request.correlationId); RequestParameterBuilder.instrumentBrokerParams( parameters, request.correlationId, performanceClient ); return UrlUtils.mapToQueryString(parameters); } /** * Http post to token endpoint * @param tokenEndpoint * @param queryString * @param headers * @param thumbprint */ export async function executePostToTokenEndpoint( tokenEndpoint: string, queryString: string, headers: Record<string, string>, thumbprint: RequestThumbprint, correlationId: string, cacheManager: CacheManager, networkClient: INetworkModule, logger: Logger, performanceClient: IPerformanceClient, serverTelemetryManager: ServerTelemetryManager | null ): Promise<NetworkResponse<ServerAuthorizationTokenResponse>> { const response = await sendPostRequest<ServerAuthorizationTokenResponse>( thumbprint, tokenEndpoint, { body: queryString, headers: headers }, correlationId, cacheManager, networkClient, logger, performanceClient ); if ( serverTelemetryManager && response.status < 500 && response.status !== 429 ) { // Telemetry data successfully logged by server, clear Telemetry cache serverTelemetryManager.clearTelemetryCache(); } return response; } /** * Wraps sendPostRequestAsync with necessary preflight and postflight logic * @param thumbprint - Request thumbprint for throttling * @param tokenEndpoint - Endpoint to make the POST to * @param options - Body and Headers to include on the POST request * @param correlationId - CorrelationId for telemetry * @param cacheManager - Cache manager instance * @param networkClient - Network module instance * @param logger - Logger instance * @param performanceClient - Performance client instance */ export async function sendPostRequest< T extends ServerAuthorizationTokenResponse >( thumbprint: RequestThumbprint, tokenEndpoint: string, options: NetworkRequestOptions, correlationId: string, cacheManager: CacheManager, networkClient: INetworkModule, logger: Logger, performanceClient: IPerformanceClient ): Promise<NetworkResponse<T>> { ThrottlingUtils.preProcess(cacheManager, thumbprint, correlationId); let response; try { response = await invokeAsync( networkClient.sendPostRequestAsync.bind(networkClient)<T>, PerformanceEvents.NetworkClientSendPostRequestAsync, logger, performanceClient, correlationId )(tokenEndpoint, options); const responseHeaders = response.headers || {}; performanceClient?.addFields( { refreshTokenSize: response.body.refresh_token?.length || 0, httpVerToken: responseHeaders[HeaderNames.X_MS_HTTP_VERSION] || "", requestId: responseHeaders[HeaderNames.X_MS_REQUEST_ID] || "", }, correlationId ); } catch (e) { if (e instanceof NetworkError) { const responseHeaders = e.responseHeaders; if (responseHeaders) { performanceClient?.addFields( { httpVerToken: responseHeaders[HeaderNames.X_MS_HTTP_VERSION] || "", requestId: responseHeaders[HeaderNames.X_MS_REQUEST_ID] || "", contentTypeHeader: responseHeaders[HeaderNames.CONTENT_TYPE] || undefined, contentLengthHeader: responseHeaders[HeaderNames.CONTENT_LENGTH] || undefined, httpStatus: e.httpStatus, }, correlationId ); } throw e.error; } if (e instanceof AuthError) { throw e; } else { throw createClientAuthError(ClientAuthErrorCodes.networkError); } } ThrottlingUtils.postProcess( cacheManager, thumbprint, response, correlationId ); return response; }