]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/c-apps/oils_auth.c
Tweaked oilsAuthVerifyPassword(), mostly for clarity:
[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 /* see if the card used to login is marked as barred */
394 static oilsEvent* oilsAuthCheckCard( const char* barcode ) {
395         if(!barcode) return NULL;
396         osrfLogDebug(OSRF_LOG_MARK, "Checking to see if barcode %s is active", barcode);
397
398         jsonObject* params = jsonParseFmt("{\"barcode\":\"%s\"}", barcode);
399         jsonObject* card = oilsUtilsQuickReq(
400                 "open-ils.cstore", "open-ils.cstore.direct.actor.card.search", params );
401         jsonObjectFree(params);
402
403         char* active = oilsFMGetString(card, "active");
404         jsonObjectFree(card);
405
406         oilsEvent* return_event = NULL;
407         if( ! oilsUtilsIsDBTrue(active) ) {
408                 osrfLogInfo(OSRF_LOG_MARK, "barcode %s is not active, returning event", barcode);
409                 return_event = oilsNewEvent(OSRF_LOG_MARK, "PATRON_CARD_INACTIVE");
410         }
411
412         free(active);
413         return return_event;
414 }
415
416
417
418 int oilsAuthComplete( osrfMethodContext* ctx ) {
419         OSRF_METHOD_VERIFY_CONTEXT(ctx);
420
421         const jsonObject* args  = jsonObjectGetIndex(ctx->params, 0);
422
423         const char* uname       = jsonObjectGetString(jsonObjectGetKeyConst(args, "username"));
424         const char* password    = jsonObjectGetString(jsonObjectGetKeyConst(args, "password"));
425         const char* type        = jsonObjectGetString(jsonObjectGetKeyConst(args, "type"));
426         double orgloc           = jsonObjectGetNumber(jsonObjectGetKeyConst(args, "org"));
427         const char* workstation = jsonObjectGetString(jsonObjectGetKeyConst(args, "workstation"));
428         const char* barcode     = jsonObjectGetString(jsonObjectGetKeyConst(args, "barcode"));
429
430         const char* ws = (workstation) ? workstation : "";
431
432         if( !type )
433                  type = OILS_AUTH_STAFF;
434
435         if( !( (uname || barcode) && password) ) {
436                 return osrfAppRequestRespondException( ctx->session, ctx->request,
437                         "username/barcode and password required for method: %s", ctx->method->name );
438         }
439
440         oilsEvent* response = NULL;
441         jsonObject* userObj = NULL;
442
443         // Fetch a row from the actor.usr table, by username if available,
444         // or by barcode if not.
445         if(uname) {
446                 userObj = oilsUtilsFetchUserByUsername( uname );
447                 if( userObj && JSON_NULL == userObj->type ) {
448                         jsonObjectFree( userObj );
449                         userObj = NULL;         // username not found
450                 }
451         }
452         else if(barcode)
453                  userObj = oilsUtilsFetchUserByBarcode( barcode );
454
455         if(!userObj) {
456                 response = oilsNewEvent( OSRF_LOG_MARK, OILS_EVENT_AUTH_FAILED );
457                 osrfLogInfo(OSRF_LOG_MARK,  "failed login: username=%s, barcode=%s, workstation=%s",
458                                 uname, (barcode ? barcode : "(none)"), ws );
459                 osrfAppRespondComplete( ctx, oilsEventToJSON(response) );
460                 oilsEventFree(response);
461                 return 0;           // No such user
462         }
463
464         // Such a user exists.  Now see if he or she has the right credentials.
465         int passOK = -1;
466         if(uname)
467                 passOK = oilsAuthVerifyPassword( ctx, userObj, uname, password );
468         else if (barcode)
469                 passOK = oilsAuthVerifyPassword( ctx, userObj, barcode, password );
470
471         if( passOK < 0 ) {
472                 jsonObjectFree(userObj);
473                 return passOK;
474         }
475
476         // See if the account is active
477         char* active = oilsFMGetString(userObj, "active");
478         if( !oilsUtilsIsDBTrue(active) ) {
479                 if( passOK )
480                         response = oilsNewEvent( OSRF_LOG_MARK, "PATRON_INACTIVE" );
481                 else
482                         response = oilsNewEvent( OSRF_LOG_MARK, OILS_EVENT_AUTH_FAILED );
483
484                 osrfAppRespondComplete( ctx, oilsEventToJSON(response) );
485                 oilsEventFree(response);
486                 jsonObjectFree(userObj);
487                 free(active);
488                 return 0;
489         }
490         free(active);
491
492         /* then see if the barcode they used is active */
493         if( barcode && ctx && userObj && (response = oilsAuthCheckCard( barcode )) ) {
494                 osrfAppRespondComplete( ctx, oilsEventToJSON(response) );
495                 oilsEventFree(response);
496                 jsonObjectFree(userObj);
497                 return 0;
498         }
499
500
501         /* check to see if the user is even allowed to login */
502         if( oilsAuthCheckLoginPerm( ctx, userObj, type ) == -1 ) {
503                 jsonObjectFree(userObj);
504                 return 0;
505         }
506
507
508         /* if a workstation is defined, flesh the user with the workstation info */
509         if( workstation != NULL ) {
510                 osrfLogDebug(OSRF_LOG_MARK, "Workstation is %s", workstation);
511                 response = oilsAuthVerifyWorkstation( ctx, userObj, workstation );
512                 if(response) {
513                         jsonObjectFree(userObj);
514                         osrfAppRespondComplete( ctx, oilsEventToJSON(response) );
515                         oilsEventFree(response);
516                         return 0;
517                 }
518
519         } else {
520                 /* otherwise, use the home org as the workstation org on the user */
521                 char* orgid = oilsFMGetString(userObj, "home_ou");
522                 oilsFMSetString(userObj, "ws_ou", orgid);
523                 free(orgid);
524         }
525
526         char* freeable_uname = NULL;
527         if(!uname) {
528                 uname = freeable_uname = oilsFMGetString( userObj, "usrname" );
529         }
530
531         if( passOK ) {
532                 response = oilsAuthHandleLoginOK( userObj, uname, type, orgloc, workstation );
533
534         } else {
535                 response = oilsNewEvent( OSRF_LOG_MARK, OILS_EVENT_AUTH_FAILED );
536                 osrfLogInfo(OSRF_LOG_MARK,  "failed login: username=%s, barcode=%s, workstation=%s",
537                                 uname, (barcode ? barcode : "(none)"), ws );
538         }
539
540         jsonObjectFree(userObj);
541         osrfAppRespondComplete( ctx, oilsEventToJSON(response) );
542         oilsEventFree(response);
543
544         if(freeable_uname)
545                 free(freeable_uname);
546
547         return 0;
548 }
549
550
551
552 int oilsAuthSessionDelete( osrfMethodContext* ctx ) {
553         OSRF_METHOD_VERIFY_CONTEXT(ctx);
554
555         const char* authToken = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0) );
556         jsonObject* resp = NULL;
557
558         if( authToken ) {
559                 osrfLogDebug(OSRF_LOG_MARK, "Removing auth session: %s", authToken );
560                 char* key = va_list_to_string("%s%s", OILS_AUTH_CACHE_PRFX, authToken ); /**/
561                 osrfCacheRemove(key);
562                 resp = jsonNewObject(authToken); /**/
563                 free(key);
564         }
565
566         osrfAppRespondComplete( ctx, resp );
567         jsonObjectFree(resp);
568         return 0;
569 }
570
571 /**
572         Resets the auth login timeout
573         @return The event object, OILS_EVENT_SUCCESS, or OILS_EVENT_NO_SESSION
574 */
575 static oilsEvent*  _oilsAuthResetTimeout( const char* authToken ) {
576         if(!authToken) return NULL;
577
578         oilsEvent* evt = NULL;
579         double timeout;
580
581         osrfLogDebug(OSRF_LOG_MARK, "Resetting auth timeout for session %s", authToken);
582         char* key = va_list_to_string("%s%s", OILS_AUTH_CACHE_PRFX, authToken );
583         jsonObject* cacheObj = osrfCacheGetObject( key );
584
585         if(!cacheObj) {
586                 osrfLogInfo(OSRF_LOG_MARK, "No user in the cache exists with key %s", key);
587                 evt = oilsNewEvent(OSRF_LOG_MARK, OILS_EVENT_NO_SESSION);
588
589         } else {
590
591                 timeout = jsonObjectGetNumber( jsonObjectGetKeyConst( cacheObj, "authtime"));
592                 osrfCacheSetExpire( timeout, key );
593                 jsonObject* payload = jsonNewNumberObject(timeout);
594                 evt = oilsNewEvent2(OSRF_LOG_MARK, OILS_EVENT_SUCCESS, payload);
595                 jsonObjectFree(payload);
596                 jsonObjectFree(cacheObj);
597         }
598
599         free(key);
600         return evt;
601 }
602
603 int oilsAuthResetTimeout( osrfMethodContext* ctx ) {
604         OSRF_METHOD_VERIFY_CONTEXT(ctx);
605         const char* authToken = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0));
606         oilsEvent* evt = _oilsAuthResetTimeout(authToken);
607         osrfAppRespondComplete( ctx, oilsEventToJSON(evt) );
608         oilsEventFree(evt);
609         return 0;
610 }
611
612
613 int oilsAuthSessionRetrieve( osrfMethodContext* ctx ) {
614         OSRF_METHOD_VERIFY_CONTEXT(ctx);
615
616         const char* authToken = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0));
617         jsonObject* cacheObj = NULL;
618         oilsEvent* evt = NULL;
619
620         if( authToken ){
621
622                 evt = _oilsAuthResetTimeout(authToken);
623
624                 if( evt && strcmp(evt->event, OILS_EVENT_SUCCESS) ) {
625                         osrfAppRespondComplete( ctx, oilsEventToJSON(evt) );
626
627                 } else {
628
629                         osrfLogDebug(OSRF_LOG_MARK, "Retrieving auth session: %s", authToken);
630                         char* key = va_list_to_string("%s%s", OILS_AUTH_CACHE_PRFX, authToken );
631                         cacheObj = osrfCacheGetObject( key );
632                         if(cacheObj) {
633                                 osrfAppRespondComplete( ctx, jsonObjectGetKeyConst( cacheObj, "userobj"));
634                                 jsonObjectFree(cacheObj);
635                         } else {
636                                 oilsEvent* evt2 = oilsNewEvent(OSRF_LOG_MARK, OILS_EVENT_NO_SESSION);
637                                 osrfAppRespondComplete( ctx, oilsEventToJSON(evt2) ); /* should be event.. */
638                                 oilsEventFree(evt2);
639                         }
640                         free(key);
641                 }
642
643         } else {
644
645                 evt = oilsNewEvent(OSRF_LOG_MARK, OILS_EVENT_NO_SESSION);
646                 osrfAppRespondComplete( ctx, oilsEventToJSON(evt) );
647         }
648
649         if(evt)
650                 oilsEventFree(evt);
651
652         return 0;
653 }