@huntsman-cancer-institute/authentication 16.0.1 → 17.0.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.
@@ -17,502 +17,502 @@ import { map, catchError, first, takeWhile } from 'rxjs/operators';
17
17
  import * as i2$1 from '@angular/platform-browser';
18
18
  import { trigger, state, style, transition, animate } from '@angular/animations';
19
19
 
20
- let AUTHENTICATION_TOKEN_KEY = new InjectionToken("authentication_token_key");
21
- class AuthenticationProvider {
22
- constructor(_localStorageService, _authenticationTokenKey) {
23
- this._localStorageService = _localStorageService;
24
- this._authenticationTokenKey = _authenticationTokenKey;
25
- this.whitelistedDomains = [
26
- "localhost",
27
- new RegExp(".*[.]utah[.]edu")
28
- ];
29
- this.tokenGetter = () => {
30
- return this.authToken;
31
- };
32
- }
33
- get authenticationTokenKey() {
34
- return this._authenticationTokenKey;
35
- }
36
- set authenticationTokenKey(_authenticationTokenKey) {
37
- this._authenticationTokenKey = _authenticationTokenKey;
38
- }
39
- get authToken() {
40
- return this._localStorageService.getItem(this._authenticationTokenKey);
41
- }
42
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AuthenticationProvider, deps: [{ token: i1.CoolLocalStorage }, { token: AUTHENTICATION_TOKEN_KEY }], target: i0.ɵɵFactoryTarget.Injectable }); }
43
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AuthenticationProvider }); }
44
- }
45
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AuthenticationProvider, decorators: [{
46
- type: Injectable
47
- }], ctorParameters: function () { return [{ type: i1.CoolLocalStorage }, { type: undefined, decorators: [{
48
- type: Inject,
49
- args: [AUTHENTICATION_TOKEN_KEY]
50
- }] }]; } });
20
+ let AUTHENTICATION_TOKEN_KEY = new InjectionToken("authentication_token_key");
21
+ class AuthenticationProvider {
22
+ constructor(_localStorageService, _authenticationTokenKey) {
23
+ this._localStorageService = _localStorageService;
24
+ this._authenticationTokenKey = _authenticationTokenKey;
25
+ this.whitelistedDomains = [
26
+ "localhost",
27
+ new RegExp(".*[.]utah[.]edu")
28
+ ];
29
+ this.tokenGetter = () => {
30
+ return this.authToken;
31
+ };
32
+ }
33
+ get authenticationTokenKey() {
34
+ return this._authenticationTokenKey;
35
+ }
36
+ set authenticationTokenKey(_authenticationTokenKey) {
37
+ this._authenticationTokenKey = _authenticationTokenKey;
38
+ }
39
+ get authToken() {
40
+ return this._localStorageService.getItem(this._authenticationTokenKey);
41
+ }
42
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: AuthenticationProvider, deps: [{ token: i1.CoolLocalStorage }, { token: AUTHENTICATION_TOKEN_KEY }], target: i0.ɵɵFactoryTarget.Injectable }); }
43
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: AuthenticationProvider }); }
44
+ }
45
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: AuthenticationProvider, decorators: [{
46
+ type: Injectable
47
+ }], ctorParameters: () => [{ type: i1.CoolLocalStorage }, { type: undefined, decorators: [{
48
+ type: Inject,
49
+ args: [AUTHENTICATION_TOKEN_KEY]
50
+ }] }] });
51
51
 
