mirror of
				https://github.com/xcat2/confluent.git
				synced 2025-10-31 11:22:28 +00:00 
			
		
		
		
	Provide hook to get registered credentials
This has to relax the session in getting and requesting validation.
This commit is contained in:
		| @@ -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: | ||||
|   | ||||
| @@ -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('/'):] | ||||
|   | ||||
| @@ -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) | ||||
		Reference in New Issue
	
	Block a user