Tweak to reflect a better understanding of oilsUtilsQuickReq().
[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 && card->type != JSON_NULL ) {
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                         if( userObj && JSON_NULL == userObj->type ) {
479                                 // user not found (shouldn't happen, due to foreign key)
480                                 jsonObjectFree( userObj );
481                                 userObj = NULL;
482                         }
483                 }
484         }
485
486         if(!userObj) {
487                 response = oilsNewEvent( OSRF_LOG_MARK, OILS_EVENT_AUTH_FAILED );
488                 osrfLogInfo(OSRF_LOG_MARK,  "failed login: username=%s, barcode=%s, workstation=%s",
489                                 uname, (barcode ? barcode : "(none)"), ws );
490                 osrfAppRespondComplete( ctx, oilsEventToJSON(response) );
491                 oilsEventFree(response);
492                 return 0;           // No such user
493         }
494
495         // Such a user exists.  Now see if he or she has the right credentials.
496         int passOK = -1;
497         if(uname)
498                 passOK = oilsAuthVerifyPassword( ctx, userObj, uname, password );
499         else if (barcode)
500                 passOK = oilsAuthVerifyPassword( ctx, userObj, barcode, password );
501
502         if( passOK < 0 ) {
503                 jsonObjectFree(userObj);
504                 return passOK;
505         }
506
507         // See if the account is active
508         char* active = oilsFMGetString(userObj, "active");
509         if( !oilsUtilsIsDBTrue(active) ) {
510                 if( passOK )
511                         response = oilsNewEvent( OSRF_LOG_MARK, "PATRON_INACTIVE" );
512                 else
513                         response = oilsNewEvent( OSRF_LOG_MARK, OILS_EVENT_AUTH_FAILED );
514
515                 osrfAppRespondComplete( ctx, oilsEventToJSON(response) );
516                 oilsEventFree(response);
517                 jsonObjectFree(userObj);
518                 free(active);
519                 return 0;
520         }
521         free(active);
522
523         osrfLogInfo( OSRF_LOG_MARK, "Fetching card by barcode %s", barcode );
524
525         if( !card_active ) {
526                 osrfLogInfo( OSRF_LOG_MARK, "barcode %s is not active, returning event", barcode );
527                 response = oilsNewEvent( OSRF_LOG_MARK, "PATRON_CARD_INACTIVE" );
528                 osrfAppRespondComplete( ctx, oilsEventToJSON( response ) );
529                 oilsEventFree( response );
530                 jsonObjectFree( userObj );
531                 return 0;
532         }
533
534
535         // See if the user is even allowed to log in
536         if( oilsAuthCheckLoginPerm( ctx, userObj, type ) == -1 ) {
537                 jsonObjectFree(userObj);
538                 return 0;
539         }
540
541         // If a workstation is defined, add the workstation info
542         if( workstation != NULL ) {
543                 osrfLogDebug(OSRF_LOG_MARK, "Workstation is %s", workstation);
544                 response = oilsAuthVerifyWorkstation( ctx, userObj, workstation );
545                 if(response) {
546                         jsonObjectFree(userObj);
547                         osrfAppRespondComplete( ctx, oilsEventToJSON(response) );
548                         oilsEventFree(response);
549                         return 0;
550                 }
551
552         } else {
553                 // Otherwise, use the home org as the workstation org on the user
554                 char* orgid = oilsFMGetString(userObj, "home_ou");
555                 oilsFMSetString(userObj, "ws_ou", orgid);
556                 free(orgid);
557         }
558
559         char* freeable_uname = NULL;
560         if(!uname) {
561                 uname = freeable_uname = oilsFMGetString( userObj, "usrname" );
562         }
563
564         if( passOK ) {
565                 response = oilsAuthHandleLoginOK( userObj, uname, type, orgloc, workstation );
566
567         } else {
568                 response = oilsNewEvent( OSRF_LOG_MARK, OILS_EVENT_AUTH_FAILED );
569                 osrfLogInfo(OSRF_LOG_MARK,  "failed login: username=%s, barcode=%s, workstation=%s",
570                                 uname, (barcode ? barcode : "(none)"), ws );
571         }
572
573         jsonObjectFree(userObj);
574         osrfAppRespondComplete( ctx, oilsEventToJSON(response) );
575         oilsEventFree(response);
576
577         if(freeable_uname)
578                 free(freeable_uname);
579
580         return 0;
581 }
582
583
584
585 int oilsAuthSessionDelete( osrfMethodContext* ctx ) {
586         OSRF_METHOD_VERIFY_CONTEXT(ctx);
587
588         const char* authToken = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0) );
589         jsonObject* resp = NULL;
590
591         if( authToken ) {
592                 osrfLogDebug(OSRF_LOG_MARK, "Removing auth session: %s", authToken );
593                 char* key = va_list_to_string("%s%s", OILS_AUTH_CACHE_PRFX, authToken ); /**/
594                 osrfCacheRemove(key);
595                 resp = jsonNewObject(authToken); /**/
596                 free(key);
597         }
598
599         osrfAppRespondComplete( ctx, resp );
600         jsonObjectFree(resp);
601         return 0;
602 }
603
604 /**
605         Resets the auth login timeout
606         @return The event object, OILS_EVENT_SUCCESS, or OILS_EVENT_NO_SESSION
607 */
608 static oilsEvent*  _oilsAuthResetTimeout( const char* authToken ) {
609         if(!authToken) return NULL;
610
611         oilsEvent* evt = NULL;
612         double timeout;
613
614         osrfLogDebug(OSRF_LOG_MARK, "Resetting auth timeout for session %s", authToken);
615         char* key = va_list_to_string("%s%s", OILS_AUTH_CACHE_PRFX, authToken );
616         jsonObject* cacheObj = osrfCacheGetObject( key );
617
618         if(!cacheObj) {
619                 osrfLogInfo(OSRF_LOG_MARK, "No user in the cache exists with key %s", key);
620                 evt = oilsNewEvent(OSRF_LOG_MARK, OILS_EVENT_NO_SESSION);
621
622         } else {
623
624                 timeout = jsonObjectGetNumber( jsonObjectGetKeyConst( cacheObj, "authtime"));
625                 osrfCacheSetExpire( timeout, key );
626                 jsonObject* payload = jsonNewNumberObject(timeout);
627                 evt = oilsNewEvent2(OSRF_LOG_MARK, OILS_EVENT_SUCCESS, payload);
628                 jsonObjectFree(payload);
629                 jsonObjectFree(cacheObj);
630         }
631
632         free(key);
633         return evt;
634 }
635
636 int oilsAuthResetTimeout( osrfMethodContext* ctx ) {
637         OSRF_METHOD_VERIFY_CONTEXT(ctx);
638         const char* authToken = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0));
639         oilsEvent* evt = _oilsAuthResetTimeout(authToken);
640         osrfAppRespondComplete( ctx, oilsEventToJSON(evt) );
641         oilsEventFree(evt);
642         return 0;
643 }
644
645
646 int oilsAuthSessionRetrieve( osrfMethodContext* ctx ) {
647         OSRF_METHOD_VERIFY_CONTEXT(ctx);
648
649         const char* authToken = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0));
650         jsonObject* cacheObj = NULL;
651         oilsEvent* evt = NULL;
652
653         if( authToken ){
654
655                 evt = _oilsAuthResetTimeout(authToken);
656
657                 if( evt && strcmp(evt->event, OILS_EVENT_SUCCESS) ) {
658                         osrfAppRespondComplete( ctx, oilsEventToJSON(evt) );
659
660                 } else {
661
662                         osrfLogDebug(OSRF_LOG_MARK, "Retrieving auth session: %s", authToken);
663                         char* key = va_list_to_string("%s%s", OILS_AUTH_CACHE_PRFX, authToken );
664                         cacheObj = osrfCacheGetObject( key );
665                         if(cacheObj) {
666                                 osrfAppRespondComplete( ctx, jsonObjectGetKeyConst( cacheObj, "userobj"));
667                                 jsonObjectFree(cacheObj);
668                         } else {
669                                 oilsEvent* evt2 = oilsNewEvent(OSRF_LOG_MARK, OILS_EVENT_NO_SESSION);
670                                 osrfAppRespondComplete( ctx, oilsEventToJSON(evt2) ); /* should be event.. */
671                                 oilsEventFree(evt2);
672                         }
673                         free(key);
674                 }
675
676         } else {
677
678                 evt = oilsNewEvent(OSRF_LOG_MARK, OILS_EVENT_NO_SESSION);
679                 osrfAppRespondComplete( ctx, oilsEventToJSON(evt) );
680         }
681
682         if(evt)
683                 oilsEventFree(evt);
684
685         return 0;
686 }