52
- /*
53
- * Copyright (c) 2016 Huntsman Cancer Institute at the University of Utah, Confidential and Proprietary
54
- */
55
- /**
56
- * The token used for injection of the server side endpoint for the currently authenticated subject.
57
- *
58
- * @type {InjectionToken}
59
- */
60
- let AUTHENTICATION_SERVER_URL = new InjectionToken("authentication_server_rest_api");
61
- let AUTHENTICATION_LOGOUT_PATH = new InjectionToken("authentication_logout_path");
62
- let AUTHENTICATION_DIRECT_ENDPOINT = new InjectionToken("authentication_direct_endpoint");
63
- let AUTHENTICATION_TOKEN_ENDPOINT = new InjectionToken("authentication_token_endpoint");
64
- let AUTHENTICATION_ROUTE = new InjectionToken("authentication_route");
65
- let AUTHENTICATION_MAX_INACTIVITY_MINUTES = new InjectionToken("authentication_max_inactivity");
66
- let AUTHENTICATION_USER_COUNTDOWN_SECONDS = new InjectionToken("authentication_user_countdown_seconds");
67
- let AUTHENTICATION_IDP_INACTIVITY_MINUTES = new InjectionToken("authentication_idp_inactivity_minutes");
68
- /**
69
- * @since 1.0.0
70
- */
71
- class AuthenticationService {
72
- /**
73
- * The generic error message used when a server error is thrown without a status.
74
- *
75
- * @type {string}
76
- */
77
- static { this.GENERIC_ERR_MSG = "Server error"; }
78
- static { this.CONTENT_TYPE = "Content-Type"; }
79
- static { this.SEC_GOV_CLASS_HEADER = "SecurityGovernorClass"; }
80
- static { this.SEC_GOV_ID_HEADER = "SecurityGovernorId"; }
81
- static { this.DEIDENT_HEADER = "DeidentifiedContext"; }
82
- static { this.LIMITED_HEADER = "LimitedContext"; }
83
- constructor(_http, _router, _localStorageService, _jwtHelper, authenticationProvider, _authenticationRoute, _logoutPath, _tokenEndpoint, _serverUrl, _directEndpoint, _maxInactivity, _userCountdownSeconds, _idpInactivityMinutes, locationStrategy) {
84
- this._http = _http;
85
- this._router = _router;
86
- this._localStorageService = _localStorageService;
87
- this._jwtHelper = _jwtHelper;
88
- this.authenticationProvider = authenticationProvider;
89
- this._authenticationRoute = _authenticationRoute;
90
- this._logoutPath = _logoutPath;
91
- this._tokenEndpoint = _tokenEndpoint;
92
- this._serverUrl = _serverUrl;
93
- this._directEndpoint = _directEndpoint;
94
- this._maxInactivity = _maxInactivity;
95
- this._userCountdownSeconds = _userCountdownSeconds;
96
- this._idpInactivityMinutes = _idpInactivityMinutes;
97
- this.locationStrategy = locationStrategy;
98
- this.userCountdownSeconds = 60;
99
- this.idpInactivityMinutes = 5;
100
- this.contentType = "application/json";
101
- this.limitedContext = false;
102
- this.deidentifiedContext = false;
103
- this.maxViewPermission = new BehaviorSubject("viewident");
104
- this._isAuthenticatedSubject = new BehaviorSubject(false);
105
- this._userIsAboutToTimeOut = new BehaviorSubject(false);
106
- this._maxInactivityMinutes = 120;
107
- this.contextRoot = "";
108
- if (isDevMode()) {
109
- console.debug("window.location.href: " + window.location.href);
110
- }
111
- if (window.location) {
112
- let parts = window.location.href.split("/");
113
- this.baseUrl = parts[0] + "//" + parts[2];
114
- if (parts.length > 3) {
115
- this.contextRoot = parts[3];
116
- }
117
- }
118
- if (this._localStorageService.getItem("maxViewPermission")) {
119
- this.maxViewPermission.next(this._localStorageService.getItem("maxViewPermission"));
120
- }
121
- if (_maxInactivity) {
122
- this._maxInactivityMinutes = _maxInactivity;
123
- }
124
- if (_userCountdownSeconds) {
125
- this.userCountdownSeconds = _userCountdownSeconds;
126
- }
127
- if (_idpInactivityMinutes) {
128
- this.idpInactivityMinutes = _idpInactivityMinutes;
129
- }
130
- this.hasValidConfig();
131
- //There could be a non-expired token in local storage.
132
- let token = this.authenticationProvider.authToken;
133
- this.storeToken(token);
134
- }
135
- getBaseUrl() {
136
- return (this.baseUrl) ? this.baseUrl : "";
137
- }
138
- getContextRoot() {
139
- return this.contextRoot;
140
- }
141
- getHeaders(req) {
142
- let headers = req.headers;
143
- //Don't set content type if already set
144
- if (!req.headers.get(AuthenticationService.CONTENT_TYPE)) {
145
- headers = headers.set(AuthenticationService.CONTENT_TYPE, this.contentType.toString());
146
- }
147
- if (headers.get(AuthenticationService.SEC_GOV_CLASS_HEADER) === "") {
148
- headers = headers.delete(AuthenticationService.SEC_GOV_CLASS_HEADER);
149
- }
150
- else if (this.securityGovernorClass && !headers.get(AuthenticationService.SEC_GOV_CLASS_HEADER)) {
151
- headers = headers.set(AuthenticationService.SEC_GOV_CLASS_HEADER, this.securityGovernorClass);
152
- }
153
- if (headers.get(AuthenticationService.SEC_GOV_ID_HEADER) === "") {
154
- headers = headers.delete(AuthenticationService.SEC_GOV_ID_HEADER);
155
- }
156
- else if (this.securityGovernorId && !headers.get(AuthenticationService.SEC_GOV_ID_HEADER)) {
157
- headers = headers.set(AuthenticationService.SEC_GOV_ID_HEADER, this.securityGovernorId.toString());
158
- }
159
- headers = headers.set(AuthenticationService.DEIDENT_HEADER, this.deidentifiedContext.toString());
160
- headers = headers.set(AuthenticationService.LIMITED_HEADER, this.limitedContext.toString());
161
- return headers;
162
- }
163
- get authenticationTokenKey() {
164
- return this.authenticationProvider.authenticationTokenKey;
165
- }
166
- get authToken() {
167
- return this.authenticationProvider.authToken;
168
- }
169
- updateUserActivity() {
170
- if (this._isAuthenticatedSubject.value) {
171
- this._lastUserInteraction = new Date();
172
- this._userIsAboutToTimeOut.next(false);
173
- }
174
- }
175
- /**
176
- * A mutator for identifying the clients original request location. Setting this value will influence the end location
177
- * navigated to by {@link #navigateToPath}.
178
- *
179
- * @param redirectUrl location of the users request before authentication
180
- */
181
- set redirectUrl(redirectUrl) {
182
- this._redirectUrl = redirectUrl;
183
- }
184
- get redirectUrl() {
185
- return this._redirectUrl;
186
- }
187
- requestAccessToken(redirectOnSuccess) {
188
- this._http.get(this.tokenLocation(), { withCredentials: true })
189
- .subscribe((response) => {
190
- this.storeToken(response.auth_token);
191
- if (redirectOnSuccess) {
192
- this.proceedIfAuthenticated();
193
- }
194
- }, (error) => {
195
- //Token refresh failed.
196
- this.logout(true);
197
- });
198
- }
199
- /**
200
- * Verifies whether or not a current user session exists.
201
- *
202
- * @returns {Observable<boolean>} evaluates to true if the user is authenticated, false otherwise.
203
- */
204
- isAuthenticated() {
205
- return this._isAuthenticatedSubject.asObservable();
206
- }
207
- isAboutToTimeOut() {
208
- return this._userIsAboutToTimeOut.asObservable();
209
- }
210
- getTimeoutStart() {
211
- if (this._lastUserInteraction) {
212
- return this._lastUserInteraction.valueOf() + (((this._maxInactivityMinutes * 60) - this.userCountdownSeconds) * 1000);
213
- }
214
- }
215
- tokenLocation() {
216
- if (this._serverUrl) {
217
- return this._serverUrl + this._tokenEndpoint;
218
- }
219
- else {
220
- return this._tokenEndpoint;
221
- }
222
- }
223
- directLoginLocation() {
224
- if (this._serverUrl) {
225
- return this._serverUrl + this._directEndpoint;
226
- }
227
- else {
228
- return this._directEndpoint;
229
- }
230
- }
231
- logoutLocation() {
232
- if (this._serverUrl) {
233
- return this._serverUrl + this._logoutPath;
234
- }
235
- else {
236
- return this._logoutPath;
237
- }
238
- }
239
- /**
240
- * A function to authenticated the user with the provided credentials. Failure results in an error that describes the
241
- * server response (status and status message) and should be actionable by the client application.
242
- *
243
- * @param username of the authenticating user to verify
244
- * @param password of the authenticating user to verify
245
- * @returns {Observable<R>} describing the result of the login action, true or an error
246
- */
247
- login(_username, _password) {
248
- return this._http.post(this.directLoginLocation(), { username: _username, password: _password }, { observe: "response" }).pipe(map((resp) => {
249
- if (resp.status === 201) {
250
- return true;
251
- }
252
- else {
253
- throw new Error("Authentication failed. " + resp.status + ": " + resp.statusText);
254
- }
255
- }), catchError(this.handleError));
256
- }
257
- clearLogin() {
258
- //Front-end logout
259
- try {
260
- this._localStorageService.removeItem(this.authenticationProvider.authenticationTokenKey);
261
- this.unsubscribeFromTokenRefresh();
262
- this._isAuthenticatedSubject.next(false);
263
- this._userIsAboutToTimeOut.next(false);
264
- }
265
- catch (Error) {
266
- }
267
- //Back-end logout
268
- let headers = new HttpHeaders().set(AuthenticationService.CONTENT_TYPE, "text/plain");
269
- return this._http.get(this.logoutLocation(), { headers: headers });
270
- }
271
- /**
272
- * A function to signal the termination of the current session. Invoking this function will clean up any relevant state
273
- * related to the last active session.
274
- */
275
- logout(keepCurrentRoute = false) {
276
- //Prevent logout if already on authentication route. Doing otherwise screws up SAML
277
- if (!this._router.routerState || this._router.routerState.snapshot.url !== this._authenticationRoute) {
278
- this._redirectUrl = (keepCurrentRoute && this._router.routerState && this._router.routerState.snapshot) ? this._router.routerState.snapshot.url : "";
279
- if (this._redirectUrl.startsWith("/")) {
280
- this._redirectUrl = this._redirectUrl.substring(1);
281
- }
282
- this.clearLogin().subscribe((response) => {
283
- window.location.replace(this._redirectUrl);
284
- }, (error) => {
285
- window.location.replace(this._redirectUrl);
286
- });
287
- }
288
- }
289
- storeToken(token) {
290
- let valid = this.validateToken(token);
291
- // unsubscribe from refesh before we decide wether to resubscribe
292
- this.unsubscribeFromTokenRefresh();
293
- if (valid) {
294
- this._localStorageService.setItem(this.authenticationProvider.authenticationTokenKey, token);
295
- this.subscribeToTokenRefresh(token);
296
- //Change the BehaviorSubject if the user was not previously authenticated.
297
- //Since other code may be subscribing to this observable, we don't want to cause new events to fire if just refreshing the JWT.
298
- if (!this._isAuthenticatedSubject.value) {
299
- this._isAuthenticatedSubject.next(true);
300
- }
301
- }
302
- else {
303
- this._localStorageService.removeItem(this.authenticationProvider.authenticationTokenKey);
304
- this._isAuthenticatedSubject.next(false);
305
- }
306
- }
307
- proceedIfAuthenticated() {
308
- if (isDevMode()) {
309
- console.debug("AuthenticationService.proceedIfAuthenticated: " + this._redirectUrl);
310
- }
311
- if (this._isAuthenticatedSubject.value) {
312
- //Login counts as user activity, too
313
- this.updateUserActivity();
314
- if (this._redirectUrl && this._redirectUrl && this._redirectUrl !== "") {
315
- this._router.navigateByUrl(this._redirectUrl);
316
- }
317
- else {
318
- this._router.navigate([""]);
319
- }
320
- return true;
321
- }
322
- else {
323
- return false;
324
- }
325
- }
326
- validateToken(token) {
327
- return (token && !this._jwtHelper.isTokenExpired(token));
328
- }
329
- subscribeToTokenRefresh(token) {
330
- let exp = this._jwtHelper.getTokenExpirationDate(token);
331
- // Use a timer to periodically check timeouts
332
- this._refreshSubscription = interval(1000)
333
- .subscribe(() => {
334
- // If a tab is inactive we can't know if our timer is accurate
335
- // so when the interval hits check against timestamps
336
- if (this._isAuthenticatedSubject.value && Date.now() > this.getTimeoutStart()) {
337
- //Don't update the subject more than once! Doing so initializes more than one countdown timer!
338
- if (this._userIsAboutToTimeOut.getValue() !== true) {
339
- this._userIsAboutToTimeOut.next(true);
340
- }
341
- }
342
- // check for refresh token
343
- let msToExpiry = (exp.valueOf() - new Date().valueOf());
344
- // Refresh 60 seconds before expiry
345
- if (msToExpiry <= 60000) {
346
- this.refreshTokenIfUserIsActive();
347
- }
348
- });
349
- }
350
- unsubscribeFromTokenRefresh() {
351
- if (this._refreshSubscription && !this._refreshSubscription.closed) {
352
- this._refreshSubscription.unsubscribe();
353
- }
354
- }
355
- getMaxViewPermission() {
356
- return this.maxViewPermission.getValue();
357
- }
358
- getMaxViewPermissionSubject() {
359
- return this.maxViewPermission;
360
- }
361
- setMaxViewPermission(maxViewPermission) {
362
- this._localStorageService.setItem("maxViewPermission", maxViewPermission);
363
- this.maxViewPermission.next(maxViewPermission);
364
- }
365
- refreshTokenIfUserIsActive() {
366
- //Only refresh if the user has been active
367
- if (this._lastUserInteraction && ((new Date().valueOf() - this._lastUserInteraction.valueOf()) <= (this._maxInactivityMinutes * 60 * 1000))) {
368
- this.requestAccessToken(false);
369
- }
370
- }
371
- hasValidConfig() {
372
- if (this._tokenEndpoint == null && (this._serverUrl === null || this._logoutPath === null)) {
373
- throw new Error("BUG ALERT! Invalid AuthenticationService configuration. No valid configuration for authentication endpoint(s).");
374
- }
375
- if (this._localStorageService === null || this.authenticationProvider.authenticationTokenKey === null) {
376
- throw new Error("BUG ALERT! Invalid AuthenticationService configuration. No valid configuration for local storage");
377
- }
378
- }
379
- handleError(error) {
380
- let errMsg = (error.message) ? error.message : AuthenticationService.GENERIC_ERR_MSG;
381
- return throwError(errMsg);
382
- }
383
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AuthenticationService, deps: [{ token: i1$1.HttpClient }, { token: i2.Router }, { token: i1.CoolLocalStorage }, { token: i4.JwtHelperService }, { token: AuthenticationProvider }, { token: AUTHENTICATION_ROUTE }, { token: AUTHENTICATION_LOGOUT_PATH }, { token: AUTHENTICATION_TOKEN_ENDPOINT }, { token: AUTHENTICATION_SERVER_URL, optional: true }, { token: AUTHENTICATION_DIRECT_ENDPOINT, optional: true }, { token: AUTHENTICATION_MAX_INACTIVITY_MINUTES, optional: true }, { token: AUTHENTICATION_USER_COUNTDOWN_SECONDS, optional: true }, { token: AUTHENTICATION_IDP_INACTIVITY_MINUTES, optional: true }, { token: LocationStrategy, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
384
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AuthenticationService }); }
385
- }
386
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AuthenticationService, decorators: [{
387
- type: Injectable
388
- }], ctorParameters: function () { return [{ type: i1$1.HttpClient }, { type: i2.Router }, { type: i1.CoolLocalStorage }, { type: i4.JwtHelperService }, { type: AuthenticationProvider }, { type: undefined, decorators: [{
389
- type: Inject,
390
- args: [AUTHENTICATION_ROUTE]
391
- }] }, { type: undefined, decorators: [{
392
- type: Inject,
393
- args: [AUTHENTICATION_LOGOUT_PATH]
394
- }] }, { type: undefined, decorators: [{
395
- type: Inject,
396
- args: [AUTHENTICATION_TOKEN_ENDPOINT]
397
- }] }, { type: undefined, decorators: [{
398
- type: Optional
399
- }, {
400
- type: Inject,
401
- args: [AUTHENTICATION_SERVER_URL]
402
- }] }, { type: undefined, decorators: [{
403
- type: Optional
404
- }, {
405
- type: Inject,
406
- args: [AUTHENTICATION_DIRECT_ENDPOINT]
407
- }] }, { type: undefined, decorators: [{
408
- type: Optional
409
- }, {
410
- type: Inject,
411
- args: [AUTHENTICATION_MAX_INACTIVITY_MINUTES]
412
- }] }, { type: undefined, decorators: [{
413
- type: Optional
414
- }, {
415
- type: Inject,
416
- args: [AUTHENTICATION_USER_COUNTDOWN_SECONDS]
417
- }] }, { type: undefined, decorators: [{
418
- type: Optional
419
- }, {
420
- type: Inject,
421
- args: [AUTHENTICATION_IDP_INACTIVITY_MINUTES]
422
- }] }, { type: i4$1.LocationStrategy, decorators: [{
423
- type: Optional
424
- }, {
425
- type: Inject,
426
- args: [LocationStrategy]
427
- }] }]; } });
52
+ /*
53
+ * Copyright (c) 2016 Huntsman Cancer Institute at the University of Utah, Confidential and Proprietary
54
+ */
55
+ /**
56
+ * The token used for injection of the server side endpoint for the currently authenticated subject.
57
+ *
58
+ * @type {InjectionToken}
59
+ */
60
+ let AUTHENTICATION_SERVER_URL = new InjectionToken("authentication_server_rest_api");
61
+ let AUTHENTICATION_LOGOUT_PATH = new InjectionToken("authentication_logout_path");
62
+ let AUTHENTICATION_DIRECT_ENDPOINT = new InjectionToken("authentication_direct_endpoint");
63
+ let AUTHENTICATION_TOKEN_ENDPOINT = new InjectionToken("authentication_token_endpoint");
64
+ let AUTHENTICATION_ROUTE = new InjectionToken("authentication_route");
65
+ let AUTHENTICATION_MAX_INACTIVITY_MINUTES = new InjectionToken("authentication_max_inactivity");
66
+ let AUTHENTICATION_USER_COUNTDOWN_SECONDS = new InjectionToken("authentication_user_countdown_seconds");
67
+ let AUTHENTICATION_IDP_INACTIVITY_MINUTES = new InjectionToken("authentication_idp_inactivity_minutes");
68
+ /**
69
+ * @since 1.0.0
70
+ */
71
+ class AuthenticationService {
72
+ /**
73
+ * The generic error message used when a server error is thrown without a status.
74
+ *
75
+ * @type {string}
76
+ */
77
+ static { this.GENERIC_ERR_MSG = "Server error"; }
78
+ static { this.CONTENT_TYPE = "Content-Type"; }
79
+ static { this.SEC_GOV_CLASS_HEADER = "SecurityGovernorClass"; }
80
+ static { this.SEC_GOV_ID_HEADER = "SecurityGovernorId"; }
81
+ static { this.DEIDENT_HEADER = "DeidentifiedContext"; }
82
+ static { this.LIMITED_HEADER = "LimitedContext"; }
83
+ constructor(_http, _router, _localStorageService, _jwtHelper, authenticationProvider, _authenticationRoute, _logoutPath, _tokenEndpoint, _serverUrl, _directEndpoint, _maxInactivity, _userCountdownSeconds, _idpInactivityMinutes, locationStrategy) {
84
+ this._http = _http;
85
+ this._router = _router;
86
+ this._localStorageService = _localStorageService;
87
+ this._jwtHelper = _jwtHelper;
88
+ this.authenticationProvider = authenticationProvider;
89
+ this._authenticationRoute = _authenticationRoute;
90
+ this._logoutPath = _logoutPath;
91
+ this._tokenEndpoint = _tokenEndpoint;
92
+ this._serverUrl = _serverUrl;
93
+ this._directEndpoint = _directEndpoint;
94
+ this._maxInactivity = _maxInactivity;
95
+ this._userCountdownSeconds = _userCountdownSeconds;
96
+ this._idpInactivityMinutes = _idpInactivityMinutes;
97
+ this.locationStrategy = locationStrategy;
98
+ this.userCountdownSeconds = 60;
99
+ this.idpInactivityMinutes = 5;
100
+ this.contentType = "application/json";
101
+ this.limitedContext = false;
102
+ this.deidentifiedContext = false;
103
+ this.maxViewPermission = new BehaviorSubject("viewident");
104
+ this._isAuthenticatedSubject = new BehaviorSubject(false);
105
+ this._userIsAboutToTimeOut = new BehaviorSubject(false);
106
+ this._maxInactivityMinutes = 120;
107
+ this.contextRoot = "";
108
+ if (isDevMode()) {
109
+ console.debug("window.location.href: " + window.location.href);
110
+ }
111
+ if (window.location) {
112
+ let parts = window.location.href.split("/");
113
+ this.baseUrl = parts[0] + "//" + parts[2];
114
+ if (parts.length > 3) {
115
+ this.contextRoot = parts[3];
116
+ }
117
+ }
118
+ if (this._localStorageService.getItem("maxViewPermission")) {
119
+ this.maxViewPermission.next(this._localStorageService.getItem("maxViewPermission"));
120
+ }
121
+ if (_maxInactivity) {
122
+ this._maxInactivityMinutes = _maxInactivity;
123
+ }
124
+ if (_userCountdownSeconds) {
125
+ this.userCountdownSeconds = _userCountdownSeconds;
126
+ }
127
+ if (_idpInactivityMinutes) {
128
+ this.idpInactivityMinutes = _idpInactivityMinutes;
129
+ }
130
+ this.hasValidConfig();
131
+ //There could be a non-expired token in local storage.
132
+ let token = this.authenticationProvider.authToken;
133
+ this.storeToken(token);
134
+ }
135
+ getBaseUrl() {
136
+ return (this.baseUrl) ? this.baseUrl : "";
137
+ }
138
+ getContextRoot() {
139
+ return this.contextRoot;
140
+ }
141
+ getHeaders(req) {
142
+ let headers = req.headers;
143
+ //Don't set content type if already set
144
+ if (!req.headers.get(AuthenticationService.CONTENT_TYPE)) {
145
+ headers = headers.set(AuthenticationService.CONTENT_TYPE, this.contentType.toString());
146
+ }
147
+ if (headers.get(AuthenticationService.SEC_GOV_CLASS_HEADER) === "") {
148
+ headers = headers.delete(AuthenticationService.SEC_GOV_CLASS_HEADER);
149
+ }
150
+ else if (this.securityGovernorClass && !headers.get(AuthenticationService.SEC_GOV_CLASS_HEADER)) {
151
+ headers = headers.set(AuthenticationService.SEC_GOV_CLASS_HEADER, this.securityGovernorClass);
152
+ }
153
+ if (headers.get(AuthenticationService.SEC_GOV_ID_HEADER) === "") {
154
+ headers = headers.delete(AuthenticationService.SEC_GOV_ID_HEADER);
155
+ }
156
+ else if (this.securityGovernorId && !headers.get(AuthenticationService.SEC_GOV_ID_HEADER)) {
157
+ headers = headers.set(AuthenticationService.SEC_GOV_ID_HEADER, this.securityGovernorId.toString());
158
+ }
159
+ headers = headers.set(AuthenticationService.DEIDENT_HEADER, this.deidentifiedContext.toString());
160
+ headers = headers.set(AuthenticationService.LIMITED_HEADER, this.limitedContext.toString());
161
+ return headers;
162
+ }
163
+ get authenticationTokenKey() {
164
+ return this.authenticationProvider.authenticationTokenKey;
165
+ }
166
+ get authToken() {
167
+ return this.authenticationProvider.authToken;
168
+ }
169
+ updateUserActivity() {
170
+ if (this._isAuthenticatedSubject.value) {
171
+ this._lastUserInteraction = new Date();
172
+ this._userIsAboutToTimeOut.next(false);
173
+ }
174
+ }
175
+ /**
176
+ * A mutator for identifying the clients original request location. Setting this value will influence the end location
177
+ * navigated to by {@link #navigateToPath}.
178
+ *
179
+ * @param redirectUrl location of the users request before authentication
180
+ */
181
+ set redirectUrl(redirectUrl) {
182
+ this._redirectUrl = redirectUrl;
183
+ }
184
+ get redirectUrl() {
185
+ return this._redirectUrl;
186
+ }
187
+ requestAccessToken(redirectOnSuccess) {
188
+ this._http.get(this.tokenLocation(), { withCredentials: true })
189
+ .subscribe((response) => {
190
+ this.storeToken(response.auth_token);
191
+ if (redirectOnSuccess) {
192
+ this.proceedIfAuthenticated();
193
+ }
194
+ }, (error) => {
195
+ //Token refresh failed.
196
+ this.logout(true);
197
+ });
198
+ }
199
+ /**
200
+ * Verifies whether or not a current user session exists.
201
+ *
202
+ * @returns {Observable<boolean>} evaluates to true if the user is authenticated, false otherwise.
203
+ */
204
+ isAuthenticated() {
205
+ return this._isAuthenticatedSubject.asObservable();
206
+ }
207
+ isAboutToTimeOut() {
208
+ return this._userIsAboutToTimeOut.asObservable();
209
+ }
210
+ getTimeoutStart() {
211
+ if (this._lastUserInteraction) {
212
+ return this._lastUserInteraction.valueOf() + (((this._maxInactivityMinutes * 60) - this.userCountdownSeconds) * 1000);
213
+ }
214
+ }
215
+ tokenLocation() {
216
+ if (this._serverUrl) {
217
+ return this._serverUrl + this._tokenEndpoint;
218
+ }
219
+ else {
220
+ return this._tokenEndpoint;
221
+ }
222
+ }
223
+ directLoginLocation() {
224
+ if (this._serverUrl) {
225
+ return this._serverUrl + this._directEndpoint;
226
+ }
227
+ else {
228
+ return this._directEndpoint;
229
+ }
230
+ }
231
+ logoutLocation() {
232
+ if (this._serverUrl) {
233
+ return this._serverUrl + this._logoutPath;
234
+ }
235
+ else {
236
+ return this._logoutPath;
237
+ }
238
+ }
239
+ /**
240
+ * A function to authenticated the user with the provided credentials. Failure results in an error that describes the
241
+ * server response (status and status message) and should be actionable by the client application.
242
+ *
243
+ * @param username of the authenticating user to verify
244
+ * @param password of the authenticating user to verify
245
+ * @returns {Observable<R>} describing the result of the login action, true or an error
246
+ */
247
+ login(_username, _password) {
248
+ return this._http.post(this.directLoginLocation(), { username: _username, password: _password }, { observe: "response" }).pipe(map((resp) => {
249
+ if (resp.status === 201) {
250
+ return true;
251
+ }
252
+ else {
253
+ throw new Error("Authentication failed. " + resp.status + ": " + resp.statusText);
254
+ }
255
+ }), catchError(this.handleError));
256
+ }
257
+ clearLogin() {
258
+ //Front-end logout
259
+ try {
260
+ this._localStorageService.removeItem(this.authenticationProvider.authenticationTokenKey);
261
+ this.unsubscribeFromTokenRefresh();
262
+ this._isAuthenticatedSubject.next(false);
263
+ this._userIsAboutToTimeOut.next(false);
264
+ }
265
+ catch (Error) {
266
+ }
267
+ //Back-end logout
268
+ let headers = new HttpHeaders().set(AuthenticationService.CONTENT_TYPE, "text/plain");
269
+ return this._http.get(this.logoutLocation(), { headers: headers });
270
+ }
271
+ /**
272
+ * A function to signal the termination of the current session. Invoking this function will clean up any relevant state
273
+ * related to the last active session.
274
+ */
275
+ logout(keepCurrentRoute = false) {
276
+ //Prevent logout if already on authentication route. Doing otherwise screws up SAML
277
+ if (!this._router.routerState || this._router.routerState.snapshot.url !== this._authenticationRoute) {
278
+ this._redirectUrl = (keepCurrentRoute && this._router.routerState && this._router.routerState.snapshot) ? this._router.routerState.snapshot.url : "";
279
+ if (this._redirectUrl.startsWith("/")) {
280
+ this._redirectUrl = this._redirectUrl.substring(1);
281
+ }
282
+ this.clearLogin().subscribe((response) => {
283
+ window.location.replace(this._redirectUrl);
284
+ }, (error) => {
285
+ window.location.replace(this._redirectUrl);
286
+ });
287
+ }
288
+ }
289
+ storeToken(token) {
290
+ let valid = this.validateToken(token);
291
+ // unsubscribe from refesh before we decide wether to resubscribe
292
+ this.unsubscribeFromTokenRefresh();
293
+ if (valid) {
294
+ this._localStorageService.setItem(this.authenticationProvider.authenticationTokenKey, token);
295
+ this.subscribeToTokenRefresh(token);
296
+ //Change the BehaviorSubject if the user was not previously authenticated.
297
+ //Since other code may be subscribing to this observable, we don't want to cause new events to fire if just refreshing the JWT.
298
+ if (!this._isAuthenticatedSubject.value) {
299
+ this._isAuthenticatedSubject.next(true);
300
+ }
301
+ }
302
+ else {
303
+ this._localStorageService.removeItem(this.authenticationProvider.authenticationTokenKey);
304
+ this._isAuthenticatedSubject.next(false);
305
+ }
306
+ }
307
+ proceedIfAuthenticated() {
308
+ if (isDevMode()) {
309
+ console.debug("AuthenticationService.proceedIfAuthenticated: " + this._redirectUrl);
310
+ }
311
+ if (this._isAuthenticatedSubject.value) {
312
+ //Login counts as user activity, too
313
+ this.updateUserActivity();
314
+ if (this._redirectUrl && this._redirectUrl && this._redirectUrl !== "") {
315
+ this._router.navigateByUrl(this._redirectUrl);
316
+ }
317
+ else {
318
+ this._router.navigate([""]);
319
+ }
320
+ return true;
321
+ }
322
+ else {
323
+ return false;
324
+ }
325
+ }
326
+ validateToken(token) {
327
+ return (token && !this._jwtHelper.isTokenExpired(token));
328
+ }
329
+ subscribeToTokenRefresh(token) {
330
+ let exp = this._jwtHelper.getTokenExpirationDate(token);
331
+ // Use a timer to periodically check timeouts
332
+ this._refreshSubscription = interval(1000)
333
+ .subscribe(() => {
334
+ // If a tab is inactive we can't know if our timer is accurate
335
+ // so when the interval hits check against timestamps
336
+ if (this._isAuthenticatedSubject.value && Date.now() > this.getTimeoutStart()) {
337
+ //Don't update the subject more than once! Doing so initializes more than one countdown timer!
338
+ if (this._userIsAboutToTimeOut.getValue() !== true) {
339
+ this._userIsAboutToTimeOut.next(true);
340
+ }
341
+ }
342
+ // check for refresh token
343
+ let msToExpiry = (exp.valueOf() - new Date().valueOf());
344
+ // Refresh 60 seconds before expiry
345
+ if (msToExpiry <= 60000) {
346
+ this.refreshTokenIfUserIsActive();
347
+ }
348
+ });
349
+ }
350
+ unsubscribeFromTokenRefresh() {
351
+ if (this._refreshSubscription && !this._refreshSubscription.closed) {
352
+ this._refreshSubscription.unsubscribe();
353
+ }
354
+ }
355
+ getMaxViewPermission() {
356
+ return this.maxViewPermission.getValue();
357
+ }
358
+ getMaxViewPermissionSubject() {
359
+ return this.maxViewPermission;
360
+ }
361
+ setMaxViewPermission(maxViewPermission) {
362
+ this._localStorageService.setItem("maxViewPermission", maxViewPermission);
363
+ this.maxViewPermission.next(maxViewPermission);
364
+ }
365
+ refreshTokenIfUserIsActive() {
366
+ //Only refresh if the user has been active
367
+ if (this._lastUserInteraction && ((new Date().valueOf() - this._lastUserInteraction.valueOf()) <= (this._maxInactivityMinutes * 60 * 1000))) {
368
+ this.requestAccessToken(false);
369
+ }
370
+ }
371
+ hasValidConfig() {
372
+ if (this._tokenEndpoint == null && (this._serverUrl === null || this._logoutPath === null)) {
373
+ throw new Error("BUG ALERT! Invalid AuthenticationService configuration. No valid configuration for authentication endpoint(s).");
374
+ }
375
+ if (this._localStorageService === null || this.authenticationProvider.authenticationTokenKey === null) {
376
+ throw new Error("BUG ALERT! Invalid AuthenticationService configuration. No valid configuration for local storage");
377
+ }
378
+ }
379
+ handleError(error) {
380
+ let errMsg = (error.message) ? error.message : AuthenticationService.GENERIC_ERR_MSG;
381
+ return throwError(errMsg);
382
+ }
383
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: AuthenticationService, deps: [{ token: i1$1.HttpClient }, { token: i2.Router }, { token: i1.CoolLocalStorage }, { token: i4.JwtHelperService }, { token: AuthenticationProvider }, { token: AUTHENTICATION_ROUTE }, { token: AUTHENTICATION_LOGOUT_PATH }, { token: AUTHENTICATION_TOKEN_ENDPOINT }, { token: AUTHENTICATION_SERVER_URL, optional: true }, { token: AUTHENTICATION_DIRECT_ENDPOINT, optional: true }, { token: AUTHENTICATION_MAX_INACTIVITY_MINUTES, optional: true }, { token: AUTHENTICATION_USER_COUNTDOWN_SECONDS, optional: true }, { token: AUTHENTICATION_IDP_INACTIVITY_MINUTES, optional: true }, { token: LocationStrategy, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
384
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: AuthenticationService }); }
385
+ }
386
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: AuthenticationService, decorators: [{
387
+ type: Injectable
388
+ }], ctorParameters: () => [{ type: i1$1.HttpClient }, { type: i2.Router }, { type: i1.CoolLocalStorage }, { type: i4.JwtHelperService }, { type: AuthenticationProvider }, { type: undefined, decorators: [{
389
+ type: Inject,
390
+ args: [AUTHENTICATION_ROUTE]
391
+ }] }, { type: undefined, decorators: [{
392
+ type: Inject,
393
+ args: [AUTHENTICATION_LOGOUT_PATH]
394
+ }] }, { type: undefined, decorators: [{
395
+ type: Inject,
396
+ args: [AUTHENTICATION_TOKEN_ENDPOINT]
397
+ }] }, { type: undefined, decorators: [{
398
+ type: Optional
399
+ }, {
400
+ type: Inject,
401
+ args: [AUTHENTICATION_SERVER_URL]
402
+ }] }, { type: undefined, decorators: [{
403
+ type: Optional
404
+ }, {
405
+ type: Inject,
406
+ args: [AUTHENTICATION_DIRECT_ENDPOINT]
407
+ }] }, { type: undefined, decorators: [{
408
+ type: Optional
409
+ }, {
410
+ type: Inject,
411
+ args: [AUTHENTICATION_MAX_INACTIVITY_MINUTES]
412
+ }] }, { type: undefined, decorators: [{
413
+ type: Optional
414
+ }, {
415
+ type: Inject,
416
+ args: [AUTHENTICATION_USER_COUNTDOWN_SECONDS]
417
+ }] }, { type: undefined, decorators: [{
418
+ type: Optional
419
+ }, {
420
+ type: Inject,
421
+ args: [AUTHENTICATION_IDP_INACTIVITY_MINUTES]
422
+ }] }, { type: i4$1.LocationStrategy, decorators: [{
423
+ type: Optional
424
+ }, {
425
+ type: Inject,
426
+ args: [LocationStrategy]
427
+ }] }] });
428
428
 
