Beispiel #1
0
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"]')))
Beispiel #2
0
def test_login_webauthn(live_server, selenium, webauthn_credential_factory):  # pylint: disable=unused-argument
    """test login by webauthn"""

    device = SoftWebauthnDevice()
    device.cred_init(webauthn.rp.id, b'randomhandle')
    wncred = webauthn_credential_factory.create(initialized_device=device)
    # factory post_generate does not call commit to propagate self.attr changes, that messes the actual db state when
    # accessing from different process such as real browser
    db.session.commit()

    selenium.get(url_for('auth.login_route', _external=True))
    selenium.find_element_by_xpath(
        '//form//input[@name="username"]').send_keys(wncred.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"]')))
Beispiel #3
0
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)
Beispiel #4
0
def test_login_webauthn(client, webauthn_credential_factory):
    """test login by webauthn"""

    device = SoftWebauthnDevice()
    device.cred_init(webauthn.rp.id, b'randomhandle')
    wncred = webauthn_credential_factory.create(initialized_device=device)

    form = client.get(url_for('auth.login_route')).form
    form['username'] = wncred.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('auth.login_webauthn_pkcro_route'), {
                'csrf_token': get_csrf_token(client)
            }).body))
    assertion = device.get(pkcro, f'https://{webauthn.rp.id}')
    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('index_route'))
    assert response.lxml.xpath('//a[text()="Logout"]')
Beispiel #5
0
def test_get_not_matching_rpid():
    """test get not mathcing rpid"""

    device = SoftWebauthnDevice()
    device.cred_init('rpid', b'randomhandle')

    pkcro = copy.deepcopy(PKCRO)
    pkcro['publicKey']['rpId'] = 'another_rpid'
    with pytest.raises(ValueError):
        device.get(pkcro, 'https://example.org')
Beispiel #6
0
    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__)
Beispiel #7
0
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)
Beispiel #9
0
def test_get():
    """test get"""

    device = SoftWebauthnDevice()
    device.cred_init(PKCRO['publicKey']['rpId'], b'randomhandle')

    assertion = device.get(PKCRO, 'https://example.org')

    assert assertion
    device.private_key.public_key().verify(
        assertion['response']['signature'],
        assertion['response']['authenticatorData'] +
        sha256(assertion['response']['clientDataJSON']),
        ec.ECDSA(hashes.SHA256()))
Beispiel #10
0
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_webauthn_authenticate(test_client, init_database):
    sign_in_response = sign_in(test_client, "jennie",
                               "9df1c362e4df3e51edd1acde9")

    device = SoftWebauthnDevice()
    user = User.query.filter_by(username="******").first()
    webauthn = Webauthn.query.filter_by(user_id=user.did).first()
    user_handle = webauthn.user_identifier

    device.cred_init(TestConfig.RP_ID, user_handle)

    device.private_key = KeyList.priv_one

    user5_first_security_key_public_key = ES256.from_cryptography_key(
        device.private_key.public_key())
    key = (Key.query.filter_by(user_id=user.did).filter_by(
        public_key=cbor.encode(user5_first_security_key_public_key)).first())
    device.credential_id = key.credential_id

    pkcro = cbor.decode(test_client.post("/webauthn/authenticate/begin").data)

    assertion = device.get(pkcro, f"https://{TestConfig.RP_ID}")

    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 = test_client.post(
        "/webauthn/authenticate/complete",
        input_stream=BytesIO(assertion_data),
        content_type="application/cbor",
    )
    authentication_response = cbor.decode(raw_response.data)

    assert authentication_response == {"status": "OK"}

    settings_response = test_client.get("/settings")
    assert settings_response.status_code == 200
Beispiel #12
0
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'}
Beispiel #13
0
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"]')