msal
Version:
Microsoft Authentication Library for js
261 lines • 11.9 kB
JavaScript
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { __spreadArrays } from "tslib";
import { CryptoUtils } from "./utils/CryptoUtils";
import { SSOTypes, Constants, PromptState, ResponseTypes } from "./utils/Constants";
import { ScopeSet } from "./ScopeSet";
import { version as libraryVersion } from "./packageMetadata";
/**
* Nonce: OIDC Nonce definition: https://openid.net/specs/openid-connect-core-1_0.html#IDToken
* State: OAuth Spec: https://tools.ietf.org/html/rfc6749#section-10.12
* @hidden
*/
var ServerRequestParameters = /** @class */ (function () {
/**
* Constructor
* @param authority
* @param clientId
* @param scope
* @param responseType
* @param redirectUri
* @param state
*/
function ServerRequestParameters(authority, clientId, responseType, redirectUri, scopes, state, correlationId) {
this.authorityInstance = authority;
this.clientId = clientId;
this.nonce = CryptoUtils.createNewGuid();
// set scope to clientId if null
this.scopes = scopes ? __spreadArrays(scopes) : Constants.oidcScopes;
this.scopes = ScopeSet.trimScopes(this.scopes);
// set state (already set at top level)
this.state = state;
// set correlationId
this.correlationId = correlationId;
// telemetry information
this.xClientSku = "MSAL.JS";
this.xClientVer = libraryVersion;
this.responseType = responseType;
this.redirectUri = redirectUri;
}
Object.defineProperty(ServerRequestParameters.prototype, "authority", {
get: function () {
return this.authorityInstance ? this.authorityInstance.CanonicalAuthority : null;
},
enumerable: false,
configurable: true
});
/**
* @hidden
* @ignore
*
* Utility to populate QueryParameters and ExtraQueryParameters to ServerRequestParamerers
* @param request
* @param serverAuthenticationRequest
*/
ServerRequestParameters.prototype.populateQueryParams = function (account, request, adalIdTokenObject, silentCall) {
var queryParameters = {};
if (request) {
// add the prompt parameter to serverRequestParameters if passed
if (request.prompt) {
this.promptValue = request.prompt;
}
// Add claims challenge to serverRequestParameters if passed
if (request.claimsRequest) {
this.claimsValue = request.claimsRequest;
}
// if the developer provides one of these, give preference to developer choice
if (ServerRequestParameters.isSSOParam(request)) {
queryParameters = this.constructUnifiedCacheQueryParameter(request, null);
}
}
if (adalIdTokenObject) {
queryParameters = this.constructUnifiedCacheQueryParameter(null, adalIdTokenObject);
}
/*
* adds sid/login_hint if not populated
* this.logger.verbose("Calling addHint parameters");
*/
queryParameters = this.addHintParameters(account, queryParameters);
// sanity check for developer passed extraQueryParameters
var eQParams = request ? request.extraQueryParameters : null;
// Populate the extraQueryParameters to be sent to the server
this.queryParameters = ServerRequestParameters.generateQueryParametersString(queryParameters);
this.extraQueryParameters = ServerRequestParameters.generateQueryParametersString(eQParams, silentCall);
};
// #region QueryParam helpers
/**
* Constructs extraQueryParameters to be sent to the server for the AuthenticationParameters set by the developer
* in any login() or acquireToken() calls
* @param idTokenObject
* @param extraQueryParameters
* @param sid
* @param loginHint
*/
// TODO: check how this behaves when domain_hint only is sent in extraparameters and idToken has no upn.
ServerRequestParameters.prototype.constructUnifiedCacheQueryParameter = function (request, idTokenObject) {
var _a;
// preference order: account > sid > login_hint
var ssoType;
var ssoData;
var serverReqParam = {};
// if account info is passed, account.login_hint claim > account.sid > account.username
if (request) {
if (request.account) {
var account = request.account;
if ((_a = account.idTokenClaims) === null || _a === void 0 ? void 0 : _a.login_hint) {
ssoType = SSOTypes.LOGIN_HINT;
ssoData = account.idTokenClaims.login_hint;
}
else if (account.sid) {
ssoType = SSOTypes.SID;
ssoData = account.sid;
}
else if (account.userName) {
ssoType = SSOTypes.LOGIN_HINT;
ssoData = account.userName;
}
}
// sid from request
else if (request.sid) {
ssoType = SSOTypes.SID;
ssoData = request.sid;
}
// loginHint from request
else if (request.loginHint) {
ssoType = SSOTypes.LOGIN_HINT;
ssoData = request.loginHint;
}
}
// adalIdToken retrieved from cache
else if (idTokenObject) {
if (idTokenObject.hasOwnProperty(Constants.upn)) {
ssoType = SSOTypes.ID_TOKEN;
ssoData = idTokenObject["upn"];
}
}
serverReqParam = this.addSSOParameter(ssoType, ssoData);
return serverReqParam;
};
/**
* @hidden
*
* Adds login_hint to authorization URL which is used to pre-fill the username field of sign in page for the user if known ahead of time
* domain_hint if added skips the email based discovery process of the user - only supported for interactive calls in implicit_flow
* domain_req utid received as part of the clientInfo
* login_req uid received as part of clientInfo
* Also does a sanity check for extraQueryParameters passed by the user to ensure no repeat queryParameters
*
* @param {@link Account} account - Account for which the token is requested
* @param queryparams
* @param {@link ServerRequestParameters}
* @ignore
*/
ServerRequestParameters.prototype.addHintParameters = function (account, params) {
var _a, _b;
/*
* This is a final check for all queryParams added so far; preference order: sid > login_hint
* sid cannot be passed along with login_hint or domain_hint, hence we check both are not populated yet in queryParameters
*/
var qParams = params;
if (account) {
if (!qParams[SSOTypes.SID] && !qParams[SSOTypes.LOGIN_HINT]) {
if ((_a = account.idTokenClaims) === null || _a === void 0 ? void 0 : _a.login_hint) {
// Use login_hint claim if available over sid or email/upn
qParams = this.addSSOParameter(SSOTypes.LOGIN_HINT, (_b = account.idTokenClaims) === null || _b === void 0 ? void 0 : _b.login_hint, qParams);
}
else if (account.sid && this.promptValue === PromptState.NONE) {
// sid - populate only if login_hint is not already populated and the account has sid
qParams = this.addSSOParameter(SSOTypes.SID, account.sid, qParams);
}
else if (account.userName) {
// Add username/upn as loginHint if nothing else available
qParams = this.addSSOParameter(SSOTypes.LOGIN_HINT, account.userName, qParams);
}
}
}
return qParams;
};
/**
* Add SID to extraQueryParameters
* @param sid
*/
ServerRequestParameters.prototype.addSSOParameter = function (ssoType, ssoData, params) {
var ssoParam = params || {};
if (!ssoData) {
return ssoParam;
}
switch (ssoType) {
case SSOTypes.SID: {
ssoParam[SSOTypes.SID] = ssoData;
break;
}
case SSOTypes.ID_TOKEN: {
ssoParam[SSOTypes.LOGIN_HINT] = ssoData;
break;
}
case SSOTypes.LOGIN_HINT: {
ssoParam[SSOTypes.LOGIN_HINT] = ssoData;
break;
}
}
return ssoParam;
};
/**
* Utility to generate a QueryParameterString from a Key-Value mapping of extraQueryParameters passed
* @param extraQueryParameters
*/
ServerRequestParameters.generateQueryParametersString = function (queryParameters, silentCall) {
var paramsString = null;
if (queryParameters) {
Object.keys(queryParameters).forEach(function (key) {
// sid cannot be passed along with login_hint or domain_hint
if (key === Constants.domain_hint && (silentCall || queryParameters[SSOTypes.SID])) {
return;
}
if (!paramsString) {
paramsString = key + "=" + encodeURIComponent(queryParameters[key]);
}
else {
paramsString += "&" + key + "=" + encodeURIComponent(queryParameters[key]);
}
});
}
return paramsString;
};
// #endregion
/**
* Check to see if there are SSO params set in the Request
* @param request
*/
ServerRequestParameters.isSSOParam = function (request) {
return !!(request && (request.account || request.sid || request.loginHint));
};
/**
* Returns the correct response_type string attribute for an acquireToken request configuration
* @param accountsMatch boolean: Determines whether the account in the request matches the cached account
* @param scopes Array<string>: AuthenticationRequest scopes configuration
* @param loginScopesOnly boolean: True if the scopes array ONLY contains the clientId or any combination of OIDC scopes, without resource scopes
*/
ServerRequestParameters.determineResponseType = function (accountsMatch, scopes) {
// Supports getting an id_token by sending in clientId as only scope or OIDC scopes as only scopes
if (ScopeSet.onlyContainsOidcScopes(scopes)) {
return ResponseTypes.id_token;
}
// If accounts match, check if OIDC scopes are included, otherwise return id_token_token
return (accountsMatch) ? this.responseTypeForMatchingAccounts(scopes) : ResponseTypes.id_token_token;
};
/**
* Returns the correct response_type string attribute for an acquireToken request configuration that contains an
* account that matches the account in the MSAL cache.
* @param scopes Array<string>: AuthenticationRequest scopes configuration
*/
ServerRequestParameters.responseTypeForMatchingAccounts = function (scopes) {
// Opt-into also requesting an ID token by sending in 'openid', 'profile' or both along with resource scopes when login is not necessary.
return (ScopeSet.containsAnyOidcScopes(scopes)) ? ResponseTypes.id_token_token : ResponseTypes.token;
};
return ServerRequestParameters;
}());
export { ServerRequestParameters };
//# sourceMappingURL=ServerRequestParameters.js.map