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;
153 double oilsAuthGetTimeout( char* type, double orgloc ) {
154 if(!__oilsAuthOPACTimeout) {
156 __oilsAuthOPACTimeout =
158 osrf_settings_host_value_object(
159 "/apps/open-ils.auth/app_settings/default_timeout/opac"));
161 __oilsAuthStaffTimeout =
163 osrf_settings_host_value_object(
164 "/apps/open-ils.auth/app_settings/default_timeout/staff" ));
166 osrfLogInfo("Set default auth timetouts: opac => %d : staff => %d",
167 __oilsAuthOPACTimeout, __oilsAuthStaffTimeout );
170 char* setting = NULL;
172 if(!strcmp(type, "opac")) {
173 if(orgloc < 1) return __oilsAuthOPACTimeout;
174 setting = OILS_ORG_SETTING_OPAC_TIMEOUT;
176 } else if(!strcmp(type, "staff")) {
177 if(orgloc < 1) return __oilsAuthStaffTimeout;
178 setting = OILS_ORG_SETTING_STAFF_TIMEOUT;
181 char* timeout = oilsUtilsFetchOrgSetting( orgloc, setting );
182 double t = atof(timeout);
187 /* Adds the authentication token to the user cache. The timeout for the
188 * auth token is based on the type of login as well as (if type=='opac')
189 * the org location id.
190 * Returns the event that should be returned to the user.
191 * Event must be freed
193 oilsEvent* oilsAuthHandleLoginOK(
194 jsonObject* userObj, char* uname, char* type, double orgloc ) {
197 osrfLogActivity( "User %s successfully logged in", uname );
199 double timeout = oilsAuthGetTimeout( type, orgloc );
200 osrfLogDebug("Auth session timeout for %s: %lf", uname, timeout );
202 char* string = va_list_to_string(
203 "%d.%d.%s", getpid(), time(NULL), uname );
204 char* authToken = md5sum(string);
205 char* authKey = va_list_to_string(
206 "%s%s", OILS_AUTH_CACHE_PRFX, authToken );
208 oilsFMSetString( userObj, "passwd", "" );
209 osrfCachePutObject( authKey, userObj, timeout );
210 osrfLogInternal("oilsAuthComplete(): Placed user object into cache");
211 response = oilsNewEvent2( OILS_EVENT_SUCCESS, jsonNewObject(authToken) );
213 free(string); free(authToken); free(authKey);
219 int oilsAuthComplete( osrfMethodContext* ctx ) {
220 OSRF_METHOD_VERIFY_CONTEXT(ctx);
222 char* uname = jsonObjectGetString(jsonObjectGetIndex(ctx->params, 0));
223 char* password = jsonObjectGetString(jsonObjectGetIndex(ctx->params, 1));
224 char* type = jsonObjectGetString(jsonObjectGetIndex(ctx->params, 2));
225 double orgloc = jsonObjectGetNumber(jsonObjectGetIndex(ctx->params, 3));
227 if(!type) type = "staff";
229 if( !(uname && password) ) {
230 return osrfAppRequestRespondException( ctx->session, ctx->request,
231 "username and password required for method: %s", ctx->method->name );
234 oilsEvent* response = NULL;
235 jsonObject* userObj = oilsUtilsFetchUserByUsername( uname );
238 response = oilsNewEvent( OILS_EVENT_AUTH_FAILED );
239 osrfAppRespondComplete( ctx, oilsEventToJSON(response) );
240 oilsEventFree(response);
244 /* check to see if the user is allowed to login */
245 if( oilsAuthCheckLoginPerm( ctx, userObj, type ) == -1 ) {
246 jsonObjectFree(userObj);
250 int passOK = oilsAuthVerifyPassword( ctx, userObj, uname, password );
251 if( passOK < 0 ) return passOK;
254 response = oilsAuthHandleLoginOK( userObj, uname, type, orgloc );
257 response = oilsNewEvent( OILS_EVENT_AUTH_FAILED );
258 osrfLogInfo( "Login failed for for %s", uname );
261 jsonObjectFree(userObj);
262 osrfAppRespondComplete( ctx, oilsEventToJSON(response) );
263 oilsEventFree(response);
268 int oilsAuthSessionRetrieve( osrfMethodContext* ctx ) {
269 OSRF_METHOD_VERIFY_CONTEXT(ctx);
271 char* authToken = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0));
272 jsonObject* userObj = NULL;
275 char* key = va_list_to_string("%s%s", OILS_AUTH_CACHE_PRFX, authToken ); /**/
276 userObj = osrfCacheGetObject( key ); /**/
280 osrfAppRespondComplete( ctx, userObj );
281 jsonObjectFree(userObj);
285 int oilsAuthSessionDelete( osrfMethodContext* ctx ) {
286 OSRF_METHOD_VERIFY_CONTEXT(ctx);
288 char* authToken = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0) );
289 jsonObject* resp = NULL;
292 char* key = va_list_to_string("%s%s", OILS_AUTH_CACHE_PRFX, authToken ); /**/
293 osrfCacheRemove(key);
294 resp = jsonNewObject(authToken); /**/
298 osrfAppRespondComplete( ctx, resp );
299 jsonObjectFree(resp);