429
- /*
430
- * Copyright (c) 2016 Huntsman Cancer Institute at the University of Utah, Confidential and Proprietary
431
- */
432
- class AuthenticationComponent {
433
- constructor(authenticationService, domSanitizer, router, location, renderer, authenticationRoute) {
434
- this.authenticationService = authenticationService;
435
- this.domSanitizer = domSanitizer;
436
- this.router = router;
437
- this.location = location;
438
- this.renderer = renderer;
439
- this.authenticationRoute = authenticationRoute;
440
- }
441
- ngOnInit() {
442
- /*
443
- * Fix back bug
444
- * Issue is that the browser will go back to the previous route. If it's guarded, the route guard will just load the login again
445
- * Eventually the browser gets to the /authenticate route and going back from there loads the iframe history and Shibboleth displays
446
- * an error relating to navigating back.
447
- */
448
- history.pushState(null, null, this.location.prepareExternalUrl(this.authenticationRoute));
449
- this.popstateSubscription = this.location.subscribe((value) => {
450
- //This is going to prevent back from working from the login component
451
- history.go(1);
452
- });
453
- this.beginAuthenticationProcess();
454
- }
455
- handleChanges() {
456
- if (!this.iframe.nativeElement.contentDocument) {
457
- return;
458
- }
459
- try {
460
- let element = this.iframe.nativeElement.contentDocument.body;
461
- if (element.querySelector("pre")) {
462
- element = element.querySelector("pre");
463
- }
464
- this._errorMsg = null;
465
- var jsonText = element.innerText;
466
- var json = JSON.parse(jsonText);
467
- this.authenticationService.storeToken(json.auth_token);
468
- var authenticated = this.authenticationService.proceedIfAuthenticated();
469
- if (!authenticated) {
470
- this.resetSubscription.unsubscribe();
471
- this.beginAuthenticationProcess();
472
- }
473
- }
474
- catch (error) {
475
- if (this.iframe.nativeElement.contentDocument.title.toUpperCase() === "ERROR") {
476
- if (this.iframe.nativeElement.contentDocument.body.innerHTML.toUpperCase() === "FORBIDDEN") {
477
- this._errorMsg = "You do not have permission to log into this application";
478
- }
479
- else {
480
- this._errorMsg = null;
481
- }
482
- //A bit of a workaround for a WildFly issue. Success on Pac4j authentication, but failure on DB load of user put things in a weird state. Just logout, and redo the login.
483
- this.clearLoginAndRetry();
484
- }
485
- }
486
- // After the iframe loads, make the background transparent so we use the implementation's background and not the sso background.
487
- this.renderer.setStyle(this.iframe.nativeElement.contentDocument.body, "background-color", "transparent");
488
- }
489
- ngOnDestroy() {
490
- this.resetSubscription.unsubscribe();
491
- this.popstateSubscription.unsubscribe();
492
- }
493
- clearLoginAndRetry() {
494
- this.resetSubscription.unsubscribe();
495
- this.authenticationService.clearLogin().subscribe(() => { this.beginAuthenticationProcess(); }, (error) => { this.beginAuthenticationProcess(); });
496
- }
497
- beginAuthenticationProcess() {
498
- var tokenEndpoint = this.authenticationService.tokenLocation();
499
- if (tokenEndpoint !== "") {
500
- this.url = this.domSanitizer.bypassSecurityTrustResourceUrl(tokenEndpoint);
501
- }
502
- /**
503
- * If the user doesn't complete authentication before the IdP session times out, that will be a problem when they eventually
504
- * attampt to log in. It is likely that users will do this often when they log out or are timed out in the evening, leave
505
- * their browser open, then attempt to log back in in the morning. In order to work around this, this component will re-request
506
- * the token prior to IdP timeout, which will reset the process. This will happen 1 minute before idpInactivityMinutes
507
- **/
508
- this.resetSubscription = interval((this.authenticationService.idpInactivityMinutes - 1) * 60 * 1000)
509
- .pipe(first())
510
- .subscribe((value) => {
511
- this.beginAuthenticationProcess();
512
- });
513
- }
514
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AuthenticationComponent, deps: [{ token: AuthenticationService }, { token: i2$1.DomSanitizer }, { token: i2.Router }, { token: i4$1.Location }, { token: i0.Renderer2 }, { token: AUTHENTICATION_ROUTE }], target: i0.ɵɵFactoryTarget.Component }); }
515
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: AuthenticationComponent, selector: "authentication-iframe", host: { classAttribute: "outlet-row" }, viewQueries: [{ propertyName: "iframe", first: true, predicate: ["iframe"], descendants: true, static: true }], ngImport: i0, template: `
429
+ /*
430
+ * Copyright (c) 2016 Huntsman Cancer Institute at the University of Utah, Confidential and Proprietary
431
+ */
432
+ class AuthenticationComponent {
433
+ constructor(authenticationService, domSanitizer, router, location, renderer, authenticationRoute) {
434
+ this.authenticationService = authenticationService;
435
+ this.domSanitizer = domSanitizer;
436
+ this.router = router;
437
+ this.location = location;
438
+ this.renderer = renderer;
439
+ this.authenticationRoute = authenticationRoute;
440
+ }
441
+ ngOnInit() {
442
+ /*
443
+ * Fix back bug
444
+ * Issue is that the browser will go back to the previous route. If it's guarded, the route guard will just load the login again
445
+ * Eventually the browser gets to the /authenticate route and going back from there loads the iframe history and Shibboleth displays
446
+ * an error relating to navigating back.
447
+ */
448
+ history.pushState(null, null, this.location.prepareExternalUrl(this.authenticationRoute));
449
+ this.popstateSubscription = this.location.subscribe((value) => {
450
+ //This is going to prevent back from working from the login component
451
+ history.go(1);
452
+ });
453
+ this.beginAuthenticationProcess();
454
+ }
455
+ handleChanges() {
456
+ if (!this.iframe.nativeElement.contentDocument) {
457
+ return;
458
+ }
459
+ try {
460
+ let element = this.iframe.nativeElement.contentDocument.body;
461
+ if (element.querySelector("pre")) {
462
+ element = element.querySelector("pre");
463
+ }
464
+ this._errorMsg = null;
465
+ var jsonText = element.innerText;
466
+ var json = JSON.parse(jsonText);
467
+ this.authenticationService.storeToken(json.auth_token);
468
+ var authenticated = this.authenticationService.proceedIfAuthenticated();
469
+ if (!authenticated) {
470
+ this.resetSubscription.unsubscribe();
471
+ this.beginAuthenticationProcess();
472
+ }
473
+ }
474
+ catch (error) {
475
+ if (this.iframe.nativeElement.contentDocument.title.toUpperCase() === "ERROR") {
476
+ if (this.iframe.nativeElement.contentDocument.body.innerHTML.toUpperCase() === "FORBIDDEN") {
477
+ this._errorMsg = "You do not have permission to log into this application";
478
+ }
479
+ else {
480
+ this._errorMsg = null;
481
+ }
482
+ //A bit of a workaround for a WildFly issue. Success on Pac4j authentication, but failure on DB load of user put things in a weird state. Just logout, and redo the login.
483
+ this.clearLoginAndRetry();
484
+ }
485
+ }
486
+ // After the iframe loads, make the background transparent so we use the implementation's background and not the sso background.
487
+ this.renderer.setStyle(this.iframe.nativeElement.contentDocument.body, "background-color", "transparent");
488
+ }
489
+ ngOnDestroy() {
490
+ this.resetSubscription.unsubscribe();
491
+ this.popstateSubscription.unsubscribe();
492
+ }
493
+ clearLoginAndRetry() {
494
+ this.resetSubscription.unsubscribe();
495
+ this.authenticationService.clearLogin().subscribe(() => { this.beginAuthenticationProcess(); }, (error) => { this.beginAuthenticationProcess(); });
496
+ }
497
+ beginAuthenticationProcess() {
498
+ var tokenEndpoint = this.authenticationService.tokenLocation();
499
+ if (tokenEndpoint !== "") {
500
+ this.url = this.domSanitizer.bypassSecurityTrustResourceUrl(tokenEndpoint);
501
+ }
502
+ /**
503
+ * If the user doesn't complete authentication before the IdP session times out, that will be a problem when they eventually
504
+ * attampt to log in. It is likely that users will do this often when they log out or are timed out in the evening, leave
505
+ * their browser open, then attempt to log back in in the morning. In order to work around this, this component will re-request
506
+ * the token prior to IdP timeout, which will reset the process. This will happen 1 minute before idpInactivityMinutes
507
+ **/
508
+ this.resetSubscription = interval((this.authenticationService.idpInactivityMinutes - 1) * 60 * 1000)
509
+ .pipe(first())
510
+ .subscribe((value) => {
511
+ this.beginAuthenticationProcess();
512
+ });
513
+ }
514
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: AuthenticationComponent, deps: [{ token: AuthenticationService }, { token: i2$1.DomSanitizer }, { token: i2.Router }, { token: i4$1.Location }, { token: i0.Renderer2 }, { token: AUTHENTICATION_ROUTE }], target: i0.ɵɵFactoryTarget.Component }); }
515
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.2", type: AuthenticationComponent, selector: "authentication-iframe", host: { classAttribute: "outlet-row" }, viewQueries: [{ propertyName: "iframe", first: true, predicate: ["iframe"], descendants: true, static: true }], ngImport: i0, template: `
516
516
  <div class="container">
