@eui/base 17.3.0 → 18.0.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,1311 +0,0 @@
1
- (function () {
2
- // private function:
3
- function isLocalDevelopmentEnvironment(href) {
4
- if (href == null) {
5
- href = window.top.location.href;
6
- }
7
-
8
- return href.indexOf("://localhost:") >= 0 || href.indexOf("://localhost/") >= 0;
9
- }
10
-
11
- var keypair = null;
12
- var publicKeyInJWKFormat = null;
13
- var hrefSavedFromIdTokenMurder = null;
14
-
15
- var OpenIdConnect = {
16
- OPENID_LOGIN_CONFIGURATION_URL: ((typeof OPENID_LOGIN_CONFIGURATION_URL) == "undefined" ? "assets/openid-login-config" + ((typeof OPENID_LOGIN_ENVIRONMENT) == "undefined" ? "" : "." + OPENID_LOGIN_ENVIRONMENT) + ".json" : OPENID_LOGIN_CONFIGURATION_URL),
17
- SESSION_STORAGE_KEY_ID_TOKEN: "ux-openid-connect-id-token",
18
- SESSION_STORAGE_KEY_USER_DETAILS: "ux-openid-connect-user-details",
19
- SESSION_STORAGE_KEY_API_GATEWAY_ACCESS_TOKEN: "ux-openid-connect-api-gateway-access-token",
20
- SESSION_STORAGE_KEY_IMPERSONATED_USER_ID: "ux-openid-connect-impersonated-user-id",
21
- SESSION_STORAGE_KEY_DEVELOPMENT_URL: "ux-openid-connect-dev-url",
22
- SESSION_STORAGE_KEY_ORIGINAL_URL: "ux-openid-connect-original-url",
23
- SESSION_STORAGE_KEY_TRACK_USERNAME: "ux-openid-connect-track-username",
24
- SESSION_STORAGE_KEY_TRACK_LOGIN: "ux-openid-connect-track-login",
25
- SESSION_STORAGE_KEY_PUBLIC_KEY: "ux-openid-connect-public-key",
26
- SESSION_STORAGE_KEY_PRIVATE_KEY: "ux-openid-connect-private-key",
27
- SESSION_STORAGE_KEY_LOGIN_TIMESTAMP: "ux-openid-connect-login-timestamp",
28
- REQUEST_PARAMETER_DEVELOPMENT_URL: "ux-openid-connect-dev-url",
29
- REQUEST_PARAMETER_DEVELOPMENT_PUBLIC_KEY: "ux-openid-connect-dev-public-key",
30
- DEFAULT_OPENID_SCOPE: "openid email profile",
31
- DEFAULT_OPENID_CLOCK_SKEW: 15 * 60, // This means a 15 minutes difference between the clock on the EU Login server and the clock on the user's PC. (Issue related to trade wars and the frequency of the AC carrier wave on the electrical grid causing clocks to run slower.)
32
- DEFAULT_MAX_REQUEST_RETRIES: 1,
33
- DEFAULT_ID_TOKEN_SIGNING_ALGORITHM: "ES256",
34
- DEFAULT_ACCESS_TOKEN_SIGNING_ALGORITHM: "ES256",
35
-
36
- config: null,
37
- configInitialised: false,
38
- metadata: null,
39
- waitForClientQueue: [],
40
- waitForConfigQueue: [],
41
- waitForIdTokenQueue: [],
42
- waitForApiGatewayAccessTokenQueue: [],
43
- loginWasRequested: false,
44
- extractingIdToken: false,
45
- requestingLogin: false,
46
- requestingApiGatewayAccessToken: false,
47
- wasLoggedIn: false,
48
- client: null,
49
- usedEuLoginAccessTokens: {},
50
-
51
- // --------------- Login with EU Login ---------------
52
- loadConfiguration: function (callbackFunction) {
53
- var configurationUrl = OpenIdConnect.OPENID_LOGIN_CONFIGURATION_URL;
54
- // Add the href of the <base> tag to it:
55
- var baseTags = document.head.getElementsByTagName("base");
56
- if (baseTags != null && baseTags.length > 0) {
57
- var baseHref = baseTags [0].getAttribute("href");
58
- if (baseHref != null) {
59
- configurationUrl = baseHref + configurationUrl;
60
- }
61
- }
62
-
63
- var xhr = new XMLHttpRequest();
64
- xhr.withCredentials = true;
65
- xhr.open("GET", configurationUrl);
66
- xhr.onload = function () {
67
- if (this.readyState == 4 && this.status == 200) {
68
- try {
69
- var config = JSON.parse(xhr.responseText);
70
- if (config != null && config.openIdConnect != null) {
71
- OpenIdConnect.config = config.openIdConnect;
72
- OpenIdConnect.loadMetadata(callbackFunction);
73
- } else {
74
- if (callbackFunction != null && (typeof callbackFunction) == "function") {
75
- callbackFunction();
76
- }
77
- }
78
- } catch (error) {
79
- console.error("Unable to properly load the configuration.");
80
- console.error(error);
81
- }
82
- }
83
- };
84
- xhr.send();
85
- },
86
-
87
- loadMetadata: function (callbackFunction) {
88
- var config = OpenIdConnect.config;
89
- if (config != null && config.enabled && config.metadataUrl != null && config.metadataUrl.trim().length > 0) {
90
- var xhr = new XMLHttpRequest();
91
- xhr.withCredentials = true;
92
- xhr.open("GET", config.metadataUrl);
93
- xhr.onload = function () {
94
- if (this.readyState == 4 && this.status == 200) {
95
- try {
96
- OpenIdConnect.metadata = JSON.parse(xhr.responseText);
97
- OpenIdConnect.createOpenIdClient();
98
- if (callbackFunction != null && (typeof callbackFunction) == "function") {
99
- callbackFunction();
100
- }
101
- } catch (error) {
102
- console.error("Unable to properly load the OpenID Connect metadata.");
103
- console.error(error);
104
- }
105
- }
106
- };
107
- xhr.send();
108
- } else {
109
- if (callbackFunction != null && (typeof callbackFunction) == "function") {
110
- callbackFunction();
111
- }
112
- }
113
- },
114
-
115
- createOpenIdClient: function () {
116
- var config = OpenIdConnect.config;
117
- var settings = {
118
- authority: OpenIdConnect.metadata.authorization_endpoint,
119
- metadataUrl: config.metadataUrl,
120
- client_id: config.spaClientId,
121
- redirect_uri: config.spaRedirectUrl,
122
- post_logout_redirect_uri: config.spaRedirectUrl,
123
- response_type: 'id_token',
124
- scope: (config.scope || OpenIdConnect.DEFAULT_OPENID_SCOPE),
125
- filterProtocolClaims: true,
126
- loadUserInfo: true
127
- };
128
- var clockSkew = config.clockSkew;
129
- if (clockSkew != null && clockSkew > 0) {
130
- settings ["clockSkew"] = clockSkew;
131
- } else {
132
- settings ["clockSkew"] = OpenIdConnect.DEFAULT_OPENID_CLOCK_SKEW;
133
- }
134
-
135
- OpenIdConnect.client = new Oidc.OidcClient(settings);
136
- // Continue the pending log in:
137
- var queue = OpenIdConnect.waitForClientQueue;
138
- while (queue.length > 0) {
139
- // Extra timeout to prevent endless loop in case of accidental recursion due to still not being authorized because of an unknown issue:
140
- setTimeout(queue.pop(), 0);
141
- }
142
- },
143
-
144
- loginWithOpenIDConnect: function (dontRenew) {
145
- // Don't renew means that we don't automatically login when there is no ID token.
146
- // This is for applications that have public areas.
147
- OpenIdConnect.loginWasRequested = true;
148
-
149
- // check for a development login first:
150
- var developmentUrl = OpenIdConnect.getRequestParameter(OpenIdConnect.REQUEST_PARAMETER_DEVELOPMENT_URL);
151
- if (developmentUrl == null) {
152
- // First check if there is a new ID token coming back from EU Login:
153
- OpenIdConnect.extractIdTokenFromLocation(function (idToken) {
154
- if (idToken != null) {
155
- OpenIdConnect.saveUserToSessionStorage(idToken);
156
- OpenIdConnect.navigateToOriginallyRequestedUrl(idToken);
157
- OpenIdConnect.removeLocationHash();
158
- } else {
159
- // There is no new ID token; check if there is already one in the session storage:
160
- var cachedIdToken = sessionStorage.getItem(OpenIdConnect.SESSION_STORAGE_KEY_ID_TOKEN);
161
- if (cachedIdToken == null && ! dontRenew) {
162
- OpenIdConnect.renewIdToken();
163
- } else {
164
- OpenIdConnect.wasLoggedIn = true;
165
- var developmentUrl = localStorage.getItem(OpenIdConnect.SESSION_STORAGE_KEY_DEVELOPMENT_URL);
166
- if (developmentUrl != null) {
167
- OpenIdConnect.navigateToOriginallyRequestedUrl(cachedIdToken);
168
- }
169
- }
170
- }
171
-
172
- var continuePendingRequests = function () {
173
- var queue = OpenIdConnect.waitForIdTokenQueue;
174
- OpenIdConnect.wasLoggedIn = true;
175
- while (queue.length > 0) {
176
- // Extra timeout to prevent endless loop in case of accidental recursion due to still not being authorized because of an unknown issue:
177
- setTimeout(queue.pop(), 0);
178
- }
179
- };
180
-
181
- // We may have the ID token already being processed, while the configuration is still loading:
182
- if (OpenIdConnect.configInitialised) {
183
- continuePendingRequests();
184
- } else {
185
- OpenIdConnect.waitForConfigQueue.push(continuePendingRequests);
186
- }
187
- });
188
- } else {
189
- // development login was requested; force the login:
190
- OpenIdConnect.renewIdToken();
191
- }
192
- },
193
-
194
- getAuthorizationHeaders: function (url, callbackFunction, errorCallbackFunction) { // calls the callback function with an object containing all the headers necessary to authenticate the request
195
- if (url != null && (typeof callbackFunction) == "function") {
196
- if (OpenIdConnect.configInitialised) {
197
- if (OpenIdConnect.config != null && OpenIdConnect.config.enabled) {
198
- if (sessionStorage.getItem(OpenIdConnect.SESSION_STORAGE_KEY_ID_TOKEN) != null) {
199
- if (OpenIdConnect.config.apiGatewayServices) {
200
- var service = OpenIdConnect.getMatchingServiceFromConfiguration(url, OpenIdConnect.config.apiGatewayServices);
201
- if (service != null) {
202
- OpenIdConnect.getApiGatewayAuthorizationHeaders(service.audienceId, callbackFunction, errorCallbackFunction, service.authenticatedByGateway);
203
- return;
204
- }
205
- }
206
-
207
- if (OpenIdConnect.config.services) {
208
- var service = OpenIdConnect.getMatchingServiceFromConfiguration(url, OpenIdConnect.config.services);
209
- if (service != null && service.audienceId != null && service.audienceId != "") {
210
- OpenIdConnect.getServiceAuthorizationHeaders(service.audienceId, callbackFunction, errorCallbackFunction, service.authenticatedByGateway);
211
- return;
212
- }
213
- }
214
-
215
- if (OpenIdConnect.config.ecasServices) {
216
- var service = OpenIdConnect.getMatchingServiceFromConfiguration(url, OpenIdConnect.config.ecasServices);
217
- if (service != null) {
218
- OpenIdConnect.getEcasServiceAuthorizationHeaders(url, callbackFunction, errorCallbackFunction);
219
- return;
220
- }
221
- }
222
-
223
- // No known OpenID service call, doing normal call:
224
- callbackFunction();
225
- } else {
226
- // We are not logged in; first check if we are already logging in, or if we need to log in automatically:
227
- if (OpenIdConnect.idTokenPresentInLocation() || (OpenIdConnect.config != null && (OpenIdConnect.config.autoLogin == null || OpenIdConnect.config.autoLogin))) {
228
- // ... then check if the request is protected:
229
- var urlIsProtected = false;
230
- if (OpenIdConnect.config.apiGatewayServices) {
231
- var service = OpenIdConnect.getMatchingServiceFromConfiguration(url, OpenIdConnect.config.apiGatewayServices);
232
- urlIsProtected = (service != null && ((service.audienceId != null && service.audienceId != "") || service.authenticatedByGateway));
233
- }
234
- if (! urlIsProtected && OpenIdConnect.config.services) {
235
- var service = OpenIdConnect.getMatchingServiceFromConfiguration(url, OpenIdConnect.config.services);
236
- urlIsProtected = (service != null && service.audienceId != null && service.audienceId != "");
237
- }
238
- if (! urlIsProtected && OpenIdConnect.config.ecasServices) {
239
- var service = OpenIdConnect.getMatchingServiceFromConfiguration(url, OpenIdConnect.config.ecasServices);
240
- urlIsProtected = (service != null && service != "");
241
- }
242
-
243
- if (urlIsProtected) {
244
- // The service URL is protected, but we are not logged in yet; queue the function call:
245
- OpenIdConnect.waitForIdTokenQueue.push(function () {
246
- OpenIdConnect.getAuthorizationHeaders(url, callbackFunction, errorCallbackFunction);
247
- });
248
-
249
- if (!OpenIdConnect.loginWasRequested) {
250
- OpenIdConnect.loginWithOpenIDConnect();
251
- }
252
- } else {
253
- // We don't need to automatically log in; resume call:
254
- callbackFunction();
255
- }
256
- } else {
257
- // The service URL is not protected; resume call:
258
- callbackFunction();
259
- }
260
- }
261
- } else {
262
- // OpenID is disabled, resume call:
263
- callbackFunction();
264
- }
265
- } else {
266
- // Configuration is not yet loaded. Try again later:
267
- OpenIdConnect.waitForIdTokenQueue.push(function () {
268
- OpenIdConnect.getAuthorizationHeaders(url, callbackFunction, errorCallbackFunction);
269
- });
270
- }
271
- } else {
272
- console.error("To be able to access a service, please specify the url, xhr and the callback function.");
273
- }
274
- },
275
-
276
- getMatchingServiceFromConfiguration: function (url, configuredServices) {
277
- if (configuredServices != null) {
278
- for (var serviceId in configuredServices) {
279
- if (configuredServices.hasOwnProperty(serviceId)) {
280
- var service = configuredServices [serviceId];
281
- if (OpenIdConnect.urlMatches(url, service.endpoint)) {
282
- return service;
283
- }
284
- }
285
- }
286
- }
287
-
288
- return null;
289
- },
290
-
291
- getApiGatewayAuthorizationHeaders: function (audienceId, callbackFunction, errorCallbackFunction, authenticatedByGateway) {
292
- if (! OpenIdConnect.requestingApiGatewayAccessToken) {
293
- // Check if we already have an API Gateway access token cached in memory:
294
- if (OpenIdConnect.cachedApiGatewayAccessTokenHasExpired()) {
295
- OpenIdConnect.requestingApiGatewayAccessToken = true;
296
- // Get an EU Login access token for the API Gateway and for the target service:
297
- var euLoginTokenApiGateway = null;
298
- var euLoginTokenService = null;
299
- var getApiGatewayAccessToken = function () {
300
- if (euLoginTokenApiGateway != null && (euLoginTokenService != null || audienceId == null)) {
301
- // Prevent the same EU Login access token from being used:
302
- if (euLoginTokenApiGateway != null && OpenIdConnect.usedEuLoginAccessTokens [euLoginTokenApiGateway.access_token]) {
303
- // Due to unexpected racing conditions, the same EU Login access token is being used to request the API Gateway token.
304
- // Simply retry:
305
- OpenIdConnect.requestingApiGatewayAccessToken = false;
306
- setTimeout(function () {
307
- OpenIdConnect.getApiGatewayAuthorizationHeaders(audienceId, callbackFunction, errorCallbackFunction, authenticatedByGateway);
308
- }, 0);
309
- return;
310
- }
311
-
312
- var impersonatedUserId = OpenIdConnect.getImpersonatedUserId();
313
- if (impersonatedUserId == null) {
314
- // We now have an EU Login access token for the API Gateway and the target service.
315
- // Continue by asking an access token to the gateway itself. It requires the EU Login access token...
316
- var xhr = new XMLHttpRequest();
317
- xhr.withCredentials = false;
318
- xhr.onload = function () {
319
- if (this.readyState == 4 && this.status == 200) {
320
- // We now have access to the API Gateway.
321
- // Continue by calling the gateway (using the API Gateway access token),
322
- // and by propagating the EU Login access token for the target service...
323
- var apiGatewayAccessToken = OpenIdConnect.parseSafely(xhr, errorCallbackFunction);
324
- OpenIdConnect.storeCachedApiGatewayAccessToken(apiGatewayAccessToken);
325
-
326
- // Prevent the same EU Login access token from being used:
327
- if (euLoginTokenService != null && OpenIdConnect.usedEuLoginAccessTokens [euLoginTokenService.access_token]) {
328
- // Due to unexpected racing conditions, the same EU Login access token is being used to request the API Gateway token.
329
- // Simply retry:
330
- OpenIdConnect.requestingApiGatewayAccessToken = false;
331
- setTimeout(function () {
332
- OpenIdConnect.getApiGatewayAuthorizationHeaders(audienceId, callbackFunction, errorCallbackFunction, authenticatedByGateway);
333
- }, 0);
334
- return;
335
- }
336
- OpenIdConnect.returnApiGatewayAuthorizationHeaders(apiGatewayAccessToken, euLoginTokenService, callbackFunction, authenticatedByGateway);
337
- } else if (xhr.status >= 400) {
338
- OpenIdConnect.handleErrorResponse(xhr, errorCallbackFunction);
339
- }
340
- };
341
- xhr.onerror = function () {
342
- OpenIdConnect.handleErrorResponse(xhr, errorCallbackFunction);
343
- };
344
- xhr.open("POST", OpenIdConnect.config.apiGatewayAccessTokenUrl);
345
- xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
346
- xhr.send(
347
- "grant_type=oauth2:eui&" +
348
- "eul_access_token=" + OpenIdConnect.signAccessToken(euLoginTokenApiGateway.access_token) + "&"+
349
- "consumer_key=" + encodeURIComponent(OpenIdConnect.config.apiGatewayConsumerKey)
350
- );
351
- if (euLoginTokenApiGateway != null) {
352
- OpenIdConnect.usedEuLoginAccessTokens [euLoginTokenApiGateway.access_token] = true;
353
- }
354
- } else {
355
- // Re-impersonate:
356
- OpenIdConnect.impersonate(impersonatedUserId, function () {
357
- OpenIdConnect.returnApiGatewayAuthorizationHeaders(OpenIdConnect.getCachedApiGatewayAccessToken(), euLoginTokenService, callbackFunction, authenticatedByGateway);
358
- }, errorCallbackFunction);
359
- }
360
- }
361
- };
362
-
363
- OpenIdConnect.doServiceAccessTokenRequest(OpenIdConnect.config.apiGatewayAccessTokenAudienceId, function (newEuLoginToken) {
364
- euLoginTokenApiGateway = newEuLoginToken;
365
- getApiGatewayAccessToken();
366
- }, errorCallbackFunction);
367
- if (audienceId != null && audienceId != "") {
368
- OpenIdConnect.doServiceAccessTokenRequest(audienceId, function (newEuLoginToken) {
369
- euLoginTokenService = newEuLoginToken;
370
- getApiGatewayAccessToken();
371
- }, errorCallbackFunction);
372
- } else {
373
- getApiGatewayAccessToken();
374
- }
375
- } else {
376
- // We already have an API Gateway access token.
377
- // Now request an EU Login access token for the target service.
378
- if (audienceId != null && audienceId != "") {
379
- var gatherHeaders = function () {
380
- OpenIdConnect.doServiceAccessTokenRequest(audienceId, function (newEuLoginToken) {
381
- // Prevent the same EU Login access token from being used:
382
- if (newEuLoginToken != null && OpenIdConnect.usedEuLoginAccessTokens [newEuLoginToken.access_token]) {
383
- // Due to unexpected racing conditions, the same EU Login access token is being used to request the API Gateway token.
384
- // Simply retry:
385
- return gatherHeaders();
386
- }
387
-
388
- // We have now both the API Gateway access token and a EU Login access token for the target service;
389
- // we can call the API Gateway.
390
- OpenIdConnect.returnApiGatewayAuthorizationHeaders(OpenIdConnect.getCachedApiGatewayAccessToken(), newEuLoginToken, callbackFunction, authenticatedByGateway);
391
- }, errorCallbackFunction);
392
- };
393
- gatherHeaders();
394
- } else {
395
- OpenIdConnect.returnApiGatewayAuthorizationHeaders(OpenIdConnect.getCachedApiGatewayAccessToken(), null, callbackFunction, authenticatedByGateway);
396
- }
397
- }
398
- } else {
399
- // An API Gateway token is already being requested; queue the request:
400
- OpenIdConnect.waitForApiGatewayAccessTokenQueue.push(function () {
401
- OpenIdConnect.getApiGatewayAuthorizationHeaders(audienceId, callbackFunction, errorCallbackFunction, authenticatedByGateway);
402
- });
403
- }
404
- },
405
-
406
- getServiceAuthorizationHeaders: function (audienceId, callbackFunction, errorCallbackFunction, authenticatedByGateway) {
407
- if (authenticatedByGateway) {
408
- OpenIdConnect.returnServiceAuthorizationHeaders(null, callbackFunction, authenticatedByGateway);
409
- } else {
410
- OpenIdConnect.doServiceAccessTokenRequest(audienceId, function (newEuLoginToken) {
411
- OpenIdConnect.returnServiceAuthorizationHeaders(newEuLoginToken, callbackFunction, authenticatedByGateway);
412
- }, errorCallbackFunction);
413
- }
414
- },
415
-
416
- getEcasServiceAuthorizationHeaders: function (url, callbackFunction, errorCallbackFunction) {
417
- OpenIdConnect.doEcasProxyTicketRequest(url, function (newProxyTicketToken) {
418
- var ecasProxyTicketToken = newProxyTicketToken;
419
- OpenIdConnect.returnEcasServiceAuthorizationHeaders(ecasProxyTicketToken, callbackFunction);
420
- }, errorCallbackFunction);
421
- },
422
-
423
- impersonate: function (userId, callbackFunction, errorCallbackFunction, reason) {
424
- var makeImpersonationCallFunction = function () {
425
- OpenIdConnect.doServiceAccessTokenRequest(OpenIdConnect.config.apiGatewayAccessTokenAudienceId, function (newEuLoginToken) {
426
- var euLoginTokenForApiGateway = newEuLoginToken;
427
- var xhr = new XMLHttpRequest();
428
- xhr.withCredentials = false;
429
- xhr.onload = function () {
430
- if (this.readyState == 4 && this.status == 200) {
431
- var apiGatewayAccessToken = OpenIdConnect.parseSafely(xhr, errorCallbackFunction);
432
- OpenIdConnect.storeCachedApiGatewayAccessToken(apiGatewayAccessToken);
433
- if (callbackFunction != null && (typeof callbackFunction) == "function") {
434
- if (apiGatewayAccessToken && apiGatewayAccessToken.access_token) {
435
- var tokenObject = OpenIdConnect.decodeJwtToken(apiGatewayAccessToken.access_token);
436
- if (tokenObject.imp_userId) {
437
- var impersonatedUser = {
438
- dg: tokenObject.imp_dg,
439
- email: tokenObject.imp_email,
440
- employeeNumber: tokenObject.imp_employeeNumber,
441
- name: tokenObject.imp_name,
442
- organisationId: tokenObject.imp_organizationId,
443
- organisation: tokenObject.imp_organization,
444
- phoneNumber: tokenObject.imp_phoneNumber,
445
- userId: tokenObject.imp_userId
446
- };
447
-
448
- OpenIdConnect.storeImpersonatedUserId(userId);
449
-
450
- callbackFunction(true, impersonatedUser);
451
- } else {
452
- callbackFunction(false);
453
- }
454
- } else {
455
- OpenIdConnect.handleErrorResponse(xhr, errorCallbackFunction);
456
- }
457
- }
458
- } else if (xhr.status >= 400) {
459
- if (xhr.status === 403) {
460
- // Not allowed to impersonate!
461
- if (callbackFunction != null && (typeof callbackFunction) == "function") {
462
- callbackFunction(false);
463
- } else {
464
- OpenIdConnect.handleErrorResponse(xhr, errorCallbackFunction);
465
- }
466
- } else {
467
- OpenIdConnect.handleErrorResponse(xhr, errorCallbackFunction);
468
- }
469
- }
470
- };
471
- xhr.onerror = function () {
472
- if (xhr.status === 403) {
473
- // Not allowed to impersonate!
474
- if (callbackFunction != null && (typeof callbackFunction) == "function") {
475
- callbackFunction(false);
476
- } else {
477
- OpenIdConnect.handleErrorResponse(xhr, errorCallbackFunction);
478
- }
479
- } else {
480
- OpenIdConnect.handleErrorResponse(xhr, errorCallbackFunction);
481
- }
482
- };
483
-
484
- var userString = sessionStorage.getItem(OpenIdConnect.SESSION_STORAGE_KEY_USER_DETAILS);
485
- if (userString == null) {
486
- throw "You are not logged in yet. Impersonation cannot be started yet.";
487
- }
488
- var user = null;
489
- try {
490
- user = JSON.parse(userString);
491
- } catch (error) {}
492
- if (user == null || user.userId == null) {
493
- throw "Unable to determine your user ID. Impersonation cannot be started.";
494
- }
495
-
496
- xhr.open("POST", OpenIdConnect.config.apiGatewayImpersonationUrl + "/" + user.userId + "/impersonate/" + userId);
497
- xhr.setRequestHeader("Content-Type", "application/json");
498
- xhr.setRequestHeader("Authorization-Propagation", "pop " + OpenIdConnect.signAccessToken(euLoginTokenForApiGateway.access_token));
499
- if (reason != null) {
500
- xhr.send(JSON.stringify({
501
- impersonationReason: reason
502
- }));
503
- } else {
504
- xhr.send();
505
- }
506
- }, errorCallbackFunction);
507
- };
508
-
509
- try {
510
- OpenIdConnect.unimpersonate(makeImpersonationCallFunction, errorCallbackFunction);
511
- } catch (error) {
512
- makeImpersonationCallFunction();
513
- }
514
- },
515
-
516
- unimpersonate: function (callbackFunction, errorCallbackFunction) {
517
- if (OpenIdConnect.getCachedApiGatewayAccessToken() != null) {
518
- OpenIdConnect.doServiceAccessTokenRequest(OpenIdConnect.config.apiGatewayAccessTokenAudienceId, function (newEuLoginToken) {
519
- var euLoginTokenForApiGateway = newEuLoginToken;
520
- var xhr = new XMLHttpRequest();
521
- xhr.withCredentials = false;
522
- xhr.onload = function () {
523
- if (this.readyState == 4 && this.status == 200) {
524
- // We now have access to the API Gateway.
525
- // Continue by calling the gateway (using the API Gateway access token),
526
- // and by propagating the EU Login access token for the target service...
527
- if (callbackFunction != null && (typeof callbackFunction) == "function") {
528
- OpenIdConnect.clearImpersonatedUserId();
529
- OpenIdConnect.clearCachedApiGatewayAccessToken();
530
- callbackFunction(true);
531
- }
532
- } else if (xhr.status >= 400) {
533
- OpenIdConnect.handleErrorResponse(xhr, errorCallbackFunction);
534
- }
535
- };
536
- xhr.onerror = function () {
537
- OpenIdConnect.handleErrorResponse(xhr, errorCallbackFunction);
538
- };
539
- xhr.open("DELETE", OpenIdConnect.config.apiGatewayImpersonationUrl);
540
- xhr.setRequestHeader("Content-Type", "text/plain");
541
- xhr.setRequestHeader("Authorization-Propagation", "pop " + OpenIdConnect.signAccessToken(euLoginTokenForApiGateway.access_token));
542
- xhr.send(OpenIdConnect.getCachedApiGatewayAccessToken().access_token);
543
- });
544
- } else {
545
- if (callbackFunction != null && (typeof callbackFunction) == "function") {
546
- callbackFunction(true);
547
- }
548
- }
549
- },
550
-
551
- returnApiGatewayAuthorizationHeaders: function (apiGatewayAccessToken, serviceAccessToken, callbackFunction, authenticatedByGateway) {
552
- var headers = {};
553
- if (apiGatewayAccessToken != null && apiGatewayAccessToken.token_type != null && apiGatewayAccessToken.access_token != null) {
554
- headers ["Authorization"] = apiGatewayAccessToken.token_type + " " + apiGatewayAccessToken.access_token;
555
- if (authenticatedByGateway) {
556
- headers ["Authorization-Propagation"] = apiGatewayAccessToken.access_token;
557
- }
558
- }
559
-
560
- if (serviceAccessToken != null && serviceAccessToken.access_token != null) {
561
- headers ["Authorization-Propagation"] = OpenIdConnect.signAccessToken(serviceAccessToken.access_token);
562
- OpenIdConnect.usedEuLoginAccessTokens [serviceAccessToken.access_token] = true;
563
- }
564
- OpenIdConnect.addImpersonationHeaders(headers);
565
-
566
- if (callbackFunction != null && (typeof callbackFunction) == "function") {
567
- callbackFunction(headers);
568
- }
569
-
570
- OpenIdConnect.continuePendingApiGatewayServiceRequests();
571
- },
572
-
573
- returnServiceAuthorizationHeaders: function (serviceAccessToken, callbackFunction, authenticatedByGateway) {
574
- var headers = {};
575
- if (authenticatedByGateway) {
576
- headers ["Authorization"] = "Bearer " + apiGatewayAccessToken.access_token;
577
- } else if (serviceAccessToken != null) {
578
- headers ["Authorization"] = serviceAccessToken.token_type + " " + OpenIdConnect.signAccessToken(serviceAccessToken.access_token);
579
- }
580
- OpenIdConnect.addImpersonationHeaders(headers);
581
-
582
- if (callbackFunction != null && (typeof callbackFunction) == "function") {
583
- callbackFunction(headers);
584
- }
585
- },
586
-
587
- returnEcasServiceAuthorizationHeaders: function (ecasProxyTicketToken, callbackFunction) {
588
- var headers = {};
589
- if (ecasProxyTicketToken != null) {
590
- headers ["Authorization"] = ecasProxyTicketToken.token_type + " " + ecasProxyTicketToken.access_token;
591
- }
592
- OpenIdConnect.addImpersonationHeaders(headers);
593
-
594
- if (callbackFunction != null && (typeof callbackFunction) == "function") {
595
- callbackFunction(headers);
596
- }
597
- },
598
-
599
- isApiGatewayTokenInvalidResponse: function (xhr) {
600
- return xhr.responseText != null && xhr.responseText.indexOf("<ams:code>900901</ams:code>") >= 0;
601
- },
602
-
603
- isEuLoginInvalidIdTokenResponse: function (xhr, responseAsJson) {
604
- return responseAsJson != null && responseAsJson.error == "invalid_request";
605
- },
606
-
607
- isEuAccessDeniedErrorResponse: function (xhr, responseAsJson) {
608
- return responseAsJson != null && responseAsJson.error == "access_denied";
609
- },
610
-
611
- handleErrorResponse: function (xhr, errorCallbackFunction) {
612
- if (xhr != null) {
613
- var response = null;
614
- try {
615
- response = JSON.parse(xhr.responseText);
616
- } catch (error) {}
617
-
618
- if (OpenIdConnect.isEuLoginInvalidIdTokenResponse(xhr, response)) {
619
- // The ID token is invalid or incorrect; retrieve another one:
620
- OpenIdConnect.renewIdToken();
621
- } else if (xhr.status === 401 || xhr.status === 403) {
622
- // Can be one of the following conditions:
623
- // * The client ID is invalid or incorrect; fail the request.
624
- // Either the developer needs to use a valid client ID or the administrator should allow the client ID access.
625
- // * The API Gateway access token is invalid. (401)
626
- // * The EU Login access token is invalid. (403)
627
- // * EU Access is returning an error object with "access_denied" error. (403)
628
- if (xhr.retry != null && (typeof xhr.retry == "function") && ! OpenIdConnect.isEuAccessDeniedErrorResponse(xhr, response)) {
629
- xhr.retry(OpenIdConnect.isApiGatewayTokenInvalidResponse(xhr));
630
- } else {
631
- if ((typeof errorCallbackFunction) == "function") {
632
- errorCallbackFunction(xhr);
633
- }
634
- }
635
- } else if (xhr.status === 0) {
636
- // One of the access token requests or the original request was not sent.
637
- // Most likely one of the CORS pre-flight requests failed, or the browser is offline.
638
- console.warn(
639
- "The OpenID Connect call may have issues:\n" +
640
- "* the CORS pre-flight requests for the OpenID Connect access tokens or for the REST call could be failing\n" +
641
- "* the browser could be currently offline."
642
- );
643
-
644
- if ((typeof errorCallbackFunction) == "function") {
645
- errorCallbackFunction(xhr);
646
- }
647
- } else {
648
- if ((typeof errorCallbackFunction) == "function") {
649
- errorCallbackFunction(xhr);
650
- }
651
- }
652
- }
653
- },
654
-
655
- doServiceAccessTokenRequest: function (audienceId, onloadFunction, errorCallbackFunction) {
656
- var parameters = "" +
657
- "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer" +
658
- "&scope=" + (OpenIdConnect.config.scope || OpenIdConnect.DEFAULT_OPENID_SCOPE) +
659
- "&assertion=" + OpenIdConnect.signIdToken() +
660
- "&audience=" + audienceId +
661
- "&client_id=" + OpenIdConnect.config.spaClientId;
662
- var url = OpenIdConnect.metadata.token_endpoint;
663
- url += (url.indexOf("?") > 0 ? "&" : "?") + parameters;
664
-
665
- var xhr = new XMLHttpRequest();
666
- xhr.withCredentials = true;
667
- xhr.onload = function () {
668
- if (this.readyState == 4) {
669
- if (this.status >= 200 && this.status < 300) {
670
- onloadFunction(OpenIdConnect.parseSafely(xhr, errorCallbackFunction));
671
- } else {
672
- OpenIdConnect.handleErrorResponse(xhr, errorCallbackFunction);
673
- }
674
- }
675
- };
676
- xhr.onerror = function () {
677
- OpenIdConnect.handleErrorResponse(xhr, errorCallbackFunction);
678
- };
679
- xhr.retry = function (clearApiGatewayAccessToken) {
680
- var retryCount = xhr.retryCount;
681
- if (retryCount == null) {
682
- retryCount = -1;
683
- }
684
- var maximumRequestRetries = OpenIdConnect.config.maximumRequestRetries;
685
- if (maximumRequestRetries == null) {
686
- maximumRequestRetries = OpenIdConnect.DEFAULT_MAX_REQUEST_RETRIES;
687
- }
688
- if (maximumRequestRetries == null) {
689
- maximumRequestRetries = 1;
690
- }
691
- if (retryCount < maximumRequestRetries) {
692
- xhr.retryCount = retryCount + 1;
693
- if (clearApiGatewayAccessToken) {
694
- // Clear the cached token to fully retry the request:
695
- OpenIdConnect.clearCachedApiGatewayAccessToken();
696
- }
697
-
698
- xhr.open("POST", url);
699
- xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
700
- xhr.send();
701
- } else {
702
- console.error(
703
- "The OpenID Connect call may have issues:\n" +
704
- "* the client ID could be invalid\n" +
705
- "* the API Gateway access token could be invalid\n" +
706
- "* the EU Login access token for the target service could be invalid."
707
- );
708
-
709
- if ((typeof errorCallbackFunction) == "function") {
710
- errorCallbackFunction(xhr);
711
- }
712
- }
713
- };
714
-
715
- xhr.retry();
716
- },
717
-
718
- doEcasProxyTicketRequest: function (url, onloadFunction, errorCallbackFunction) {
719
- var parameters = "" +
720
- "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer" +
721
- "&requested_token_type=urn:ietf:params:oauth:token-type:cas_ticket" +
722
- "&assertion=" + OpenIdConnect.signIdToken() +
723
- "&resource=" + encodeURIComponent(url) +
724
- "&client_id=" + OpenIdConnect.config.spaClientId;
725
- var url = OpenIdConnect.metadata.token_endpoint;
726
- url += (url.indexOf("?") > 0 ? "&" : "?") + parameters;
727
-
728
- var xhr = new XMLHttpRequest();
729
- xhr.withCredentials = true;
730
- xhr.onload = function () {
731
- if (this.readyState == 4) {
732
- if (this.status >= 200 && this.status < 300) {
733
- onloadFunction(OpenIdConnect.parseSafely(xhr, errorCallbackFunction));
734
- } else {
735
- OpenIdConnect.handleErrorResponse(xhr, errorCallbackFunction);
736
- }
737
- }
738
- };
739
- xhr.onerror = function () {
740
- OpenIdConnect.handleErrorResponse(xhr, errorCallbackFunction);
741
- };
742
- xhr.retry = function (clearApiGatewayAccessToken) {
743
- var retryCount = xhr.retryCount;
744
- if (retryCount == null) {
745
- retryCount = -1;
746
- }
747
- var maximumRequestRetries = OpenIdConnect.config.maximumRequestRetries;
748
- if (maximumRequestRetries == null) {
749
- maximumRequestRetries = OpenIdConnect.DEFAULT_MAX_REQUEST_RETRIES;
750
- }
751
- if (maximumRequestRetries == null) {
752
- maximumRequestRetries = 1;
753
- }
754
- if (retryCount < maximumRequestRetries) {
755
- xhr.retryCount = retryCount + 1;
756
- if (clearApiGatewayAccessToken) {
757
- // Clear the cached token to fully retry the request:
758
- OpenIdConnect.clearCachedApiGatewayAccessToken();
759
- }
760
-
761
- xhr.open("POST", url);
762
- xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
763
- xhr.send();
764
- } else {
765
- console.error(
766
- "The OpenID Connect call may have issues:\n" +
767
- "* the client ID could be invalid\n" +
768
- "* the API Gateway access token could be invalid\n" +
769
- "* the EU Login access token for the target service could be invalid."
770
- );
771
-
772
- if ((typeof errorCallbackFunction) == "function") {
773
- errorCallbackFunction(xhr);
774
- }
775
- }
776
- };
777
-
778
- xhr.retry();
779
- },
780
-
781
- continuePendingApiGatewayServiceRequests: function () {
782
- OpenIdConnect.requestingApiGatewayAccessToken = false;
783
-
784
- var queue = OpenIdConnect.waitForApiGatewayAccessTokenQueue;
785
- while (queue.length > 0) {
786
- // Extra timeout to prevent endless loop in case of accidental recursion due to still not being authorized because of an unknown issue:
787
- setTimeout(queue.pop(), 0);
788
- }
789
- },
790
-
791
- continuePendingUserTracking: function () {
792
- var fullName = sessionStorage.getItem(OpenIdConnect.SESSION_STORAGE_KEY_TRACK_USERNAME);
793
- if (fullName != null && (typeof dtrum) != "undefined" && (typeof dtrum.identifyUser) == "function") {
794
- dtrum.identifyUser(fullName);
795
- }
796
- sessionStorage.removeItem(OpenIdConnect.SESSION_STORAGE_KEY_TRACK_USERNAME);
797
-
798
- var loginAction = sessionStorage.getItem(OpenIdConnect.SESSION_STORAGE_KEY_TRACK_LOGIN);
799
- if (loginAction != null && (typeof dtrum) != "undefined" && (typeof dtrum.leaveAction) == "function" && (typeof dtrum.sendBeacon) == "function") {
800
- dtrum.leaveAction(loginAction);
801
- dtrum.sendBeacon(true, true, true);
802
- sessionStorage.removeItem(OpenIdConnect.SESSION_STORAGE_KEY_TRACK_LOGIN);
803
- }
804
- },
805
-
806
-
807
- // --------------- Utility functions ---------------
808
- idTokenPresentInLocation: function () {
809
- var href = window.top.location.href;
810
- if (href != null) {
811
- return href.indexOf("#id_token=") >= 0 || href.indexOf("&id_token=") >= 0;
812
- } else {
813
- return false;
814
- }
815
- },
816
-
817
- getIdToken: function (callbackFunction) {
818
- // This function support delayed logins and checking if the ID token is available.
819
- // Also waits for the ID token when a user is still logging in.
820
- if ((typeof callbackFunction) == "function") {
821
- var responseFunction = function () {
822
- callbackFunction(OpenIdConnect.decodeIdToken());
823
- };
824
-
825
- // Check if we are still initialising:
826
- if (OpenIdConnect.client == null || OpenIdConnect.config == null || OpenIdConnect.metadata == null || OpenIdConnect.idTokenPresentInLocation()) {
827
- OpenIdConnect.waitForIdTokenQueue.push(responseFunction);
828
- } else {
829
- responseFunction();
830
- }
831
- } else {
832
- console.error("You need to specify a callback function to be able to wait for the ID token to be retrieved.")
833
- }
834
- },
835
-
836
- preventIdTokenMurder: function () {
837
- // In case the UI framework uses hash-based Routers,
838
- // there can be certain race conditions where the ID token in the location's hash is being replaced with the default route,
839
- // while the OpenID Connect client is waiting for it's configuration to be loaded.
840
- // Since the OpenID Connect client cannot verify the ID token without the Identity Server's configuration, we have no choice but to store the id_token hash and to swap it out with the router's hash when verifying it.
841
- if (OpenIdConnect.idTokenPresentInLocation()) {
842
- hrefSavedFromIdTokenMurder = window.top.location.href;
843
- }
844
- },
845
-
846
- extractIdTokenFromLocation: function (callbackFunction) {
847
- if (callbackFunction != null && (typeof callbackFunction) == "function") {
848
- if (OpenIdConnect.client != null) {
849
- if (! isLocalDevelopmentEnvironment()) {
850
- if (hrefSavedFromIdTokenMurder != null) {
851
- if (! OpenIdConnect.extractingIdToken) {
852
- OpenIdConnect.extractingIdToken = true;
853
- OpenIdConnect.client.processSigninResponse(hrefSavedFromIdTokenMurder).then(function (response) {
854
- if (response != null && response.id_token) {
855
- callbackFunction(response.id_token);
856
- } else {
857
- console.error(response);
858
- OpenIdConnect.loginFailed(callbackFunction);
859
- }
860
- }).catch(function (error) {
861
- console.error(error);
862
- if (("" + error).indexOf("is in the future") >= 0) {
863
- console.error("The device's clock is running behind the world's time.\nUnable to validate the ID token.");
864
- alert("The clock on your device is running behind the world's time.\nWithout synchronized clocks, it's difficult to verify your identity.\nPlease change the clock on your device and restart the application.");
865
- OpenIdConnect.removeLocationHash();
866
- } else if (("" + error).indexOf("is in the past") >= 0) {
867
- alert("The log in failed.\nOne possible cause is that the clock on your device is ahead of the world's time.\nWithout synchronized clocks, it's difficult to verify your identity.\nIf your clock is set to a future date & time, please change the clock on your device.\n\nThe application will now attempt to log in again...");
868
- OpenIdConnect.loginFailed(callbackFunction);
869
- } else {
870
- OpenIdConnect.loginFailed(callbackFunction);
871
- }
872
- });
873
- }
874
- } else {
875
- OpenIdConnect.loginFailed(callbackFunction);
876
- }
877
- } else {
878
- var idTokenIndex = (hrefSavedFromIdTokenMurder != null ? (hrefSavedFromIdTokenMurder.indexOf("#id_token=") >= 0 ? hrefSavedFromIdTokenMurder.indexOf("#id_token=") : hrefSavedFromIdTokenMurder.indexOf("&id_token=") + 1) : -1);
879
- if (idTokenIndex >= 0) {
880
- callbackFunction(hrefSavedFromIdTokenMurder.substr(idTokenIndex).split("&")[0].split("=")[1]);
881
- } else {
882
- OpenIdConnect.loginFailed(callbackFunction);
883
- }
884
- }
885
- } else {
886
- // The client isn't loaded yet; wait for it to load:
887
- OpenIdConnect.waitForClientQueue.push(function () {
888
- OpenIdConnect.extractIdTokenFromLocation(callbackFunction);
889
- });
890
- }
891
- }
892
- },
893
-
894
- loginFailed: function (callbackFunction) {
895
- OpenIdConnect.removeLocationHash();
896
- if (callbackFunction != null && (typeof callbackFunction) == "function") {
897
- callbackFunction(undefined);
898
- }
899
- },
900
-
901
- getRequestParameter: function (name) {
902
- if (name = (new RegExp("[?&]" + encodeURIComponent(name) + "=([^&]*)")).exec(window.top.location.search)) {
903
- return decodeURIComponent(name [1]);
904
- } else {
905
- return null;
906
- }
907
- },
908
-
909
- renewIdToken: function () {
910
- if (OpenIdConnect.client != null) {
911
- // Check for errors first:
912
- var search = window.top.location.search;
913
- if (search.indexOf("?error=invalid_client") < 0 && search.indexOf("&error=invalid_client") < 0 && search.indexOf("?error=invalid_request") < 0 && search.indexOf("&error=invalid_request") < 0) {
914
- // First check if we are not in a login loop:
915
- var lastLoginAttempt = sessionStorage.getItem(OpenIdConnect.SESSION_STORAGE_KEY_LOGIN_TIMESTAMP);
916
- var now = new Date().getTime();
917
- if (lastLoginAttempt != null && (now - lastLoginAttempt) < 30000) {
918
- throw "Login loop detected; 2 login attempts were made in less than half a minute.\nCheck the OpenID Connect configuration for errors.";
919
- } else {
920
- sessionStorage.setItem(OpenIdConnect.SESSION_STORAGE_KEY_LOGIN_TIMESTAMP, now);
921
- }
922
-
923
- sessionStorage.removeItem(OpenIdConnect.SESSION_STORAGE_KEY_ID_TOKEN);
924
- // Also invalidate the API Gateway token because it can be used for authentication too:
925
- OpenIdConnect.clearCachedApiGatewayAccessToken();
926
- OpenIdConnect.trackUserLogin();
927
-
928
- var redirectUrl = OpenIdConnect.config.spaRedirectUrl;
929
- // Also allow the redirect URL to go to localhost in case of mock OpenIDConnect servers:
930
- if (! isLocalDevelopmentEnvironment() || isLocalDevelopmentEnvironment(redirectUrl)) {
931
- var developmentUrl = OpenIdConnect.getRequestParameter(OpenIdConnect.REQUEST_PARAMETER_DEVELOPMENT_URL);
932
- if (developmentUrl == null) {
933
- localStorage.setItem(OpenIdConnect.SESSION_STORAGE_KEY_ORIGINAL_URL, window.top.location.href);
934
- } else {
935
- localStorage.setItem(OpenIdConnect.SESSION_STORAGE_KEY_DEVELOPMENT_URL, developmentUrl);
936
- }
937
-
938
- var cnfParameter = publicKeyInJWKFormat;
939
- var developmentPublicKey = OpenIdConnect.getRequestParameter(OpenIdConnect.REQUEST_PARAMETER_DEVELOPMENT_PUBLIC_KEY);
940
- if (developmentPublicKey != null) {
941
- cnfParameter = developmentPublicKey
942
- }
943
- var extraQueryParams = { req_cnf: cnfParameter };
944
- if (OpenIdConnect.config.claims != null) {
945
- if ((typeof OpenIdConnect.config.claims) == "object") {
946
- extraQueryParams ["claims"] = JSON.stringify(OpenIdConnect.config.claims);
947
- } else if ((typeof OpenIdConnect.config.claims) == "string") {
948
- extraQueryParams ["claims"] = OpenIdConnect.config.claims;
949
- }
950
- }
951
-
952
- var extraEuLoginParameters = OpenIdConnect.config.extraEuLoginParameters;
953
- if (extraEuLoginParameters != null && (typeof extraEuLoginParameters) == "object") {
954
- for (var parameter in extraEuLoginParameters) {
955
- extraQueryParams [parameter] = extraEuLoginParameters [parameter];
956
- }
957
- }
958
-
959
- // Check for functional test account logins:
960
- var parameters = new URLSearchParams(window.top.location.search);
961
- if (parameters != null && parameters.get("1fa") != null) {
962
- extraQueryParams ["acr_values"] = "https://ecas.ec.europa.eu/loa/basic";
963
- }
964
-
965
- if (! OpenIdConnect.requestingLogin) {
966
- OpenIdConnect.requestingLogin = true;
967
- OpenIdConnect.client.createSigninRequest({redirect_uri: redirectUrl, extraQueryParams: extraQueryParams}).then(function (req) {
968
- if (req != null && req.url != null) {
969
- window.top.location.href = req.url;
970
- } else {
971
- window.top.location.href = redirectUrl;
972
- }
973
- }).catch(function (err) {
974
- console.error(err);
975
- });
976
- }
977
- } else {
978
- localStorage.setItem(OpenIdConnect.SESSION_STORAGE_KEY_ORIGINAL_URL, window.top.location.href);
979
-
980
- // Automatically add the return URL:
981
- if (redirectUrl.indexOf(OpenIdConnect.REQUEST_PARAMETER_DEVELOPMENT_URL) < 0) {
982
- var currentUrl = window.top.location.href;
983
- redirectUrl = redirectUrl + (redirectUrl.indexOf("?") >= 0 ? "&" : "?") + OpenIdConnect.REQUEST_PARAMETER_DEVELOPMENT_URL + "=" + encodeURIComponent(currentUrl);
984
- // Check for single-factor authentication override:
985
- if (currentUrl != null && currentUrl.indexOf("?1fa") >= 0 || currentUrl.indexOf("&1fa") >= 0) {
986
- redirectUrl += "&1fa";
987
- }
988
- }
989
- if (redirectUrl.indexOf(OpenIdConnect.REQUEST_PARAMETER_DEVELOPMENT_PUBLIC_KEY) < 0) {
990
- redirectUrl = redirectUrl + (redirectUrl.indexOf("?") >= 0 ? "&" : "?") + OpenIdConnect.REQUEST_PARAMETER_DEVELOPMENT_PUBLIC_KEY + "=" + publicKeyInJWKFormat;
991
- }
992
- window.top.location.href = redirectUrl;
993
- }
994
- } else {
995
- throw "EU Login does not recognise the application; please configure a proper OpenID Connect client ID.\n" +
996
- "This is configured in the spaClientId environment variable.";
997
- }
998
- } else {
999
- // The client isn't loaded yet; wait for it to load:
1000
- OpenIdConnect.waitForClientQueue.push(OpenIdConnect.renewIdToken);
1001
- }
1002
- },
1003
-
1004
- decodeJwtToken: function (jwtToken) {
1005
- if (jwtToken != null) {
1006
- var base64Url = jwtToken.split(".")[1];
1007
- return JSON.parse(b64utoutf8(base64Url));
1008
- } else {
1009
- return null;
1010
- }
1011
- },
1012
-
1013
- decodeIdToken: function (callback) {
1014
- if (callback != null) {
1015
- var decodeIdToken = function () {
1016
- callback(OpenIdConnect.decodeJwtToken(sessionStorage.getItem(OpenIdConnect.SESSION_STORAGE_KEY_ID_TOKEN)));
1017
- };
1018
-
1019
- if (sessionStorage.getItem(OpenIdConnect.SESSION_STORAGE_KEY_ID_TOKEN) != null) {
1020
- decodeIdToken();
1021
- } else {
1022
- OpenIdConnect.waitForIdTokenQueue.push(decodeIdToken);
1023
- }
1024
- } else {
1025
- var idToken = sessionStorage.getItem(OpenIdConnect.SESSION_STORAGE_KEY_ID_TOKEN);
1026
- if (idToken != null) {
1027
- return OpenIdConnect.decodeJwtToken(idToken);
1028
- } else {
1029
- return null;
1030
- }
1031
- }
1032
- },
1033
-
1034
- saveUserToSessionStorage: function (idToken) {
1035
- if (idToken != null) {
1036
- sessionStorage.setItem(OpenIdConnect.SESSION_STORAGE_KEY_ID_TOKEN, idToken);
1037
- // Also invalidate the API Gateway token because it can be used for authentication too:
1038
- OpenIdConnect.clearCachedApiGatewayAccessToken();
1039
-
1040
- var tokenObject = OpenIdConnect.decodeJwtToken(idToken);
1041
- if (tokenObject != null) {
1042
- // Also validate the audienceId of the SPA:
1043
- if (tokenObject.aud === OpenIdConnect.config.spaClientId) {
1044
- sessionStorage.setItem(OpenIdConnect.SESSION_STORAGE_KEY_USER_DETAILS, JSON.stringify({
1045
- userId: tokenObject.sub,
1046
- departmentNumber: null,
1047
- domain: tokenObject.domain,
1048
- domainUsername: tokenObject.preferred_username,
1049
- email: tokenObject.email,
1050
- firstName: tokenObject.given_name,
1051
- lastName: tokenObject.family_name
1052
- }));
1053
- OpenIdConnect.trackUserName(tokenObject);
1054
- } else {
1055
- console.error("Not accepting ID token; incorrect audience (SPA) detected.");
1056
- }
1057
- } else {
1058
- console.error("Not accepting ID token; replay detected.");
1059
- }
1060
- }
1061
- },
1062
-
1063
- removeLocationHash: function () {
1064
- if (OpenIdConnect.idTokenPresentInLocation() && (OpenIdConnect.config == null || (OpenIdConnect.config.stripIdTokenFromLocation == null || OpenIdConnect.config.stripIdTokenFromLocation))) {
1065
- var location = window.top.location;
1066
- if ("pushState" in history) {
1067
- history.pushState("", document.title, location.pathname + location.search);
1068
- } else {
1069
- location.hash = "";
1070
- }
1071
- }
1072
- },
1073
-
1074
- navigateToOriginallyRequestedUrl: function (idToken) {
1075
- if (OpenIdConnect.config != null && OpenIdConnect.config.enabled) {
1076
- var originalUrl = localStorage.getItem(OpenIdConnect.SESSION_STORAGE_KEY_ORIGINAL_URL);
1077
- var developmentUrl = localStorage.getItem(OpenIdConnect.SESSION_STORAGE_KEY_DEVELOPMENT_URL);
1078
- // Remove any deep-linking state before redirecting:
1079
- localStorage.removeItem(OpenIdConnect.SESSION_STORAGE_KEY_ORIGINAL_URL);
1080
- localStorage.removeItem(OpenIdConnect.SESSION_STORAGE_KEY_DEVELOPMENT_URL);
1081
-
1082
- if (OpenIdConnect.config.allowDevelopmentLogin && developmentUrl != null && developmentUrl.length > 0) {
1083
- if (isLocalDevelopmentEnvironment(developmentUrl)) {
1084
- window.top.location.href = developmentUrl + "#id_token=" + idToken;
1085
- } else {
1086
- console.warn("Not a development URL: " + developmentUrl);
1087
- }
1088
- } else if (originalUrl != null) {
1089
- // setTimeout is to fix a bug when URL fragments are being used in the original URL:
1090
- setTimeout(function () {
1091
- window.top.location.href = originalUrl;
1092
- }, 0);
1093
- }
1094
- }
1095
- },
1096
-
1097
- urlMatches: function (requestUrl, serviceUrl) {
1098
- return serviceUrl != "" && new RegExp("^" + serviceUrl.replace(/\*/g, ".*")).test(requestUrl);
1099
- },
1100
-
1101
- cachedApiGatewayAccessTokenHasExpired: function () {
1102
- var cachedAccessToken = OpenIdConnect.getCachedApiGatewayAccessToken();
1103
- if (cachedAccessToken != null) {
1104
- var tokenObject = OpenIdConnect.decodeJwtToken(cachedAccessToken.access_token);
1105
- if (tokenObject != null && tokenObject.exp != null) {
1106
- var expirationTimeInMilliseconds = 1000 * tokenObject.exp;
1107
- return new Date().getTime() >= expirationTimeInMilliseconds;
1108
- } else {
1109
- return true;
1110
- }
1111
- } else {
1112
- return true;
1113
- }
1114
- },
1115
-
1116
- getCachedApiGatewayAccessToken: function () {
1117
- var accessToken = sessionStorage.getItem(OpenIdConnect.SESSION_STORAGE_KEY_API_GATEWAY_ACCESS_TOKEN);
1118
- if (accessToken) {
1119
- try {
1120
- return JSON.parse(accessToken);
1121
- } catch (error) {
1122
- console.warn("Unable to parse cached API Gateway access token; now attempting to renew it...");
1123
- return null;
1124
- }
1125
- } else {
1126
- return null;
1127
- }
1128
- },
1129
-
1130
- storeCachedApiGatewayAccessToken: function (apiGatewayToken) {
1131
- if (apiGatewayToken) {
1132
- sessionStorage.setItem(OpenIdConnect.SESSION_STORAGE_KEY_API_GATEWAY_ACCESS_TOKEN, JSON.stringify(apiGatewayToken));
1133
- }
1134
- },
1135
-
1136
- clearCachedApiGatewayAccessToken: function () {
1137
- sessionStorage.removeItem(OpenIdConnect.SESSION_STORAGE_KEY_API_GATEWAY_ACCESS_TOKEN);
1138
- },
1139
-
1140
- getImpersonatedUserId: function () {
1141
- return sessionStorage.getItem(OpenIdConnect.SESSION_STORAGE_KEY_IMPERSONATED_USER_ID);
1142
- },
1143
-
1144
- storeImpersonatedUserId: function (userId) {
1145
- if (userId != null) {
1146
- sessionStorage.setItem(OpenIdConnect.SESSION_STORAGE_KEY_IMPERSONATED_USER_ID, userId);
1147
- } else {
1148
- OpenIdConnect.clearImpersonatedUserId();
1149
- }
1150
- },
1151
-
1152
- clearImpersonatedUserId: function () {
1153
- sessionStorage.removeItem(OpenIdConnect.SESSION_STORAGE_KEY_IMPERSONATED_USER_ID);
1154
- },
1155
-
1156
- addImpersonationHeaders: function (headers) {
1157
- if (headers != null) {
1158
- var apiGatewayAccessToken = OpenIdConnect.getCachedApiGatewayAccessToken();
1159
- if (apiGatewayAccessToken != null && apiGatewayAccessToken.access_token != null) {
1160
- var tokenObject = OpenIdConnect.decodeJwtToken(apiGatewayAccessToken.access_token);
1161
- if (tokenObject && tokenObject.imp_userId) {
1162
- headers ["Impersonated"] = apiGatewayAccessToken.access_token;
1163
- }
1164
- }
1165
- }
1166
-
1167
- return headers;
1168
- },
1169
-
1170
- initializeKeypair: function () {
1171
- var serializedPublicKey = localStorage.getItem(OpenIdConnect.SESSION_STORAGE_KEY_PUBLIC_KEY);
1172
- var serializedPrivateKey = localStorage.getItem(OpenIdConnect.SESSION_STORAGE_KEY_PRIVATE_KEY);
1173
-
1174
- if (serializedPublicKey == null || serializedPrivateKey == null) {
1175
- keypair = KEYUTIL.generateKeypair("EC");
1176
- serializedPublicKey = KEYUTIL.getPEM(keypair.pubKeyObj);
1177
- serializedPrivateKey = KEYUTIL.getPEM(keypair.prvKeyObj, "PKCS8PRV");
1178
-
1179
- localStorage.setItem(OpenIdConnect.SESSION_STORAGE_KEY_PUBLIC_KEY, serializedPublicKey);
1180
- localStorage.setItem(OpenIdConnect.SESSION_STORAGE_KEY_PRIVATE_KEY, serializedPrivateKey);
1181
- } else {
1182
- keypair = {
1183
- pubKeyObj: KEYUTIL.getKey(serializedPublicKey),
1184
- prvKeyObj: KEYUTIL.getKey(serializedPrivateKey)
1185
- }
1186
- }
1187
- publicKeyInJWKFormat = window.btoa(JSON.stringify(KEYUTIL.getJWKFromKey(keypair.pubKeyObj)));
1188
- },
1189
-
1190
- signIdToken: function (algorithm) {
1191
- if ((typeof algorithm) == "undefined") {
1192
- algorithm = OpenIdConnect.DEFAULT_ID_TOKEN_SIGNING_ALGORITHM;
1193
- }
1194
-
1195
- var idToken = sessionStorage.getItem(OpenIdConnect.SESSION_STORAGE_KEY_ID_TOKEN);
1196
- var now = new Date().getTime();
1197
- var expiration = now + 1000 * 60; // 1 minute
1198
- var body = {
1199
- "iss" : OpenIdConnect.config.spaClientId,
1200
- "sub" : OpenIdConnect.config.spaClientId,
1201
- "aud" : OpenIdConnect.metadata.token_endpoint,
1202
- "jti" : KJUR.crypto.Util.getRandomHexOfNbytes(32),
1203
- "exp" : expiration,
1204
- "iat" : now,
1205
- "id_token" : idToken
1206
- };
1207
-
1208
- return KJUR.jws.JWS.sign(algorithm, '{"alg": "' + algorithm + '", "cty":"JWT"}', JSON.stringify(body), keypair.prvKeyObj);
1209
- },
1210
-
1211
- signAccessToken: function (accessToken, algorithm) {
1212
- if ((typeof algorithm) == "undefined") {
1213
- algorithm = OpenIdConnect.DEFAULT_ACCESS_TOKEN_SIGNING_ALGORITHM;
1214
- }
1215
-
1216
- var body = {
1217
- "at": accessToken,
1218
- "ts": new Date().getTime()
1219
- };
1220
-
1221
- return KJUR.jws.JWS.sign(algorithm, '{"alg": "' + algorithm + '", "cty":"JWT"}', JSON.stringify(body), keypair.prvKeyObj);
1222
- },
1223
-
1224
- parseSafely: function (xhr, errorCallbackFunction) {
1225
- try {
1226
- return JSON.parse(xhr.responseText);
1227
- } catch (error) {
1228
- OpenIdConnect.handleErrorResponse(xhr, errorCallbackFunction);
1229
- throw(error);
1230
- }
1231
- },
1232
-
1233
- continuePendingConfigRequests: function () {
1234
- var queue = OpenIdConnect.waitForConfigQueue;
1235
- while (queue.length > 0) {
1236
- // Extra timeout to prevent endless loop in case of accidental recursion due to still not being authorized because of an unknown issue:
1237
- setTimeout(queue.pop(), 0);
1238
- }
1239
- },
1240
-
1241
- makeSessionApplicationSpecific: function () {
1242
- // Sometimes multiple applications are deployed on the same domain.
1243
- // Make the session application-specific:
1244
- if (OpenIdConnect.config != null && OpenIdConnect.config.spaClientId != null) {
1245
- var applicationSuffix = "-" + OpenIdConnect.config.spaClientId;
1246
- OpenIdConnect.SESSION_STORAGE_KEY_ID_TOKEN += applicationSuffix;
1247
- OpenIdConnect.SESSION_STORAGE_KEY_USER_DETAILS += applicationSuffix;
1248
- OpenIdConnect.SESSION_STORAGE_KEY_API_GATEWAY_ACCESS_TOKEN += applicationSuffix;
1249
- OpenIdConnect.SESSION_STORAGE_KEY_IMPERSONATED_USER_ID += applicationSuffix;
1250
- OpenIdConnect.SESSION_STORAGE_KEY_DEVELOPMENT_URL += applicationSuffix;
1251
- OpenIdConnect.SESSION_STORAGE_KEY_ORIGINAL_URL += applicationSuffix;
1252
- OpenIdConnect.SESSION_STORAGE_KEY_PUBLIC_KEY += applicationSuffix;
1253
- OpenIdConnect.SESSION_STORAGE_KEY_PRIVATE_KEY += applicationSuffix;
1254
- OpenIdConnect.SESSION_STORAGE_KEY_LOGIN_TIMESTAMP += applicationSuffix;
1255
- }
1256
- },
1257
-
1258
- trackUserLogin: function () {
1259
- if ((typeof dtrum) != "undefined" && (typeof dtrum.actionName) == "function" && (typeof dtrum.enterAction) == "function" && (typeof dtrum.sendBeacon) == "function") {
1260
- sessionStorage.setItem(OpenIdConnect.SESSION_STORAGE_KEY_TRACK_LOGIN, dtrum.enterAction("EU Login (old client)"));
1261
- dtrum.actionName("EU Login (old client)");
1262
- dtrum.sendBeacon(true, true, true);
1263
- }
1264
- },
1265
-
1266
- trackUserName: function (tokenObject) {
1267
- if (tokenObject != null) {
1268
- var firstName = tokenObject.given_name;
1269
- if (firstName == "UNKNOWN") {
1270
- firstName = tokenObject.sub;
1271
- }
1272
- var lastName = tokenObject.family_name;
1273
- if (lastName == "UNKNOWN") {
1274
- lastName = "Generic User";
1275
- }
1276
- var fullName = lastName + " " + firstName;
1277
-
1278
- if ((typeof dtrum) != "undefined" && (typeof dtrum.identifyUser) == "function") {
1279
- dtrum.identifyUser(fullName);
1280
- } else {
1281
- // The username will be picked up after restoring the original URL:
1282
- sessionStorage.setItem(OpenIdConnect.SESSION_STORAGE_KEY_TRACK_USERNAME, fullName);
1283
- }
1284
- }
1285
- }
1286
- };
1287
-
1288
- window.OpenIdConnect = OpenIdConnect;
1289
-
1290
- try {
1291
- OpenIdConnect.preventIdTokenMurder();
1292
- OpenIdConnect.loadConfiguration(function () {
1293
- if (OpenIdConnect.config != null && OpenIdConnect.config.enabled) {
1294
- OpenIdConnect.makeSessionApplicationSpecific();
1295
- OpenIdConnect.initializeKeypair();
1296
- OpenIdConnect.configInitialised = true;
1297
- OpenIdConnect.continuePendingConfigRequests();
1298
- if (OpenIdConnect.config.autoLogin == null || OpenIdConnect.config.autoLogin) {
1299
- OpenIdConnect.loginWithOpenIDConnect();
1300
- } else {
1301
- OpenIdConnect.loginWithOpenIDConnect(true);
1302
- }
1303
- } else {
1304
- OpenIdConnect.configInitialised = true;
1305
- OpenIdConnect.continuePendingConfigRequests();
1306
- }
1307
- });
1308
- } catch (error) {
1309
- console.error(error);
1310
- }
1311
- }());