def test_login_webauthn(live_server, selenium, test_user): # pylint: disable=unused-argument """test login by webauthn""" device = SoftWebauthnDevice() device.cred_init(webauthn.rp.id, b'randomhandle') persist_and_detach( WebauthnCredential(user=test_user, user_handle=device.user_handle, credential_data=cbor.encode( device.cred_as_attested().__dict__))) selenium.get(url_for('auth.login_route', _external=True)) selenium.find_element_by_xpath( '//form//input[@name="username"]').send_keys(test_user.username) selenium.find_element_by_xpath('//form//input[@type="submit"]').click() # some javascript code must be emulated webdriver_waituntil(selenium, js_variable_ready('window.pkcro_raw')) pkcro = cbor.decode( b64decode( selenium.execute_script('return window.pkcro_raw;').encode( 'utf-8'))) assertion = device.get(pkcro, 'https://%s' % webauthn.rp.id) selenium.execute_script( 'authenticate_assertion(CBOR.decode(Sner.base64_to_array_buffer("%s")));' % b64encode(cbor.encode(assertion)).decode('utf-8')) # and back to standard test codeflow webdriver_waituntil( selenium, EC.presence_of_element_located((By.XPATH, '//a[text()="Logout"]')))
def test_as_attested_cred(): """test straight credential generation and access""" device = SoftWebauthnDevice() device.cred_init('rpid', b'randomhandle') assert isinstance(device.cred_as_attested(), AttestedCredentialData)
def initialized_device(self, create, extracted, **kwargs): # pylint: disable=unused-argument """DI or self initialize device""" if extracted: device = extracted else: device = SoftWebauthnDevice() device.cred_init(webauthn.rp.id, b'randomhandle') self.user_handle = device.user_handle self.credential_data = cbor.encode(device.cred_as_attested().__dict__)
def create_test_wncred(a_test_user): """test webauthn credential""" device = SoftWebauthnDevice() device.cred_init(webauthn.rp.id, b'randomhandle') return WebauthnCredential(user_id=a_test_user.id, user=a_test_user, user_handle=device.user_handle, credential_data=cbor.encode( device.cred_as_attested().__dict__), name='testcredential')
def test_wncred(test_user): # pylint: disable=redefined-outer-name """persistent test registered webauthn credential""" device = SoftWebauthnDevice() device.cred_init(webauthn.rp.ident, b'randomhandle') wncred = WebauthnCredential(user_id=test_user.id, user=test_user, user_handle=device.user_handle, credential_data=cbor.encode( device.cred_as_attested().__dict__), name='testcredential') yield persist_and_detach(wncred)
def test_authenticate(): """test authentication""" device = SoftWebauthnDevice() device.cred_init('example.org', b'randomhandle') registered_credential = device.cred_as_attested() server = Fido2Server( PublicKeyCredentialRpEntity('example.org', 'test server')) options, state = server.authenticate_begin([registered_credential]) assertion = device.get(options, 'https://example.org') server.authenticate_complete( state, [registered_credential], assertion['rawId'], ClientData(assertion['response']['clientDataJSON']), AuthenticatorData(assertion['response']['authenticatorData']), assertion['response']['signature'])
def test_example_server_authentication(client): # pylint: disable=redefined-outer-name """Authentication example""" # Already registered credential is typicaly part of fixture test-case code. # # NOTE: the storage of the credential data on the RP side is not in scope # of Webauthn spec. Yubico example server uses module scoped variable. device = SoftWebauthnDevice() device.cred_init('localhost', b'randomhandle') tests.example_server.credentials = [device.cred_as_attested()] # Browser starts authentication by requesting # publicKeyCredentialRequestOptions (pkcro) from the RP. pkcro = cbor.decode(client.post('/api/authenticate/begin').data) print('publicKeyCredentialRequestOptions: ', pkcro) # publicKeyCredentialRequestOptions object is passed to the authenticator, # which performs requester user verification and return credential object # (assertion). assertion = device.get(pkcro, 'https://localhost') print('credential assertion: ', assertion) # Browser conveys assertion data to the RP for authentication. assertion_data = cbor.encode({ 'credentialId': assertion['rawId'], 'clientDataJSON': assertion['response']['clientDataJSON'], 'authenticatorData': assertion['response']['authenticatorData'], 'signature': assertion['response']['signature'], 'userHandle': assertion['response']['userHandle'] }) raw_response = client.post( '/api/authenticate/complete', input_stream=BytesIO(assertion_data), content_type='application/cbor' ) authentication_response = cbor.decode(raw_response.data) print('authentication response:', authentication_response) # RP will verify assertion and on success proceeds with user logon. assert authentication_response == {'status': 'OK'}
def test_webauthn_login_route(client, test_user): """test login by webauthn""" device = SoftWebauthnDevice() device.cred_init(webauthn.rp.ident, b'randomhandle') persist_and_detach( WebauthnCredential(user=test_user, user_handle=device.user_handle, credential_data=cbor.encode( device.cred_as_attested().__dict__))) form = client.get(url_for('app.login_route')).form form['username'] = test_user.username response = form.submit() assert response.status_code == HTTPStatus.FOUND response = response.follow() # some javascript code muset be emulated pkcro = cbor.decode( b64decode( client.post(url_for('app.webauthn_pkcro_route'), { 'csrf_token': get_csrf_token(client) }).body)) assertion = device.get(pkcro, 'https://%s' % webauthn.rp.ident) assertion_data = { 'credentialRawId': assertion['rawId'], 'authenticatorData': assertion['response']['authenticatorData'], 'clientDataJSON': assertion['response']['clientDataJSON'], 'signature': assertion['response']['signature'], 'userHandle': assertion['response']['userHandle'] } form = response.form form['assertion'] = b64encode(cbor.encode(assertion_data)) response = form.submit() # and back to standard test codeflow assert response.status_code == HTTPStatus.FOUND response = client.get(url_for('app.index_route')) assert response.lxml.xpath('//a[text()="Logout"]')