bc5a4407d4610f3853b8eaeb6ce4969b03e96eee
[working/Evergreen.git] / Open-ILS / src / c-apps / oils_auth.c
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"
9
10 #define OILS_AUTH_CACHE_PRFX "oils_auth_"
11
12 #define MODULENAME "open-ils.auth"
13
14 #define OILS_AUTH_OPAC "opac"
15 #define OILS_AUTH_STAFF "staff"
16 #define OILS_AUTH_TEMP "temp"
17
18 int osrfAppInitialize();
19 int osrfAppChildInit();
20
21 static int _oilsAuthOPACTimeout = 0;
22 static int _oilsAuthStaffTimeout = 0;
23 static int _oilsAuthOverrideTimeout = 0;
24
25
26 /**
27         @brief Initialize the application by registering functions for method calls.
28         @return Zero in all cases.
29 */
30 int osrfAppInitialize() {
31
32         osrfLogInfo(OSRF_LOG_MARK, "Initializing Auth Server...");
33
34         /* load and parse the IDL */
35         if (!oilsInitIDL(NULL)) return 1; /* return non-zero to indicate error */
36
37         osrfAppRegisterMethod(
38                 MODULENAME,
39                 "open-ils.auth.authenticate.init",
40                 "oilsAuthInit",
41                 "Start the authentication process and returns the intermediate authentication seed"
42                 " PARAMS( username )", 1, 0 );
43
44         osrfAppRegisterMethod(
45                 MODULENAME,
46                 "open-ils.auth.authenticate.complete",
47                 "oilsAuthComplete",
48                 "Completes the authentication process.  Returns an object like so: "
49                 "{authtoken : <token>, authtime:<time>}, where authtoken is the login "
50                 "token and authtime is the number of seconds the session will be active"
51                 "PARAMS(username, md5sum( seed + md5sum( password ) ), type, org_id ) "
52                 "type can be one of 'opac','staff', or 'temp' and it defaults to 'staff' "
53                 "org_id is the location at which the login should be considered "
54                 "active for login timeout purposes", 1, 0 );
55
56         osrfAppRegisterMethod(
57                 MODULENAME,
58                 "open-ils.auth.session.retrieve",
59                 "oilsAuthSessionRetrieve",
60                 "Pass in the auth token and this retrieves the user object.  The auth "
61                 "timeout is reset when this call is made "
62                 "Returns the user object (password blanked) for the given login session "
63                 "PARAMS( authToken )", 1, 0 );
64
65         osrfAppRegisterMethod(
66                 MODULENAME,
67                 "open-ils.auth.session.delete",
68                 "oilsAuthSessionDelete",
69                 "Destroys the given login session "
70                 "PARAMS( authToken )",  1, 0 );
71
72         osrfAppRegisterMethod(
73                 MODULENAME,
74                 "open-ils.auth.session.reset_timeout",
75                 "oilsAuthResetTimeout",
76                 "Resets the login timeout for the given session "
77                 "Returns an ILS Event with payload = session_timeout of session "
78                 "if found, otherwise returns the NO_SESSION event"
79                 "PARAMS( authToken )", 1, 0 );
80
81         return 0;
82 }
83
84 /**
85         @brief Dummy placeholder for initializing a server drone.
86
87         There is nothing to do, so do nothing.
88 */
89 int osrfAppChildInit() {
90         return 0;
91 }
92
93 /**
94         @brief Implement the "init" method.
95         @param ctx The method context.
96         @return Zero if successful, or -1 if not.
97
98         Method parameters:
99         - username
100
101         Return to client: Intermediate authentication seed.
102
103         Combine the username with a timestamp and process ID, and take an md5 hash of the result.
104         Store the hash in memcache, with a key based on the username.  Then return the hash to
105         the client.
106
107         However: if the username includes one or more embedded blank spaces, return a dummy
108         hash without storing anything in memcache.  The dummy will never match a stored hash, so
109         any attempt to authenticate with it will fail.
110 */
111 int oilsAuthInit( osrfMethodContext* ctx ) {
112         OSRF_METHOD_VERIFY_CONTEXT(ctx);
113
114         char* username  = jsonObjectToSimpleString( jsonObjectGetIndex(ctx->params, 0) );
115         if( username ) {
116
117                 jsonObject* resp;
118
119                 if( strchr( username, ' ' ) ) {
120
121                         // Embedded spaces are not allowed in a username.  Use "x" as a dummy
122                         // seed.  It will never be a valid seed because 'x' is not a hex digit.
123                         resp = jsonNewObject( "x" );
124
125                 } else {
126
127                         // Build a key and a seed; store them in memcache.
128                         char* key  = va_list_to_string( "%s%s", OILS_AUTH_CACHE_PRFX, username );
129                         char* seed = md5sum( "%d.%ld.%s", (int) time(NULL), (long) getpid(), username );
130                         osrfCachePutString( key, seed, 30 );
131
132                         osrfLogDebug( OSRF_LOG_MARK, "oilsAuthInit(): has seed %s and key %s", seed, key );
133
134                         // Build a returnable object containing the seed.
135                         resp = jsonNewObject( seed );
136
137                         free( seed );
138                         free( key );
139                 }
140
141                 // Return the seed to the client.
142                 osrfAppRespondComplete( ctx, resp );
143
144                 jsonObjectFree(resp);
145                 free(username);
146                 return 0;
147         }
148
149         return -1;  // Error: no username parameter
150 }
151
152 /**
153         Verifies that the user has permission to login with the
154         given type.  If the permission fails, an oilsEvent is returned
155         to the caller.
156         @return -1 if the permission check failed, 0 if the permission
157         is granted
158 */
159 static int oilsAuthCheckLoginPerm(
160                 osrfMethodContext* ctx, const jsonObject* userObj, const char* type ) {
161
162         if(!(userObj && type)) return -1;
163         oilsEvent* perm = NULL;
164
165         if(!strcasecmp(type, OILS_AUTH_OPAC)) {
166                 char* permissions[] = { "OPAC_LOGIN" };
167                 perm = oilsUtilsCheckPerms( oilsFMGetObjectId( userObj ), -1, permissions, 1 );
168
169         } else if(!strcasecmp(type, OILS_AUTH_STAFF)) {
170                 char* permissions[] = { "STAFF_LOGIN" };
171                 perm = oilsUtilsCheckPerms( oilsFMGetObjectId( userObj ), -1, permissions, 1 );
172
173         } else if(!strcasecmp(type, OILS_AUTH_TEMP)) {
174                 char* permissions[] = { "STAFF_LOGIN" };
175                 perm = oilsUtilsCheckPerms( oilsFMGetObjectId( userObj ), -1, permissions, 1 );
176         }
177
178         if(perm) {
179                 osrfAppRespondComplete( ctx, oilsEventToJSON(perm) );
180                 oilsEventFree(perm);
181                 return -1;
182         }
183
184         return 0;
185 }
186
187 /**
188         Returns 1 if the password provided matches the user's real password
189         Returns 0 otherwise
190         Returns -1 on error
191 */
192 /**
193         @brief Verify the password received from the client.
194         @param ctx The method context.
195         @param userObj An object from the database, representing the user.
196         @param password An obfuscated password received from the client.
197         @return 1 if the password is valid; 0 if it isn't; or -1 upon error.
198
199         (None of the so-called "passwords" used here are in plaintext.  All have been passed
200         through at least one layer of hashing to obfuscate them.)
201
202         Take the password from the user object.  Append it to the username seed from memcache,
203         as stored previously by a call to the init method.  Take an md5 hash of the result.
204         Then compare this hash to the password received from the client.
205
206         In order for the two to match, other than by dumb luck, the client had to construct
207         the password it passed in the same way.  That means it neded to know not only the
208         original password (either hashed or plaintext), but also the seed.  The latter requirement
209         means that the client process needs either to be the same process that called the init
210         method or to receive the seed from the process that did so.
211 */
212 static int oilsAuthVerifyPassword( const osrfMethodContext* ctx,
213                 const jsonObject* userObj, const char* uname, const char* password ) {
214
215         // Get the username seed, as stored previously in memcache by the init method
216         char* seed = osrfCacheGetString( "%s%s", OILS_AUTH_CACHE_PRFX, uname );
217         if(!seed) {
218                 return osrfAppRequestRespondException( ctx->session,
219                         ctx->request, "No authentication seed found. "
220                         "open-ils.auth.authenticate.init must be called first");
221         }
222
223         // Get the hashed password from the user object
224         char* realPassword = oilsFMGetString( userObj, "passwd" );
225
226         osrfLogInternal(OSRF_LOG_MARK, "oilsAuth retrieved real password: [%s]", realPassword);
227         osrfLogDebug(OSRF_LOG_MARK, "oilsAuth retrieved seed from cache: %s", seed );
228
229         // Concatenate them and take an MD5 hash of the result
230         char* maskedPw = md5sum( "%s%s", seed, realPassword );
231
232         free(realPassword);
233         free(seed);
234
235         if( !maskedPw ) {
236                 // This happens only if md5sum() runs out of memory
237                 free( maskedPw );
238                 return -1;  // md5sum() ran out of memory
239         }
240
241         osrfLogDebug(OSRF_LOG_MARK,  "oilsAuth generated masked password %s. "
242                         "Testing against provided password %s", maskedPw, password );
243
244         int ret = 0;
245         if( !strcmp( maskedPw, password ) )
246                 ret = 1;
247
248         free(maskedPw);
249
250         return ret;
251 }
252
253 /**
254         Calculates the login timeout
255         1. If orgloc is 1 or greater and has a timeout specified as an
256         org unit setting, it is used
257         2. If orgloc is not valid, we check the org unit auth timeout
258         setting for the home org unit of the user logging in
259         3. If that setting is not defined, we use the configured defaults
260 */
261 static double oilsAuthGetTimeout( const jsonObject* userObj, const char* type, double orgloc ) {
262
263         if(!_oilsAuthOPACTimeout) { /* Load the default timeouts */
264
265                 jsonObject* value_obj;
266
267                 value_obj = osrf_settings_host_value_object(
268                         "/apps/open-ils.auth/app_settings/default_timeout/opac" );
269                 _oilsAuthOPACTimeout = jsonObjectGetNumber(value_obj);
270                 jsonObjectFree(value_obj);
271
272                 value_obj = osrf_settings_host_value_object(
273                         "/apps/open-ils.auth/app_settings/default_timeout/staff" );
274                 _oilsAuthStaffTimeout = jsonObjectGetNumber(value_obj);
275                 jsonObjectFree(value_obj);
276
277                 value_obj = osrf_settings_host_value_object(
278                                 "/apps/open-ils.auth/app_settings/default_timeout/temp" );
279                 _oilsAuthOverrideTimeout = jsonObjectGetNumber(value_obj);
280                 jsonObjectFree(value_obj);
281
282
283                 osrfLogInfo(OSRF_LOG_MARK,
284                                 "Set default auth timeouts: opac => %d : staff => %d : temp => %d",
285                                 _oilsAuthOPACTimeout, _oilsAuthStaffTimeout, _oilsAuthOverrideTimeout );
286         }
287
288         char* setting = NULL;
289
290         double home_ou = jsonObjectGetNumber( oilsFMGetObject( userObj, "home_ou" ) );
291         if(orgloc < 1) orgloc = (int) home_ou;
292
293         if(!strcmp(type, OILS_AUTH_OPAC))
294                 setting = OILS_ORG_SETTING_OPAC_TIMEOUT;
295         else if(!strcmp(type, OILS_AUTH_STAFF))
296                 setting = OILS_ORG_SETTING_STAFF_TIMEOUT;
297         else if(!strcmp(type, OILS_AUTH_TEMP))
298                 setting = OILS_ORG_SETTING_TEMP_TIMEOUT;
299
300         char* timeout = oilsUtilsFetchOrgSetting( orgloc, setting );
301
302         if(!timeout) {
303                 if( orgloc != home_ou ) {
304                         osrfLogDebug(OSRF_LOG_MARK, "Auth timeout not defined for org %d, "
305                                                                 "trying home_ou %d", orgloc, home_ou );
306                         timeout = oilsUtilsFetchOrgSetting( (int) home_ou, setting );
307                 }
308                 if(!timeout) {
309                         if(!strcmp(type, OILS_AUTH_STAFF)) return _oilsAuthStaffTimeout;
310                         if(!strcmp(type, OILS_AUTH_TEMP)) return _oilsAuthOverrideTimeout;
311                         return _oilsAuthOPACTimeout;
312                 }
313         }
314
315         double t = atof(timeout);
316         free(timeout);
317         return t ;
318 }
319
320 /*
321         Adds the authentication token to the user cache.  The timeout for the
322         auth token is based on the type of login as well as (if type=='opac')
323         the org location id.
324         Returns the event that should be returned to the user.
325         Event must be freed
326 */
327 static oilsEvent* oilsAuthHandleLoginOK( jsonObject* userObj, const char* uname,
328                 const char* type, double orgloc, const char* workstation ) {
329
330         oilsEvent* response;
331
332         double timeout;
333         char* wsorg = jsonObjectToSimpleString(oilsFMGetObject(userObj, "ws_ou"));
334         if(wsorg) { /* if there is a workstation, use it for the timeout */
335                 osrfLogDebug( OSRF_LOG_MARK,
336                                 "Auth session trying workstation id %d for auth timeout", atoi(wsorg));
337                 timeout = oilsAuthGetTimeout( userObj, type, atoi(wsorg) );
338                 free(wsorg);
339         } else {
340                 osrfLogDebug( OSRF_LOG_MARK,
341                                 "Auth session trying org from param [%d] for auth timeout", orgloc );
342                 timeout = oilsAuthGetTimeout( userObj, type, orgloc );
343         }
344         osrfLogDebug(OSRF_LOG_MARK, "Auth session timeout for %s: %f", uname, timeout );
345
346         char* string = va_list_to_string(
347                         "%d.%ld.%s", (long) getpid(), time(NULL), uname );
348         char* authToken = md5sum(string);
349         char* authKey = va_list_to_string(
350                         "%s%s", OILS_AUTH_CACHE_PRFX, authToken );
351
352         const char* ws = (workstation) ? workstation : "";
353         osrfLogActivity(OSRF_LOG_MARK,
354                 "successful login: username=%s, authtoken=%s, workstation=%s", uname, authToken, ws );
355
356         oilsFMSetString( userObj, "passwd", "" );
357         jsonObject* cacheObj = jsonParseFmt("{\"authtime\": %f}", timeout);
358         jsonObjectSetKey( cacheObj, "userobj", jsonObjectClone(userObj));
359
360         osrfCachePutObject( authKey, cacheObj, timeout );
361         jsonObjectFree(cacheObj);
362         osrfLogInternal(OSRF_LOG_MARK, "oilsAuthHandleLoginOK(): Placed user object into cache");
363         jsonObject* payload = jsonParseFmt(
364                 "{ \"authtoken\": \"%s\", \"authtime\": %f }", authToken, timeout );
365
366         response = oilsNewEvent2( OSRF_LOG_MARK, OILS_EVENT_SUCCESS, payload );
367         free(string); free(authToken); free(authKey);
368         jsonObjectFree(payload);
369
370         return response;
371 }
372
373 static oilsEvent* oilsAuthVerifyWorkstation(
374                 const osrfMethodContext* ctx, jsonObject* userObj, const char* ws ) {
375         osrfLogInfo(OSRF_LOG_MARK, "Attaching workstation to user at login: %s", ws);
376         jsonObject* workstation = oilsUtilsFetchWorkstationByName(ws);
377         if(!workstation || workstation->type == JSON_NULL) {
378                 jsonObjectFree(workstation);
379                 return oilsNewEvent(OSRF_LOG_MARK, "WORKSTATION_NOT_FOUND");
380         }
381         long wsid = oilsFMGetObjectId(workstation);
382         LONG_TO_STRING(wsid);
383         char* orgid = oilsFMGetString(workstation, "owning_lib");
384         oilsFMSetString(userObj, "wsid", LONGSTR);
385         oilsFMSetString(userObj, "ws_ou", orgid);
386         free(orgid);
387         jsonObjectFree(workstation);
388         return NULL;
389 }
390
391
392
393 /**
394         @brief Implement the "complete" method.
395         @param ctx The method context.
396         @return -1 upon error; zero if successful, and if a STATUS message has been sent to the
397         client to indicate completion; a positive integer if successful but no such STATUS
398         message has been sent.
399
400         Method parameters:
401         - a hash with some combination of the following elements:
402                 - "username"
403                 - "barcode"
404                 - "password" (hashed with the cached seed; not plaintext)
405                 - "type"
406                 - "org"
407                 - "workstation"
408
409         The password is required.  Either a username or a barcode must also be present.
410
411         Return to client: Intermediate authentication seed.
412
413         Validate the password, using the username if available, or the barcode if not.  The
414         user must be active, and not barred from logging on.  The barcode, if used for
415         authentication, must be active as well.  The workstation, if specified, must be valid.
416
417         Upon deciding whether to allow the logon, return a corresponding event to the client.
418 */
419 int oilsAuthComplete( osrfMethodContext* ctx ) {
420         OSRF_METHOD_VERIFY_CONTEXT(ctx);
421
422         const jsonObject* args  = jsonObjectGetIndex(ctx->params, 0);
423
424         const char* uname       = jsonObjectGetString(jsonObjectGetKeyConst(args, "username"));
425         const char* password    = jsonObjectGetString(jsonObjectGetKeyConst(args, "password"));
426         const char* type        = jsonObjectGetString(jsonObjectGetKeyConst(args, "type"));
427         double orgloc           = jsonObjectGetNumber(jsonObjectGetKeyConst(args, "org"));
428         const char* workstation = jsonObjectGetString(jsonObjectGetKeyConst(args, "workstation"));
429         const char* barcode     = jsonObjectGetString(jsonObjectGetKeyConst(args, "barcode"));
430
431         const char* ws = (workstation) ? workstation : "";
432
433         if( !type )
434                  type = OILS_AUTH_STAFF;
435
436         if( !( (uname || barcode) && password) ) {
437                 return osrfAppRequestRespondException( ctx->session, ctx->request,
438                         "username/barcode and password required for method: %s", ctx->method->name );
439         }
440
441         oilsEvent* response = NULL;
442         jsonObject* userObj = NULL;
443         int card_active     = 1;      // boolean; assume active until proven otherwise
444
445         // Fetch a row from the actor.usr table, by username if available,
446         // or by barcode if not.
447         if(uname) {
448                 userObj = oilsUtilsFetchUserByUsername( uname );
449                 if( userObj && JSON_NULL == userObj->type ) {
450                         jsonObjectFree( userObj );
451                         userObj = NULL;         // username not found
452                 }
453         }
454         else if(barcode) {
455                 // Read from actor.card by barcode
456
457                 osrfLogInfo( OSRF_LOG_MARK, "Fetching user by barcode %s", barcode );
458
459                 jsonObject* params = jsonParseFmt("{\"barcode\":\"%s\"}", barcode);
460                 jsonObject* card = oilsUtilsQuickReq(
461                         "open-ils.cstore", "open-ils.cstore.direct.actor.card.search", params );
462                 jsonObjectFree( params );
463
464                 if( card ) {
465                         // Determine whether the card is active
466                         char* card_active_str = oilsFMGetString( card, "active" );
467                         card_active = oilsUtilsIsDBTrue( card_active_str );
468                         free( card_active_str );
469
470                         // Look up the user who owns the card
471                         char* userid = oilsFMGetString( card, "usr" );
472                         jsonObjectFree( card );
473                         params = jsonParseFmt( "[%s]", userid );
474                         free( userid );
475                         userObj = oilsUtilsQuickReq(
476                                         "open-ils.cstore", "open-ils.cstore.direct.actor.user.retrieve", params );
477                         jsonObjectFree( params );
478                 }
479         }
480
481         if(!userObj) {
482                 response = oilsNewEvent( OSRF_LOG_MARK, OILS_EVENT_AUTH_FAILED );
483                 osrfLogInfo(OSRF_LOG_MARK,  "failed login: username=%s, barcode=%s, workstation=%s",
484                                 uname, (barcode ? barcode : "(none)"), ws );
485                 osrfAppRespondComplete( ctx, oilsEventToJSON(response) );
486                 oilsEventFree(response);
487                 return 0;           // No such user
488         }
489
490         // Such a user exists.  Now see if he or she has the right credentials.
491         int passOK = -1;
492         if(uname)
493                 passOK = oilsAuthVerifyPassword( ctx, userObj, uname, password );
494         else if (barcode)
495                 passOK = oilsAuthVerifyPassword( ctx, userObj, barcode, password );
496
497         if( passOK < 0 ) {
498                 jsonObjectFree(userObj);
499                 return passOK;
500         }
501
502         // See if the account is active
503         char* active = oilsFMGetString(userObj, "active");
504         if( !oilsUtilsIsDBTrue(active) ) {
505                 if( passOK )
506                         response = oilsNewEvent( OSRF_LOG_MARK, "PATRON_INACTIVE" );
507                 else
508                         response = oilsNewEvent( OSRF_LOG_MARK, OILS_EVENT_AUTH_FAILED );
509
510                 osrfAppRespondComplete( ctx, oilsEventToJSON(response) );
511                 oilsEventFree(response);
512                 jsonObjectFree(userObj);
513                 free(active);
514                 return 0;
515         }
516         free(active);
517
518         osrfLogInfo( OSRF_LOG_MARK, "Fetching card by barcode %s", barcode );
519
520         if( !card_active ) {
521                 osrfLogInfo( OSRF_LOG_MARK, "barcode %s is not active, returning event", barcode );
522                 response = oilsNewEvent( OSRF_LOG_MARK, "PATRON_CARD_INACTIVE" );
523                 osrfAppRespondComplete( ctx, oilsEventToJSON( response ) );
524                 oilsEventFree( response );
525                 jsonObjectFree( userObj );
526                 return 0;
527         }
528
529
530         // See if the user is even allowed to log in
531         if( oilsAuthCheckLoginPerm( ctx, userObj, type ) == -1 ) {
532                 jsonObjectFree(userObj);
533                 return 0;
534         }
535
536         // If a workstation is defined, add the workstation info
537         if( workstation != NULL ) {
538                 osrfLogDebug(OSRF_LOG_MARK, "Workstation is %s", workstation);
539                 response = oilsAuthVerifyWorkstation( ctx, userObj, workstation );
540                 if(response) {
541                         jsonObjectFree(userObj);
542                         osrfAppRespondComplete( ctx, oilsEventToJSON(response) );
543                         oilsEventFree(response);
544                         return 0;
545                 }
546
547         } else {
548                 // Otherwise, use the home org as the workstation org on the user
549                 char* orgid = oilsFMGetString(userObj, "home_ou");
550                 oilsFMSetString(userObj, "ws_ou", orgid);
551                 free(orgid);
552         }
553
554         char* freeable_uname = NULL;
555         if(!uname) {
556                 uname = freeable_uname = oilsFMGetString( userObj, "usrname" );
557         }
558
559         if( passOK ) {
560                 response = oilsAuthHandleLoginOK( userObj, uname, type, orgloc, workstation );
561
562         } else {
563                 response = oilsNewEvent( OSRF_LOG_MARK, OILS_EVENT_AUTH_FAILED );
564                 osrfLogInfo(OSRF_LOG_MARK,  "failed login: username=%s, barcode=%s, workstation=%s",
565                                 uname, (barcode ? barcode : "(none)"), ws );
566         }
567
568         jsonObjectFree(userObj);
569         osrfAppRespondComplete( ctx, oilsEventToJSON(response) );
570         oilsEventFree(response);
571
572         if(freeable_uname)
573                 free(freeable_uname);
574
575         return 0;
576 }
577
578
579
580 int oilsAuthSessionDelete( osrfMethodContext* ctx ) {
581         OSRF_METHOD_VERIFY_CONTEXT(ctx);
582
583         const char* authToken = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0) );
584         jsonObject* resp = NULL;
585
586         if( authToken ) {
587                 osrfLogDebug(OSRF_LOG_MARK, "Removing auth session: %s", authToken );
588                 char* key = va_list_to_string("%s%s", OILS_AUTH_CACHE_PRFX, authToken ); /**/
589                 osrfCacheRemove(key);
590                 resp = jsonNewObject(authToken); /**/
591                 free(key);
592         }
593
594         osrfAppRespondComplete( ctx, resp );
595         jsonObjectFree(resp);
596         return 0;
597 }
598
599 /**
600         Resets the auth login timeout
601         @return The event object, OILS_EVENT_SUCCESS, or OILS_EVENT_NO_SESSION
602 */
603 static oilsEvent*  _oilsAuthResetTimeout( const char* authToken ) {
604         if(!authToken) return NULL;
605
606         oilsEvent* evt = NULL;
607         double timeout;
608
609         osrfLogDebug(OSRF_LOG_MARK, "Resetting auth timeout for session %s", authToken);
610         char* key = va_list_to_string("%s%s", OILS_AUTH_CACHE_PRFX, authToken );
611         jsonObject* cacheObj = osrfCacheGetObject( key );
612
613         if(!cacheObj) {
614                 osrfLogInfo(OSRF_LOG_MARK, "No user in the cache exists with key %s", key);
615                 evt = oilsNewEvent(OSRF_LOG_MARK, OILS_EVENT_NO_SESSION);
616
617         } else {
618
619                 timeout = jsonObjectGetNumber( jsonObjectGetKeyConst( cacheObj, "authtime"));
620                 osrfCacheSetExpire( timeout, key );
621                 jsonObject* payload = jsonNewNumberObject(timeout);
622                 evt = oilsNewEvent2(OSRF_LOG_MARK, OILS_EVENT_SUCCESS, payload);
623                 jsonObjectFree(payload);
624                 jsonObjectFree(cacheObj);
625         }
626
627         free(key);
628         return evt;
629 }
630
631 int oilsAuthResetTimeout( osrfMethodContext* ctx ) {
632         OSRF_METHOD_VERIFY_CONTEXT(ctx);
633         const char* authToken = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0));
634         oilsEvent* evt = _oilsAuthResetTimeout(authToken);
635         osrfAppRespondComplete( ctx, oilsEventToJSON(evt) );
636         oilsEventFree(evt);
637         return 0;
638 }
639
640
641 int oilsAuthSessionRetrieve( osrfMethodContext* ctx ) {
642         OSRF_METHOD_VERIFY_CONTEXT(ctx);
643
644         const char* authToken = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0));
645         jsonObject* cacheObj = NULL;
646         oilsEvent* evt = NULL;
647
648         if( authToken ){
649
650                 evt = _oilsAuthResetTimeout(authToken);
651
652                 if( evt && strcmp(evt->event, OILS_EVENT_SUCCESS) ) {
653                         osrfAppRespondComplete( ctx, oilsEventToJSON(evt) );
654
655                 } else {
656
657                         osrfLogDebug(OSRF_LOG_MARK, "Retrieving auth session: %s", authToken);
658                         char* key = va_list_to_string("%s%s", OILS_AUTH_CACHE_PRFX, authToken );
659                         cacheObj = osrfCacheGetObject( key );
660                         if(cacheObj) {
661                                 osrfAppRespondComplete( ctx, jsonObjectGetKeyConst( cacheObj, "userobj"));
662                                 jsonObjectFree(cacheObj);
663                         } else {
664                                 oilsEvent* evt2 = oilsNewEvent(OSRF_LOG_MARK, OILS_EVENT_NO_SESSION);
665                                 osrfAppRespondComplete( ctx, oilsEventToJSON(evt2) ); /* should be event.. */
666                                 oilsEventFree(evt2);
667                         }
668                         free(key);
669                 }
670
671         } else {
672
673                 evt = oilsNewEvent(OSRF_LOG_MARK, OILS_EVENT_NO_SESSION);
674                 osrfAppRespondComplete( ctx, oilsEventToJSON(evt) );
675         }
676
677         if(evt)
678                 oilsEventFree(evt);
679
680         return 0;
681 }