diff --git a/TODO b/TODO index d8c50881..bf0ab2a6 100644 --- a/TODO +++ b/TODO @@ -1,11 +1,3 @@ --user can bog down all requests by hammering it with bad auth requests causing - the auth facility to get bogged down in PBKDF - Option: - -a multiprocessing pool to handle new authentications. The auth action - itself would be stalled out whilst an attack was underway, but once - in, the respective session layers will provide a caching session that - should accelerate things after the client gets in once - -penalizing a client clearly trying to break in -other auth -pam if user exists but has no passphrase -keystone? @@ -14,13 +6,6 @@ -When a user account is changed, have httpapi and sockapi notified of changes to kill off related sessions. password changes are given a pass, but user deletion will result in immediate session termination --need event notification for config change- e.g. set attribute triggers consol - session object check to see if credentials changed - design is that calling code on init registers a callback for related node to - the in-context config manager object. callback shall be OO so no context - object parametr passed in. ipmi will use it for user/password/hardwaremanagement.manager - changes to console and command objects. console will use it to hook add/deletion - of nodes and/or indicating a different console.method or hardwaremanagement.method -When the time comes to dole out configuration/discovery, take page from xCAT 'flexdiscover' command, if possible bring an ipmi device under management by way of ipv6 to eliminate requirement for ip to be specified. @@ -40,8 +25,4 @@ Traceback (most recent call last): KeyError: '' --have pyghmi and friends do multiprocessing pools (particularly the PBKDF stuff in auth) --have console sessions be instructed as to more specific clue for unconnected - -misconfigured - console.method probably not set right - -unreachable - hardwaremanagement.manager probably wrong - -authentication failure - user/passphrase probable not right +-have pyghmi and friends do multiprocessing pools \ No newline at end of file diff --git a/confluent/auth.py b/confluent/auth.py index f60a2fc6..2276dfac 100644 --- a/confluent/auth.py +++ b/confluent/auth.py @@ -21,14 +21,18 @@ import confluent.config.configmanager as configmanager import eventlet +import eventlet.tpool import Crypto.Protocol.KDF as KDF import hashlib import hmac +import multiprocessing import time _passcache = {} _passchecking = {} +authworkers = None + def _prune_passcache(): # This function makes sure we don't remember a passphrase in memory more @@ -143,9 +147,13 @@ def check_user_passphrase(name, passphrase, element=None, tenant=False): # throw it at the worker pool when implemented # maybe a distinct worker pool, wondering about starving out non-auth stuff salt, crypt = ucfg['cryptpass'] - crypted = KDF.PBKDF2(passphrase, salt, 32, 10000, - lambda p, s: hmac.new(p, s, hashlib.sha256).digest() - ) + # execute inside tpool to get greenthreads to give it a special thread + # world + #TODO(jbjohnso): util function to generically offload a call + #such a beast could be passed into pyghmi as a way for pyghmi to + #magically get offload of the crypto functions without having + #to explicitly get into the eventlet tpool game + crypted = eventlet.tpool.execute(_do_pbkdf, passphrase, salt) del _passchecking[(user, tenant)] eventlet.sleep(0.05) # either way, we want to stall so that client can't # determine failure because there is a delay, valid response will @@ -154,3 +162,26 @@ def check_user_passphrase(name, passphrase, element=None, tenant=False): _passcache[(user, tenant)] = passphrase return authorize(user, element, tenant) return None + + +def _apply_pbkdf(passphrase, salt): + return KDF.PBKDF2(passphrase, salt, 32, 10000, + lambda p, s: hmac.new(p, s, hashlib.sha256).digest()) + + +def _do_pbkdf(passphrase, salt): + # we must get it over to the authworkers pool or else get blocked in + # compute. However, we do want to wait for result, so we have + # one of the exceedingly rare sort of circumstances where 'apply' + # actually makes sense + return authworkers.apply(_apply_pbkdf, [passphrase, salt]) + + +def init_auth(): + # have a some auth workers available. Keep them distinct from + # the general populace of workers to avoid unauthorized users + # starving out productive work + global authworkers + # for now we'll just have one auth worker and see if there is any + # demand for more. I personally doubt it. + authworkers = multiprocessing.Pool(processes=1) \ No newline at end of file diff --git a/confluent/main.py b/confluent/main.py index adf0e6d4..bb00aff3 100644 --- a/confluent/main.py +++ b/confluent/main.py @@ -25,6 +25,7 @@ # It also will optionally snoop SLP DA requests import atexit +import confluent.auth as auth import confluent.consoleserver as consoleserver import confluent.pluginapi as pluginapi import confluent.httpapi as httpapi @@ -111,6 +112,7 @@ def run(): pluginapi.load_plugins() _daemonize() _updatepidfile() + auth.init_auth() signal.signal(signal.SIGINT, terminate) signal.signal(signal.SIGTERM, terminate) #TODO(jbjohnso): eventlet has a bug about unix domain sockets, this code