1 | ;
|
2 | /*
|
3 | * Copyright (c) Microsoft Corporation. All rights reserved.
|
4 | * Licensed under the MIT License.
|
5 | */
|
6 | Object.defineProperty(exports, "__esModule", { value: true });
|
7 | exports.ServerRequestParameters = void 0;
|
8 | var tslib_1 = require("tslib");
|
9 | var CryptoUtils_1 = require("./utils/CryptoUtils");
|
10 | var Constants_1 = require("./utils/Constants");
|
11 | var ScopeSet_1 = require("./ScopeSet");
|
12 | var packageMetadata_1 = require("./packageMetadata");
|
13 | /**
|
14 | * Nonce: OIDC Nonce definition: https://openid.net/specs/openid-connect-core-1_0.html#IDToken
|
15 | * State: OAuth Spec: https://tools.ietf.org/html/rfc6749#section-10.12
|
16 | * @hidden
|
17 | */
|
18 | var ServerRequestParameters = /** @class */ (function () {
|
19 | /**
|
20 | * Constructor
|
21 | * @param authority
|
22 | * @param clientId
|
23 | * @param scope
|
24 | * @param responseType
|
25 | * @param redirectUri
|
26 | * @param state
|
27 | */
|
28 | function ServerRequestParameters(authority, clientId, responseType, redirectUri, scopes, state, correlationId) {
|
29 | this.authorityInstance = authority;
|
30 | this.clientId = clientId;
|
31 | this.nonce = CryptoUtils_1.CryptoUtils.createNewGuid();
|
32 | // set scope to clientId if null
|
33 | this.scopes = scopes ? tslib_1.__spreadArrays(scopes) : Constants_1.Constants.oidcScopes;
|
34 | this.scopes = ScopeSet_1.ScopeSet.trimScopes(this.scopes);
|
35 | // set state (already set at top level)
|
36 | this.state = state;
|
37 | // set correlationId
|
38 | this.correlationId = correlationId;
|
39 | // telemetry information
|
40 | this.xClientSku = "MSAL.JS";
|
41 | this.xClientVer = packageMetadata_1.version;
|
42 | this.responseType = responseType;
|
43 | this.redirectUri = redirectUri;
|
44 | }
|
45 | Object.defineProperty(ServerRequestParameters.prototype, "authority", {
|
46 | get: function () {
|
47 | return this.authorityInstance ? this.authorityInstance.CanonicalAuthority : null;
|
48 | },
|
49 | enumerable: false,
|
50 | configurable: true
|
51 | });
|
52 | /**
|
53 | * @hidden
|
54 | * @ignore
|
55 | *
|
56 | * Utility to populate QueryParameters and ExtraQueryParameters to ServerRequestParamerers
|
57 | * @param request
|
58 | * @param serverAuthenticationRequest
|
59 | */
|
60 | ServerRequestParameters.prototype.populateQueryParams = function (account, request, adalIdTokenObject, silentCall) {
|
61 | var queryParameters = {};
|
62 | if (request) {
|
63 | // add the prompt parameter to serverRequestParameters if passed
|
64 | if (request.prompt) {
|
65 | this.promptValue = request.prompt;
|
66 | }
|
67 | // Add claims challenge to serverRequestParameters if passed
|
68 | if (request.claimsRequest) {
|
69 | this.claimsValue = request.claimsRequest;
|
70 | }
|
71 | // if the developer provides one of these, give preference to developer choice
|
72 | if (ServerRequestParameters.isSSOParam(request)) {
|
73 | queryParameters = this.constructUnifiedCacheQueryParameter(request, null);
|
74 | }
|
75 | }
|
76 | if (adalIdTokenObject) {
|
77 | queryParameters = this.constructUnifiedCacheQueryParameter(null, adalIdTokenObject);
|
78 | }
|
79 | /*
|
80 | * adds sid/login_hint if not populated
|
81 | * this.logger.verbose("Calling addHint parameters");
|
82 | */
|
83 | queryParameters = this.addHintParameters(account, queryParameters);
|
84 | // sanity check for developer passed extraQueryParameters
|
85 | var eQParams = request ? request.extraQueryParameters : null;
|
86 | // Populate the extraQueryParameters to be sent to the server
|
87 | this.queryParameters = ServerRequestParameters.generateQueryParametersString(queryParameters);
|
88 | this.extraQueryParameters = ServerRequestParameters.generateQueryParametersString(eQParams, silentCall);
|
89 | };
|
90 | // #region QueryParam helpers
|
91 | /**
|
92 | * Constructs extraQueryParameters to be sent to the server for the AuthenticationParameters set by the developer
|
93 | * in any login() or acquireToken() calls
|
94 | * @param idTokenObject
|
95 | * @param extraQueryParameters
|
96 | * @param sid
|
97 | * @param loginHint
|
98 | */
|
99 | // TODO: check how this behaves when domain_hint only is sent in extraparameters and idToken has no upn.
|
100 | ServerRequestParameters.prototype.constructUnifiedCacheQueryParameter = function (request, idTokenObject) {
|
101 | var _a;
|
102 | // preference order: account > sid > login_hint
|
103 | var ssoType;
|
104 | var ssoData;
|
105 | var serverReqParam = {};
|
106 | // if account info is passed, account.login_hint claim > account.sid > account.username
|
107 | if (request) {
|
108 | if (request.account) {
|
109 | var account = request.account;
|
110 | if ((_a = account.idTokenClaims) === null || _a === void 0 ? void 0 : _a.login_hint) {
|
111 | ssoType = Constants_1.SSOTypes.LOGIN_HINT;
|
112 | ssoData = account.idTokenClaims.login_hint;
|
113 | }
|
114 | else if (account.sid) {
|
115 | ssoType = Constants_1.SSOTypes.SID;
|
116 | ssoData = account.sid;
|
117 | }
|
118 | else if (account.userName) {
|
119 | ssoType = Constants_1.SSOTypes.LOGIN_HINT;
|
120 | ssoData = account.userName;
|
121 | }
|
122 | }
|
123 | // sid from request
|
124 | else if (request.sid) {
|
125 | ssoType = Constants_1.SSOTypes.SID;
|
126 | ssoData = request.sid;
|
127 | }
|
128 | // loginHint from request
|
129 | else if (request.loginHint) {
|
130 | ssoType = Constants_1.SSOTypes.LOGIN_HINT;
|
131 | ssoData = request.loginHint;
|
132 | }
|
133 | }
|
134 | // adalIdToken retrieved from cache
|
135 | else if (idTokenObject) {
|
136 | if (idTokenObject.hasOwnProperty(Constants_1.Constants.upn)) {
|
137 | ssoType = Constants_1.SSOTypes.ID_TOKEN;
|
138 | ssoData = idTokenObject["upn"];
|
139 | }
|
140 | }
|
141 | serverReqParam = this.addSSOParameter(ssoType, ssoData);
|
142 | return serverReqParam;
|
143 | };
|
144 | /**
|
145 | * @hidden
|
146 | *
|
147 | * 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
|
148 | * domain_hint if added skips the email based discovery process of the user - only supported for interactive calls in implicit_flow
|
149 | * domain_req utid received as part of the clientInfo
|
150 | * login_req uid received as part of clientInfo
|
151 | * Also does a sanity check for extraQueryParameters passed by the user to ensure no repeat queryParameters
|
152 | *
|
153 | * @param {@link Account} account - Account for which the token is requested
|
154 | * @param queryparams
|
155 | * @param {@link ServerRequestParameters}
|
156 | * @ignore
|
157 | */
|
158 | ServerRequestParameters.prototype.addHintParameters = function (account, params) {
|
159 | var _a, _b;
|
160 | /*
|
161 | * This is a final check for all queryParams added so far; preference order: sid > login_hint
|
162 | * sid cannot be passed along with login_hint or domain_hint, hence we check both are not populated yet in queryParameters
|
163 | */
|
164 | var qParams = params;
|
165 | if (account) {
|
166 | if (!qParams[Constants_1.SSOTypes.SID] && !qParams[Constants_1.SSOTypes.LOGIN_HINT]) {
|
167 | if ((_a = account.idTokenClaims) === null || _a === void 0 ? void 0 : _a.login_hint) {
|
168 | // Use login_hint claim if available over sid or email/upn
|
169 | qParams = this.addSSOParameter(Constants_1.SSOTypes.LOGIN_HINT, (_b = account.idTokenClaims) === null || _b === void 0 ? void 0 : _b.login_hint, qParams);
|
170 | }
|
171 | else if (account.sid && this.promptValue === Constants_1.PromptState.NONE) {
|
172 | // sid - populate only if login_hint is not already populated and the account has sid
|
173 | qParams = this.addSSOParameter(Constants_1.SSOTypes.SID, account.sid, qParams);
|
174 | }
|
175 | else if (account.userName) {
|
176 | // Add username/upn as loginHint if nothing else available
|
177 | qParams = this.addSSOParameter(Constants_1.SSOTypes.LOGIN_HINT, account.userName, qParams);
|
178 | }
|
179 | }
|
180 | }
|
181 | return qParams;
|
182 | };
|
183 | /**
|
184 | * Add SID to extraQueryParameters
|
185 | * @param sid
|
186 | */
|
187 | ServerRequestParameters.prototype.addSSOParameter = function (ssoType, ssoData, params) {
|
188 | var ssoParam = params || {};
|
189 | if (!ssoData) {
|
190 | return ssoParam;
|
191 | }
|
192 | switch (ssoType) {
|
193 | case Constants_1.SSOTypes.SID: {
|
194 | ssoParam[Constants_1.SSOTypes.SID] = ssoData;
|
195 | break;
|
196 | }
|
197 | case Constants_1.SSOTypes.ID_TOKEN: {
|
198 | ssoParam[Constants_1.SSOTypes.LOGIN_HINT] = ssoData;
|
199 | break;
|
200 | }
|
201 | case Constants_1.SSOTypes.LOGIN_HINT: {
|
202 | ssoParam[Constants_1.SSOTypes.LOGIN_HINT] = ssoData;
|
203 | break;
|
204 | }
|
205 | }
|
206 | return ssoParam;
|
207 | };
|
208 | /**
|
209 | * Utility to generate a QueryParameterString from a Key-Value mapping of extraQueryParameters passed
|
210 | * @param extraQueryParameters
|
211 | */
|
212 | ServerRequestParameters.generateQueryParametersString = function (queryParameters, silentCall) {
|
213 | var paramsString = null;
|
214 | if (queryParameters) {
|
215 | Object.keys(queryParameters).forEach(function (key) {
|
216 | // sid cannot be passed along with login_hint or domain_hint
|
217 | if (key === Constants_1.Constants.domain_hint && (silentCall || queryParameters[Constants_1.SSOTypes.SID])) {
|
218 | return;
|
219 | }
|
220 | if (!paramsString) {
|
221 | paramsString = key + "=" + encodeURIComponent(queryParameters[key]);
|
222 | }
|
223 | else {
|
224 | paramsString += "&" + key + "=" + encodeURIComponent(queryParameters[key]);
|
225 | }
|
226 | });
|
227 | }
|
228 | return paramsString;
|
229 | };
|
230 | // #endregion
|
231 | /**
|
232 | * Check to see if there are SSO params set in the Request
|
233 | * @param request
|
234 | */
|
235 | ServerRequestParameters.isSSOParam = function (request) {
|
236 | return !!(request && (request.account || request.sid || request.loginHint));
|
237 | };
|
238 | /**
|
239 | * Returns the correct response_type string attribute for an acquireToken request configuration
|
240 | * @param accountsMatch boolean: Determines whether the account in the request matches the cached account
|
241 | * @param scopes Array<string>: AuthenticationRequest scopes configuration
|
242 | * @param loginScopesOnly boolean: True if the scopes array ONLY contains the clientId or any combination of OIDC scopes, without resource scopes
|
243 | */
|
244 | ServerRequestParameters.determineResponseType = function (accountsMatch, scopes) {
|
245 | // Supports getting an id_token by sending in clientId as only scope or OIDC scopes as only scopes
|
246 | if (ScopeSet_1.ScopeSet.onlyContainsOidcScopes(scopes)) {
|
247 | return Constants_1.ResponseTypes.id_token;
|
248 | }
|
249 | // If accounts match, check if OIDC scopes are included, otherwise return id_token_token
|
250 | return (accountsMatch) ? this.responseTypeForMatchingAccounts(scopes) : Constants_1.ResponseTypes.id_token_token;
|
251 | };
|
252 | /**
|
253 | * Returns the correct response_type string attribute for an acquireToken request configuration that contains an
|
254 | * account that matches the account in the MSAL cache.
|
255 | * @param scopes Array<string>: AuthenticationRequest scopes configuration
|
256 | */
|
257 | ServerRequestParameters.responseTypeForMatchingAccounts = function (scopes) {
|
258 | // Opt-into also requesting an ID token by sending in 'openid', 'profile' or both along with resource scopes when login is not necessary.
|
259 | return (ScopeSet_1.ScopeSet.containsAnyOidcScopes(scopes)) ? Constants_1.ResponseTypes.id_token_token : Constants_1.ResponseTypes.token;
|
260 | };
|
261 | return ServerRequestParameters;
|
262 | }());
|
263 | exports.ServerRequestParameters = ServerRequestParameters;
|
264 | //# sourceMappingURL=ServerRequestParameters.js.map |
\ | No newline at end of file |