]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/c-apps/oils_auth.c
Auth now looks at orgid passed in, if it has no settings for auth timeout,
[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 "objson/object.h"
5 #include "opensrf/log.h"
6 #include "oils_utils.h"
7 #include "oils_constants.h"
8 #include "oils_event.h"
9
10 #define OILS_AUTH_CACHE_PRFX "oils_auth_"
11
12 #define MODULENAME "open-ils.auth"
13
14 int osrfAppInitialize();
15 int osrfAppChildInit();
16
17 int __oilsAuthOPACTimeout = 0;
18 int __oilsAuthStaffTimeout = 0;
19
20
21 int osrfAppInitialize() {
22
23         osrfAppRegisterMethod( 
24                 MODULENAME, 
25                 "open-ils.auth.authenticate.init", 
26                 "oilsAuthInit", 
27                 "Start the authentication process and returns the intermediate authentication seed"
28                 " PARAMS( username )", 1, 0 );
29
30         osrfAppRegisterMethod( 
31                 MODULENAME, 
32                 "open-ils.auth.authenticate.complete", 
33                 "oilsAuthComplete", 
34                 "Completes the authentication process and returns the auth token "
35                 "PARAMS(username, md5sum( seed + password ), type )", 2, 0 );
36
37         osrfAppRegisterMethod( 
38                 MODULENAME, 
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 );
43
44         osrfAppRegisterMethod( 
45                 MODULENAME, 
46                 "open-ils.auth.session.delete", 
47                 "oilsAuthSessionDelete", 
48                 "Destroys the given login session "
49                 "PARAMS( authToken )",  1, 0 );
50
51         return 0;
52 }
53
54 int osrfAppChildInit() {
55         return 0;
56 }
57
58 int oilsAuthInit( osrfMethodContext* ctx ) {
59         OSRF_METHOD_VERIFY_CONTEXT(ctx); 
60
61         jsonObject* resp;
62         char* username = NULL;
63         char* seed = NULL;
64         char* md5seed = NULL;
65         char* key = NULL;
66
67         if( (username = jsonObjectGetString(jsonObjectGetIndex(ctx->params, 0))) ) {
68
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 );
71
72                 md5seed = md5sum(seed);
73                 osrfCachePutString( key, md5seed, 30 );
74
75                 osrfLogDebug( "oilsAuthInit(): has seed %s and key %s", md5seed, key );
76
77                 resp = jsonNewObject(md5seed);  
78                 osrfAppRespondComplete( ctx, resp );
79
80                 jsonObjectFree(resp);
81                 free(seed);
82                 free(md5seed);
83                 free(key);
84                 return 0;
85         }
86
87         return -1;
88 }
89
90 /** Verifies that the user has permission to login with the 
91  * given type.  If the permission fails, an oilsEvent is returned
92  * to the caller.
93  * @return -1 if the permission check failed, 0 if ther permission
94  * is granted
95  */
96 int oilsAuthCheckLoginPerm( 
97                 osrfMethodContext* ctx, jsonObject* userObj, char* type ) {
98
99         if(!(userObj && type)) return -1;
100         oilsEvent* perm = NULL;
101
102         if(!strcmp(type, "opac")) {
103                 char* permissions[] = { "OPAC_LOGIN" };
104                 perm = oilsUtilsCheckPerms( oilsFMGetObjectId( userObj ), -1, permissions, 1 );
105
106         } else if(!strcmp(type, "staff")) {
107                 char* permissions[] = { "STAFF_LOGIN" };
108                 perm = oilsUtilsCheckPerms( oilsFMGetObjectId( userObj ), -1, permissions, 1 );
109         }
110
111         if(perm) {
112                 osrfAppRespondComplete( ctx, oilsEventToJSON(perm) ); 
113                 oilsEventFree(perm);
114                 return -1;
115         }
116
117         return 0;
118 }
119
120 /**
121  * Returns 1 if the password provided matches the user's real password
122  * Returns 0 otherwise
123  * Returns -1 on error
124  */
125 int oilsAuthVerifyPassword( 
126                 osrfMethodContext* ctx, jsonObject* userObj, char* uname, char* password ) {
127
128         int ret = 0;
129         char* realPassword = oilsFMGetString( userObj, "passwd" ); /**/
130         char* seed = osrfCacheGetString( "%s%s", OILS_AUTH_CACHE_PRFX, uname ); /**/
131
132         if(!seed) {
133                 return osrfAppRequestRespondException( ctx->session,
134                         ctx->request, "No authentication seed found. "
135                         "open-ils.auth.authenticate.init must be called first");
136         }
137
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 );
143
144         if( !strcmp( maskedPw, password ) ) ret = 1;
145
146         free(realPassword);
147         free(seed);
148         free(maskedPw);
149
150         return ret;
151 }
152
153 /**
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
160  */
161 double oilsAuthGetTimeout( jsonObject* userObj, char* type, double orgloc ) {
162
163         if(!__oilsAuthOPACTimeout) { /* Load the default timeouts */
164
165                 __oilsAuthOPACTimeout = 
166                         jsonObjectGetNumber( 
167                                 osrf_settings_host_value_object( 
168                                         "/apps/open-ils.auth/app_settings/default_timeout/opac"));
169
170                 __oilsAuthStaffTimeout = 
171                         jsonObjectGetNumber( 
172                                 osrf_settings_host_value_object( 
173                                         "/apps/open-ils.auth/app_settings/default_timeout/staff" ));
174
175                 osrfLogInfo("Set default auth timetouts: opac => %d : staff => %d",
176                                 __oilsAuthOPACTimeout, __oilsAuthStaffTimeout );
177         }
178
179         char* setting = NULL;
180
181         double home_ou = jsonObjectGetNumber( oilsFMGetObject( userObj, "home_ou" ) );
182         if(orgloc < 1) orgloc = (int) home_ou;
183
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;
188
189         char* timeout = oilsUtilsFetchOrgSetting( orgloc, setting );
190
191         if(!timeout) {
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 );
196                 }
197                 if(!timeout) {
198                         if(!strcmp(type, "staff")) return __oilsAuthStaffTimeout;
199                         return __oilsAuthStaffTimeout;
200                 }
201         }
202         double t = atof(timeout);
203         free(timeout);
204         return t ;
205 }
206
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
212  */
213 oilsEvent* oilsAuthHandleLoginOK( 
214                 jsonObject* userObj, char* uname, char* type, double orgloc ) { 
215                 
216         oilsEvent* response;
217         osrfLogActivity( "User %s successfully logged in", uname );
218
219         double timeout = oilsAuthGetTimeout( userObj, type, orgloc );
220         osrfLogDebug("Auth session timeout for %s: %lf", uname, timeout );
221
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 ); 
227
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) );
232
233         free(string); free(authToken); free(authKey);
234         return response;
235 }
236
237
238
239 int oilsAuthComplete( osrfMethodContext* ctx ) {
240         OSRF_METHOD_VERIFY_CONTEXT(ctx); 
241
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));
246
247         if(!type) type = "staff";
248
249         if( !(uname && password) ) {
250                 return osrfAppRequestRespondException( ctx->session, ctx->request, 
251                         "username and password required for method: %s", ctx->method->name );
252         }
253
254         oilsEvent* response = NULL;
255         jsonObject* userObj = oilsUtilsFetchUserByUsername( uname ); 
256         
257         if(!userObj) { 
258                 response = oilsNewEvent( OILS_EVENT_AUTH_FAILED );
259                 osrfAppRespondComplete( ctx, oilsEventToJSON(response) ); 
260                 oilsEventFree(response);
261                 return 0;
262         }
263
264         /* check to see if the user is allowed to login */
265         if( oilsAuthCheckLoginPerm( ctx, userObj, type ) == -1 ) {
266                 jsonObjectFree(userObj);
267                 return 0;
268         }
269
270         int passOK = oilsAuthVerifyPassword( ctx, userObj, uname, password );
271         if( passOK < 0 ) return passOK;
272
273         if( passOK ) {
274                 response = oilsAuthHandleLoginOK( userObj, uname, type, orgloc );
275
276         } else {
277                 response = oilsNewEvent( OILS_EVENT_AUTH_FAILED );
278                 osrfLogInfo( "Login failed for for %s", uname );
279         }
280
281         jsonObjectFree(userObj);
282         osrfAppRespondComplete( ctx, oilsEventToJSON(response) ); 
283         oilsEventFree(response);
284
285         return 0;
286 }
287
288 int oilsAuthSessionRetrieve( osrfMethodContext* ctx ) {
289         OSRF_METHOD_VERIFY_CONTEXT(ctx); 
290
291         char* authToken = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0));
292         jsonObject* userObj = NULL;
293
294         if( authToken ){
295                 char* key = va_list_to_string("%s%s", OILS_AUTH_CACHE_PRFX, authToken ); /**/
296                 userObj = osrfCacheGetObject( key ); /**/
297                 free(key);
298         }
299
300         osrfAppRespondComplete( ctx, userObj );
301         jsonObjectFree(userObj);
302         return 0;
303 }
304
305 int oilsAuthSessionDelete( osrfMethodContext* ctx ) {
306         OSRF_METHOD_VERIFY_CONTEXT(ctx); 
307
308         char* authToken = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0) );
309         jsonObject* resp = NULL;
310
311         if( authToken ) {
312                 char* key = va_list_to_string("%s%s", OILS_AUTH_CACHE_PRFX, authToken ); /**/
313                 osrfCacheRemove(key);
314                 resp = jsonNewObject(authToken); /**/
315                 free(key);
316         }
317
318         osrfAppRespondComplete( ctx, resp );
319         jsonObjectFree(resp);
320         return 0;
321 }
322
323
324