LP#1468422 auth API continued
authorBill Erickson <berickxx@gmail.com>
Thu, 23 Jul 2015 17:51:29 +0000 (13:51 -0400)
committerBill Erickson <berickxx@gmail.com>
Mon, 23 Nov 2015 16:17:05 +0000 (11:17 -0500)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/c-apps/oils_auth.c

index 9404d07..7464df3 100644 (file)
@@ -160,14 +160,14 @@ int osrfAppChildInit() {
 }
 
 // free() response
-static char* oilsAuthGetSalt(int userId) {
+static char* oilsAuthGetSalt(int user_id) {
     char* salt_str = NULL;
 
-    jsonObject* params = jsonParseFmt(
-        "{\"from\":[\"actor.get_salt\",%d,\"%s\"]}", userId, "main");
+    jsonObject* params = jsonParseFmt( // free
+        "{\"from\":[\"actor.get_salt\",%d,\"%s\"]}", user_id, "main");
 
-    jsonObject* salt_obj = oilsUtilsQuickReq(
-        "open-ils.cstore", "open-ils.cstore.json_query", params);
+    jsonObject* salt_obj = // free
+        oilsUtilsCStoreReq("open-ils.cstore.json_query", params);
 
     jsonObjectFree(params);
 
@@ -463,59 +463,47 @@ static int oilsAuthCheckLoginPerm(
        means that the client process needs either to be the same process that called the init
        method or to receive the seed from the process that did so.
 */
-static int oilsAuthVerifyPassword( const osrfMethodContext* ctx,
-               const jsonObject* userObj, const char* uname,
-               const char* password, const char* nonce ) {
-
-       // Get the username seed, as stored previously in memcache by the init method
-       char* seed = osrfCacheGetString( "%s%s%s", OILS_AUTH_CACHE_PRFX, uname, nonce );
-       if(!seed) {
-               return osrfAppRequestRespondException( ctx->session,
-                       ctx->request, "No authentication seed found. "
-                       "open-ils.auth.authenticate.init must be called first "
-                       " (check that memcached is running and can be connected to) "
-               );
-       }
-    
-       // We won't be needing the seed again, remove it
-       osrfCacheRemove( "%s%s%s", OILS_AUTH_CACHE_PRFX, uname, nonce );
+static int oilsAuthVerifyPassword( const osrfMethodContext* ctx, int user_id, 
+        const char* identifier, const char* password, const char* nonce) {
 
-       // Get the hashed password from the user object
-       char* realPassword = oilsFMGetString( userObj, "passwd" );
+    int verified = 0;
 
-       osrfLogInternal(OSRF_LOG_MARK, "oilsAuth retrieved real password: [%s]", realPassword);
-       osrfLogDebug(OSRF_LOG_MARK, "oilsAuth retrieved seed from cache: %s", seed );
+       // We won't be needing the seed again, remove it
+       osrfCacheRemove("%s%s%s", OILS_AUTH_CACHE_PRFX, identifier, nonce);
 
-       // Concatenate them and take an MD5 hash of the result
-       char* maskedPw = md5sum( "%s%s", seed, realPassword );
+    // Ask the DB to verify the user's password.
+    // Here, the password is md5(md5(password) + salt)
 
-       free(realPassword);
-       free(seed);
+    jsonObject* params = jsonParseFmt( // free
+        "{\"from\":[\"actor.verify_passwd\",%d,\"main\",\"%s\"]}", 
+        user_id, password);
 
-       if( !maskedPw ) {
-               // This happens only if md5sum() runs out of memory
-               free( maskedPw );
-               return -1;  // md5sum() ran out of memory
-       }
+    jsonObject* verify_obj = // free 
+        oilsUtilsCStoreReq("open-ils.cstore.json_query", params);
 
-       osrfLogDebug(OSRF_LOG_MARK,  "oilsAuth generated masked password %s. "
-                       "Testing against provided password %s", maskedPw, password );
+    jsonObjectFree(params);
 
-       int ret = 0;
-       if( !strcmp( maskedPw, password ) )
-               ret = 1;
+    if (verify_obj) {
+        verified = oilsUtilsIsDBTrue(
+            jsonObjectGetString(
+                jsonObjectGetKeyConst(
+                    verify_obj, "actor.verify_passwd")));
 
-       free(maskedPw);
+        jsonObjectFree(verify_obj);
+    }
 
-       char* countkey = va_list_to_string( "%s%s%s", OILS_AUTH_CACHE_PRFX, uname, OILS_AUTH_COUNT_SFFX );
+       char* countkey = va_list_to_string("%s%s%s", 
+        OILS_AUTH_CACHE_PRFX, identifier, OILS_AUTH_COUNT_SFFX );
        jsonObject* countobject = osrfCacheGetObject( countkey );
        if(countobject) {
                long failcount = (long) jsonObjectGetNumber( countobject );
                if(failcount >= _oilsAuthBlockCount) {
-                       ret = 0;
-                   osrfLogInfo(OSRF_LOG_MARK, "oilsAuth found too many recent failures for '%s' : %i, forcing failure state.", uname, failcount);
+                       verified = 0;
+                   osrfLogInfo(OSRF_LOG_MARK, 
+                "oilsAuth found too many recent failures for '%s' : %i, "
+                "forcing failure state.", identifier, failcount);
                }
-               if(ret == 0) {
+               if(verified == 0) {
                        failcount += 1;
                }
                jsonObjectSetNumber( countobject, failcount );
@@ -524,7 +512,7 @@ static int oilsAuthVerifyPassword( const osrfMethodContext* ctx,
        }
        free(countkey);
 
-       return ret;
+       return verified;
 }
 
 /**
@@ -771,6 +759,7 @@ int oilsAuthComplete( osrfMethodContext* ctx ) {
        const jsonObject* args  = jsonObjectGetIndex(ctx->params, 0);
 
        const char* uname       = jsonObjectGetString(jsonObjectGetKeyConst(args, "username"));
+       const char* identifier  = jsonObjectGetString(jsonObjectGetKeyConst(args, "identifier"));
        const char* password    = jsonObjectGetString(jsonObjectGetKeyConst(args, "password"));
        const char* type        = jsonObjectGetString(jsonObjectGetKeyConst(args, "type"));
        int orgloc        = (int) jsonObjectGetNumber(jsonObjectGetKeyConst(args, "org"));
@@ -782,6 +771,23 @@ int oilsAuthComplete( osrfMethodContext* ctx ) {
        const char* ws = (workstation) ? workstation : "";
        if (!nonce) nonce = "";
 
+    // we no longer care how the identifier reaches us, 
+    // as long as we have one.
+    if (!identifier) {
+        if (uname) {
+            identifier = uname;
+        } else if (barcode) {
+            identifier = barcode;
+        }
+    }
+
+       if (!identifier) {
+               return osrfAppRequestRespondException(ctx->session, ctx->request,
+                       "username/barcode and password required for method: %s", 
+            ctx->method->name);
+       }
+
+
        /* Use __FILE__, harmless_line_number for creating
         * OILS_EVENT_AUTH_FAILED events (instead of OSRF_LOG_MARK) to avoid
         * giving away information about why an authentication attempt failed.
@@ -791,67 +797,62 @@ int oilsAuthComplete( osrfMethodContext* ctx ) {
        if( !type )
                 type = OILS_AUTH_STAFF;
 
-       if( !( (uname || barcode) && password) ) {
-               return osrfAppRequestRespondException( ctx->session, ctx->request,
-                       "username/barcode and password required for method: %s", ctx->method->name );
-       }
+       oilsEvent* response = NULL; // free
+       jsonObject* userObj = NULL; // free
+       int card_active = 1; // boolean; assume active until proven otherwise
+    int using_card  = 0; // true if this is a barcode login
 
-       oilsEvent* response = NULL;
-       jsonObject* userObj = NULL;
-       int card_active     = 1;      // boolean; assume active until proven otherwise
-
-       // Fetch a row from the actor.usr table, by username if available,
-       // or by barcode if not.
-       if(uname) {
-               userObj = oilsUtilsFetchUserByUsername( uname );
-               if( userObj && JSON_NULL == userObj->type ) {
-                       jsonObjectFree( userObj );
-                       userObj = NULL;         // username not found
-               }
-       }
-       else if(barcode) {
-               // Read from actor.card by barcode
-
-               osrfLogInfo( OSRF_LOG_MARK, "Fetching user by barcode %s", barcode );
-
-               jsonObject* params = jsonParseFmt("{\"barcode\":\"%s\"}", barcode);
-               jsonObject* card = oilsUtilsQuickReq(
-                       "open-ils.cstore", "open-ils.cstore.direct.actor.card.search", params );
-               jsonObjectFree( params );
-
-               if( card && card->type != JSON_NULL ) {
-                       // Determine whether the card is active
-                       char* card_active_str = oilsFMGetString( card, "active" );
-                       card_active = oilsUtilsIsDBTrue( card_active_str );
-                       free( card_active_str );
-
-                       // Look up the user who owns the card
-                       char* userid = oilsFMGetString( card, "usr" );
-                       jsonObjectFree( card );
-                       params = jsonParseFmt( "[%s]", userid );
-                       free( userid );
-                       userObj = oilsUtilsQuickReq(
-                                       "open-ils.cstore", "open-ils.cstore.direct.actor.user.retrieve", params );
-                       jsonObjectFree( params );
-                       if( userObj && JSON_NULL == userObj->type ) {
-                               // user not found (shouldn't happen, due to foreign key)
-                               jsonObjectFree( userObj );
-                               userObj = NULL;
+    char* cache_key = va_list_to_string(
+        "%s%s%s", OILS_AUTH_CACHE_PRFX, identifier, nonce);
+    jsonObject* cacheObj = osrfCacheGetObject(cache_key); // free
+
+       if (!cacheObj) {
+               return osrfAppRequestRespondException(ctx->session,
+                       ctx->request, "No authentication seed found. "
+                       "open-ils.auth.authenticate.init must be called first "
+                       " (check that memcached is running and can be connected to) "
+               );
+    }
+
+    int user_id = jsonObjectGetNumber(
+        jsonObjectGetKeyConst(cacheObj, "user_id"));
+
+    jsonObject* param = jsonNewNumberObject(user_id); // free
+    userObj = oilsUtilsCStoreReq(
+        "open-ils.cstore.direct.actor.user.retrieve", param);
+    jsonObjectFree(param);
+
+    using_card = (jsonObjectGetKeyConst(cacheObj, "barcode") != NULL);
+
+    if (using_card) {
+        // see if the card is inactive
+
+               jsonObject* params = jsonParseFmt("{\"barcode\":\"%s\"}", identifier);
+               jsonObject* card = oilsUtilsCStoreReq(
+                       "open-ils.cstore.direct.actor.card.search", params);
+               jsonObjectFree(params);
+
+        if (card) {
+            if (card->type != JSON_NULL) {
+                           char* card_active_str = oilsFMGetString(card, "active");
+                           card_active = oilsUtilsIsDBTrue(card_active_str);
+                           free(card_active_str);
                        }
+            jsonObjectFree(card);
                }
        }
 
        int     barred = 0, deleted = 0;
        char   *barred_str, *deleted_str;
 
-       if(userObj) {
-               barred_str = oilsFMGetString( userObj, "barred" );
-               barred = oilsUtilsIsDBTrue( barred_str );
-               free( barred_str );
+       if (userObj) {
+               barred_str = oilsFMGetString(userObj, "barred");
+               barred = oilsUtilsIsDBTrue(barred_str);
+               free(barred_str);
 
-               deleted_str = oilsFMGetString( userObj, "deleted" );
-               deleted = oilsUtilsIsDBTrue( deleted_str );
-               free( deleted_str );
+               deleted_str = oilsFMGetString(userObj, "deleted");
+               deleted = oilsUtilsIsDBTrue(deleted_str);
+               free(deleted_str);
        }
 
        if(!userObj || barred || deleted) {
@@ -865,11 +866,8 @@ int oilsAuthComplete( osrfMethodContext* ctx ) {
 
        // Such a user exists and isn't barred or deleted.
        // Now see if he or she has the right credentials.
-       int passOK = -1;
-       if(uname)
-               passOK = oilsAuthVerifyPassword( ctx, userObj, uname, password, nonce );
-       else if (barcode)
-               passOK = oilsAuthVerifyPassword( ctx, userObj, barcode, password, nonce );
+       int passOK = oilsAuthVerifyPassword(
+        ctx, user_id, identifier, password, nonce);
 
        if( passOK < 0 ) {
                jsonObjectFree(userObj);
@@ -892,8 +890,6 @@ int oilsAuthComplete( osrfMethodContext* ctx ) {
        }
        free(active);
 
-       osrfLogInfo( OSRF_LOG_MARK, "Fetching card by barcode %s", barcode );
-
        if( !card_active ) {
                osrfLogInfo( OSRF_LOG_MARK, "barcode %s is not active, returning event", barcode );
                response = oilsNewEvent( OSRF_LOG_MARK, "PATRON_CARD_INACTIVE" );