From dd111ffef50f0c2b12596f8edd9693a2ab277a88 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Tue, 8 Oct 2013 18:25:59 -0400 Subject: [PATCH] Flesh out auth to the point where set and check of password is plausible --- confluent/auth.py | 50 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/confluent/auth.py b/confluent/auth.py index 36722ed5..029683c2 100644 --- a/confluent/auth.py +++ b/confluent/auth.py @@ -6,10 +6,24 @@ import confluent.config as config import eventlet import Crypto.Protocol.KDF as kdf import Crypto.Hash as hash +import os +import time _passcache = {} _passchecking = {} + +def _prune_passcache(): + # This function makes sure we don't remember a passphrase in memory more + # than 10 seconds + while (1): + curtime = time.time() + for passent in _passcache.iterkeys(): + if passent[2] < curtime - 10: + del _passcache[passent] + eventlet.sleep(10) + + def _get_usertenant(name, tenant=False): """_get_usertenant @@ -32,6 +46,8 @@ def _get_usertenant(name, tenant=False): else: user = name tenant = None + yield user + yield tenant def authorize(name, element, tenant=False, access='rw'): #TODO: actually use the element to ascertain if this user is good enough @@ -57,18 +73,18 @@ def authorize(name, element, tenant=False, access='rw'): return None -def set_user_password(name, password, tenant=None): - """Set user password +def set_user_password(name, passphrase, tenant=None): + """Set user passphrase :param name: The unique shortname of the user - :param password: The password to set for given user + :param passphrase: The passphrase to set for given user :param tenant: The tenant to which the user belongs. """ # TODO(jbjohnso): WORKERPOOL # When worker pool implemented, hand off the # PBKDF2 to a worker instead of blocking user, tenant = _get_usertenant(name, tenant) - _passcache[(user, tenant)] = password + _passcache[(user, tenant)] = passphrase salt = os.urandom(8) crypted = kdf.PBKDF2(passphrase, salt, 32, 10000, lambda p, s: hash.HMAC.new(p, s, hash.SHA256).digest()) @@ -78,22 +94,22 @@ def set_user_password(name, password, tenant=None): def check_user_passphrase(name, passphrase, tenant=None): user, tenant = _get_usertenant(name, tenant) - if (user,tenant) in _passcache: - if passphrase == passcache[(user,tenant)]: - return True - else: - # In case of someone trying to guess, - # while someone is legitimately logged in - # invalidate cache and force the slower check - del _passchache[(user, tenant)] - return False - eventlet.sleep(0.1) # limit throughput of remote guessing while (user,tenant) in _passchecking: # Want to serialize passphrase checking activity # by a user, which might be malicious # would normally make an event and wait # but here there's no need for that eventlet.sleep(0.5) + if (user,tenant) in _passcache: + if passphrase == _passcache[(user,tenant)]: + return True + else: + # In case of someone trying to guess, + # while someone is legitimately logged in + # invalidate cache and force the slower check + del _passcache[(user, tenant)] + return False + eventlet.sleep(0.1) # limit throughput of remote guessing cfm = config.ConfigManager(tenant) ucfg = cfm.get_user(user) if ucfg is None or 'cryptpass' not in ucfg: @@ -105,3 +121,9 @@ def check_user_passphrase(name, passphrase, tenant=None): salt, crypt = ucfg['cryptpass'] crypted = kdf.PBKDF2(passphrase, salt, 32, 10000, lambda p, s: hash.HMAC.new(p, s, hash.SHA256).digest()) + del _passchecking[(user, tenant)] + if crypt == crypted: + _passcache[(user, tenant)] = passphrase + return True + return False +