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 )", 2, 0 );
39 osrfAppRegisterMethod(
41 "open-ils.auth.session.retrieve",
42 "oilsAuthSessionRetrieve",
43 "Returns the user object (password blanked) for the given login session "
44 "PARAMS( authToken )", 1, 0 );
46 osrfAppRegisterMethod(
48 "open-ils.auth.session.delete",
49 "oilsAuthSessionDelete",
50 "Destroys the given login session "
51 "PARAMS( authToken )", 1, 0 );
56 int osrfAppChildInit() {
60 int oilsAuthInit( osrfMethodContext* ctx ) {
61 OSRF_METHOD_VERIFY_CONTEXT(ctx);
64 char* username = NULL;
69 if( (username = jsonObjectGetString(jsonObjectGetIndex(ctx->params, 0))) ) {
71 seed = va_list_to_string( "%d.%d.%s", time(NULL), getpid(), username );
72 key = va_list_to_string( "%s%s", OILS_AUTH_CACHE_PRFX, username );
74 md5seed = md5sum(seed);
75 osrfCachePutString( key, md5seed, 30 );
77 osrfLogDebug( "oilsAuthInit(): has seed %s and key %s", md5seed, key );
79 resp = jsonNewObject(md5seed);
80 osrfAppRespondComplete( ctx, resp );
92 /** Verifies that the user has permission to login with the
93 * given type. If the permission fails, an oilsEvent is returned
95 * @return -1 if the permission check failed, 0 if ther permission
98 int oilsAuthCheckLoginPerm(
99 osrfMethodContext* ctx, jsonObject* userObj, char* type ) {
101 if(!(userObj && type)) return -1;
102 oilsEvent* perm = NULL;
104 if(!strcmp(type, "opac")) {
105 char* permissions[] = { "OPAC_LOGIN" };
106 perm = oilsUtilsCheckPerms( oilsFMGetObjectId( userObj ), -1, permissions, 1 );
108 } else if(!strcmp(type, "staff")) {
109 char* permissions[] = { "STAFF_LOGIN" };
110 perm = oilsUtilsCheckPerms( oilsFMGetObjectId( userObj ), -1, permissions, 1 );
114 osrfAppRespondComplete( ctx, oilsEventToJSON(perm) );
123 * Returns 1 if the password provided matches the user's real password
124 * Returns 0 otherwise
125 * Returns -1 on error
127 int oilsAuthVerifyPassword(
128 osrfMethodContext* ctx, jsonObject* userObj, char* uname, char* password ) {
131 char* realPassword = oilsFMGetString( userObj, "passwd" ); /**/
132 char* seed = osrfCacheGetString( "%s%s", OILS_AUTH_CACHE_PRFX, uname ); /**/
135 return osrfAppRequestRespondException( ctx->session,
136 ctx->request, "No authentication seed found. "
137 "open-ils.auth.authenticate.init must be called first");
140 osrfLogDebug( "oilsAuth retrieved seed from cache: %s", seed );
141 char* maskedPw = md5sum( "%s%s", seed, realPassword );
142 if(!maskedPw) return -1;
143 osrfLogDebug( "oilsAuth generated masked password %s. "
144 "Testing against provided password %s", maskedPw, password );
146 if( !strcmp( maskedPw, password ) ) ret = 1;
156 * Calculates the login timeout
157 * 1. If orgloc is 1 or greater and has a timeout specified as an
158 * org unit setting, it is used
159 * 2. If orgloc is not valid, we check the org unit auth timeout
160 * setting for the home org unit of the user logging in
161 * 3. If that setting is not defined, we use the configured defaults
163 double oilsAuthGetTimeout( jsonObject* userObj, char* type, double orgloc ) {
165 if(!__oilsAuthOPACTimeout) { /* Load the default timeouts */
167 __oilsAuthOPACTimeout =
169 osrf_settings_host_value_object(
170 "/apps/open-ils.auth/app_settings/default_timeout/opac"));
172 __oilsAuthStaffTimeout =
174 osrf_settings_host_value_object(
175 "/apps/open-ils.auth/app_settings/default_timeout/staff" ));
177 osrfLogInfo("Set default auth timetouts: opac => %d : staff => %d",
178 __oilsAuthOPACTimeout, __oilsAuthStaffTimeout );
181 char* setting = NULL;
183 double home_ou = jsonObjectGetNumber( oilsFMGetObject( userObj, "home_ou" ) );
184 if(orgloc < 1) orgloc = (int) home_ou;
186 if(!strcmp(type, "opac"))
187 setting = OILS_ORG_SETTING_OPAC_TIMEOUT;
188 else if(!strcmp(type, "staff"))
189 setting = OILS_ORG_SETTING_STAFF_TIMEOUT;
191 char* timeout = oilsUtilsFetchOrgSetting( orgloc, setting );
194 if( orgloc != home_ou ) {
195 osrfLogDebug("Auth timeout not defined for org %d, "
196 "trying home_ou %d", orgloc, home_ou );
197 timeout = oilsUtilsFetchOrgSetting( (int) home_ou, setting );
200 if(!strcmp(type, "staff")) return __oilsAuthStaffTimeout;
201 return __oilsAuthOPACTimeout;
204 double t = atof(timeout);
209 /* Adds the authentication token to the user cache. The timeout for the
210 * auth token is based on the type of login as well as (if type=='opac')
211 * the org location id.
212 * Returns the event that should be returned to the user.
213 * Event must be freed
215 oilsEvent* oilsAuthHandleLoginOK(
216 jsonObject* userObj, char* uname, char* type, double orgloc ) {
219 osrfLogActivity( "User %s successfully logged in", uname );
221 double timeout = oilsAuthGetTimeout( userObj, type, orgloc );
222 osrfLogDebug("Auth session timeout for %s: %lf", uname, timeout );
224 char* string = va_list_to_string(
225 "%d.%d.%s", getpid(), time(NULL), uname );
226 char* authToken = md5sum(string);
227 char* authKey = va_list_to_string(
228 "%s%s", OILS_AUTH_CACHE_PRFX, authToken );
230 oilsFMSetString( userObj, "passwd", "" );
231 osrfCachePutObject( authKey, userObj, timeout );
232 osrfLogInternal("oilsAuthComplete(): Placed user object into cache");
233 jsonObject* payload = jsonParseString(
234 "{ \"authtoken\": \"%s\", \"authtime\": %lf }", authToken, timeout );
236 response = oilsNewEvent2( OILS_EVENT_SUCCESS, payload );
237 free(string); free(authToken); free(authKey);
238 jsonObjectFree(payload);
244 int oilsAuthComplete( osrfMethodContext* ctx ) {
245 OSRF_METHOD_VERIFY_CONTEXT(ctx);
247 char* uname = jsonObjectGetString(jsonObjectGetIndex(ctx->params, 0));
248 char* password = jsonObjectGetString(jsonObjectGetIndex(ctx->params, 1));
249 char* type = jsonObjectGetString(jsonObjectGetIndex(ctx->params, 2));
250 double orgloc = jsonObjectGetNumber(jsonObjectGetIndex(ctx->params, 3));
252 if(!type) type = "staff";
254 if( !(uname && password) ) {
255 return osrfAppRequestRespondException( ctx->session, ctx->request,
256 "username and password required for method: %s", ctx->method->name );
259 oilsEvent* response = NULL;
260 jsonObject* userObj = oilsUtilsFetchUserByUsername( uname );
263 response = oilsNewEvent( OILS_EVENT_AUTH_FAILED );
264 osrfAppRespondComplete( ctx, oilsEventToJSON(response) );
265 oilsEventFree(response);
269 /* check to see if the user is allowed to login */
270 if( oilsAuthCheckLoginPerm( ctx, userObj, type ) == -1 ) {
271 jsonObjectFree(userObj);
275 int passOK = oilsAuthVerifyPassword( ctx, userObj, uname, password );
276 if( passOK < 0 ) return passOK;
279 response = oilsAuthHandleLoginOK( userObj, uname, type, orgloc );
282 response = oilsNewEvent( OILS_EVENT_AUTH_FAILED );
283 osrfLogInfo( "Login failed for for %s", uname );
286 jsonObjectFree(userObj);
287 osrfAppRespondComplete( ctx, oilsEventToJSON(response) );
288 oilsEventFree(response);
293 int oilsAuthSessionRetrieve( osrfMethodContext* ctx ) {
294 OSRF_METHOD_VERIFY_CONTEXT(ctx);
296 char* authToken = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0));
297 jsonObject* userObj = NULL;
300 char* key = va_list_to_string("%s%s", OILS_AUTH_CACHE_PRFX, authToken ); /**/
301 userObj = osrfCacheGetObject( key ); /**/
305 osrfAppRespondComplete( ctx, userObj );
306 jsonObjectFree(userObj);
310 int oilsAuthSessionDelete( osrfMethodContext* ctx ) {
311 OSRF_METHOD_VERIFY_CONTEXT(ctx);
313 char* authToken = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0) );
314 jsonObject* resp = NULL;
317 char* key = va_list_to_string("%s%s", OILS_AUTH_CACHE_PRFX, authToken ); /**/
318 osrfCacheRemove(key);
319 resp = jsonNewObject(authToken); /**/
323 osrfAppRespondComplete( ctx, resp );
324 jsonObjectFree(resp);