517
517
  <iframe #iframe class="frame" [src]="url" (load)="handleChanges()"></iframe>
518
518
  <div *ngIf="_errorMsg" class="alert-box">
@@ -522,10 +522,10 @@ class AuthenticationComponent {
522
522
  </div>
523
523
  </div>
524
524
  </div>
525
- `, isInline: true, styles: [":host{background-color:#fff}.container{max-width:100%;margin-top:60px;padding-top:15px}.frame{width:100%;height:100%;border:0px}\n"], dependencies: [{ kind: "directive", type: i4$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); }
526
- }
527
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AuthenticationComponent, decorators: [{
528
- type: Component,
525
+ `, isInline: true, styles: [":host{background-color:#fff}.container{max-width:100%;margin-top:60px;padding-top:15px}.frame{width:100%;height:100%;border:0px}\n"], dependencies: [{ kind: "directive", type: i4$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); }
526
+ }
527
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: AuthenticationComponent, decorators: [{
528
+ type: Component,
529
529
  args: [{ selector: "authentication-iframe", template: `
530
530
  <div class="container">
531
531
  <iframe #iframe class="frame" [src]="url" (load)="handleChanges()"></iframe>
@@ -536,48 +536,48 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
536
536
  </div>
537
537
  </div>
538
538
  </div>
539
- `, host: { class: "outlet-row" }, styles: [":host{background-color:#fff}.container{max-width:100%;margin-top:60px;padding-top:15px}.frame{width:100%;height:100%;border:0px}\n"] }]
540
- }], ctorParameters: function () { return [{ type: AuthenticationService }, { type: i2$1.DomSanitizer }, { type: i2.Router }, { type: i4$1.Location }, { type: i0.Renderer2 }, { type: undefined, decorators: [{
541
- type: Inject,
542
- args: [AUTHENTICATION_ROUTE]
543
- }] }]; }, propDecorators: { iframe: [{
544
- type: ViewChild,
545
- args: ["iframe", { static: true }]
539
+ `, host: { class: "outlet-row" }, styles: [":host{background-color:#fff}.container{max-width:100%;margin-top:60px;padding-top:15px}.frame{width:100%;height:100%;border:0px}\n"] }]
540
+ }], ctorParameters: () => [{ type: AuthenticationService }, { type: i2$1.DomSanitizer }, { type: i2.Router }, { type: i4$1.Location }, { type: i0.Renderer2 }, { type: undefined, decorators: [{
541
+ type: Inject,
542
+ args: [AUTHENTICATION_ROUTE]
543
+ }] }], propDecorators: { iframe: [{
544
+ type: ViewChild,
545
+ args: ["iframe", { static: true }]
546
546
  }] } });
547
547
 
548
- /*
549
- * Copyright (c) 2016 Huntsman Cancer Institute at the University of Utah, Confidential and Proprietary
550
- */
551
- class DirectLoginComponent {
552
- constructor(_authenticationService, _formBuilder) {
553
- this._authenticationService = _authenticationService;
554
- this._formBuilder = _formBuilder;
555
- }
556
- /**
557
- * Initializes the authentication form.
558
- */
559
- ngOnInit() {
560
- this._loginForm = this._formBuilder.group({
561
- username: ["", Validators.required],
562
- password: ["", Validators.required]
563
- });
564
- }
565
- /**
566
- * A function to submit the login form the the {@link UserService}.
567
- */
568
- login() {
569
- this._authenticationService.login(this._loginForm.value.username, this._loginForm.value.password)
570
- .subscribe((res) => {
571
- if (res) {
572
- this._errorMsg = null;
573
- this._authenticationService.requestAccessToken(true);
574
- }
575
- }, (error) => {
576
- this._errorMsg = "Please check your username and password.";
577
- });
578
- }
579
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DirectLoginComponent, deps: [{ token: AuthenticationService }, { token: i2$2.UntypedFormBuilder }], target: i0.ɵɵFactoryTarget.Component }); }
580
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: DirectLoginComponent, selector: "hci-login-form", ngImport: i0, template: `
548
+ /*
549
+ * Copyright (c) 2016 Huntsman Cancer Institute at the University of Utah, Confidential and Proprietary
550
+ */
551
+ class DirectLoginComponent {
552
+ constructor(_authenticationService, _formBuilder) {
553
+ this._authenticationService = _authenticationService;
554
+ this._formBuilder = _formBuilder;
555
+ }
556
+ /**
557
+ * Initializes the authentication form.
558
+ */
559
+ ngOnInit() {
560
+ this._loginForm = this._formBuilder.group({
561
+ username: ["", Validators.required],
562
+ password: ["", Validators.required]
563
+ });
564
+ }
565
+ /**
566
+ * A function to submit the login form the the {@link UserService}.
567
+ */
568
+ login() {
569
+ this._authenticationService.login(this._loginForm.value.username, this._loginForm.value.password)
570
+ .subscribe((res) => {
571
+ if (res) {
572
+ this._errorMsg = null;
573
+ this._authenticationService.requestAccessToken(true);
574
+ }
575
+ }, (error) => {
576
+ this._errorMsg = "Please check your username and password.";
577
+ });
578
+ }
579
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: DirectLoginComponent, deps: [{ token: AuthenticationService }, { token: i2$2.UntypedFormBuilder }], target: i0.ɵɵFactoryTarget.Component }); }
580
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.2", type: DirectLoginComponent, selector: "hci-login-form", ngImport: i0, template: `
581
581
  <div class="container">
582
582
  <div class="login-box" id="hci-login-form-box">
583
583
  <div class="login-heading" id="hci-login-form-heading">
@@ -602,10 +602,10 @@ class DirectLoginComponent {
602
602
  </div>
603
603
  </div>
604
604
  </div>
605
- `, isInline: true, styles: [".container{max-width:400px;margin-top:20px;padding-top:15px}.login-box{border-radius:10px;box-shadow:0 0 2px #ccc;padding:15px}.login-box .login-heading h3{line-height:1.5;margin:0 0 10px}.login-box .form-control{padding:10px;border:1px solid #ccc}.login-box input[type=password]{margin-bottom:10px;border-top-left-radius:0;border-top-right-radius:0}.login-box input[type=text]{margin-bottom:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0}.login-box .alert-box{margin:10px 0 -5px}.login-box .alert-text{font-size:small}.login-box .btn-box{margin:10px 0 0}\n"], dependencies: [{ kind: "directive", type: i4$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] }); }
606
- }
607
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DirectLoginComponent, decorators: [{
608
- type: Component,
605
+ `, isInline: true, styles: [".container{max-width:400px;margin-top:20px;padding-top:15px}.login-box{border-radius:10px;box-shadow:0 0 2px #ccc;padding:15px}.login-box .login-heading h3{line-height:1.5;margin:0 0 10px}.login-box .form-control{padding:10px;border:1px solid #ccc}.login-box input[type=password]{margin-bottom:10px;border-top-left-radius:0;border-top-right-radius:0}.login-box input[type=text]{margin-bottom:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0}.login-box .alert-box{margin:10px 0 -5px}.login-box .alert-text{font-size:small}.login-box .btn-box{margin:10px 0 0}\n"], dependencies: [{ kind: "directive", type: i4$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] }); }
606
+ }
607
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: DirectLoginComponent, decorators: [{
608
+ type: Component,
609
609
  args: [{ selector: "hci-login-form", template: `
610
610
  <div class="container">
611
611
  <div class="login-box" id="hci-login-form-box">
@@ -631,51 +631,51 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
631
631
  </div>
632
632
  </div>
633
633
  </div>
634
- `, styles: [".container{max-width:400px;margin-top:20px;padding-top:15px}.login-box{border-radius:10px;box-shadow:0 0 2px #ccc;padding:15px}.login-box .login-heading h3{line-height:1.5;margin:0 0 10px}.login-box .form-control{padding:10px;border:1px solid #ccc}.login-box input[type=password]{margin-bottom:10px;border-top-left-radius:0;border-top-right-radius:0}.login-box input[type=text]{margin-bottom:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0}.login-box .alert-box{margin:10px 0 -5px}.login-box .alert-text{font-size:small}.login-box .btn-box{margin:10px 0 0}\n"] }]
635
- }], ctorParameters: function () { return [{ type: AuthenticationService }, { type: i2$2.UntypedFormBuilder }]; } });
634
+ `, styles: [".container{max-width:400px;margin-top:20px;padding-top:15px}.login-box{border-radius:10px;box-shadow:0 0 2px #ccc;padding:15px}.login-box .login-heading h3{line-height:1.5;margin:0 0 10px}.login-box .form-control{padding:10px;border:1px solid #ccc}.login-box input[type=password]{margin-bottom:10px;border-top-left-radius:0;border-top-right-radius:0}.login-box input[type=text]{margin-bottom:-1px;border-bottom-right-radius:0;border-bottom-left-radius:0}.login-box .alert-box{margin:10px 0 -5px}.login-box .alert-text{font-size:small}.login-box .btn-box{margin:10px 0 0}\n"] }]
635
+ }], ctorParameters: () => [{ type: AuthenticationService }, { type: i2$2.UntypedFormBuilder }] });
636
636
 
637
- /*
638
- * Copyright (c) 2016 Huntsman Cancer Institute at the University of Utah, Confidential and Proprietary
639
- */
640
- class TimeoutNotificationComponent {
641
- constructor(authenticationService) {
642
- this.authenticationService = authenticationService;
643
- this.openState = "hidden";
644
- authenticationService.isAboutToTimeOut().subscribe((isAboutToTimeOut) => {
645
- if (isAboutToTimeOut) {
646
- this.openState = "opened";
647
- this.startCountdown();
648
- }
649
- else {
650
- this.openState = "hidden";
651
- //If something changed mid-timeout, cancel the timeout/logout.
652
- if (this.subscription != null && !this.subscription.closed) {
653
- this.subscription.unsubscribe();
654
- }
655
- }
656
- });
657
- }
658
- startCountdown() {
659
- this.seconds = timer(0, 1000)
660
- .pipe(map(() => {
661
- const elapsed = Math.round((Date.now() - this.authenticationService.getTimeoutStart()) / 1000);
662
- return this.authenticationService.userCountdownSeconds - elapsed;
663
- }),
664
- // The true argument emits the final value that completed the observable
665
- takeWhile((value) => value > 0, true));
666
- this.subscription = this.seconds.subscribe((value) => {
667
- if (value < 1) {
668
- this.subscription.unsubscribe();
669
- this.authenticationService.logout(true);
670
- }
671
- });
672
- }
673
- click() {
674
- this.subscription.unsubscribe();
675
- this.authenticationService.updateUserActivity();
676
- }
677
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TimeoutNotificationComponent, deps: [{ token: AuthenticationService }], target: i0.ɵɵFactoryTarget.Component }); }
678
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: TimeoutNotificationComponent, selector: "timeout-notification", ngImport: i0, template: `
637
+ /*
638
+ * Copyright (c) 2016 Huntsman Cancer Institute at the University of Utah, Confidential and Proprietary
639
+ */
640
+ class TimeoutNotificationComponent {
641
+ constructor(authenticationService) {
642
+ this.authenticationService = authenticationService;
643
+ this.openState = "hidden";
644
+ authenticationService.isAboutToTimeOut().subscribe((isAboutToTimeOut) => {
645
+ if (isAboutToTimeOut) {
646
+ this.openState = "opened";
647
+ this.startCountdown();
648
+ }
649
+ else {
650
+ this.openState = "hidden";
651
+ //If something changed mid-timeout, cancel the timeout/logout.
652
+ if (this.subscription != null && !this.subscription.closed) {
653
+ this.subscription.unsubscribe();
654
+ }
655
+ }
656
+ });
657
+ }
658
+ startCountdown() {
659
+ this.seconds = timer(0, 1000)
660
+ .pipe(map(() => {
661
+ const elapsed = Math.round((Date.now() - this.authenticationService.getTimeoutStart()) / 1000);
662
+ return this.authenticationService.userCountdownSeconds - elapsed;
663
+ }),
664
+ // The true argument emits the final value that completed the observable
665
+ takeWhile((value) => value > 0, true));
666
+ this.subscription = this.seconds.subscribe((value) => {
667
+ if (value < 1) {
668
+ this.subscription.unsubscribe();
669
+ this.authenticationService.logout(true);
670
+ }
671
+ });
672
+ }
673
+ click() {
674
+ this.subscription.unsubscribe();
675
+ this.authenticationService.updateUserActivity();
676
+ }
677
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: TimeoutNotificationComponent, deps: [{ token: AuthenticationService }], target: i0.ɵɵFactoryTarget.Component }); }
678
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.2", type: TimeoutNotificationComponent, selector: "timeout-notification", ngImport: i0, template: `
679
679
  <div class="flyout-max" [@openBacksplash]="openState">
