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 and returns the auth token "
35 "PARAMS(username, md5sum( seed + password ), type )", 2, 0 );
37 osrfAppRegisterMethod(
39 "open-ils.auth.session.retrieve",
40 "oilsAuthSessionRetrieve",
41 "Returns the user object (password blanked) for the given login session "
42 "PARAMS( authToken )", 1, 0 );
44 osrfAppRegisterMethod(
46 "open-ils.auth.session.delete",
47 "oilsAuthSessionDelete",
48 "Destroys the given login session "
49 "PARAMS( authToken )", 1, 0 );
54 int osrfAppChildInit() {
58 int oilsAuthInit( osrfMethodContext* ctx ) {
59 OSRF_METHOD_VERIFY_CONTEXT(ctx);
62 char* username = NULL;
67 if( (username = jsonObjectGetString(jsonObjectGetIndex(ctx->params, 0))) ) {
69 seed = va_list_to_string( "%d.%d.%s", time(NULL), getpid(), username );
70 key = va_list_to_string( "%s%s", OILS_AUTH_CACHE_PRFX, username );
72 md5seed = md5sum(seed);
73 osrfCachePutString( key, md5seed, 30 );
75 osrfLogDebug( "oilsAuthInit(): has seed %s and key %s", md5seed, key );
77 resp = jsonNewObject(md5seed);
78 osrfAppRespondComplete( ctx, resp );
90 /** Verifies that the user has permission to login with the
91 * given type. If the permission fails, an oilsEvent is returned
93 * @return -1 if the permission check failed, 0 if ther permission
96 int oilsAuthCheckLoginPerm(
97 osrfMethodContext* ctx, jsonObject* userObj, char* type ) {
99 if(!(userObj && type)) return -1;
100 oilsEvent* perm = NULL;
102 if(!strcmp(type, "opac")) {
103 char* permissions[] = { "OPAC_LOGIN" };
104 perm = oilsUtilsCheckPerms( oilsFMGetObjectId( userObj ), -1, permissions, 1 );
106 } else if(!strcmp(type, "staff")) {
107 char* permissions[] = { "STAFF_LOGIN" };
108 perm = oilsUtilsCheckPerms( oilsFMGetObjectId( userObj ), -1, permissions, 1 );
112 osrfAppRespondComplete( ctx, oilsEventToJSON(perm) );
121 * Returns 1 if the password provided matches the user's real password
122 * Returns 0 otherwise
123 * Returns -1 on error
125 int oilsAuthVerifyPassword(
126 osrfMethodContext* ctx, jsonObject* userObj, char* uname, char* password ) {
129 char* realPassword = oilsFMGetString( userObj, "passwd" ); /**/
130 char* seed = osrfCacheGetString( "%s%s", OILS_AUTH_CACHE_PRFX, uname ); /**/
133 return osrfAppRequestRespondException( ctx->session,
134 ctx->request, "No authentication seed found. "
135 "open-ils.auth.authenticate.init must be called first");
138 osrfLogDebug( "oilsAuth retrieved seed from cache: %s", seed );
139 char* maskedPw = md5sum( "%s%s", seed, realPassword );
140 if(!maskedPw) return -1;
141 osrfLogDebug( "oilsAuth generated masked password %s. "
142 "Testing against provided password %s", maskedPw, password );
144 if( !strcmp( maskedPw, password ) ) ret = 1;
154 * Calculates the login timeout
155 * 1. If orgloc is 1 or greater and has a timeout specified as an
156 * org unit setting, it is used
157 * 2. If orgloc is not valid, we check the org unit auth timeout
158 * setting for the home org unit of the user logging in
159 * 3. If that setting is not defined, we use the configured defaults
161 double oilsAuthGetTimeout( jsonObject* userObj, char* type, double orgloc ) {
163 if(!__oilsAuthOPACTimeout) { /* Load the default timeouts */
165 __oilsAuthOPACTimeout =
167 osrf_settings_host_value_object(
168 "/apps/open-ils.auth/app_settings/default_timeout/opac"));
170 __oilsAuthStaffTimeout =
172 osrf_settings_host_value_object(
173 "/apps/open-ils.auth/app_settings/default_timeout/staff" ));
175 osrfLogInfo("Set default auth timetouts: opac => %d : staff => %d",
176 __oilsAuthOPACTimeout, __oilsAuthStaffTimeout );
179 char* setting = NULL;
181 double home_ou = jsonObjectGetNumber( oilsFMGetObject( userObj, "home_ou" ) );
182 if(orgloc < 1) orgloc = (int) home_ou;
184 if(!strcmp(type, "opac"))
185 setting = OILS_ORG_SETTING_OPAC_TIMEOUT;
186 else if(!strcmp(type, "staff"))
187 setting = OILS_ORG_SETTING_STAFF_TIMEOUT;
189 char* timeout = oilsUtilsFetchOrgSetting( orgloc, setting );
192 if( orgloc != home_ou ) {
193 osrfLogDebug("Auth timeout not defined for org %d, "
194 "trying home_ou %d", orgloc, home_ou );
195 timeout = oilsUtilsFetchOrgSetting( (int) home_ou, setting );
198 if(!strcmp(type, "staff")) return __oilsAuthStaffTimeout;
199 return __oilsAuthStaffTimeout;
202 double t = atof(timeout);
207 /* Adds the authentication token to the user cache. The timeout for the
208 * auth token is based on the type of login as well as (if type=='opac')
209 * the org location id.
210 * Returns the event that should be returned to the user.
211 * Event must be freed
213 oilsEvent* oilsAuthHandleLoginOK(
214 jsonObject* userObj, char* uname, char* type, double orgloc ) {
217 osrfLogActivity( "User %s successfully logged in", uname );
219 double timeout = oilsAuthGetTimeout( userObj, type, orgloc );
220 osrfLogDebug("Auth session timeout for %s: %lf", uname, timeout );
222 char* string = va_list_to_string(
223 "%d.%d.%s", getpid(), time(NULL), uname );
224 char* authToken = md5sum(string);
225 char* authKey = va_list_to_string(
226 "%s%s", OILS_AUTH_CACHE_PRFX, authToken );
228 oilsFMSetString( userObj, "passwd", "" );
229 osrfCachePutObject( authKey, userObj, timeout );
230 osrfLogInternal("oilsAuthComplete(): Placed user object into cache");
231 response = oilsNewEvent2( OILS_EVENT_SUCCESS, jsonNewObject(authToken) );
233 free(string); free(authToken); free(authKey);
239 int oilsAuthComplete( osrfMethodContext* ctx ) {
240 OSRF_METHOD_VERIFY_CONTEXT(ctx);
242 char* uname = jsonObjectGetString(jsonObjectGetIndex(ctx->params, 0));
243 char* password = jsonObjectGetString(jsonObjectGetIndex(ctx->params, 1));
244 char* type = jsonObjectGetString(jsonObjectGetIndex(ctx->params, 2));
245 double orgloc = jsonObjectGetNumber(jsonObjectGetIndex(ctx->params, 3));
247 if(!type) type = "staff";
249 if( !(uname && password) ) {
250 return osrfAppRequestRespondException( ctx->session, ctx->request,
251 "username and password required for method: %s", ctx->method->name );
254 oilsEvent* response = NULL;
255 jsonObject* userObj = oilsUtilsFetchUserByUsername( uname );
258 response = oilsNewEvent( OILS_EVENT_AUTH_FAILED );
259 osrfAppRespondComplete( ctx, oilsEventToJSON(response) );
260 oilsEventFree(response);
264 /* check to see if the user is allowed to login */
265 if( oilsAuthCheckLoginPerm( ctx, userObj, type ) == -1 ) {
266 jsonObjectFree(userObj);
270 int passOK = oilsAuthVerifyPassword( ctx, userObj, uname, password );
271 if( passOK < 0 ) return passOK;
274 response = oilsAuthHandleLoginOK( userObj, uname, type, orgloc );
277 response = oilsNewEvent( OILS_EVENT_AUTH_FAILED );
278 osrfLogInfo( "Login failed for for %s", uname );
281 jsonObjectFree(userObj);
282 osrfAppRespondComplete( ctx, oilsEventToJSON(response) );
283 oilsEventFree(response);
288 int oilsAuthSessionRetrieve( osrfMethodContext* ctx ) {
289 OSRF_METHOD_VERIFY_CONTEXT(ctx);
291 char* authToken = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0));
292 jsonObject* userObj = NULL;
295 char* key = va_list_to_string("%s%s", OILS_AUTH_CACHE_PRFX, authToken ); /**/
296 userObj = osrfCacheGetObject( key ); /**/
300 osrfAppRespondComplete( ctx, userObj );
301 jsonObjectFree(userObj);
305 int oilsAuthSessionDelete( osrfMethodContext* ctx ) {
306 OSRF_METHOD_VERIFY_CONTEXT(ctx);
308 char* authToken = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0) );
309 jsonObject* resp = NULL;
312 char* key = va_list_to_string("%s%s", OILS_AUTH_CACHE_PRFX, authToken ); /**/
313 osrfCacheRemove(key);
314 resp = jsonNewObject(authToken); /**/
318 osrfAppRespondComplete( ctx, resp );
319 jsonObjectFree(resp);