1 #include "opensrf/osrf_app_session.h"
2 #include "opensrf/osrf_application.h"
3 #include "opensrf/osrf_settings.h"
4 #include "objson/object.h"
5 #include "opensrf/log.h"
6 #include "oils_utils.h"
7 #include "oils_constants.h"
8 #include "oils_event.h"
10 #define OILS_AUTH_CACHE_PRFX "oils_auth_"
12 #define MODULENAME "open-ils.auth"
14 int osrfAppInitialize();
15 int osrfAppChildInit();
17 int __oilsAuthOPACTimeout = 0;
18 int __oilsAuthStaffTimeout = 0;
21 int osrfAppInitialize() {
23 osrfAppRegisterMethod(
25 "open-ils.auth.authenticate.init",
27 "Start the authentication process and returns the intermediate authentication seed"
28 " PARAMS( username )", 1, 0 );
30 osrfAppRegisterMethod(
32 "open-ils.auth.authenticate.complete",
34 "Completes the authentication process. Returns an object like so: "
35 "{authtoken : <token>, authtime:<time>}, where authtoken is the login "
36 "tokena and authtime is the number of seconds the session will be active"
37 "PARAMS(username, md5sum( seed + password ), type, org_id ) "
38 "type can be one of 'opac' or 'staff' and it defaults to 'staff' "
39 "org_id is the location at which the login should be considered "
40 "active for login timeout purposes" , 2, 0 );
42 osrfAppRegisterMethod(
44 "open-ils.auth.session.retrieve",
45 "oilsAuthSessionRetrieve",
46 "Pass in the auth token and an optional second parameter which tells the "
47 "method to reset the session timeout for the user"
48 "Returns the user object (password blanked) for the given login session "
49 "PARAMS( authToken, [reset?] )", 1, 0 );
51 osrfAppRegisterMethod(
53 "open-ils.auth.session.delete",
54 "oilsAuthSessionDelete",
55 "Destroys the given login session "
56 "PARAMS( authToken )", 1, 0 );
58 osrfAppRegisterMethod(
60 "open-ils.auth.session.reset_timeout",
61 "oilsAuthResetTimeout",
62 "Resets the login timeout for the given session "
63 "Returns an ILS Event with payload = session_timeout of session "
64 "is found, otherwise returns the NO_SESSION event"
65 "PARAMS( authToken )", 1, 0 );
70 int osrfAppChildInit() {
74 int oilsAuthInit( osrfMethodContext* ctx ) {
75 OSRF_METHOD_VERIFY_CONTEXT(ctx);
78 char* username = NULL;
83 if( (username = jsonObjectGetString(jsonObjectGetIndex(ctx->params, 0))) ) {
85 seed = va_list_to_string( "%d.%d.%s", time(NULL), getpid(), username );
86 key = va_list_to_string( "%s%s", OILS_AUTH_CACHE_PRFX, username );
88 md5seed = md5sum(seed);
89 osrfCachePutString( key, md5seed, 30 );
91 osrfLogDebug( "oilsAuthInit(): has seed %s and key %s", md5seed, key );
93 resp = jsonNewObject(md5seed);
94 osrfAppRespondComplete( ctx, resp );
106 /** Verifies that the user has permission to login with the
107 * given type. If the permission fails, an oilsEvent is returned
109 * @return -1 if the permission check failed, 0 if ther permission
112 int oilsAuthCheckLoginPerm(
113 osrfMethodContext* ctx, jsonObject* userObj, char* type ) {
115 if(!(userObj && type)) return -1;
116 oilsEvent* perm = NULL;
118 if(!strcasecmp(type, "opac")) {
119 char* permissions[] = { "OPAC_LOGIN" };
120 perm = oilsUtilsCheckPerms( oilsFMGetObjectId( userObj ), -1, permissions, 1 );
122 } else if(!strcasecmp(type, "staff")) {
123 char* permissions[] = { "STAFF_LOGIN" };
124 perm = oilsUtilsCheckPerms( oilsFMGetObjectId( userObj ), -1, permissions, 1 );
128 osrfAppRespondComplete( ctx, oilsEventToJSON(perm) );
137 * Returns 1 if the password provided matches the user's real password
138 * Returns 0 otherwise
139 * Returns -1 on error
141 int oilsAuthVerifyPassword(
142 osrfMethodContext* ctx, jsonObject* userObj, char* uname, char* password ) {
145 char* realPassword = oilsFMGetString( userObj, "passwd" ); /**/
146 char* seed = osrfCacheGetString( "%s%s", OILS_AUTH_CACHE_PRFX, uname ); /**/
149 return osrfAppRequestRespondException( ctx->session,
150 ctx->request, "No authentication seed found. "
151 "open-ils.auth.authenticate.init must be called first");
154 osrfLogDebug( "oilsAuth retrieved seed from cache: %s", seed );
155 char* maskedPw = md5sum( "%s%s", seed, realPassword );
156 if(!maskedPw) return -1;
157 osrfLogDebug( "oilsAuth generated masked password %s. "
158 "Testing against provided password %s", maskedPw, password );
160 if( !strcmp( maskedPw, password ) ) ret = 1;
170 * Calculates the login timeout
171 * 1. If orgloc is 1 or greater and has a timeout specified as an
172 * org unit setting, it is used
173 * 2. If orgloc is not valid, we check the org unit auth timeout
174 * setting for the home org unit of the user logging in
175 * 3. If that setting is not defined, we use the configured defaults
177 double oilsAuthGetTimeout( jsonObject* userObj, char* type, double orgloc ) {
179 if(!__oilsAuthOPACTimeout) { /* Load the default timeouts */
181 __oilsAuthOPACTimeout =
183 osrf_settings_host_value_object(
184 "/apps/open-ils.auth/app_settings/default_timeout/opac"));
186 __oilsAuthStaffTimeout =
188 osrf_settings_host_value_object(
189 "/apps/open-ils.auth/app_settings/default_timeout/staff" ));
191 osrfLogInfo("Set default auth timetouts: opac => %d : staff => %d",
192 __oilsAuthOPACTimeout, __oilsAuthStaffTimeout );
195 char* setting = NULL;
197 double home_ou = jsonObjectGetNumber( oilsFMGetObject( userObj, "home_ou" ) );
198 if(orgloc < 1) orgloc = (int) home_ou;
200 if(!strcmp(type, "opac"))
201 setting = OILS_ORG_SETTING_OPAC_TIMEOUT;
202 else if(!strcmp(type, "staff"))
203 setting = OILS_ORG_SETTING_STAFF_TIMEOUT;
205 char* timeout = oilsUtilsFetchOrgSetting( orgloc, setting );
208 if( orgloc != home_ou ) {
209 osrfLogDebug("Auth timeout not defined for org %d, "
210 "trying home_ou %d", orgloc, home_ou );
211 timeout = oilsUtilsFetchOrgSetting( (int) home_ou, setting );
214 if(!strcmp(type, "staff")) return __oilsAuthStaffTimeout;
215 return __oilsAuthOPACTimeout;
218 double t = atof(timeout);
223 /* Adds the authentication token to the user cache. The timeout for the
224 * auth token is based on the type of login as well as (if type=='opac')
225 * the org location id.
226 * Returns the event that should be returned to the user.
227 * Event must be freed
229 oilsEvent* oilsAuthHandleLoginOK(
230 jsonObject* userObj, char* uname, char* type, double orgloc ) {
233 osrfLogActivity( "User %s successfully logged in", uname );
235 double timeout = oilsAuthGetTimeout( userObj, type, orgloc );
236 osrfLogDebug("Auth session timeout for %s: %lf", uname, timeout );
238 char* string = va_list_to_string(
239 "%d.%d.%s", getpid(), time(NULL), uname );
240 char* authToken = md5sum(string);
241 char* authKey = va_list_to_string(
242 "%s%s", OILS_AUTH_CACHE_PRFX, authToken );
244 oilsFMSetString( userObj, "passwd", "" );
245 jsonObject* cacheObj = jsonParseString("{\"authtime\": %lf}", timeout);
246 jsonObjectSetKey( cacheObj, "userobj", jsonObjectClone(userObj));
248 //osrfCachePutObject( authKey, userObj, timeout );
249 osrfCachePutObject( authKey, cacheObj, timeout );
250 jsonObjectFree(cacheObj);
251 osrfLogInternal("oilsAuthComplete(): Placed user object into cache");
252 jsonObject* payload = jsonParseString(
253 "{ \"authtoken\": \"%s\", \"authtime\": %lf }", authToken, timeout );
255 response = oilsNewEvent2( OILS_EVENT_SUCCESS, payload );
256 free(string); free(authToken); free(authKey);
257 jsonObjectFree(payload);
263 int oilsAuthComplete( osrfMethodContext* ctx ) {
264 OSRF_METHOD_VERIFY_CONTEXT(ctx);
266 char* uname = jsonObjectGetString(jsonObjectGetIndex(ctx->params, 0));
267 char* password = jsonObjectGetString(jsonObjectGetIndex(ctx->params, 1));
268 char* type = jsonObjectGetString(jsonObjectGetIndex(ctx->params, 2));
269 double orgloc = jsonObjectGetNumber(jsonObjectGetIndex(ctx->params, 3));
271 if(!type) type = "staff";
273 if( !(uname && password) ) {
274 return osrfAppRequestRespondException( ctx->session, ctx->request,
275 "username and password required for method: %s", ctx->method->name );
278 oilsEvent* response = NULL;
279 jsonObject* userObj = oilsUtilsFetchUserByUsername( uname );
282 response = oilsNewEvent( OILS_EVENT_AUTH_FAILED );
283 osrfAppRespondComplete( ctx, oilsEventToJSON(response) );
284 oilsEventFree(response);
288 /* check to see if the user is allowed to login */
289 if( oilsAuthCheckLoginPerm( ctx, userObj, type ) == -1 ) {
290 jsonObjectFree(userObj);
294 int passOK = oilsAuthVerifyPassword( ctx, userObj, uname, password );
295 if( passOK < 0 ) return passOK;
298 response = oilsAuthHandleLoginOK( userObj, uname, type, orgloc );
301 response = oilsNewEvent( OILS_EVENT_AUTH_FAILED );
302 osrfLogInfo( "Login failed for for %s", uname );
305 jsonObjectFree(userObj);
306 osrfAppRespondComplete( ctx, oilsEventToJSON(response) );
307 oilsEventFree(response);
314 int oilsAuthSessionDelete( osrfMethodContext* ctx ) {
315 OSRF_METHOD_VERIFY_CONTEXT(ctx);
317 char* authToken = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0) );
318 jsonObject* resp = NULL;
321 osrfLogDebug("Removing auth session: %s", authToken );
322 char* key = va_list_to_string("%s%s", OILS_AUTH_CACHE_PRFX, authToken ); /**/
323 osrfCacheRemove(key);
324 resp = jsonNewObject(authToken); /**/
328 osrfAppRespondComplete( ctx, resp );
329 jsonObjectFree(resp);
333 /** Resets the auth login timeout
334 * @return The event object, OILS_EVENT_SUCCESS, or OILS_EVENT_NO_SESSION
336 oilsEvent* _oilsAuthResetTimeout( char* authToken ) {
337 if(!authToken) return NULL;
339 oilsEvent* evt = NULL;
342 osrfLogDebug("Resetting auth timeout for session %s", authToken);
343 char* key = va_list_to_string("%s%s", OILS_AUTH_CACHE_PRFX, authToken );
344 jsonObject* cacheObj = osrfCacheGetObject( key );
347 evt = oilsNewEvent(OILS_EVENT_NO_SESSION);
351 timeout = jsonObjectGetNumber( jsonObjectGetKey( cacheObj, "authtime"));
352 osrfCacheSetExpire( timeout, key );
353 jsonObject* payload = jsonNewNumberObject(timeout);
354 evt = oilsNewEvent2(OILS_EVENT_SUCCESS, payload);
355 jsonObjectFree(payload);
356 jsonObjectFree(cacheObj);
363 int oilsAuthResetTimeout( osrfMethodContext* ctx ) {
364 OSRF_METHOD_VERIFY_CONTEXT(ctx);
365 char* authToken = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0));
366 oilsEvent* evt = _oilsAuthResetTimeout(authToken);
367 osrfAppRespondComplete( ctx, oilsEventToJSON(evt) );
373 int oilsAuthSessionRetrieve( osrfMethodContext* ctx ) {
374 OSRF_METHOD_VERIFY_CONTEXT(ctx);
376 char* authToken = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0));
377 char* reset = jsonObjectToSimpleString( jsonObjectGetIndex(ctx->params, 1));
378 jsonObject* cacheObj = NULL;
383 oilsEvent* evt = _oilsAuthResetTimeout(authToken);
384 if( evt && strcmp(evt->event,OILS_EVENT_SUCCESS) ) {
385 osrfAppRespondComplete( ctx, oilsEventToJSON(evt) );
391 osrfLogDebug("Retrieving auth session: %s", authToken);
392 char* key = va_list_to_string("%s%s", OILS_AUTH_CACHE_PRFX, authToken );
393 cacheObj = osrfCacheGetObject( key );
395 osrfAppRespondComplete( ctx, jsonObjectGetKey( cacheObj, "userobj"));
396 jsonObjectFree(cacheObj);
398 oilsEvent* evt = oilsNewEvent(OILS_EVENT_NO_SESSION);
399 osrfAppRespondComplete( ctx, oilsEventToJSON(evt) ); /* should be event.. */