[open-ils-commits] [GIT] Evergreen ILS branch master updated. cd22fa01980e6c9343012353bd9c43cf61f9838d

Evergreen Git git at git.evergreen-ils.org
Fri Sep 1 13:05:42 EDT 2017


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Evergreen ILS".

The branch, master has been updated
       via  cd22fa01980e6c9343012353bd9c43cf61f9838d (commit)
       via  f1f6489e89f7e40b5ba69b5c36367d17a376c82a (commit)
       via  d067a0027241720bb90058fa5d4751b08e3f05bf (commit)
       via  3bc96cf97f88aa07b6373dbd2c8bf6714b255dd8 (commit)
       via  18b313d5c933a43dc02ced2ab035197797ea36b3 (commit)
      from  b437f50243e90b63dd3ba6f9532448df8c601a5f (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit cd22fa01980e6c9343012353bd9c43cf61f9838d
Author: Galen Charlton <gmc at equinoxinitiative.org>
Date:   Fri Sep 1 12:31:41 2017 -0400

    LP#1710949: add tests for blocking after failed attempts
    
    Enhance the live tests to verify that attempts to log in
    get blocked after too many failed ones; this assumes
    a stock value for block_count.
    
    General testing plan:
    
    [1] Use srfsh to test, e.g.,
    
    srfsh# request open-ils.auth open-ils.auth.login {"identifier":"99999389406","password":"12345","type":"opac","org":1}
    
    [2] Try various scenarios:
    
        - wrong password
        - type = staff but user doesn't have STAFF_LOGIN
        - repeated failed attempts
        - barcode is inactive
        - using "identifier" in conjunction with opac.barcode_regex set
        - using "username" or "barcode"
        - supplying a workstation name that exists
        - ... or does not
        - user is inactive
        - user is marked barrred
    
    Signed-off-by: Galen Charlton <gmc at equinoxinitiative.org>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/src/perlmods/live_t/24-lp1710949-login-api.t b/Open-ILS/src/perlmods/live_t/24-lp1710949-login-api.t
index ba4e4df..e32ec61 100644
--- a/Open-ILS/src/perlmods/live_t/24-lp1710949-login-api.t
+++ b/Open-ILS/src/perlmods/live_t/24-lp1710949-login-api.t
@@ -1,12 +1,13 @@
 #!perl
 
-use Test::More tests => 6;
+use Test::More tests => 22;
 
 diag("Tests open-ils.auth.login");
 
 use strict; use warnings;
 use OpenILS::Utils::TestUtils;
 use OpenILS::Application::AppUtils;
+use OpenSRF::Utils::Cache;
 our $U = "OpenILS::Application::AppUtils";
 
 OpenILS::Utils::TestUtils->new->bootstrap;
@@ -67,3 +68,28 @@ $resp = $U->simplereq(
 
 is($resp->{textcode}, 'SUCCESS', 'Identifier check for br1mclark OK');
 
+foreach my $i (1..15) {
+    $resp = $U->simplereq(
+        'open-ils.auth',
+        'open-ils.auth.login', {
+            identifier => 'br1mclark',
+            password => 'justplainwrong',
+            type => 'staff'
+        }
+    );
+    isnt($resp->{textcode}, 'SUCCESS', "Attempt $i: wrong password br1mclark does not work");
+}
+
+$resp = $U->simplereq(
+    'open-ils.auth',
+    'open-ils.auth.login', {
+        identifier => 'br1mclark',
+        password => 'montyc1234',
+        type => 'staff'
+    }
+);
+isnt($resp->{textcode}, 'SUCCESS', '... and consequently multiple failed attempts block');
+
+# and clean up
+my $cache = OpenSRF::Utils::Cache->new("global", 0);
+$cache->delete_cache('oils_auth_br1mclark_count');

commit f1f6489e89f7e40b5ba69b5c36367d17a376c82a
Author: Bill Erickson <berickxx at gmail.com>
Date:   Wed Aug 16 10:55:26 2017 -0400

    LP#1710949 Release notes for auth.login
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Galen Charlton <gmc at equinoxinitiative.org>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/docs/RELEASE_NOTES_NEXT/API/auth-login-api.adoc b/docs/RELEASE_NOTES_NEXT/API/auth-login-api.adoc
new file mode 100644
index 0000000..892cb9b
--- /dev/null
+++ b/docs/RELEASE_NOTES_NEXT/API/auth-login-api.adoc
@@ -0,0 +1,38 @@
+New open-ils.auth.login API
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The open-ils.auth service has a new API for requesting an authentication
+token.  It performs the same steps as the 
+open-ils.auth.authenticate.init and .complete APIs in a single call,
+using the bare password.  No intermediate password hashing is required.
+
+The paramters are the same as the .complete call with a few modifications.
+
+1. Using the generic "identifier" parameter in combination with the
+   "org" parameter allows the API to reliably determine if an identifier
+   value is a username or barcode.  The caller is no longer required to 
+   make that determination up front.  
+
+2. The 'nonce' parameter is no longer used.
+
+Upgrade Notes
++++++++++++++
+
+The new open-ils.auth.login API must be added to the list of <log_protect>
+API's in the opensrf_core.xml file.
+
+Sample diff:
+
+[code,sh]
+---------------------------------------------------------------------
+--- a/Open-ILS/examples/opensrf_core.xml.example
++++ b/Open-ILS/examples/opensrf_core.xml.example
+@@ -180,6 +180,7 @@ Example OpenSRF bootstrap configuration file for Evergreen
+     <log_protect>
+       <match_string>open-ils.auth.authenticate.verify</match_string>
+       <match_string>open-ils.auth.authenticate.complete</match_string>
++      <match_string>open-ils.auth.login</match_string>
+       <match_string>open-ils.auth_proxy.login</match_string>
+       <match_string>open-ils.actor.patron.password_reset.commit</match_string>
+       <match_string>open-ils.actor.user.password</match_string>
+---------------------------------------------------------------------
+

commit d067a0027241720bb90058fa5d4751b08e3f05bf
Author: Bill Erickson <berickxx at gmail.com>
Date:   Tue Aug 15 17:45:19 2017 -0400

    LP#1710949 Redact open-ils.auth.login params
    
    Add open-ils.auth.login to the list of API calls whose parameters should
    not be logged.
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Galen Charlton <gmc at equinoxinitiative.org>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/examples/opensrf_core.xml.example b/Open-ILS/examples/opensrf_core.xml.example
index ba21693..45e5f5a 100644
--- a/Open-ILS/examples/opensrf_core.xml.example
+++ b/Open-ILS/examples/opensrf_core.xml.example
@@ -180,6 +180,7 @@ Example OpenSRF bootstrap configuration file for Evergreen
     <log_protect>
       <match_string>open-ils.auth.authenticate.verify</match_string>
       <match_string>open-ils.auth.authenticate.complete</match_string>
+      <match_string>open-ils.auth.login</match_string>
       <match_string>open-ils.auth_proxy.login</match_string>
       <match_string>open-ils.actor.patron.password_reset.commit</match_string>
       <match_string>open-ils.actor.user.password</match_string>

commit 3bc96cf97f88aa07b6373dbd2c8bf6714b255dd8
Author: Bill Erickson <berickxx at gmail.com>
Date:   Tue Aug 15 15:21:01 2017 -0400

    LP#1710949 auth.login Perl live test script
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Galen Charlton <gmc at equinoxinitiative.org>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/src/perlmods/live_t/24-lp1710949-login-api.t b/Open-ILS/src/perlmods/live_t/24-lp1710949-login-api.t
new file mode 100644
index 0000000..ba4e4df
--- /dev/null
+++ b/Open-ILS/src/perlmods/live_t/24-lp1710949-login-api.t
@@ -0,0 +1,69 @@
+#!perl
+
+use Test::More tests => 6;
+
+diag("Tests open-ils.auth.login");
+
+use strict; use warnings;
+use OpenILS::Utils::TestUtils;
+use OpenILS::Application::AppUtils;
+our $U = "OpenILS::Application::AppUtils";
+
+OpenILS::Utils::TestUtils->new->bootstrap;
+
+my $resp = $U->simplereq(
+    'open-ils.auth',
+    'open-ils.auth.login', {
+        username => 'admin',
+        password => 'demo123',
+        type => 'staff'
+    }
+);
+
+is($resp->{textcode}, 'SUCCESS', 'Admin username login OK');
+
+my $authtoken = $resp->{payload}->{authtoken};
+ok($authtoken, 'Have an authtoken');
+
+$resp = $U->simplereq(
+    'open-ils.auth',
+    'open-ils.auth.session.retrieve', $authtoken);
+
+ok( 
+    (ref($resp) && !$U->event_code($resp) && $resp->usrname eq 'admin'), 
+    'Able to retrieve session'
+);
+
+$resp = $U->simplereq(
+    'open-ils.auth',
+    'open-ils.auth.login', {
+        username => 'admin',
+        password => 'demo123x', # bad password
+        type => 'staff'
+    }
+);
+
+isnt($resp->{textcode}, 'SUCCESS', 'Admin bad password rejected');
+
+$resp = $U->simplereq(
+    'open-ils.auth',
+    'open-ils.auth.login', {
+        barcode => '99999381970',
+        password => 'montyc1234',
+        type => 'staff'
+    }
+);
+
+is($resp->{textcode}, 'SUCCESS', '99999381970 login OK');
+
+$resp = $U->simplereq(
+    'open-ils.auth',
+    'open-ils.auth.login', {
+        identifier => 'br1mclark',
+        password => 'montyc1234',
+        type => 'staff'
+    }
+);
+
+is($resp->{textcode}, 'SUCCESS', 'Identifier check for br1mclark OK');
+

commit 18b313d5c933a43dc02ced2ab035197797ea36b3
Author: Bill Erickson <berickxx at gmail.com>
Date:   Tue Aug 15 13:13:03 2017 -0400

    LP#1710949 open-ils.auth.login API
    
    Adds a new open-ils.auth API call 'open-ils.auth.login' which performs
    the combined steps of open-ils.auth.authenticate.init and
    open-ils.auth.authenticate.complete so the caller only need call one API
    to login.
    
    API params are consistent with open-ils.auth.authenticate.complete with
    2 notable excpetions.  The API uses the bare password instead of the
    hashed password, so the caller also need not perform the extra hashing
    steps.  Also, no 'nonce' parameter is used as it's no longer needed,
    because there is no intermediate authentication cache object as with
    .init.
    
    Response data is consistent with open-ils.auth.authenticate.complete.
    
    Example:
    
    srfsh# request open-ils.auth open-ils.auth.login {"username":"admin","password":"fakepassword"}
    
    Other changes in the new code:
    
    1. Using the generic "identifier" parameter in combination with the
       "org" parameter allows the API to reliably determine if a value
       is a username or barcode.
    
    2. Once a caller has reached the configured maximum number of login
       failures, no further attempts to track failures occurs, based on the
       idea that no additional cpu/network cycles should be used on a lost
       cause.
    
    3. A failure count object is only added to memcache when failures
       occur, unlike open-ils.auth.authenticate.init which creates a
       failure tracking object for every login.
    
    4. The code avoids use of the jsonParseFmt() and va_list_to_string()
       functions as these functions require extra data cleansing.
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Galen Charlton <gmc at equinoxinitiative.org>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/src/c-apps/oils_auth.c b/Open-ILS/src/c-apps/oils_auth.c
index 0fd924f..4afb36c 100644
--- a/Open-ILS/src/c-apps/oils_auth.c
+++ b/Open-ILS/src/c-apps/oils_auth.c
@@ -75,6 +75,18 @@ int osrfAppInitialize() {
 
 	osrfAppRegisterMethod(
 		MODULENAME,
+		"open-ils.auth.login",
+		"oilsAuthLogin",
+        "Request an authentication token logging in with username or "
+        "barcode.  Parameter is a keyword arguments hash with keys "
+        "username, barcode, identifier, password, type, org, workstation, "
+        "agent.  The 'identifier' option is used when the caller wants the "
+        "API to determine if an identifier string is a username or barcode "
+        "using the barcode format configuration.",
+        1, 0);
+
+	osrfAppRegisterMethod(
+		MODULENAME,
 		"open-ils.auth.authenticate.verify",
 		"oilsAuthComplete",
 		"Verifies the user provided a valid username and password."
@@ -317,12 +329,12 @@ int oilsAuthInitBarcode(osrfMethodContext* ctx) {
 }
 
 // returns true if the provided identifier matches the barcode regex.
-static int oilsAuthIdentIsBarcode(const char* identifier) {
+static int oilsAuthIdentIsBarcode(const char* identifier, int org_id) {
 
-    // Assumes barcode regex is a global setting.
-    // TODO: add an org_unit param to the .init API for future use?
-    char* bc_regex = oilsUtilsFetchOrgSetting(
-        oilsUtilsGetRootOrgId(), "opac.barcode_regex");
+    if (org_id < 1)
+        org_id = oilsUtilsGetRootOrgId();
+
+    char* bc_regex = oilsUtilsFetchOrgSetting(org_id, "opac.barcode_regex");
 
     if (!bc_regex) {
         // if no regex is set, assume any identifier starting
@@ -396,7 +408,7 @@ int oilsAuthInit(osrfMethodContext* ctx) {
     if (!nonce) nonce = "";
     if (!identifier) return -1;  // we need an identifier
 
-    if (oilsAuthIdentIsBarcode(identifier)) {
+    if (oilsAuthIdentIsBarcode(identifier, 0)) {
         resp = oilsAuthInitBarcodeHandler(ctx, identifier, nonce);
     } else {
         resp = oilsAuthInitUsernameHandler(ctx, identifier, nonce);
@@ -483,6 +495,110 @@ static int oilsAuthVerifyPassword( const osrfMethodContext* ctx, int user_id,
     return verified;
 }
 
+/**
+ * Returns true if the provided password is correct.
+ * Turn the password into the nested md5 hash required of migrated
+ * passwords, then check the password in the DB.
+ */
+static int oilsAuthLoginCheckPassword(int user_id, const char* password) {
+
+    growing_buffer* gb = buffer_init(33); // free me 1
+    char* salt = oilsAuthGetSalt(user_id); // free me 2
+    char* passhash = md5sum(password); // free me 3
+
+    buffer_add(gb, salt); // gb strdup's internally
+    buffer_add(gb, passhash);
+
+    free(salt); // free 2
+    free(passhash); // free 3
+
+    // salt + md5(password)
+    passhash = buffer_release(gb); // free 1 ; free me 4
+    char* finalpass = md5sum(passhash); // free me 5
+
+    free(passhash); // free 4
+
+    jsonObject *arr = jsonNewObjectType(JSON_ARRAY);
+    jsonObjectPush(arr, jsonNewObject("actor.verify_passwd"));
+    jsonObjectPush(arr, jsonNewNumberObject((long) user_id));
+    jsonObjectPush(arr, jsonNewObject("main"));
+    jsonObjectPush(arr, jsonNewObject(finalpass));
+    jsonObject *params = jsonNewObjectType(JSON_HASH); // free me 6
+    jsonObjectSetKey(params, "from", arr);
+
+    free(finalpass); // free 5
+
+    jsonObject* verify_obj = // free 
+        oilsUtilsCStoreReq("open-ils.cstore.json_query", params);
+
+    jsonObjectFree(params); // free 6
+
+    if (!verify_obj) return 0; // error
+
+    int verified = oilsUtilsIsDBTrue(
+        jsonObjectGetString(
+            jsonObjectGetKeyConst(verify_obj, "actor.verify_passwd")
+        )
+    );
+
+    jsonObjectFree(verify_obj);
+
+    return verified;
+}
+
+static int oilsAuthLoginVerifyPassword(const osrfMethodContext* ctx, 
+    int user_id, const char* username, const char* password) {
+
+    // build the cache key
+    growing_buffer* gb = buffer_init(64); // free me
+    buffer_add(gb, OILS_AUTH_CACHE_PRFX);
+    buffer_add(gb, username);
+    buffer_add(gb, OILS_AUTH_COUNT_SFFX);
+    char* countkey = buffer_release(gb); // free me
+
+    jsonObject* countobject = osrfCacheGetObject(countkey); // free me
+
+    long failcount = 0;
+    if (countobject) {
+        failcount = (long) jsonObjectGetNumber(countobject);
+
+        if (failcount >= _oilsAuthBlockCount) {
+            // User is blocked.  Don't waste any more CPU cycles on them.
+
+            osrfLogInfo(OSRF_LOG_MARK, 
+                "oilsAuth found too many recent failures for '%s' : %i, "
+                "forcing failure state.", username, failcount);
+
+            jsonObjectFree(countobject);
+            free(countkey);   
+            return 0;
+        }
+    }
+
+    int verified = oilsAuthLoginCheckPassword(user_id, password);
+
+    if (!verified) { // login failed.  increment failure counter.
+        failcount++;
+
+        if (countobject) {
+            // append to existing counter
+            jsonObjectSetNumber(countobject, failcount);
+
+        } else { 
+            // first failure, create a new counter
+            countobject = jsonNewNumberObject((double) failcount);
+        }
+
+        osrfCachePutObject(countkey, countobject, _oilsAuthBlockTimeout);
+    }
+
+    jsonObjectFree(countobject); // NULL OK
+    free(countkey);
+
+    return verified;
+}
+
+
 /*
 	Adds the authentication token to the user cache.  The timeout for the
 	auth token is based on the type of login as well as (if type=='opac')
@@ -616,7 +732,6 @@ int oilsAuthComplete( osrfMethodContext* ctx ) {
 
     oilsEvent* response = NULL; // free
     jsonObject* userObj = NULL; // free
-    int card_active = 1; // boolean; assume active until proven otherwise
 
     char* cache_key = va_list_to_string(
         "%s%s%s", OILS_AUTH_CACHE_PRFX, identifier, nonce);
@@ -767,6 +882,171 @@ int oilsAuthComplete( osrfMethodContext* ctx ) {
     if(freeable_uname)
         free(freeable_uname);
 
+    return 0;
+}
+
+
+int oilsAuthLogin(osrfMethodContext* ctx) {
+    OSRF_METHOD_VERIFY_CONTEXT(ctx);
+
+    const jsonObject* args  = jsonObjectGetIndex(ctx->params, 0);
+
+    const char* username    = 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"));
+    const char* workstation = jsonObjectGetString(jsonObjectGetKeyConst(args, "workstation"));
+    const char* barcode     = jsonObjectGetString(jsonObjectGetKeyConst(args, "barcode"));
+    const char* ewho        = jsonObjectGetString(jsonObjectGetKeyConst(args, "agent"));
+
+    const char* ws = (workstation) ? workstation : "";
+    if (!type) type = OILS_AUTH_STAFF;
+
+    jsonObject* userObj = NULL; // free me
+    oilsEvent* response = NULL; // free me
+
+    /* 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.
+     */
+    int harmless_line_number = __LINE__;
+
+    // translate a generic identifier into a username or barcode if necessary.
+    if (identifier && !username && !barcode) {
+        if (oilsAuthIdentIsBarcode(identifier, orgloc)) {
+            barcode = identifier;
+        } else {
+            username = identifier;
+        }
+    }
+
+    if (username) {
+        barcode = NULL; // avoid superfluous identifiers
+        userObj = oilsUtilsFetchUserByUsername(ctx, username);
+
+    } else if (barcode) {
+        userObj = oilsUtilsFetchUserByBarcode(ctx, barcode);
+
+    } else {
+        // not enough params
+        return osrfAppRequestRespondException(ctx->session, ctx->request,
+            "username/barcode and password required for method: %s", 
+            ctx->method->name);
+    }
+
+    if (!userObj) { // user not found.  
+        response = oilsNewEvent(
+            __FILE__, harmless_line_number, OILS_EVENT_AUTH_FAILED);
+        osrfAppRespondComplete(ctx, oilsEventToJSON(response));
+        oilsEventFree(response); // frees event JSON
+        return 0;
+    }
+
+    long user_id = oilsFMGetObjectId(userObj);
+
+    // username is freed when userObj is freed.
+    // From here we can use the username as the generic identifier
+    // since it's guaranteed to have a value.
+    if (!username) username = oilsFMGetStringConst(userObj, "usrname");
+
+    // See if the user is allowed to login.
+    jsonObject* params = jsonNewObject(NULL);
+    jsonObjectSetKey(params, "user_id", jsonNewNumberObject(user_id));
+    jsonObjectSetKey(params,"org_unit", jsonNewNumberObject(orgloc));
+    jsonObjectSetKey(params, "login_type", jsonNewObject(type));
+    if (barcode) jsonObjectSetKey(params, "barcode", jsonNewObject(barcode));
+
+    jsonObject* authEvt = oilsUtilsQuickReqCtx( // freed after password test
+        ctx,
+        "open-ils.auth_internal",
+        "open-ils.auth_internal.user.validate", params);
+    jsonObjectFree(params);
+
+    if (!authEvt) { // unknown error
+        jsonObjectFree(userObj);
+        return -1;
+    }
+
+    const char* authEvtCode = 
+        jsonObjectGetString(jsonObjectGetKey(authEvt, "textcode"));
+
+    if (!strcmp(authEvtCode, OILS_EVENT_AUTH_FAILED)) {
+        // Received the generic login failure event.
+
+        osrfLogInfo(OSRF_LOG_MARK,  
+            "failed login: username=%s, barcode=%s, workstation=%s",
+            username, (barcode ? barcode : "(none)"), ws);
+
+        response = oilsNewEvent(
+            __FILE__, harmless_line_number, OILS_EVENT_AUTH_FAILED);
+    }
+
+    if (!response && // user exists and is not barred, etc.
+        !oilsAuthLoginVerifyPassword(ctx, user_id, username, password)) {
+        // User provided the wrong password or is blocked from too 
+        // many previous login failures.
+
+        response = oilsNewEvent(
+            __FILE__, harmless_line_number, OILS_EVENT_AUTH_FAILED);
+
+        osrfLogInfo(OSRF_LOG_MARK,  
+            "failed login: username=%s, barcode=%s, workstation=%s",
+                username, (barcode ? barcode : "(none)"), ws );
+    }
+
+    // Below here, we know the password check succeeded if no response
+    // object is present.
+
+    if (!response && (
+        !strcmp(authEvtCode, "PATRON_INACTIVE") ||
+        !strcmp(authEvtCode, "PATRON_CARD_INACTIVE"))) {
+        // Patron and/or card is inactive but the correct password 
+        // was provided.  Alert the caller to the inactive-ness.
+        response = oilsNewEvent2(
+            OSRF_LOG_MARK, authEvtCode,
+            jsonObjectGetKey(authEvt, "payload")   // cloned within Event
+        );
+    }
+
+    if (!response && strcmp(authEvtCode, OILS_EVENT_SUCCESS)) {
+        // Validate API returned an unexpected non-success event.
+        // To be safe, treat this as a generic login failure.
+
+        response = oilsNewEvent(
+            __FILE__, harmless_line_number, OILS_EVENT_AUTH_FAILED);
+    }
+
+    if (!response) {
+        // password OK and no other events have prevented login completion.
+
+        char* ewhat = "login";
+
+        if (0 == strcmp(ctx->method->name, "open-ils.auth.authenticate.verify")) {
+            response = oilsNewEvent( OSRF_LOG_MARK, OILS_EVENT_SUCCESS );
+            ewhat = "verify";
+
+        } else {
+            response = oilsAuthHandleLoginOK(
+                ctx, userObj, username, type, orgloc, workstation);
+        }
+
+        oilsUtilsTrackUserActivity(
+            ctx,
+            oilsFMGetObjectId(userObj), 
+            ewho, ewhat, 
+            osrfAppSessionGetIngress()
+        );
+    }
+
+    // reply
+    osrfAppRespondComplete(ctx, oilsEventToJSON(response));
+
+    // clean up
+    oilsEventFree(response);
+    jsonObjectFree(userObj);
+    jsonObjectFree(authEvt);
+
 	return 0;
 }
 

-----------------------------------------------------------------------

Summary of changes:
 Open-ILS/examples/opensrf_core.xml.example         |    1 +
 Open-ILS/src/c-apps/oils_auth.c                    |  294 +++++++++++++++++++-
 .../src/perlmods/live_t/24-lp1710949-login-api.t   |   95 +++++++
 docs/RELEASE_NOTES_NEXT/API/auth-login-api.adoc    |   38 +++
 4 files changed, 421 insertions(+), 7 deletions(-)
 create mode 100644 Open-ILS/src/perlmods/live_t/24-lp1710949-login-api.t
 create mode 100644 docs/RELEASE_NOTES_NEXT/API/auth-login-api.adoc


hooks/post-receive
-- 
Evergreen ILS


More information about the open-ils-commits mailing list