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

Provide hook to get registered credentials

This has to relax the session in getting and requesting validation.
This commit is contained in:
Jarrod Johnson 2022-05-24 19:17:31 -04:00
parent 9b39c96135
commit c93f09bc91
3 changed files with 56 additions and 12 deletions

View File

@ -162,6 +162,8 @@ def authorize(name, element, tenant=False, operation='create',
return False
manager = configmanager.ConfigManager(tenant, username=user)
userobj = manager.get_user(user)
if element in ('/sessions/current/webauthn/registered_credentials', '/sessions/current/webauthn/validate'):
return userobj, manager, user, tenant, skipuserobj
if userobj and userobj.get('role', None) == 'Stub':
userobj = None
if not userobj:

View File

@ -211,6 +211,8 @@ def _should_skip_authlog(env):
if '/sessions/current/async' in env['PATH_INFO']:
# this is effectively invisible
return True
if '/sessions/current/webauthn/registered_credentials' in env['PATH_INFO']:
return True
if (env['REQUEST_METHOD'] == 'GET' and
('/sensors/' in env['PATH_INFO'] or
'/health/' in env['PATH_INFO'] or
@ -274,11 +276,18 @@ def _authorize_request(env, operation):
authdata = None
name = ''
sessionid = None
sessid = None
cookie = Cookie.SimpleCookie()
element = env['PATH_INFO']
if element.startswith('/sessions/current/'):
element = None
if 'HTTP_COOKIE' in env:
if (element.startswith('/sessions/current/webauthn/registered_credentials/')
or element.startswith('/sessions/current/webauthn/validate/')):
username = element.rsplit('/')[-1]
element = element.replace('/' + username, '')
authdata = auth.authorize(name, element=element, operation=operation)
else:
element = None
if (not authdata) and 'HTTP_COOKIE' in env:
cidx = (env['HTTP_COOKIE']).find('confluentsessionid=')
if cidx >= 0:
sessionid = env['HTTP_COOKIE'][cidx+19:cidx+51]
@ -356,11 +365,11 @@ def _authorize_request(env, operation):
auditmsg['user'] = util.stringify(authdata[2])
if sessid is not None:
authinfo['sessionid'] = sessid
if 'csrftoken' in httpsessions[sessid]:
authinfo['authtoken'] = httpsessions[sessid]['csrftoken']
httpsessions[sessid]['cfgmgr'] = authdata[1]
if not skiplog:
auditlog.log(auditmsg)
if 'csrftoken' in httpsessions[sessid]:
authinfo['authtoken'] = httpsessions[sessid]['csrftoken']
httpsessions[sessid]['cfgmgr'] = authdata[1]
return authinfo
elif authdata is None:
return {'code': 401}
@ -636,7 +645,7 @@ def resourcehandler_backend(env, start_response):
raise Exception("Unrecognized code from auth engine")
headers.extend(
("Set-Cookie", m.OutputString())
for m in authorized['cookie'].values())
for m in authorized.get('cookie', {}).values())
cfgmgr = authorized['cfgmgr']
if (operation == 'create') and env['PATH_INFO'] == '/sessions/current/async':
pagecontent = ""
@ -839,7 +848,7 @@ def resourcehandler_backend(env, start_response):
start_response('501 Not Implemented', headers)
yield ''
return
for rsp in webauthn.handle_api_request(url, env, start_response, authorized['username'], cfgmgr, headers):
for rsp in webauthn.handle_api_request(url, env, start_response, authorized['username'], cfgmgr, headers, reqbody):
yield rsp
return
resource = '.' + url[url.rindex('/'):]

View File

@ -1,3 +1,4 @@
import base64
import confluent.util as util
import json
import pywarp
@ -11,9 +12,13 @@ class TestBackend(pywarp.backends.CredentialStorageBackend):
pass
def get_credential_by_email(self, email):
if not isinstance(email, str):
email = email.decode('utf8')
return creds[email]
def save_credential_for_user(self, email, credential):
if not isinstance(email, str):
email = email.decode('utf8')
creds[email] = credential
def save_challenge_for_user(self, email, challenge, type):
@ -23,15 +28,12 @@ class TestBackend(pywarp.backends.CredentialStorageBackend):
return challenges[email]
def handle_api_request(url, env, start_response, username, cfm, headers):
def handle_api_request(url, env, start_response, username, cfm, headers, reqbody):
if env['REQUEST_METHOD'] != 'POST':
raise Exception('Only POST supported for webauthn operations')
url = url.replace('/sessions/current/webauthn', '')
if'CONTENT_LENGTH' in env and int(env['CONTENT_LENGTH']) > 0:
reqbody = env['wsgi.input'].read(int(env['CONTENT_LENGTH']))
reqtype = env['CONTENT_TYPE']
if url == '/registration_options':
rp = pywarp.RelyingPartyManager('Confluent Web UI', credential_storage_backend=TestBackend())
rp = pywarp.RelyingPartyManager('Confluent Web UI', credential_storage_backend=TestBackend(), require_attestation=False)
userinfo = cfm.get_user(username)
if not userinfo:
cfm.create_user(username, role='Stub')
@ -47,5 +49,36 @@ def handle_api_request(url, env, start_response, username, cfm, headers):
opts['user']['id'] = authid
if 'icon' in opts['user']:
del opts['user']['icon']
if 'id' in opts['rp']:
del opts['rp']['id']
start_response('200 OK', headers)
yield json.dumps(opts)
elif url.startswith('/registered_credentials/'):
username = url.rsplit('/', 1)[-1]
rp = pywarp.RelyingPartyManager('Confluent Web UI', credential_storage_backend=TestBackend())
if not isinstance(username, bytes):
username = username.encode('utf8')
opts = rp.get_authentication_options(username)
opts['challenge'] = base64.b64encode(opts['challenge']).decode('utf8')
start_response('200 OK', headers)
yield json.dumps(opts)
elif url == '/validate':
rp = pywarp.RelyingPartyManager('Confluent Web UI', credential_storage_backend=TestBackend())
req = json.loads(reqbody)
for x in req:
req[x] = base64.b64decode(req[x].replace('-', '+').replace('_', '/'))
req['email'] = username
rsp = rp.verify(**req)
start_response('200 OK')
yield json.dumps(rsp)
elif url == '/register_credential':
rp = pywarp.RelyingPartyManager('Confluent Web UI', credential_storage_backend=TestBackend(), require_attestation=False)
req = json.loads(reqbody)
for x in req:
req[x] = base64.b64decode(req[x].replace('-', '+').replace('_', '/'))
if not isinstance(username, bytes):
username = username.encode('utf8')
req['email'] = username
rsp = rp.register(**req)
start_response('200 OK', headers)
yield json.dumps(rsp)