Exemple #1
0
/**
	Resets the auth login timeout
	@return The event object, OILS_EVENT_SUCCESS, or OILS_EVENT_NO_SESSION
*/
static oilsEvent*  _oilsAuthResetTimeout( const char* authToken ) {
	if(!authToken) return NULL;

	oilsEvent* evt = NULL;
	time_t timeout;

	osrfLogDebug(OSRF_LOG_MARK, "Resetting auth timeout for session %s", authToken);
	char* key = va_list_to_string("%s%s", OILS_AUTH_CACHE_PRFX, authToken );
	jsonObject* cacheObj = osrfCacheGetObject( key );

	if(!cacheObj) {
		osrfLogInfo(OSRF_LOG_MARK, "No user in the cache exists with key %s", key);
		evt = oilsNewEvent(OSRF_LOG_MARK, OILS_EVENT_NO_SESSION);

	} else {
		// Determine a new timeout value
		jsonObject* endtime_obj = jsonObjectGetKey( cacheObj, "endtime" );
		if( endtime_obj ) {
			// Extend the current endtime by a fixed amount
			time_t endtime = (time_t) jsonObjectGetNumber( endtime_obj );
			int reset_interval = DEFAULT_RESET_INTERVAL;
			const jsonObject* reset_interval_obj = jsonObjectGetKeyConst(
				cacheObj, "reset_interval" );
			if( reset_interval_obj ) {
				reset_interval = (int) jsonObjectGetNumber( reset_interval_obj );
				if( reset_interval <= 0 )
					reset_interval = DEFAULT_RESET_INTERVAL;
			}

			time_t now = time( NULL );
			time_t new_endtime = now + reset_interval;
			if( new_endtime > endtime ) {
				// Keep the session alive a little longer
				jsonObjectSetNumber( endtime_obj, (double) new_endtime );
				timeout = reset_interval;
				osrfCachePutObject( key, cacheObj, timeout );
			} else {
				// The session isn't close to expiring, so don't reset anything.
				// Just report the time remaining.
				timeout = endtime - now;
			}
		} else {
			// Reapply the existing timeout from the current time
			timeout = (time_t) jsonObjectGetNumber( jsonObjectGetKeyConst( cacheObj, "authtime"));
			osrfCachePutObject( key, cacheObj, timeout );
		}

		jsonObject* payload = jsonNewNumberObject( (double) timeout );
		evt = oilsNewEvent2(OSRF_LOG_MARK, OILS_EVENT_SUCCESS, payload);
		jsonObjectFree(payload);
		jsonObjectFree(cacheObj);
	}

	free(key);
	return evt;
}
Exemple #2
0
/**
	@brief Verify the password received from the client.
	@param ctx The method context.
	@param userObj An object from the database, representing the user.
	@param password An obfuscated password received from the client.
	@return 1 if the password is valid; 0 if it isn't; or -1 upon error.

	(None of the so-called "passwords" used here are in plaintext.  All have been passed
	through at least one layer of hashing to obfuscate them.)

	Take the password from the user object.  Append it to the username seed from memcache,
	as stored previously by a call to the init method.  Take an md5 hash of the result.
	Then compare this hash to the password received from the client.

	In order for the two to match, other than by dumb luck, the client had to construct
	the password it passed in the same way.  That means it neded to know not only the
	original password (either hashed or plaintext), but also the seed.  The latter requirement
	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, int user_id, 
        const char* identifier, const char* password, const char* nonce) {

    int verified = 0;

    // We won't be needing the seed again, remove it
    osrfCacheRemove("%s%s%s", OILS_AUTH_CACHE_PRFX, identifier, nonce);

    // Ask the DB to verify the user's password.
    // Here, the password is md5(md5(password) + salt)

    jsonObject* params = jsonParseFmt( // free
        "{\"from\":[\"actor.verify_passwd\",%d,\"main\",\"%s\"]}", 
        user_id, password);

    jsonObject* verify_obj = // free 
        oilsUtilsCStoreReq("open-ils.cstore.json_query", params);

    jsonObjectFree(params);

    if (verify_obj) {
        verified = oilsUtilsIsDBTrue(
            jsonObjectGetString(
                jsonObjectGetKeyConst(
                    verify_obj, "actor.verify_passwd")));

        jsonObjectFree(verify_obj);
    }

    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) {
            verified = 0;
            osrfLogInfo(OSRF_LOG_MARK, 
                "oilsAuth found too many recent failures for '%s' : %i, "
                "forcing failure state.", identifier, failcount);
        }
        if(verified == 0) {
            failcount += 1;
        }
        jsonObjectSetNumber( countobject, failcount );
        osrfCachePutObject( countkey, countobject, _oilsAuthBlockTimeout );
        jsonObjectFree(countobject);
    }
    free(countkey);

    return verified;
}
Exemple #3
0
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;
}
Exemple #4
0
/**
	@brief Verify the password received from the client.
	@param ctx The method context.
	@param userObj An object from the database, representing the user.
	@param password An obfuscated password received from the client.
	@return 1 if the password is valid; 0 if it isn't; or -1 upon error.

	(None of the so-called "passwords" used here are in plaintext.  All have been passed
	through at least one layer of hashing to obfuscate them.)

	Take the password from the user object.  Append it to the username seed from memcache,
	as stored previously by a call to the init method.  Take an md5 hash of the result.
	Then compare this hash to the password received from the client.

	In order for the two to match, other than by dumb luck, the client had to construct
	the password it passed in the same way.  That means it neded to know not only the
	original password (either hashed or plaintext), but also the seed.  The latter requirement
	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 );

	// Get the hashed password from the user object
	char* realPassword = oilsFMGetString( userObj, "passwd" );

	osrfLogInternal(OSRF_LOG_MARK, "oilsAuth retrieved real password: [%s]", realPassword);
	osrfLogDebug(OSRF_LOG_MARK, "oilsAuth retrieved seed from cache: %s", seed );

	// Concatenate them and take an MD5 hash of the result
	char* maskedPw = md5sum( "%s%s", seed, realPassword );

	free(realPassword);
	free(seed);

	if( !maskedPw ) {
		// This happens only if md5sum() runs out of memory
		free( maskedPw );
		return -1;  // md5sum() ran out of memory
	}

	osrfLogDebug(OSRF_LOG_MARK,  "oilsAuth generated masked password %s. "
			"Testing against provided password %s", maskedPw, password );

	int ret = 0;
	if( !strcmp( maskedPw, password ) )
		ret = 1;

	free(maskedPw);

	char* countkey = va_list_to_string( "%s%s%s", OILS_AUTH_CACHE_PRFX, uname, 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);
		}
		if(ret == 0) {
			failcount += 1;
		}
		jsonObjectSetNumber( countobject, failcount );
		osrfCachePutObject( countkey, countobject, _oilsAuthBlockTimeout );
		jsonObjectFree(countobject);
	}
	free(countkey);

	return ret;
}