680
680
  <div class="modal-dialog" [@openModal]="openState" role="document">
681
681
  <div class="modal-header">
@@ -691,40 +691,40 @@ class TimeoutNotificationComponent {
691
691
  </div>
692
692
  </div>
693
693
  </div>
694
- `, isInline: true, styles: [".flyout-max{position:fixed;z-index:9999;top:0;bottom:0;background-color:#0006;width:100vw}.modal-dialog{position:fixed;max-width:50vw;min-width:50vw;left:-50vw;top:25vw;margin:0;background-color:#fff;border:black 1px solid;border-left:none;border-radius:20px;pointer-events:all}.modal-body{width:100%;display:inline-block}.modal-body-left{display:inline-block;overflow-y:auto;overflow-x:hidden;min-height:300px;max-height:300px}.modal-body-right{width:70%;vertical-align:top;padding-left:15px;border-left:black 1px solid;margin-left:15px;display:inline-block;overflow-y:auto;min-height:300px;max-height:300px}\n"], dependencies: [{ kind: "pipe", type: i4$1.AsyncPipe, name: "async" }], animations: [
695
- trigger("openBacksplash", [
696
- state("in", style({
697
- "display": "none"
698
- })),
699
- state("hidden", style({
700
- "display": "none"
701
- })),
702
- state("opened", style({
703
- "display": "inherit"
704
- })),
705
- transition("hidden => opened", animate(100)),
706
- transition("opened => hidden", animate(200))
707
- ]),
708
- trigger("openModal", [
709
- state("in", style({
710
- "opacity": "0",
711
- "left": "-50vw"
712
- })),
713
- state("hidden", style({
714
- "opacity": "0",
715
- "left": "-50vw"
716
- })),
717
- state("opened", style({
718
- "opacity": "1",
719
- "left": "25vw"
720
- })),
721
- transition("hidden => opened", animate(500)),
722
- transition("opened => hidden", animate(300))
723
- ])
724
- ] }); }
725
- }
726
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TimeoutNotificationComponent, decorators: [{
727
- type: Component,
694
+ `, isInline: true, styles: [".flyout-max{position:fixed;z-index:9999;top:0;bottom:0;background-color:#0006;width:100vw}.modal-dialog{position:fixed;max-width:50vw;min-width:50vw;left:-50vw;top:25vw;margin:0;background-color:#fff;border:black 1px solid;border-left:none;border-radius:20px;pointer-events:all}.modal-body{width:100%;display:inline-block}.modal-body-left{display:inline-block;overflow-y:auto;overflow-x:hidden;min-height:300px;max-height:300px}.modal-body-right{width:70%;vertical-align:top;padding-left:15px;border-left:black 1px solid;margin-left:15px;display:inline-block;overflow-y:auto;min-height:300px;max-height:300px}\n"], dependencies: [{ kind: "pipe", type: i4$1.AsyncPipe, name: "async" }], animations: [
695
+ trigger("openBacksplash", [
696
+ state("in", style({
697
+ "display": "none"
698
+ })),
699
+ state("hidden", style({
700
+ "display": "none"
701
+ })),
702
+ state("opened", style({
703
+ "display": "inherit"
704
+ })),
705
+ transition("hidden => opened", animate(100)),
706
+ transition("opened => hidden", animate(200))
707
+ ]),
708
+ trigger("openModal", [
709
+ state("in", style({
710
+ "opacity": "0",
711
+ "left": "-50vw"
712
+ })),
713
+ state("hidden", style({
714
+ "opacity": "0",
715
+ "left": "-50vw"
716
+ })),
717
+ state("opened", style({
718
+ "opacity": "1",
719
+ "left": "25vw"
720
+ })),
721
+ transition("hidden => opened", animate(500)),
722
+ transition("opened => hidden", animate(300))
723
+ ])
724
+ ] }); }
725
+ }
726
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: TimeoutNotificationComponent, decorators: [{
727
+ type: Component,
728
728
  args: [{ selector: "timeout-notification", template: `
729
729
  <div class="flyout-max" [@openBacksplash]="openState">
730
730
  <div class="modal-dialog" [@openModal]="openState" role="document">
@@ -741,222 +741,222 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
741
741
  </div>
742
742
  </div>
743
743
  </div>
744
- `, animations: [
745
- trigger("openBacksplash", [
746
- state("in", style({
747
- "display": "none"
748
- })),
749
- state("hidden", style({
750
- "display": "none"
751
- })),
752
- state("opened", style({
753
- "display": "inherit"
754
- })),
755
- transition("hidden => opened", animate(100)),
756
- transition("opened => hidden", animate(200))
757
- ]),
758
- trigger("openModal", [
759
- state("in", style({
760
- "opacity": "0",
761
- "left": "-50vw"
762
- })),
763
- state("hidden", style({
764
- "opacity": "0",
765
- "left": "-50vw"
766
- })),
767
- state("opened", style({
768
- "opacity": "1",
769
- "left": "25vw"
770
- })),
771
- transition("hidden => opened", animate(500)),
772
- transition("opened => hidden", animate(300))
773
- ])
774
- ], styles: [".flyout-max{position:fixed;z-index:9999;top:0;bottom:0;background-color:#0006;width:100vw}.modal-dialog{position:fixed;max-width:50vw;min-width:50vw;left:-50vw;top:25vw;margin:0;background-color:#fff;border:black 1px solid;border-left:none;border-radius:20px;pointer-events:all}.modal-body{width:100%;display:inline-block}.modal-body-left{display:inline-block;overflow-y:auto;overflow-x:hidden;min-height:300px;max-height:300px}.modal-body-right{width:70%;vertical-align:top;padding-left:15px;border-left:black 1px solid;margin-left:15px;display:inline-block;overflow-y:auto;min-height:300px;max-height:300px}\n"] }]
775
- }], ctorParameters: function () { return [{ type: AuthenticationService }]; } });
744
+ `, animations: [
745
+ trigger("openBacksplash", [
746
+ state("in", style({
747
+ "display": "none"
748
+ })),
749
+ state("hidden", style({
750
+ "display": "none"
751
+ })),
752
+ state("opened", style({
753
+ "display": "inherit"
754
+ })),
755
+ transition("hidden => opened", animate(100)),
756
+ transition("opened => hidden", animate(200))
757
+ ]),
758
+ trigger("openModal", [
759
+ state("in", style({
760
+ "opacity": "0",
761
+ "left": "-50vw"
762
+ })),
763
+ state("hidden", style({
764
+ "opacity": "0",
765
+ "left": "-50vw"
766
+ })),
767
+ state("opened", style({
768
+ "opacity": "1",
769
+ "left": "25vw"
770
+ })),
771
+ transition("hidden => opened", animate(500)),
772
+ transition("opened => hidden", animate(300))
773
+ ])
774
+ ], styles: [".flyout-max{position:fixed;z-index:9999;top:0;bottom:0;background-color:#0006;width:100vw}.modal-dialog{position:fixed;max-width:50vw;min-width:50vw;left:-50vw;top:25vw;margin:0;background-color:#fff;border:black 1px solid;border-left:none;border-radius:20px;pointer-events:all}.modal-body{width:100%;display:inline-block}.modal-body-left{display:inline-block;overflow-y:auto;overflow-x:hidden;min-height:300px;max-height:300px}.modal-body-right{width:70%;vertical-align:top;padding-left:15px;border-left:black 1px solid;margin-left:15px;display:inline-block;overflow-y:auto;min-height:300px;max-height:300px}\n"] }]
775
+ }], ctorParameters: () => [{ type: AuthenticationService }] });
776
776
 
777
- class AuthorizationInterceptor {
778
- constructor(injector) {
779
- this.injector = injector;
780
- }
781
- intercept(req, next) {
782
- if (isDevMode()) {
783
- console.debug("AuthorizationInterceptor.intercept");
784
- }
785
- let authService = this.injector.get(AuthenticationService);
786
- //Don't want to include background token refreshes in considering the user 'active'
787
- if (req.url !== authService.tokenLocation()) {
788
- //Update user activity. Done here instead of the previous method using a subscription to a subject in AuthenticationProvider
789
- authService.updateUserActivity();
790
- }
791
- let headers = authService.getHeaders(req);
792
- let url = req.url;
793
- if (url.startsWith("/")) {
794
- url = authService.getBaseUrl() + url;
795
- }
796
- else if (!url.startsWith("http")) {
797
- if (authService.getContextRoot().length > 0) {
798
- url = authService.getBaseUrl() + "/" + authService.getContextRoot() + "/" + url;
799
- }
800
- else {
801
- url = authService.getBaseUrl() + "/" + url;
802
- }
803
- }
804
- let params = req.params;
805
- if (url.indexOf("/crud/") > 0) {
806
- params = params.set("maxViewPermission", authService.getMaxViewPermission());
807
- }
808
- let reqClone = req.clone({
809
- url: url,
810
- withCredentials: true,
811
- headers: headers,
812
- params: params
813
- });
814
- return next.handle(reqClone)
815
- .pipe(catchError((error) => {
816
- if (isDevMode()) {
817
- console.error("AuthorizationInterceptor.error");
818
- console.error(error);
819
- }
820
- /**
821
- * If the token is not authenticated which angular does not know about, then a REST request to the backend will
822
- * return a 401. To duplicate this, open Core in two tabs. In one tab, logout, in the other, perform a request
823
- * that hits a protected resource.
824
- */
825
- if (error.status === 401) {
826
- authService.isAuthenticated().subscribe((authenticated) => {
827
- if (authenticated) {
828
- // If authenticated, then logout which will redirect.
829
- authService.logout(true);
830
- return throwError(error.message);
831
- }
832
- else {
833
- // Otherwise, for example, when the user first opens Core, 401s are expected.
834
- return throwError(error);
835
- }
836
- });
837
- }
838
- if (error.status === 403) {
839
- // TODO: Trigger notification for unauthorized.
840
- }
841
- return throwError(error);
842
- }));
843
- }
844
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AuthorizationInterceptor, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable }); }
845
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AuthorizationInterceptor }); }
846
- }
847
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AuthorizationInterceptor, decorators: [{
848
- type: Injectable
849
- }], ctorParameters: function () { return [{ type: i0.Injector }]; } });
777
+ class AuthorizationInterceptor {
778
+ constructor(injector) {
779
+ this.injector = injector;
780
+ }
781
+ intercept(req, next) {
782
+ if (isDevMode()) {
783
+ console.debug("AuthorizationInterceptor.intercept");
784
+ }
785
+ let authService = this.injector.get(AuthenticationService);
786
+ //Don't want to include background token refreshes in considering the user 'active'
787
+ if (req.url !== authService.tokenLocation()) {
788
+ //Update user activity. Done here instead of the previous method using a subscription to a subject in AuthenticationProvider
789
+ authService.updateUserActivity();
790
+ }
791
+ let headers = authService.getHeaders(req);
792
+ let url = req.url;
793
+ if (url.startsWith("/")) {
794
+ url = authService.getBaseUrl() + url;
795
+ }
796
+ else if (!url.startsWith("http")) {
797
+ if (authService.getContextRoot().length > 0) {
798
+ url = authService.getBaseUrl() + "/" + authService.getContextRoot() + "/" + url;
799
+ }
800
+ else {
801
+ url = authService.getBaseUrl() + "/" + url;
802
+ }
803
+ }
804
+ let params = req.params;
805
+ if (url.indexOf("/crud/") > 0) {
806
+ params = params.set("maxViewPermission", authService.getMaxViewPermission());
807
+ }
808
+ let reqClone = req.clone({
809
+ url: url,
810
+ withCredentials: true,
811
+ headers: headers,
812
+ params: params
813
+ });
814
+ return next.handle(reqClone)
815
+ .pipe(catchError((error) => {
816
+ if (isDevMode()) {
817
+ console.error("AuthorizationInterceptor.error");
818
+ console.error(error);
819
+ }
820
+ /**
821
+ * If the token is not authenticated which angular does not know about, then a REST request to the backend will
822
+ * return a 401. To duplicate this, open Core in two tabs. In one tab, logout, in the other, perform a request
823
+ * that hits a protected resource.
824
+ */
825
+ if (error.status === 401) {
826
+ authService.isAuthenticated().subscribe((authenticated) => {
827
+ if (authenticated) {
828
+ // If authenticated, then logout which will redirect.
829
+ authService.logout(true);
830
+ return throwError(error.message);
831
+ }
832
+ else {
833
+ // Otherwise, for example, when the user first opens Core, 401s are expected.
834
+ return throwError(error);
835
+ }
836
+ });
837
+ }
838
+ if (error.status === 403) {
839
+ // TODO: Trigger notification for unauthorized.
840
+ }
841
+ return throwError(error);
842
+ }));
843
+ }
844
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: AuthorizationInterceptor, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable }); }
845
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: AuthorizationInterceptor }); }
846
+ }
847
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: AuthorizationInterceptor, decorators: [{
848
+ type: Injectable
849
+ }], ctorParameters: () => [{ type: i0.Injector }] });
850
850
 
851
- /*
852
- * Copyright (c) 2016 Huntsman Cancer Institute at the University of Utah, Confidential and Proprietary
853
- */
854
- /**
855
- * Provide a single auth service and interceptor for the implementing application. Also provide everything
856
- * from the angular-jwt library.
857
- *
858
- * @since 1.0.0
859
- */
860
- class AuthenticationModule {
861
- constructor(parentModule) {
862
- if (parentModule) {
863
- throw new Error("AuthenticationModule is already loaded.");
864
- }
865
- }
866
- static forRoot() {
867
- return {
868
- providers: [
869
- AuthenticationProvider,
870
- JwtHelperService,
871
- AuthenticationService,
872
- {
873
- provide: HTTP_INTERCEPTORS,
874
- useClass: AuthorizationInterceptor,
875
- multi: true
876
- },
877
- {
878
- provide: HTTP_INTERCEPTORS,
879
- useClass: JwtInterceptor,
880
- multi: true
881
- },
882
- {
883
- provide: JWT_OPTIONS,
884
- useClass: AuthenticationProvider
885
- }
886
- ],
887
- ngModule: AuthenticationModule
888
- };
889
- }
890
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AuthenticationModule, deps: [{ token: i4.JwtModule, optional: true, skipSelf: true }], target: i0.ɵɵFactoryTarget.NgModule }); }
891
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.2.12", ngImport: i0, type: AuthenticationModule, declarations: [AuthenticationComponent,
892
- DirectLoginComponent,
893
- TimeoutNotificationComponent], imports: [CommonModule,
894
- HttpClientModule,
895
- //JwtModule,
896
- RouterModule,
897
- FormsModule,
898
- ReactiveFormsModule,
899
- CoolStorageModule], exports: [AuthenticationComponent,
900
- DirectLoginComponent,
901
- TimeoutNotificationComponent] }); }
902
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AuthenticationModule, imports: [CommonModule,
903
- HttpClientModule,
904
- //JwtModule,
905
- RouterModule,
906
- FormsModule,
907
- ReactiveFormsModule,
908
- CoolStorageModule] }); }
909
- }
910
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AuthenticationModule, decorators: [{
911
- type: NgModule,
912
- args: [{
913
- imports: [
914
- CommonModule,
915
- HttpClientModule,
916
- //JwtModule,
917
- RouterModule,
918
- FormsModule,
919
- ReactiveFormsModule,
920
- CoolStorageModule
921
- ],
922
- declarations: [
923
- AuthenticationComponent,
924
- DirectLoginComponent,
925
- TimeoutNotificationComponent
926
- ],
927
- exports: [
928
- AuthenticationComponent,
929
- DirectLoginComponent,
930
- TimeoutNotificationComponent
931
- ]
932
- }]
933
- }], ctorParameters: function () { return [{ type: i4.JwtModule, decorators: [{
934
- type: Optional
935
- }, {
936
- type: SkipSelf
937
- }] }]; } });
851
+ /*
852
+ * Copyright (c) 2016 Huntsman Cancer Institute at the University of Utah, Confidential and Proprietary
853
+ */
854
+ /**
855
+ * Provide a single auth service and interceptor for the implementing application. Also provide everything
856
+ * from the angular-jwt library.
857
+ *
858
+ * @since 1.0.0
859
+ */
860
+ class AuthenticationModule {
861
+ constructor(parentModule) {
862
+ if (parentModule) {
863
+ throw new Error("AuthenticationModule is already loaded.");
864
+ }
865
+ }
866
+ static forRoot() {
867
+ return {
868
+ providers: [
869
+ AuthenticationProvider,
870
+ JwtHelperService,
871
+ AuthenticationService,
872
+ {
873
+ provide: HTTP_INTERCEPTORS,
874
+ useClass: AuthorizationInterceptor,
875
+ multi: true
876
+ },
877
+ {
878
+ provide: HTTP_INTERCEPTORS,
879
+ useClass: JwtInterceptor,
880
+ multi: true
881
+ },
882
+ {
883
+ provide: JWT_OPTIONS,
884
+ useClass: AuthenticationProvider
885
+ }
886
+ ],
887
+ ngModule: AuthenticationModule
888
+ };
889
+ }
890
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: AuthenticationModule, deps: [{ token: i4.JwtModule, optional: true, skipSelf: true }], target: i0.ɵɵFactoryTarget.NgModule }); }
891
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.1.2", ngImport: i0, type: AuthenticationModule, declarations: [AuthenticationComponent,
892
+ DirectLoginComponent,
893
+ TimeoutNotificationComponent], imports: [CommonModule,
894
+ HttpClientModule,
895
+ //JwtModule,
896
+ RouterModule,
897
+ FormsModule,
898
+ ReactiveFormsModule,
899
+ CoolStorageModule], exports: [AuthenticationComponent,
900
+ DirectLoginComponent,
901
+ TimeoutNotificationComponent] }); }
902
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: AuthenticationModule, imports: [CommonModule,
903
+ HttpClientModule,
904
+ //JwtModule,
905
+ RouterModule,
906
+ FormsModule,
907
+ ReactiveFormsModule,
908
+ CoolStorageModule] }); }
909
+ }
910
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: AuthenticationModule, decorators: [{
911
+ type: NgModule,
912
+ args: [{
913
+ imports: [
914
+ CommonModule,
915
+ HttpClientModule,
916
+ //JwtModule,
917
+ RouterModule,
918
+ FormsModule,
919
+ ReactiveFormsModule,
920
+ CoolStorageModule
921
+ ],
922
+ declarations: [
923
+ AuthenticationComponent,
924
+ DirectLoginComponent,
925
+ TimeoutNotificationComponent
926
+ ],
927
+ exports: [
928
+ AuthenticationComponent,
929
+ DirectLoginComponent,
930
+ TimeoutNotificationComponent
931
+ ]
932
+ }]
933
+ }], ctorParameters: () => [{ type: i4.JwtModule, decorators: [{
934
+ type: Optional
935
+ }, {
936
+ type: SkipSelf
937
+ }] }] });
938
938
 
939
- /*
940
- * Copyright (c) 2016 Huntsman Cancer Institute at the University of Utah, Confidential and Proprietary
941
- */
942
- const RouteGuardService = () => {
943
- const authenticationService = inject(AuthenticationService);
944
- const router = inject(Router);
945
- const state = inject(RouterStateSnapshot);
946
- const authenticationRoute = inject(AUTHENTICATION_ROUTE);
947
- if (authenticationService.isAuthenticated()) {
948
- return true;
949
- }
950
- else {
951
- // Store the attempted URL for redirecting
952
- authenticationService.redirectUrl = state.url;
953
- // Navigate to the login page
954
- return router.navigate([authenticationRoute]);
955
- }
939
+ /*
940
+ * Copyright (c) 2016 Huntsman Cancer Institute at the University of Utah, Confidential and Proprietary
941
+ */
942
+ const RouteGuardService = () => {
943
+ const authenticationService = inject(AuthenticationService);
944
+ const router = inject(Router);
945
+ const state = inject(RouterStateSnapshot);
946
+ const authenticationRoute = inject(AUTHENTICATION_ROUTE);
947
+ if (authenticationService.isAuthenticated()) {
948
+ return true;
949
+ }
950
+ else {
951
+ // Store the attempted URL for redirecting
952
+ authenticationService.redirectUrl = state.url;
953
+ // Navigate to the login page
954
+ return router.navigate([authenticationRoute]);
955
+ }
956
956
  };
957
957
 
958
- /**
959
- * Generated bundle index. Do not edit.
958
+ /**
959
+ * Generated bundle index. Do not edit.
960
960
  */
961
961
 
962
962
  export { AUTHENTICATION_DIRECT_ENDPOINT, AUTHENTICATION_IDP_INACTIVITY_MINUTES, AUTHENTICATION_LOGOUT_PATH, AUTHENTICATION_MAX_INACTIVITY_MINUTES, AUTHENTICATION_ROUTE, AUTHENTICATION_SERVER_URL, AUTHENTICATION_TOKEN_ENDPOINT, AUTHENTICATION_TOKEN_KEY, AUTHENTICATION_USER_COUNTDOWN_SECONDS, AuthenticationComponent, AuthenticationModule, AuthenticationService, AuthorizationInterceptor, DirectLoginComponent, RouteGuardService, TimeoutNotificationComponent };