2
0
mirror of https://github.com/xcat2/confluent.git synced 2024-11-25 02:52:07 +00:00

Implement offload of compute-intensive authentication.

With this change, an instance under pressure from new or bad authentication attempts
will continue to be viable to authenticated sessions and clients with tokens (e.g. any
http client that honors cookies).
This commit is contained in:
jbjohnso 2014-04-24 13:00:07 -04:00
parent 7d9b355bed
commit c514c2c121
3 changed files with 37 additions and 23 deletions

21
TODO
View File

@ -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

View File

@ -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)

View File

@ -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