1 #include "opensrf/osrf_app_session.h"
2 #include "opensrf/osrf_application.h"
3 #include "opensrf/osrf_settings.h"
4 #include "opensrf/osrf_json.h"
5 #include "opensrf/log.h"
6 #include "openils/oils_utils.h"
7 #include "openils/oils_constants.h"
8 #include "openils/oils_event.h"
10 #define OILS_AUTH_CACHE_PRFX "oils_auth_"
12 #define MODULENAME "open-ils.auth"
14 #define OILS_AUTH_OPAC "opac"
15 #define OILS_AUTH_STAFF "staff"
16 #define OILS_AUTH_TEMP "temp"
17 #define OILS_AUTH_PERSIST "persist"
19 // Default time for extending a persistent session: ten minutes
20 #define DEFAULT_RESET_INTERVAL 10 * 60
22 int osrfAppInitialize();
23 int osrfAppChildInit();
25 static long _oilsAuthOPACTimeout = 0;
26 static long _oilsAuthStaffTimeout = 0;
27 static long _oilsAuthOverrideTimeout = 0;
28 static long _oilsAuthPersistTimeout = 0;
32 @brief Initialize the application by registering functions for method calls.
33 @return Zero in all cases.
35 int osrfAppInitialize() {
37 osrfLogInfo(OSRF_LOG_MARK, "Initializing Auth Server...");
39 /* load and parse the IDL */
40 if (!oilsInitIDL(NULL)) return 1; /* return non-zero to indicate error */
42 osrfAppRegisterMethod(
44 "open-ils.auth.authenticate.init",
46 "Start the authentication process and returns the intermediate authentication seed"
47 " PARAMS( username )", 1, 0 );
49 osrfAppRegisterMethod(
51 "open-ils.auth.authenticate.complete",
53 "Completes the authentication process. Returns an object like so: "
54 "{authtoken : <token>, authtime:<time>}, where authtoken is the login "
55 "token and authtime is the number of seconds the session will be active"
56 "PARAMS(username, md5sum( seed + md5sum( password ) ), type, org_id ) "
57 "type can be one of 'opac','staff', or 'temp' and it defaults to 'staff' "
58 "org_id is the location at which the login should be considered "
59 "active for login timeout purposes", 1, 0 );
61 osrfAppRegisterMethod(
63 "open-ils.auth.session.retrieve",
64 "oilsAuthSessionRetrieve",
65 "Pass in the auth token and this retrieves the user object. The auth "
66 "timeout is reset when this call is made "
67 "Returns the user object (password blanked) for the given login session "
68 "PARAMS( authToken )", 1, 0 );
70 osrfAppRegisterMethod(
72 "open-ils.auth.session.delete",
73 "oilsAuthSessionDelete",
74 "Destroys the given login session "
75 "PARAMS( authToken )", 1, 0 );
77 osrfAppRegisterMethod(
79 "open-ils.auth.session.reset_timeout",
80 "oilsAuthResetTimeout",
81 "Resets the login timeout for the given session "
82 "Returns an ILS Event with payload = session_timeout of session "
83 "if found, otherwise returns the NO_SESSION event"
84 "PARAMS( authToken )", 1, 0 );
90 @brief Dummy placeholder for initializing a server drone.
92 There is nothing to do, so do nothing.
94 int osrfAppChildInit() {
99 @brief Implement the "init" method.
100 @param ctx The method context.
101 @return Zero if successful, or -1 if not.
106 Return to client: Intermediate authentication seed.
108 Combine the username with a timestamp and process ID, and take an md5 hash of the result.
109 Store the hash in memcache, with a key based on the username. Then return the hash to
112 However: if the username includes one or more embedded blank spaces, return a dummy
113 hash without storing anything in memcache. The dummy will never match a stored hash, so
114 any attempt to authenticate with it will fail.
116 int oilsAuthInit( osrfMethodContext* ctx ) {
117 OSRF_METHOD_VERIFY_CONTEXT(ctx);
119 char* username = jsonObjectToSimpleString( jsonObjectGetIndex(ctx->params, 0) );
124 if( strchr( username, ' ' ) ) {
126 // Embedded spaces are not allowed in a username. Use "x" as a dummy
127 // seed. It will never be a valid seed because 'x' is not a hex digit.
128 resp = jsonNewObject( "x" );
132 // Build a key and a seed; store them in memcache.
133 char* key = va_list_to_string( "%s%s", OILS_AUTH_CACHE_PRFX, username );
134 char* seed = md5sum( "%d.%ld.%s", (int) time(NULL), (long) getpid(), username );
135 osrfCachePutString( key, seed, 30 );
137 osrfLogDebug( OSRF_LOG_MARK, "oilsAuthInit(): has seed %s and key %s", seed, key );
139 // Build a returnable object containing the seed.
140 resp = jsonNewObject( seed );
146 // Return the seed to the client.
147 osrfAppRespondComplete( ctx, resp );
149 jsonObjectFree(resp);
154 return -1; // Error: no username parameter
158 Verifies that the user has permission to login with the
159 given type. If the permission fails, an oilsEvent is returned
161 @return -1 if the permission check failed, 0 if the permission
164 static int oilsAuthCheckLoginPerm(
165 osrfMethodContext* ctx, const jsonObject* userObj, const char* type ) {
167 if(!(userObj && type)) return -1;
168 oilsEvent* perm = NULL;
170 if(!strcasecmp(type, OILS_AUTH_OPAC)) {
171 char* permissions[] = { "OPAC_LOGIN" };
172 perm = oilsUtilsCheckPerms( oilsFMGetObjectId( userObj ), -1, permissions, 1 );
174 } else if(!strcasecmp(type, OILS_AUTH_STAFF)) {
175 char* permissions[] = { "STAFF_LOGIN" };
176 perm = oilsUtilsCheckPerms( oilsFMGetObjectId( userObj ), -1, permissions, 1 );
178 } else if(!strcasecmp(type, OILS_AUTH_TEMP)) {
179 char* permissions[] = { "STAFF_LOGIN" };
180 perm = oilsUtilsCheckPerms( oilsFMGetObjectId( userObj ), -1, permissions, 1 );
181 } else if(!strcasecmp(type, OILS_AUTH_PERSIST)) {
182 char* permissions[] = { "PERSISTENT_LOGIN" };
183 perm = oilsUtilsCheckPerms( oilsFMGetObjectId( userObj ), -1, permissions, 1 );
187 osrfAppRespondComplete( ctx, oilsEventToJSON(perm) );
196 Returns 1 if the password provided matches the user's real password
201 @brief Verify the password received from the client.
202 @param ctx The method context.
203 @param userObj An object from the database, representing the user.
204 @param password An obfuscated password received from the client.
205 @return 1 if the password is valid; 0 if it isn't; or -1 upon error.
207 (None of the so-called "passwords" used here are in plaintext. All have been passed
208 through at least one layer of hashing to obfuscate them.)
210 Take the password from the user object. Append it to the username seed from memcache,
211 as stored previously by a call to the init method. Take an md5 hash of the result.
212 Then compare this hash to the password received from the client.
214 In order for the two to match, other than by dumb luck, the client had to construct
215 the password it passed in the same way. That means it neded to know not only the
216 original password (either hashed or plaintext), but also the seed. The latter requirement
217 means that the client process needs either to be the same process that called the init
218 method or to receive the seed from the process that did so.
220 static int oilsAuthVerifyPassword( const osrfMethodContext* ctx,
221 const jsonObject* userObj, const char* uname, const char* password ) {
223 // Get the username seed, as stored previously in memcache by the init method
224 char* seed = osrfCacheGetString( "%s%s", OILS_AUTH_CACHE_PRFX, uname );
226 return osrfAppRequestRespondException( ctx->session,
227 ctx->request, "No authentication seed found. "
228 "open-ils.auth.authenticate.init must be called first");
231 // Get the hashed password from the user object
232 char* realPassword = oilsFMGetString( userObj, "passwd" );
234 osrfLogInternal(OSRF_LOG_MARK, "oilsAuth retrieved real password: [%s]", realPassword);
235 osrfLogDebug(OSRF_LOG_MARK, "oilsAuth retrieved seed from cache: %s", seed );
237 // Concatenate them and take an MD5 hash of the result
238 char* maskedPw = md5sum( "%s%s", seed, realPassword );
244 // This happens only if md5sum() runs out of memory
246 return -1; // md5sum() ran out of memory
249 osrfLogDebug(OSRF_LOG_MARK, "oilsAuth generated masked password %s. "
250 "Testing against provided password %s", maskedPw, password );
253 if( !strcmp( maskedPw, password ) )
262 @brief Determine the login timeout.
263 @param userObj Pointer to an object describing the user.
264 @param type Pointer to one of four possible character strings identifying the login type.
265 @param orgloc Org unit to use for settings lookups (negative or zero means unspecified)
266 @return The length of the timeout, in seconds.
268 The default timeout value comes from the configuration file, and depends on the
271 The default may be overridden by a corresponding org unit setting. The @a orgloc
272 parameter says what org unit to use for the lookup. If @a orgloc <= 0, or if the
273 lookup for @a orgloc yields no result, we look up the setting for the user's home org unit
274 instead (except that if it's the same as @a orgloc we don't bother repeating the lookup).
276 Whether defined in the config file or in an org unit setting, a timeout value may be
277 expressed as a raw number (i.e. all digits, possibly with leading and/or trailing white
278 space) or as an interval string to be translated into seconds by PostgreSQL.
280 static long oilsAuthGetTimeout( const jsonObject* userObj, const char* type, int orgloc ) {
282 if(!_oilsAuthOPACTimeout) { /* Load the default timeouts */
284 jsonObject* value_obj;
286 value_obj = osrf_settings_host_value_object(
287 "/apps/open-ils.auth/app_settings/default_timeout/opac" );
288 _oilsAuthOPACTimeout = oilsUtilsIntervalToSeconds( jsonObjectGetString( value_obj ));
289 jsonObjectFree(value_obj);
290 if( -1 == _oilsAuthOPACTimeout ) {
291 osrfLogWarning( OSRF_LOG_MARK, "Invalid default timeout for OPAC logins" );
292 _oilsAuthOPACTimeout = 0;
295 value_obj = osrf_settings_host_value_object(
296 "/apps/open-ils.auth/app_settings/default_timeout/staff" );
297 _oilsAuthStaffTimeout = oilsUtilsIntervalToSeconds( jsonObjectGetString( value_obj ));
298 jsonObjectFree(value_obj);
299 if( -1 == _oilsAuthStaffTimeout ) {
300 osrfLogWarning( OSRF_LOG_MARK, "Invalid default timeout for staff logins" );
301 _oilsAuthStaffTimeout = 0;
304 value_obj = osrf_settings_host_value_object(
305 "/apps/open-ils.auth/app_settings/default_timeout/temp" );
306 _oilsAuthOverrideTimeout = oilsUtilsIntervalToSeconds( jsonObjectGetString( value_obj ));
307 jsonObjectFree(value_obj);
308 if( -1 == _oilsAuthOverrideTimeout ) {
309 osrfLogWarning( OSRF_LOG_MARK, "Invalid default timeout for temp logins" );
310 _oilsAuthOverrideTimeout = 0;
313 value_obj = osrf_settings_host_value_object(
314 "/apps/open-ils.auth/app_settings/default_timeout/persist" );
315 _oilsAuthPersistTimeout = oilsUtilsIntervalToSeconds( jsonObjectGetString( value_obj ));
316 jsonObjectFree(value_obj);
317 if( -1 == _oilsAuthPersistTimeout ) {
318 osrfLogWarning( OSRF_LOG_MARK, "Invalid default timeout for persist logins" );
319 _oilsAuthPersistTimeout = 0;
322 osrfLogInfo(OSRF_LOG_MARK, "Set default auth timeouts: "
323 "opac => %ld : staff => %ld : temp => %ld : persist => %ld",
324 _oilsAuthOPACTimeout, _oilsAuthStaffTimeout,
325 _oilsAuthOverrideTimeout, _oilsAuthPersistTimeout );
328 int home_ou = (int) jsonObjectGetNumber( oilsFMGetObject( userObj, "home_ou" ));
332 char* setting = NULL;
333 long default_timeout = 0;
335 if( !strcmp( type, OILS_AUTH_OPAC )) {
336 setting = OILS_ORG_SETTING_OPAC_TIMEOUT;
337 default_timeout = _oilsAuthOPACTimeout;
338 } else if( !strcmp( type, OILS_AUTH_STAFF )) {
339 setting = OILS_ORG_SETTING_STAFF_TIMEOUT;
340 default_timeout = _oilsAuthStaffTimeout;
341 } else if( !strcmp( type, OILS_AUTH_TEMP )) {
342 setting = OILS_ORG_SETTING_TEMP_TIMEOUT;
343 default_timeout = _oilsAuthOverrideTimeout;
344 } else if( !strcmp( type, OILS_AUTH_PERSIST )) {
345 setting = OILS_ORG_SETTING_PERSIST_TIMEOUT;
346 default_timeout = _oilsAuthPersistTimeout;
349 // Get the org unit setting, if there is one.
350 char* timeout = oilsUtilsFetchOrgSetting( orgloc, setting );
352 if( orgloc != home_ou ) {
353 osrfLogDebug(OSRF_LOG_MARK, "Auth timeout not defined for org %d, "
354 "trying home_ou %d", orgloc, home_ou );
355 timeout = oilsUtilsFetchOrgSetting( home_ou, setting );
360 return default_timeout; // No override from org unit setting
362 // Translate the org unit setting to a number
365 osrfLogWarning( OSRF_LOG_MARK,
366 "Timeout org unit setting is an empty string for %s login; using default",
370 // Treat timeout string as an interval, and convert it to seconds
371 t = oilsUtilsIntervalToSeconds( timeout );
373 // Unable to convert; possibly an invalid interval string
374 osrfLogError( OSRF_LOG_MARK,
375 "Unable to convert timeout interval \"%s\" for %s login; using default",
386 Adds the authentication token to the user cache. The timeout for the
387 auth token is based on the type of login as well as (if type=='opac')
389 Returns the event that should be returned to the user.
392 static oilsEvent* oilsAuthHandleLoginOK( jsonObject* userObj, const char* uname,
393 const char* type, int orgloc, const char* workstation ) {
398 char* wsorg = jsonObjectToSimpleString(oilsFMGetObject(userObj, "ws_ou"));
399 if(wsorg) { /* if there is a workstation, use it for the timeout */
400 osrfLogDebug( OSRF_LOG_MARK,
401 "Auth session trying workstation id %d for auth timeout", atoi(wsorg));
402 timeout = oilsAuthGetTimeout( userObj, type, atoi(wsorg) );
405 osrfLogDebug( OSRF_LOG_MARK,
406 "Auth session trying org from param [%d] for auth timeout", orgloc );
407 timeout = oilsAuthGetTimeout( userObj, type, orgloc );
409 osrfLogDebug(OSRF_LOG_MARK, "Auth session timeout for %s: %ld", uname, timeout );
411 char* string = va_list_to_string(
412 "%d.%ld.%s", (long) getpid(), time(NULL), uname );
413 char* authToken = md5sum(string);
414 char* authKey = va_list_to_string(
415 "%s%s", OILS_AUTH_CACHE_PRFX, authToken );
417 const char* ws = (workstation) ? workstation : "";
418 osrfLogActivity(OSRF_LOG_MARK,
419 "successful login: username=%s, authtoken=%s, workstation=%s", uname, authToken, ws );
421 oilsFMSetString( userObj, "passwd", "" );
422 jsonObject* cacheObj = jsonParseFmt( "{\"authtime\": %ld}", timeout );
423 jsonObjectSetKey( cacheObj, "userobj", jsonObjectClone(userObj));
425 if( !strcmp( type, OILS_AUTH_PERSIST )) {
426 // Add entries for endtime and reset_interval, so that we can gracefully
427 // extend the session a bit if the user is active toward the end of the
428 // timeout originally specified.
429 time_t endtime = time( NULL ) + timeout;
430 jsonObjectSetKey( cacheObj, "endtime", jsonNewNumberObject( (double) endtime ) );
432 // Reset interval is hard-coded for now, but if we ever want to make it
433 // configurable, this is the place to do it:
434 jsonObjectSetKey( cacheObj, "reset_interval",
435 jsonNewNumberObject( (double) DEFAULT_RESET_INTERVAL ));
438 osrfCachePutObject( authKey, cacheObj, (time_t) timeout );
439 jsonObjectFree(cacheObj);
440 osrfLogInternal(OSRF_LOG_MARK, "oilsAuthHandleLoginOK(): Placed user object into cache");
441 jsonObject* payload = jsonParseFmt(
442 "{ \"authtoken\": \"%s\", \"authtime\": %ld }", authToken, timeout );
444 response = oilsNewEvent2( OSRF_LOG_MARK, OILS_EVENT_SUCCESS, payload );
445 free(string); free(authToken); free(authKey);
446 jsonObjectFree(payload);
451 static oilsEvent* oilsAuthVerifyWorkstation(
452 const osrfMethodContext* ctx, jsonObject* userObj, const char* ws ) {
453 osrfLogInfo(OSRF_LOG_MARK, "Attaching workstation to user at login: %s", ws);
454 jsonObject* workstation = oilsUtilsFetchWorkstationByName(ws);
455 if(!workstation || workstation->type == JSON_NULL) {
456 jsonObjectFree(workstation);
457 return oilsNewEvent(OSRF_LOG_MARK, "WORKSTATION_NOT_FOUND");
459 long wsid = oilsFMGetObjectId(workstation);
460 LONG_TO_STRING(wsid);
461 char* orgid = oilsFMGetString(workstation, "owning_lib");
462 oilsFMSetString(userObj, "wsid", LONGSTR);
463 oilsFMSetString(userObj, "ws_ou", orgid);
465 jsonObjectFree(workstation);
472 @brief Implement the "complete" method.
473 @param ctx The method context.
474 @return -1 upon error; zero if successful, and if a STATUS message has been sent to the
475 client to indicate completion; a positive integer if successful but no such STATUS
476 message has been sent.
479 - a hash with some combination of the following elements:
482 - "password" (hashed with the cached seed; not plaintext)
487 The password is required. Either a username or a barcode must also be present.
489 Return to client: Intermediate authentication seed.
491 Validate the password, using the username if available, or the barcode if not. The
492 user must be active, and not barred from logging on. The barcode, if used for
493 authentication, must be active as well. The workstation, if specified, must be valid.
495 Upon deciding whether to allow the logon, return a corresponding event to the client.
497 int oilsAuthComplete( osrfMethodContext* ctx ) {
498 OSRF_METHOD_VERIFY_CONTEXT(ctx);
500 const jsonObject* args = jsonObjectGetIndex(ctx->params, 0);
502 const char* uname = jsonObjectGetString(jsonObjectGetKeyConst(args, "username"));
503 const char* password = jsonObjectGetString(jsonObjectGetKeyConst(args, "password"));
504 const char* type = jsonObjectGetString(jsonObjectGetKeyConst(args, "type"));
505 int orgloc = (int) jsonObjectGetNumber(jsonObjectGetKeyConst(args, "org"));
506 const char* workstation = jsonObjectGetString(jsonObjectGetKeyConst(args, "workstation"));
507 const char* barcode = jsonObjectGetString(jsonObjectGetKeyConst(args, "barcode"));
509 const char* ws = (workstation) ? workstation : "";
512 type = OILS_AUTH_STAFF;
514 if( !( (uname || barcode) && password) ) {
515 return osrfAppRequestRespondException( ctx->session, ctx->request,
516 "username/barcode and password required for method: %s", ctx->method->name );
519 oilsEvent* response = NULL;
520 jsonObject* userObj = NULL;
521 int card_active = 1; // boolean; assume active until proven otherwise
523 // Fetch a row from the actor.usr table, by username if available,
524 // or by barcode if not.
526 userObj = oilsUtilsFetchUserByUsername( uname );
527 if( userObj && JSON_NULL == userObj->type ) {
528 jsonObjectFree( userObj );
529 userObj = NULL; // username not found
533 // Read from actor.card by barcode
535 osrfLogInfo( OSRF_LOG_MARK, "Fetching user by barcode %s", barcode );
537 jsonObject* params = jsonParseFmt("{\"barcode\":\"%s\"}", barcode);
538 jsonObject* card = oilsUtilsQuickReq(
539 "open-ils.cstore", "open-ils.cstore.direct.actor.card.search", params );
540 jsonObjectFree( params );
542 if( card && card->type != JSON_NULL ) {
543 // Determine whether the card is active
544 char* card_active_str = oilsFMGetString( card, "active" );
545 card_active = oilsUtilsIsDBTrue( card_active_str );
546 free( card_active_str );
548 // Look up the user who owns the card
549 char* userid = oilsFMGetString( card, "usr" );
550 jsonObjectFree( card );
551 params = jsonParseFmt( "[%s]", userid );
553 userObj = oilsUtilsQuickReq(
554 "open-ils.cstore", "open-ils.cstore.direct.actor.user.retrieve", params );
555 jsonObjectFree( params );
556 if( userObj && JSON_NULL == userObj->type ) {
557 // user not found (shouldn't happen, due to foreign key)
558 jsonObjectFree( userObj );
565 response = oilsNewEvent( OSRF_LOG_MARK, OILS_EVENT_AUTH_FAILED );
566 osrfLogInfo(OSRF_LOG_MARK, "failed login: username=%s, barcode=%s, workstation=%s",
567 uname, (barcode ? barcode : "(none)"), ws );
568 osrfAppRespondComplete( ctx, oilsEventToJSON(response) );
569 oilsEventFree(response);
570 return 0; // No such user
573 // Such a user exists. Now see if he or she has the right credentials.
576 passOK = oilsAuthVerifyPassword( ctx, userObj, uname, password );
578 passOK = oilsAuthVerifyPassword( ctx, userObj, barcode, password );
581 jsonObjectFree(userObj);
585 // See if the account is active
586 char* active = oilsFMGetString(userObj, "active");
587 if( !oilsUtilsIsDBTrue(active) ) {
589 response = oilsNewEvent( OSRF_LOG_MARK, "PATRON_INACTIVE" );
591 response = oilsNewEvent( OSRF_LOG_MARK, OILS_EVENT_AUTH_FAILED );
593 osrfAppRespondComplete( ctx, oilsEventToJSON(response) );
594 oilsEventFree(response);
595 jsonObjectFree(userObj);
601 osrfLogInfo( OSRF_LOG_MARK, "Fetching card by barcode %s", barcode );
604 osrfLogInfo( OSRF_LOG_MARK, "barcode %s is not active, returning event", barcode );
605 response = oilsNewEvent( OSRF_LOG_MARK, "PATRON_CARD_INACTIVE" );
606 osrfAppRespondComplete( ctx, oilsEventToJSON( response ) );
607 oilsEventFree( response );
608 jsonObjectFree( userObj );
613 // See if the user is even allowed to log in
614 if( oilsAuthCheckLoginPerm( ctx, userObj, type ) == -1 ) {
615 jsonObjectFree(userObj);
619 // If a workstation is defined, add the workstation info
620 if( workstation != NULL ) {
621 osrfLogDebug(OSRF_LOG_MARK, "Workstation is %s", workstation);
622 response = oilsAuthVerifyWorkstation( ctx, userObj, workstation );
624 jsonObjectFree(userObj);
625 osrfAppRespondComplete( ctx, oilsEventToJSON(response) );
626 oilsEventFree(response);
631 // Otherwise, use the home org as the workstation org on the user
632 char* orgid = oilsFMGetString(userObj, "home_ou");
633 oilsFMSetString(userObj, "ws_ou", orgid);
637 char* freeable_uname = NULL;
639 uname = freeable_uname = oilsFMGetString( userObj, "usrname" );
643 response = oilsAuthHandleLoginOK( userObj, uname, type, orgloc, workstation );
646 response = oilsNewEvent( OSRF_LOG_MARK, OILS_EVENT_AUTH_FAILED );
647 osrfLogInfo(OSRF_LOG_MARK, "failed login: username=%s, barcode=%s, workstation=%s",
648 uname, (barcode ? barcode : "(none)"), ws );
651 jsonObjectFree(userObj);
652 osrfAppRespondComplete( ctx, oilsEventToJSON(response) );
653 oilsEventFree(response);
656 free(freeable_uname);
663 int oilsAuthSessionDelete( osrfMethodContext* ctx ) {
664 OSRF_METHOD_VERIFY_CONTEXT(ctx);
666 const char* authToken = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0) );
667 jsonObject* resp = NULL;
670 osrfLogDebug(OSRF_LOG_MARK, "Removing auth session: %s", authToken );
671 char* key = va_list_to_string("%s%s", OILS_AUTH_CACHE_PRFX, authToken ); /**/
672 osrfCacheRemove(key);
673 resp = jsonNewObject(authToken); /**/
677 osrfAppRespondComplete( ctx, resp );
678 jsonObjectFree(resp);
683 Resets the auth login timeout
684 @return The event object, OILS_EVENT_SUCCESS, or OILS_EVENT_NO_SESSION
686 static oilsEvent* _oilsAuthResetTimeout( const char* authToken ) {
687 if(!authToken) return NULL;
689 oilsEvent* evt = NULL;
692 osrfLogDebug(OSRF_LOG_MARK, "Resetting auth timeout for session %s", authToken);
693 char* key = va_list_to_string("%s%s", OILS_AUTH_CACHE_PRFX, authToken );
694 jsonObject* cacheObj = osrfCacheGetObject( key );
697 osrfLogInfo(OSRF_LOG_MARK, "No user in the cache exists with key %s", key);
698 evt = oilsNewEvent(OSRF_LOG_MARK, OILS_EVENT_NO_SESSION);
701 // Determine a new timeout value
702 jsonObject* endtime_obj = jsonObjectGetKey( cacheObj, "endtime" );
704 // Extend the current endtime by a fixed amount
705 time_t endtime = (time_t) jsonObjectGetNumber( endtime_obj );
706 int reset_interval = DEFAULT_RESET_INTERVAL;
707 jsonObject* reset_interval_obj = jsonObjectGetKey( cacheObj, "reset_interval" );
708 if( reset_interval_obj ) {
709 reset_interval = (int) jsonObjectGetNumber( reset_interval_obj );
710 if( reset_interval <= 0 )
711 reset_interval = DEFAULT_RESET_INTERVAL;
714 time_t now = time( NULL );
715 time_t new_endtime = now + reset_interval;
716 if( new_endtime > endtime ) {
717 // Keep the session alive a little longer
718 jsonObjectSetNumber( endtime_obj, (double) new_endtime );
719 timeout = reset_interval;
720 osrfCachePutObject( key, cacheObj, timeout );
722 // The session isn't close to expiring, so don't reset anything.
723 // Just report the time remaining.
724 timeout = endtime - now;
727 // Reapply the existing timeout from the current time
728 timeout = (time_t) jsonObjectGetNumber( jsonObjectGetKeyConst( cacheObj, "authtime"));
729 osrfCachePutObject( key, cacheObj, timeout );
732 jsonObject* payload = jsonNewNumberObject( (double) timeout );
733 evt = oilsNewEvent2(OSRF_LOG_MARK, OILS_EVENT_SUCCESS, payload);
734 jsonObjectFree(payload);
735 jsonObjectFree(cacheObj);
742 int oilsAuthResetTimeout( osrfMethodContext* ctx ) {
743 OSRF_METHOD_VERIFY_CONTEXT(ctx);
744 const char* authToken = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0));
745 oilsEvent* evt = _oilsAuthResetTimeout(authToken);
746 osrfAppRespondComplete( ctx, oilsEventToJSON(evt) );
752 int oilsAuthSessionRetrieve( osrfMethodContext* ctx ) {
753 OSRF_METHOD_VERIFY_CONTEXT(ctx);
755 const char* authToken = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0));
756 jsonObject* cacheObj = NULL;
757 oilsEvent* evt = NULL;
761 // Reset the timeout to keep the session alive
762 evt = _oilsAuthResetTimeout(authToken);
764 if( evt && strcmp(evt->event, OILS_EVENT_SUCCESS) ) {
765 osrfAppRespondComplete( ctx, oilsEventToJSON( evt )); // can't reset timeout
769 // Retrieve the cached session object
770 osrfLogDebug(OSRF_LOG_MARK, "Retrieving auth session: %s", authToken);
771 char* key = va_list_to_string("%s%s", OILS_AUTH_CACHE_PRFX, authToken );
772 cacheObj = osrfCacheGetObject( key );
774 // Return a copy of the cached user object
775 osrfAppRespondComplete( ctx, jsonObjectGetKeyConst( cacheObj, "userobj"));
776 jsonObjectFree(cacheObj);
778 // Auth token is invalid or expired
779 oilsEvent* evt2 = oilsNewEvent(OSRF_LOG_MARK, OILS_EVENT_NO_SESSION);
780 osrfAppRespondComplete( ctx, oilsEventToJSON(evt2) ); /* should be event.. */
789 evt = oilsNewEvent(OSRF_LOG_MARK, OILS_EVENT_NO_SESSION);
790 osrfAppRespondComplete( ctx, oilsEventToJSON(evt) );