Code development platform for open source projects from the European Union institutions

Skip to content
Snippets Groups Projects
Commit 8b7bb442 authored by Joze RIHTARSIC's avatar Joze RIHTARSIC
Browse files

Pull request #176: [EDELIVERY-13996] [UI] automatic session extension on user ui activity.

Merge in EDELIVERY/smp from bugfix/EDELIVERY-13996-session-should-not-expire-if-user-is-editing-the-document to development

* commit '31cd1689':
  fix oasis smp 2.0 context path example
  [EDELIVERY-13996] [UI] automatic session extension on user ui activity.
parents 5e6ce207 31cd1689
No related branches found
No related tags found
No related merge requests found
import {Component, ViewChild} from '@angular/core';
import {Component, HostListener, ViewChild} from '@angular/core';
import {SecurityService} from './security/security.service';
import {Router} from '@angular/router';
import {Authority} from "./security/authority.model";
import {AlertMessageService} from "./common/alert-message/alert-message.service";
import {
AlertMessageService
} from "./common/alert-message/alert-message.service";
import {MatDialog} from "@angular/material/dialog";
import {GlobalLookups} from "./common/global-lookups";
import {HttpClient} from "@angular/common/http";
......@@ -92,7 +94,7 @@ export class AppComponent {
this.alertService.clearAlert();
}
onDrawerContentScroll(scrollEvent: any){
onDrawerContentScroll(scrollEvent: any) {
let scrollTop = scrollEvent.srcElement.scrollTop;
this.alertService.setKeepAfterNavigationChange(scrollTop > 0)
}
......@@ -100,4 +102,34 @@ export class AppComponent {
get showSpinner(): boolean {
return this.windowSpinnerService.showSpinner
}
// Listeners for activity monitoring
// Every time one of these events are triggered, all the "watches" are reseted
@HostListener('window:mousemove')
mouseMove() {
this.refreshUserState();
}
@HostListener('keydown')
keyboardClick() {
this.refreshUserState();
}
@HostListener('touchstart')
screenTouched() {
this.refreshUserState();
}
@HostListener('touchmove')
screenDragged() {
this.refreshUserState();
}
refreshUserState() {
// if user is not logged in, do nothing
if (!this.securityService.isAuthenticated(false)) {
return;
}
this.securityService.uiUserActivityDetected()
}
}
......@@ -115,7 +115,6 @@ export class GlobalLookups {
console.log("getSmpInfo:" + err);
}
});
}
public refreshApplicationConfiguration() {
......
......@@ -20,9 +20,6 @@ import {TranslateService} from "@ngx-translate/core";
})
export class HttpSessionInterceptor implements HttpInterceptor {
private readonly TIME_BEFORE_EXPIRATION_IN_SECONDS = 60;
private readonly MAXIMUM_TIMEOUT_VALUE = 2147483647;
private timerId: number;
private timerToLogoutId: number;
......@@ -36,23 +33,28 @@ export class HttpSessionInterceptor implements HttpInterceptor {
clearTimeout(this.timerId);
clearTimeout(this.timerToLogoutId);
let user = this.securityService.getCurrentUser();
if (user?.sessionMaxIntervalTimeoutInSeconds && user.sessionMaxIntervalTimeoutInSeconds > this.TIME_BEFORE_EXPIRATION_IN_SECONDS) {
let timeout = Math.min((user.sessionMaxIntervalTimeoutInSeconds - this.TIME_BEFORE_EXPIRATION_IN_SECONDS) * 1000, this.MAXIMUM_TIMEOUT_VALUE);
// set the last UI session call
this.securityService.uiUserSessionCallDetected()
if (user?.sessionMaxIntervalTimeoutInSeconds && user.sessionMaxIntervalTimeoutInSeconds > SecurityService.TIME_BEFORE_EXPIRATION_IN_SECONDS) {
let timeout = Math.min((user.sessionMaxIntervalTimeoutInSeconds - SecurityService.TIME_BEFORE_EXPIRATION_IN_SECONDS) * 1000, SecurityService.MAXIMUM_TIMEOUT_VALUE);
this.timerId = setTimeout(() => this.sessionExpiringSoon(user.sessionMaxIntervalTimeoutInSeconds), timeout);
}
return next.handle(req);
}
private sessionExpiringSoon(timeout) {
// Logout the user after the session expires
this.timerToLogoutId = setTimeout(() => {
this.securityService.logout();
this.alertService.errorForTranslation("session.alert.message.logout.expired", true);
}, this.TIME_BEFORE_EXPIRATION_IN_SECONDS * 1000);
}, SecurityService.TIME_BEFORE_EXPIRATION_IN_SECONDS * 1000);
// disable the automatic UI session extension,
// because the user has dialog to extend the session
this.securityService.uiUserSessionExtensionDisable();
this.dialog.open(SessionExpirationDialogComponent, {
data: {
timeLeft: this.TIME_BEFORE_EXPIRATION_IN_SECONDS,
timeLeft: SecurityService.TIME_BEFORE_EXPIRATION_IN_SECONDS,
timeout
}
});
......
......@@ -16,12 +16,19 @@ import {Router} from "@angular/router";
import {TranslateService} from "@ngx-translate/core";
import {WindowSpinnerService} from "../common/services/window-spinner.service";
import {SmpErrorCode} from "../common/enums/smp-error-code.enum";
import {SmpInfo} from "../app-info/smp-info.model";
@Injectable()
export class SecurityService {
public static readonly TIME_BEFORE_EXPIRATION_IN_SECONDS: number = 60;
public static readonly DELAY_BEFORE_UI_SESSION_EXTENSION_IN_MS: number = 3000;
public static readonly MAXIMUM_TIMEOUT_VALUE: number = 2147483647;
readonly LOCAL_STORAGE_KEY_CURRENT_USER = 'currentUser';
lastUIActivity: Date = new Date();
lastUISessionCall: Date = new Date();
constructor(
private http: HttpClient,
private alertService: AlertMessageService,
......@@ -277,4 +284,51 @@ export class SecurityService {
public clearLocalStorage() {
localStorage.removeItem(this.LOCAL_STORAGE_KEY_CURRENT_USER);
}
/**
*
*/
uiUserActivityDetected() {
console.log("User activity detected");
let user = this.getCurrentUser();
if (!this.isAuthenticated(false)
|| !user
|| !this.lastUISessionCall) {
return;
}
this.lastUIActivity = new Date();
// to prevent multiple calls to the backend, we check if the last call
// was more than DELAY_BEFORE_UI_SESSION_EXTENSION_IN_MS
if (this.lastUIActivity.getTime() - this.lastUISessionCall.getTime() > SecurityService.DELAY_BEFORE_UI_SESSION_EXTENSION_IN_MS) {
// make a call to the backend to extend the session
this.refreshApplicationInfo();
}
}
/**
* This method is called when a UI session call to server is detected.
*/
uiUserSessionCallDetected() {
if (!this.isAuthenticated(false)) {
return;
}
this.lastUISessionCall = new Date();
}
uiUserSessionExtensionDisable() {
this.lastUISessionCall = null;
}
public refreshApplicationInfo() {
this.http.get<SmpInfo>(SmpConstants.REST_PUBLIC_APPLICATION_INFO)
.subscribe({
next: (res: SmpInfo): void => {
},
error: (err: any): void => {
console.log("getSmpInfo:" + err);
}
});
}
}
......@@ -53,7 +53,7 @@ public class OasisSMPResource20 implements ResourceDefinitionSpi {
@Override
public String defaultUrlSegment() {
return "oasis-bdxr-smp-2";
return "bdxr-smp-2";
}
@Override
......
......@@ -48,7 +48,7 @@ class OasisSMPResource20Test {
void defaultUrlSegment() {
String result = testInstance.defaultUrlSegment();
assertEquals("oasis-bdxr-smp-2", result);
assertEquals("bdxr-smp-2", result);
}
@Test
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment