From aff63882ac6b193570a0abab64f7f7e6d9647b48 Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Thu, 19 Oct 2017 14:46:01 -0400 Subject: [PATCH] LP#1724915 Webstaff auth timeout works w/ multiple tabs Adds a new API parameter to open-ils.session.retrieve which allows the session to be fetched without extending the auth session timeout. Teach the browser client to use the new API. Teach the browser client to notify all webstaff tabs when a logout event has occurred, so every tab can immediately log out. Signed-off-by: Bill Erickson --- Open-ILS/src/c-apps/oils_auth.c | 19 +++++++++-- Open-ILS/web/js/ui/default/staff/services/auth.js | 37 ++++++++++++++++++---- .../web/js/ui/default/staff/services/startup.js | 9 ++++-- 3 files changed, 53 insertions(+), 12 deletions(-) diff --git a/Open-ILS/src/c-apps/oils_auth.c b/Open-ILS/src/c-apps/oils_auth.c index 4afb36cf50..35199e8394 100644 --- a/Open-ILS/src/c-apps/oils_auth.c +++ b/Open-ILS/src/c-apps/oils_auth.c @@ -98,8 +98,11 @@ int osrfAppInitialize() { MODULENAME, "open-ils.auth.session.retrieve", "oilsAuthSessionRetrieve", - "Pass in the auth token and this retrieves the user object. The auth " - "timeout is reset when this call is made " + "Pass in the auth token and this retrieves the user object. By " + "default, the auth timeout is reset when this call is made. If " + "a second non-zero parameter is passed, the auth timeout info is " + "returned to the caller along with the user object. If a 3rd " + "non-zero parameter is passed, the auth timeout will not be reset." "Returns the user object (password blanked) for the given login session " "PARAMS( authToken )", 1, 0 ); @@ -1206,6 +1209,7 @@ int oilsAuthResetTimeout( osrfMethodContext* ctx ) { int oilsAuthSessionRetrieve( osrfMethodContext* ctx ) { OSRF_METHOD_VERIFY_CONTEXT(ctx); bool returnFull = false; + bool noTimeoutReset = false; const char* authToken = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0)); @@ -1214,6 +1218,14 @@ int oilsAuthSessionRetrieve( osrfMethodContext* ctx ) { const char* rt = jsonObjectGetString(jsonObjectGetIndex(ctx->params, 1)); if(rt && strcmp(rt, "0") != 0) returnFull = true; + + if (ctx->params->size > 2) { + // Avoid resetting the auth session timeout. + const char* noReset = + jsonObjectGetString(jsonObjectGetIndex(ctx->params, 2)); + if (noReset && strcmp(noReset, "0") != 0) + noTimeoutReset = true; + } } jsonObject* cacheObj = NULL; @@ -1222,7 +1234,8 @@ int oilsAuthSessionRetrieve( osrfMethodContext* ctx ) { if( authToken ){ // Reset the timeout to keep the session alive - evt = _oilsAuthResetTimeout(authToken, 0); + if (!noTimeoutReset) + evt = _oilsAuthResetTimeout(authToken, 0); if( evt && strcmp(evt->event, OILS_EVENT_SUCCESS) ) { osrfAppRespondComplete( ctx, oilsEventToJSON( evt )); // can't reset timeout diff --git a/Open-ILS/web/js/ui/default/staff/services/auth.js b/Open-ILS/web/js/ui/default/staff/services/auth.js index 3ee2296923..8912c78a4b 100644 --- a/Open-ILS/web/js/ui/default/staff/services/auth.js +++ b/Open-ILS/web/js/ui/default/staff/services/auth.js @@ -50,7 +50,10 @@ function($q , $timeout , $rootScope , $window , $location , egNet , egHatch) { // For ws_ou or wsid(), see egAuth.user().ws_ou(), etc. workstation : function() { return this.ws; - } + }, + + // Listen for logout events in other tabs + authChannel : new BroadcastChannel('eg.auth') }; /* Returns a promise, which is resolved if valid @@ -268,19 +271,33 @@ function($q , $timeout , $rootScope , $window , $location , egNet , egHatch) { * Does that setting serve a purpose in a browser environment? */ service.poll = function() { - if (!service.authtime()) return; + + if (!service.authChannel.onmessage) { + // Now that we have an authtoken, listen for logout events + // initiated by other tabs. + service.authChannel.onmessage = function(e) { + if (e.data.action == 'logout') { + $rootScope.$broadcast( + 'egAuthExpired', {startedElsewhere : true}); + } + } + } $timeout( function() { - if (!service.authtime()) return; egNet.request( 'open-ils.auth', - 'open-ils.auth.session.retrieve', service.token()) - .then(function(user) { + 'open-ils.auth.session.retrieve', + service.token(), + 0, // return extra auth details, unneeded here. + 1 // avoid extending the auth timeout + ).then(function(user) { if (user && user.classname) { // all good service.poll(); } else { - $rootScope.$broadcast('egAuthExpired') + // NOTE: we should never get here, since egNet + // filters responses for NO_SESSION events. + $rootScope.$broadcast('egAuthExpired'); } }) }, @@ -290,7 +307,13 @@ function($q , $timeout , $rootScope , $window , $location , egNet , egHatch) { ); } - service.logout = function() { + service.logout = function(broadcast) { + + if (broadcast) { + // Tell the other tabs to shut it all down. + service.authChannel.postMessage({action : 'logout'}); + } + if (service.token()) { egNet.request( 'open-ils.auth', diff --git a/Open-ILS/web/js/ui/default/staff/services/startup.js b/Open-ILS/web/js/ui/default/staff/services/startup.js index 07e1f8c0fe..f463030142 100644 --- a/Open-ILS/web/js/ui/default/staff/services/startup.js +++ b/Open-ILS/web/js/ui/default/staff/services/startup.js @@ -52,11 +52,16 @@ function($q, $rootScope, $location, $window, egIDL, egAuth, egEnv , egOrg // returns true if we are staying on the current page // false if we are redirecting to login - service.expiredAuthHandler = function() { + service.expiredAuthHandler = function(data) { if (lf.isOffline) return true; // Only set by the offline UI console.debug('egStartup.expiredAuthHandler()'); - egAuth.logout(); // clean up + + // Only notify other tabs the auth session has expired + // when this tab was the first tab to know it. + var broadcast = !(data && data.startedElsewhere); + + egAuth.logout(broadcast); // clean up // no need to redirect if we're on the /login page if ($location.path() == '/login') return true; -- 2.11.0