From 71d85bc02211a6984a127e1c6128c5bb817dce3a Mon Sep 17 00:00:00 2001 From: scottmk Date: Mon, 7 Jun 2010 13:52:29 +0000 Subject: [PATCH] Added a new login type "persist", as a peer of "opac", "staff", and "temp". It is intended for sessions that may stay open for days or weeks at a time even in the absence of activity. The default timeout interval is defined as two weeks in opensrf.xml, and may be overridden by the org unit setting "auth.persistent_login_interval". Timeout resets work a little differently for persistent logins. They have no effect unless the session is within ten minutes of expiring. When they do take effect, they reset the timeout to ten minutes, rather than to the full length of the original timeout. That way we can avoid rudely interrupting an active session without extending it excessively. The ten minute reset interval for persistent timeouts is currently hard-coded. With some further work it could be made configurable. The timeout resets for the older login types still work the way they always have. ------------ In order to make it easier to specify long timeout intervals, the auth server now accepts PostgreSQL-style interval strings, such as "15 minutes" or "2 weeks". Such strings work for any of the login types, and they work either in opensrf.xml or in the org unit setting values. If the timeout setting (in either context) is all digits, then it will be interpreted as an integral number of seconds, as it has been in the past. So existing settings will almost certainly continue to work without change. The exception -- an unlikely one -- is if the existing setting carries a leading plus sign. Under the old regime, a leading plus sign was simply superfluous, and had no effect. With the new version, a leading plus sign means that the following number is to be treated as a number of hours, rather than a number of seconds (just because that's what PostgreSQL does with it). Hence in the unlikely event that existing settings use a leading plus sign, this change will make those timeouts 3600 times as long as they should be. If the timeout interval is expressed as anything other than a string of all digits (possibly with leading and/or trailing white space), we make a database call to get PostgreSQL to interpret it for us. So the convenience of using interval strings comes at the price of some additional overhead. -------------- Besides applying the changes to the C code, it will be necessary to update the opensrf.xml file in order to define a default timeout interval for the new login type. M Open-ILS/include/openils/oils_constants.h M Open-ILS/src/c-apps/oils_auth.c M Open-ILS/examples/opensrf.xml.example git-svn-id: svn://svn.open-ils.org/ILS/trunk@16612 dcc99617-32d9-48b4-a31d-7c20da2025e4 --- Open-ILS/examples/opensrf.xml.example | 1 + Open-ILS/include/openils/oils_constants.h | 2 +- Open-ILS/src/c-apps/oils_auth.c | 130 +++++++++++++++++----- 3 files changed, 102 insertions(+), 31 deletions(-) diff --git a/Open-ILS/examples/opensrf.xml.example b/Open-ILS/examples/opensrf.xml.example index 6a98594ddc..a25277c454 100644 --- a/Open-ILS/examples/opensrf.xml.example +++ b/Open-ILS/examples/opensrf.xml.example @@ -395,6 +395,7 @@ vim:et:ts=4:sw=4: 420 7200 300 + 2 weeks diff --git a/Open-ILS/include/openils/oils_constants.h b/Open-ILS/include/openils/oils_constants.h index ab4ecf9cad..b2ec580ecd 100644 --- a/Open-ILS/include/openils/oils_constants.h +++ b/Open-ILS/include/openils/oils_constants.h @@ -9,7 +9,7 @@ extern "C" { #define OILS_ORG_SETTING_OPAC_TIMEOUT "auth.opac_timeout" #define OILS_ORG_SETTING_STAFF_TIMEOUT "auth.staff_timeout" #define OILS_ORG_SETTING_TEMP_TIMEOUT "auth.temp_timeout" - +#define OILS_ORG_SETTING_PERSIST_TIMEOUT "auth.persistent_login_interval" /* Events ------------------------------------------------------ */ #define OILS_EVENT_SUCCESS "SUCCESS" diff --git a/Open-ILS/src/c-apps/oils_auth.c b/Open-ILS/src/c-apps/oils_auth.c index 2c572a6f0b..2f04ac2e4e 100644 --- a/Open-ILS/src/c-apps/oils_auth.c +++ b/Open-ILS/src/c-apps/oils_auth.c @@ -14,7 +14,7 @@ #define OILS_AUTH_OPAC "opac" #define OILS_AUTH_STAFF "staff" #define OILS_AUTH_TEMP "temp" -#define OILS_AUTH_PERSISTENT "persistent" +#define OILS_AUTH_PERSIST "persist" // Default time for extending a persistent session: ten minutes #define DEFAULT_RESET_INTERVAL 10 * 60 @@ -25,6 +25,7 @@ int osrfAppChildInit(); static long _oilsAuthOPACTimeout = 0; static long _oilsAuthStaffTimeout = 0; static long _oilsAuthOverrideTimeout = 0; +static long _oilsAuthPersistTimeout = 0; /** @@ -177,6 +178,9 @@ static int oilsAuthCheckLoginPerm( } else if(!strcasecmp(type, OILS_AUTH_TEMP)) { char* permissions[] = { "STAFF_LOGIN" }; perm = oilsUtilsCheckPerms( oilsFMGetObjectId( userObj ), -1, permissions, 1 ); + } else if(!strcasecmp(type, OILS_AUTH_PERSIST)) { + char* permissions[] = { "PERSISTENT_LOGIN" }; + perm = oilsUtilsCheckPerms( oilsFMGetObjectId( userObj ), -1, permissions, 1 ); } if(perm) { @@ -255,12 +259,23 @@ static int oilsAuthVerifyPassword( const osrfMethodContext* ctx, } /** - Calculates the login timeout - 1. If orgloc is 1 or greater and has a timeout specified as an - org unit setting, it is used - 2. If orgloc is not valid, we check the org unit auth timeout - setting for the home org unit of the user logging in - 3. If that setting is not defined, we use the configured defaults + @brief Determine the login timeout. + @param userObj Pointer to an object describing the user. + @param type Pointer to one of four possible character strings identifying the login type. + @param orgloc Org unit to use for settings lookups (negative or zero means unspecified) + @return The length of the timeout, in seconds. + + The default timeout value comes from the configuration file, and depends on the + login type. + + The default may be overridden by a corresponding org unit setting. The @a orgloc + parameter says what org unit to use for the lookup. If @a orgloc <= 0, or if the + lookup for @a orgloc yields no result, we look up the setting for the user's home org unit + instead (except that if it's the same as @a orgloc we don't bother repeating the lookup). + + Whether defined in the config file or in an org unit setting, a timeout value may be + expressed as a raw number (i.e. all digits, possibly with leading and/or trailing white + space) or as an interval string to be translated into seconds by PostgreSQL. */ static long oilsAuthGetTimeout( const jsonObject* userObj, const char* type, int orgloc ) { @@ -270,59 +285,101 @@ static long oilsAuthGetTimeout( const jsonObject* userObj, const char* type, int value_obj = osrf_settings_host_value_object( "/apps/open-ils.auth/app_settings/default_timeout/opac" ); - _oilsAuthOPACTimeout = (long) jsonObjectGetNumber(value_obj); + _oilsAuthOPACTimeout = oilsUtilsIntervalToSeconds( jsonObjectGetString( value_obj )); jsonObjectFree(value_obj); + if( -1 == _oilsAuthOPACTimeout ) { + osrfLogWarning( OSRF_LOG_MARK, "Invalid default timeout for OPAC logins" ); + _oilsAuthOPACTimeout = 0; + } value_obj = osrf_settings_host_value_object( "/apps/open-ils.auth/app_settings/default_timeout/staff" ); - _oilsAuthStaffTimeout = (long) jsonObjectGetNumber(value_obj); + _oilsAuthStaffTimeout = oilsUtilsIntervalToSeconds( jsonObjectGetString( value_obj )); jsonObjectFree(value_obj); + if( -1 == _oilsAuthStaffTimeout ) { + osrfLogWarning( OSRF_LOG_MARK, "Invalid default timeout for staff logins" ); + _oilsAuthStaffTimeout = 0; + } value_obj = osrf_settings_host_value_object( - "/apps/open-ils.auth/app_settings/default_timeout/temp" ); - _oilsAuthOverrideTimeout = (long) jsonObjectGetNumber(value_obj); + "/apps/open-ils.auth/app_settings/default_timeout/temp" ); + _oilsAuthOverrideTimeout = oilsUtilsIntervalToSeconds( jsonObjectGetString( value_obj )); jsonObjectFree(value_obj); + if( -1 == _oilsAuthOverrideTimeout ) { + osrfLogWarning( OSRF_LOG_MARK, "Invalid default timeout for temp logins" ); + _oilsAuthOverrideTimeout = 0; + } + value_obj = osrf_settings_host_value_object( + "/apps/open-ils.auth/app_settings/default_timeout/persist" ); + _oilsAuthPersistTimeout = oilsUtilsIntervalToSeconds( jsonObjectGetString( value_obj )); + jsonObjectFree(value_obj); + if( -1 == _oilsAuthPersistTimeout ) { + osrfLogWarning( OSRF_LOG_MARK, "Invalid default timeout for persist logins" ); + _oilsAuthPersistTimeout = 0; + } - osrfLogInfo(OSRF_LOG_MARK, - "Set default auth timeouts: opac => %ld : staff => %ld : temp => %ld", - _oilsAuthOPACTimeout, _oilsAuthStaffTimeout, _oilsAuthOverrideTimeout ); + osrfLogInfo(OSRF_LOG_MARK, "Set default auth timeouts: " + "opac => %ld : staff => %ld : temp => %ld : persist => %ld", + _oilsAuthOPACTimeout, _oilsAuthStaffTimeout, + _oilsAuthOverrideTimeout, _oilsAuthPersistTimeout ); } - char* setting = NULL; - int home_ou = (int) jsonObjectGetNumber( oilsFMGetObject( userObj, "home_ou" )); if(orgloc < 1) orgloc = home_ou; - if(!strcmp(type, OILS_AUTH_OPAC)) + char* setting = NULL; + long default_timeout = 0; + + if( !strcmp( type, OILS_AUTH_OPAC )) { setting = OILS_ORG_SETTING_OPAC_TIMEOUT; - else if(!strcmp(type, OILS_AUTH_STAFF)) + default_timeout = _oilsAuthOPACTimeout; + } else if( !strcmp( type, OILS_AUTH_STAFF )) { setting = OILS_ORG_SETTING_STAFF_TIMEOUT; - else if(!strcmp(type, OILS_AUTH_TEMP)) + default_timeout = _oilsAuthStaffTimeout; + } else if( !strcmp( type, OILS_AUTH_TEMP )) { setting = OILS_ORG_SETTING_TEMP_TIMEOUT; + default_timeout = _oilsAuthOverrideTimeout; + } else if( !strcmp( type, OILS_AUTH_PERSIST )) { + setting = OILS_ORG_SETTING_PERSIST_TIMEOUT; + default_timeout = _oilsAuthPersistTimeout; + } + // Get the org unit setting, if there is one. char* timeout = oilsUtilsFetchOrgSetting( orgloc, setting ); - if(!timeout) { if( orgloc != home_ou ) { osrfLogDebug(OSRF_LOG_MARK, "Auth timeout not defined for org %d, " - "trying home_ou %d", orgloc, home_ou ); + "trying home_ou %d", orgloc, home_ou ); timeout = oilsUtilsFetchOrgSetting( home_ou, setting ); } - if(!timeout) { - if( !strcmp(type, OILS_AUTH_STAFF )) - return _oilsAuthStaffTimeout; - else if( !strcmp( type, OILS_AUTH_TEMP )) - return _oilsAuthOverrideTimeout; - else - return _oilsAuthOPACTimeout; + } + + if(!timeout) + return default_timeout; // No override from org unit setting + + // Translate the org unit setting to a number + long t; + if( !*timeout ) { + osrfLogWarning( OSRF_LOG_MARK, + "Timeout org unit setting is an empty string for %s login; using default", + timeout, type ); + t = default_timeout; + } else { + // Treat timeout string as an interval, and convert it to seconds + t = oilsUtilsIntervalToSeconds( timeout ); + if( -1 == t ) { + // Unable to convert; possibly an invalid interval string + osrfLogError( OSRF_LOG_MARK, + "Unable to convert timeout interval \"%s\" for %s login; using default", + timeout, type ); + t = default_timeout; } } - long t = (long) atof(timeout); free(timeout); - return t ; + return t; } /* @@ -365,6 +422,19 @@ static oilsEvent* oilsAuthHandleLoginOK( jsonObject* userObj, const char* uname, jsonObject* cacheObj = jsonParseFmt( "{\"authtime\": %ld}", timeout ); jsonObjectSetKey( cacheObj, "userobj", jsonObjectClone(userObj)); + if( !strcmp( type, OILS_AUTH_PERSIST )) { + // Add entries for endtime and reset_interval, so that we can gracefully + // extend the session a bit if the user is active toward the end of the + // timeout originally specified. + time_t endtime = time( NULL ) + timeout; + jsonObjectSetKey( cacheObj, "endtime", jsonNewNumberObject( (double) endtime ) ); + + // Reset interval is hard-coded for now, but if we ever want to make it + // configurable, this is the place to do it: + jsonObjectSetKey( cacheObj, "reset_interval", + jsonNewNumberObject( (double) DEFAULT_RESET_INTERVAL )); + } + osrfCachePutObject( authKey, cacheObj, (time_t) timeout ); jsonObjectFree(cacheObj); osrfLogInternal(OSRF_LOG_MARK, "oilsAuthHandleLoginOK(): Placed user object into cache"); -- 2.43.2