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

Have validate serve as session info request

This should facilitate login.

Further, provide a quick persistence for the
credential test backend
This commit is contained in:
Jarrod Johnson 2022-05-25 15:58:20 -04:00
parent e0079b5a86
commit f6a17b5f32
3 changed files with 58 additions and 23 deletions

View File

@ -162,7 +162,7 @@ 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'):
if element.startswith('/sessions/current/webauthn/registered_credentials/') or element.startswith('/sessions/current/webauthn/validate/'):
return userobj, manager, user, tenant, skipuserobj
if userobj and userobj.get('role', None) == 'Stub':
userobj = None

View File

@ -269,7 +269,7 @@ def _csrf_valid(env, session):
env['HTTP_CONFLUENTAUTHTOKEN'] == session['csrftoken'])
def _authorize_request(env, operation):
def _authorize_request(env, operation, reqbody):
"""Grant/Deny access based on data from wsgi env
"""
@ -282,8 +282,7 @@ def _authorize_request(env, operation):
if element.startswith('/sessions/current/'):
if (element.startswith('/sessions/current/webauthn/registered_credentials/')
or element.startswith('/sessions/current/webauthn/validate/')):
username = element.rsplit('/')[-1]
element = element.replace('/' + username, '')
name = element.rsplit('/')[-1]
authdata = auth.authorize(name, element=element, operation=operation)
else:
element = None
@ -335,18 +334,13 @@ def _authorize_request(env, operation):
return {'code': 403}
elif not authdata:
return {'code': 401}
sessid = util.randomstring(32)
while sessid in httpsessions:
sessid = util.randomstring(32)
httpsessions[sessid] = {'name': name, 'expiry': time.time() + 90,
'skipuserobject': authdata[4],
'inflight': set([])}
if 'HTTP_CONFLUENTAUTHTOKEN' in env:
httpsessions[sessid]['csrftoken'] = util.randomstring(32)
cookie['confluentsessionid'] = util.stringify(sessid)
cookie['confluentsessionid']['secure'] = 1
cookie['confluentsessionid']['httponly'] = 1
cookie['confluentsessionid']['path'] = '/'
sessid = _establish_http_session(env, authdata, name, cookie)
if authdata and element and element.startswith('/sessions/current/webauthn/validate/'):
if webauthn:
for rsp in webauthn.handle_api_request(element, env, None, authdata[2], authdata[1], None, reqbody, None):
if rsp['verified']:
sessid = _establish_http_session(env, authdata, name, cookie)
break
skiplog = _should_skip_authlog(env)
if authdata:
auditmsg = {
@ -376,6 +370,21 @@ def _authorize_request(env, operation):
else:
return {'code': 403}
def _establish_http_session(env, authdata, name, cookie):
sessid = util.randomstring(32)
while sessid in httpsessions:
sessid = util.randomstring(32)
httpsessions[sessid] = {'name': name, 'expiry': time.time() + 90,
'skipuserobject': authdata[4],
'inflight': set([])}
if 'HTTP_CONFLUENTAUTHTOKEN' in env:
httpsessions[sessid]['csrftoken'] = util.randomstring(32)
cookie['confluentsessionid'] = util.stringify(sessid)
cookie['confluentsessionid']['secure'] = 1
cookie['confluentsessionid']['httponly'] = 1
cookie['confluentsessionid']['path'] = '/'
return sessid
def _pick_mimetype(env):
"""Detect the http indicated mime to send back.
@ -616,7 +625,7 @@ def resourcehandler_backend(env, start_response):
if operation != 'retrieve' and 'restexplorerop' in querydict:
operation = querydict['restexplorerop']
del querydict['restexplorerop']
authorized = _authorize_request(env, operation)
authorized = _authorize_request(env, operation, reqbody)
if 'logout' in authorized:
start_response('200 Successful logout', headers)
yield('{"result": "200 - Successful logout"}')
@ -848,7 +857,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, reqbody):
for rsp in webauthn.handle_api_request(url, env, start_response, authorized['username'], cfgmgr, headers, reqbody, authorized):
yield rsp
return
resource = '.' + url[url.rindex('/'):]

View File

@ -1,34 +1,51 @@
import base64
import confluent.tlvdata as tlvdata
import confluent.util as util
import json
import pywarp
import pywarp.backends
import pywarp.credentials
creds = {}
challenges = {}
class TestBackend(pywarp.backends.CredentialStorageBackend):
def __init__(self):
pass
global creds
try:
with open('/tmp/mycreds.json', 'r') as ji:
creds = json.load(ji)
except Exception:
pass
def get_credential_by_email(self, email):
if not isinstance(email, str):
email = email.decode('utf8')
return creds[email]
cred = creds[email]
cid = base64.b64decode(cred['cid'])
cpk = base64.b64decode(cred['cpk'])
return pywarp.credentials.Credential(credential_id=cid, credential_public_key=cpk)
def save_credential_for_user(self, email, credential):
if not isinstance(email, str):
email = email.decode('utf8')
credential = {'cid': base64.b64encode(credential.id).decode('utf8'), 'cpk': base64.b64encode(bytes(credential.public_key)).decode('utf8')}
creds[email] = credential
with open('/tmp/mycreds.json', 'w') as jo:
json.dump(creds, jo)
def save_challenge_for_user(self, email, challenge, type):
if not isinstance(email, str):
email = email.decode('utf8')
challenges[email] = challenge
def get_challenge_for_user(self, email, type):
if not isinstance(email, str):
email = email.decode('utf8')
return challenges[email]
def handle_api_request(url, env, start_response, username, cfm, headers, reqbody):
def handle_api_request(url, env, start_response, username, cfm, headers, reqbody, authorized):
if env['REQUEST_METHOD'] != 'POST':
raise Exception('Only POST supported for webauthn operations')
url = url.replace('/sessions/current/webauthn', '')
@ -72,8 +89,17 @@ def handle_api_request(url, env, start_response, username, cfm, headers, reqbody
req[x] = base64.b64decode(req[x].replace('-', '+').replace('_', '/'))
req['email'] = username
rsp = rp.verify(**req)
start_response('200 OK')
yield json.dumps(rsp)
if start_response:
start_response('200 OK', headers)
sessinfo = {'username': username}
if 'authtoken' in authorized:
sessinfo['authtoken'] = authorized['authtoken']
if 'sessionid' in authorized:
sessinfo['sessionid'] = authorized['sessionid']
tlvdata.unicode_dictvalues(sessinfo)
yield json.dumps(sessinfo)
else:
yield rsp
elif url == '/register_credential':
rp = pywarp.RelyingPartyManager('Confluent Web UI', credential_storage_backend=TestBackend(), require_attestation=False)
req = json.loads(reqbody)