mirror of
https://github.com/xcat2/confluent.git
synced 2024-11-25 19:10:10 +00:00
Begin work to support complex PAM conversations
For example, TOTP setups need more prompts, this will pass the info to the client for the client to adjust.
This commit is contained in:
parent
d86fc664e9
commit
b8c9e9c535
@ -283,9 +283,14 @@ def check_user_passphrase(name, passphrase, operation=None, element=None, tenant
|
||||
# pam_unix uses unix_chkpwd which reque
|
||||
os.setuid(pwe.pw_uid)
|
||||
usergood = pam.authenticate(user, passphrase, service=_pamservice)
|
||||
except pam.PromptsNeeded:
|
||||
os._exit(2)
|
||||
finally:
|
||||
os._exit(0 if usergood else 1)
|
||||
usergood = os.waitpid(pid, 0)[1] == 0
|
||||
usergood = os.waitpid(pid, 0)[1]
|
||||
if (usergood >> 8) == 2:
|
||||
pam.authenticate(user, passphrase, service=_pamservice)
|
||||
usergood = usergood == 0
|
||||
else:
|
||||
# We are running as root, we don't need to fork in order to authenticate the
|
||||
# user
|
||||
|
@ -307,7 +307,12 @@ def _authorize_request(env, operation):
|
||||
return ('logout',)
|
||||
name, passphrase = base64.b64decode(
|
||||
env['HTTP_AUTHORIZATION'].replace('Basic ', '')).split(b':', 1)
|
||||
authdata = auth.check_user_passphrase(name, passphrase, operation=operation, element=element)
|
||||
try:
|
||||
authdata = auth.check_user_passphrase(name, passphrase, operation=operation, element=element)
|
||||
except Exception as e:
|
||||
if hasattr(e, 'prompts'):
|
||||
return {'code': 403, 'prompts': e.prompts}
|
||||
raise
|
||||
if authdata is False:
|
||||
return {'code': 403}
|
||||
elif not authdata:
|
||||
@ -519,7 +524,14 @@ def resourcehandler_backend(env, start_response):
|
||||
return
|
||||
if authorized['code'] == 403:
|
||||
start_response('403 Forbidden', badauth)
|
||||
yield 'Forbidden'
|
||||
response = {'result': 'Forbidden'}
|
||||
if 'prompts' in authorized:
|
||||
response['prompts'] = []
|
||||
for prompt in authorized['prompts']:
|
||||
if not isinstance(prompt, str):
|
||||
prompt = prompt.decode('utf8')
|
||||
response['prompts'].append(prompt)
|
||||
yield json.dumps(response)
|
||||
return
|
||||
if authorized['code'] != 200:
|
||||
raise Exception("Unrecognized code from auth engine")
|
||||
|
@ -103,6 +103,12 @@ pam_authenticate = libpam.pam_authenticate
|
||||
pam_authenticate.restype = c_int
|
||||
pam_authenticate.argtypes = [PamHandle, c_int]
|
||||
|
||||
|
||||
class PromptsNeeded(Exception):
|
||||
def __init__(self, prompts):
|
||||
self.prompts = prompts
|
||||
|
||||
|
||||
class pam():
|
||||
code = 0
|
||||
reason = None
|
||||
@ -110,7 +116,7 @@ class pam():
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def authenticate(self, username, password, service='login', encoding='utf-8', resetcreds=True):
|
||||
def authenticate(self, username, password, service='login', encoding='utf-8', resetcreds=True, answers=None):
|
||||
"""username and password authentication for the given service.
|
||||
|
||||
Returns True for success, or False for failure.
|
||||
@ -142,8 +148,15 @@ class pam():
|
||||
p_response[0] = response
|
||||
for i in range(n_messages):
|
||||
if messages[i].contents.msg_style == PAM_PROMPT_ECHO_OFF:
|
||||
dst = calloc(len(password)+1, sizeof(c_char))
|
||||
memmove(dst, cpassword, len(password))
|
||||
prompts.add(messages[i].contents.msg)
|
||||
if answers and messages[i].contents.msg in answers:
|
||||
currpassword = answers[messages[i].contents.msg]
|
||||
currcpassword = c_char_p(currpassword)
|
||||
else:
|
||||
currpassword = password
|
||||
currcpassword = cpassword
|
||||
dst = calloc(len(currpassword)+1, sizeof(c_char))
|
||||
memmove(dst, currcpassword, len(currpassword))
|
||||
response[i].resp = dst
|
||||
response[i].resp_retcode = 0
|
||||
return 0
|
||||
@ -169,6 +182,7 @@ class pam():
|
||||
# do this up front so we can safely throw an exception if there's
|
||||
# anything wrong with it
|
||||
cpassword = c_char_p(password)
|
||||
prompts = set([])
|
||||
|
||||
handle = PamHandle()
|
||||
conv = PamConv(my_conv, 0)
|
||||
@ -198,7 +212,8 @@ class pam():
|
||||
|
||||
if hasattr(libpam, 'pam_end'):
|
||||
pam_end(handle, retval)
|
||||
|
||||
if answers is None and len(prompts) > 1 and not auth_success:
|
||||
raise PromptsNeeded(prompts)
|
||||
return auth_success
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user