Example #1
0
def test_create_not_supported_attestation():
    """test for internal class check"""

    device = SoftWebauthnDevice()
    pkcco = copy.deepcopy(PKCCO)
    pkcco['publicKey']['attestation'] = 'direct'

    with pytest.raises(ValueError):
        device.create(pkcco, 'https://example.org')
Example #2
0
def test_create_not_supported_type():
    """test for internal class check"""

    device = SoftWebauthnDevice()
    pkcco = copy.deepcopy(PKCCO)
    pkcco['publicKey']['pubKeyCredParams'][0]['alg'] = -8

    with pytest.raises(ValueError):
        device.create(pkcco, 'https://example.org')
Example #3
0
def test_profile_webauthn_register_route(live_server, sl_user):  # pylint: disable=unused-argument
    """register new credential for user"""

    device = SoftWebauthnDevice()

    sl_user.get(url_for('auth.profile_webauthn_register_route',
                        _external=True))
    # some javascript code must be emulated
    webdriver_waituntil(sl_user, js_variable_ready('window.pkcco_raw'))
    pkcco = cbor.decode(
        b64decode(
            sl_user.execute_script('return window.pkcco_raw;').encode(
                'utf-8')))
    attestation = device.create(pkcco, 'https://%s' % webauthn.rp.id)
    sl_user.execute_script(
        'pack_attestation(CBOR.decode(Sner.base64_to_array_buffer("%s")));' %
        b64encode(cbor.encode(attestation)).decode('utf-8'))
    # and back to standard test codeflow
    sl_user.find_element_by_xpath(
        '//form[@id="webauthn_register_form"]//input[@name="name"]').send_keys(
            'pytest token')
    sl_user.find_element_by_xpath(
        '//form[@id="webauthn_register_form"]//input[@type="submit"]').click()

    user = User.query.filter(User.username == 'pytest_user').one()
    assert user.webauthn_credentials
Example #4
0
def test_webauthn_register_route(cl_user):
    """register new credential for user"""

    device = SoftWebauthnDevice()

    response = cl_user.get(url_for('app.webauthn_register_route'))
    # some javascript code must be emulated
    pkcco = cbor.decode(
        b64decode(
            cl_user.post(url_for('app.webauthn_pkcco_route'), {
                'csrf_token': get_csrf_token(cl_user)
            }).body))
    attestation = device.create(pkcco, 'https://%s' % webauthn.rp.ident)
    attestation_data = {
        'clientDataJSON': attestation['response']['clientDataJSON'],
        'attestationObject': attestation['response']['attestationObject']
    }
    form = response.form
    form['attestation'] = b64encode(cbor.encode(attestation_data))
    # and back to standard test codeflow
    form['name'] = 'pytest token'
    response = form.submit()

    assert response.status_code == HTTPStatus.FOUND
    user = User.query.filter(User.username == 'pytest_user').one()
    assert user.webauthn_credentials
Example #5
0
def test_webauthn_register_new_key(test_client, init_database):
    sign_in_response = sign_in(test_client, "dave", "wselfknskjdksdaiujlj")
    device = SoftWebauthnDevice()
    begin_register_response = test_client.post("/webauthn/register/begin",
                                               data=json.dumps(
                                                   {"resident": False}))
    pkcco = cbor.decode(begin_register_response.data)

    attestation = device.create(pkcco, f"https://{TestConfig.RP_ID}")

    attestation_data = cbor.encode({
        "clientDataJSON":
        attestation["response"]["clientDataJSON"],
        "attestationObject":
        attestation["response"]["attestationObject"],
    })
    raw_response = test_client.post(
        "/webauthn/register/complete",
        input_stream=BytesIO(attestation_data),
        content_type="application/cbor",
    )
    registration_response = cbor.decode(raw_response.data)

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

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

    assert webauthn
    assert webauthn.number == 1
    assert webauthn.is_enabled is False
Example #6
0
def test_create():
    """test create"""

    device = SoftWebauthnDevice()
    attestation = device.create(PKCCO, 'https://example.org')

    assert attestation
    assert device.private_key
    assert device.rp_id == 'example.org'
Example #7
0
def test_register():
    """test registering generated credential"""

    device = SoftWebauthnDevice()

    server = Fido2Server(
        PublicKeyCredentialRpEntity('example.org', 'test server'))
    exclude_credentials = []
    options, state = server.register_begin(
        {
            'id': b'randomhandle',
            'name': 'username',
            'displayName': 'User Name'
        }, exclude_credentials)
    attestation = device.create(options, 'https://example.org')
    auth_data = server.register_complete(
        state, ClientData(attestation['response']['clientDataJSON']),
        AttestationObject(attestation['response']['attestationObject']))

    assert isinstance(auth_data, AuthenticatorData)
Example #8
0
def test_example_server_registration(client):  # pylint: disable=redefined-outer-name
    """Registration example"""

    # User holds an authenticator.
    #
    # NOTE: SoftWebauthnDevice emulates mixed client and authenticator behavior
    # and can be used for testing Webauthn/FIDO2 enabled applications during
    # continuous integration test-cases.
    device = SoftWebauthnDevice()

    # The browser starts registration process by requesting
    # publicKeyCredentialCreationOptions (pkcco) from the server/web
    # application/relying party (RP).
    #
    # NOTE: The transfer encoding and format is not in scope of Webauthn spec,
    # Yubico fido2 example server uses application/cbor.
    pkcco = cbor.decode(client.post('/api/register/begin').data)
    print('publicKeyCredentialCreationOptions: ', pkcco)

    # publicKeyCredentialCreationOptions object is passed from browser/client
    # to the authenticator. Authenticator will generate new credential and
    # return credential object (attestation).
    attestation = device.create(pkcco, 'https://localhost')
    print('new credential attestation: ', attestation)

    # Browser conveys the attestation data to the RP for registration.
    attestation_data = cbor.encode({
        'clientDataJSON': attestation['response']['clientDataJSON'],
        'attestationObject': attestation['response']['attestationObject']
    })
    raw_response = client.post(
        '/api/register/complete',
        input_stream=BytesIO(attestation_data),
        content_type='application/cbor'
    )
    registration_response = cbor.decode(raw_response.data)
    print('registration response:', registration_response)

    # After verification, RP stores attested credential data associated with
    # user account for later authentication.
    assert registration_response == {'status': 'OK'}
Example #9
0
def init_database():

    db.create_all()

    user1 = User(username="******", email="*****@*****.**")
    user1.set_password("[email protected]<")
    user2 = User(username="******", email="*****@*****.**")
    user2.set_password("m7ZTbjQdwuUFU/Zy6la+k6uUtniBExIgEhmBPduKexM=")
    user3 = User(username="******", email="*****@*****.**")
    user3.set_password("wselfknskjdksdaiujlj")
    db.session.add(user1)
    db.session.add(user2)
    db.session.add(user3)

    user4 = User(username="******", email="*****@*****.**")
    user4.set_password("c1c149afbf4c8996fb92427ae41e4649b934ca")

    user5 = User(username="******", email="*****@*****.**")
    user5.set_password("9df1c362e4df3e51edd1acde9")

    user6 = User(username="******", email="*****@*****.**")
    user6.set_password("ukehjwqbjhwqkbejw")

    user7 = User(username="******", email="*****@*****.**")
    user7.set_password("qghjoiwjiklwek")

    user8 = User(username="******", email="*****@*****.**")
    user8.set_password("2398wqshjduiwd8932")

    db.session.add(user4)
    db.session.add(user5)
    db.session.add(user6)
    db.session.add(user7)
    db.session.add(user8)
    db.session.commit()

    got_user4 = User.query.filter_by(username="******").first()
    webauthn_for_user4 = Webauthn(
        number=0, is_enabled=True, user_id=got_user4.did
    )

    got_user5 = User.query.filter_by(username="******").first()
    webauthn_for_user5 = Webauthn(
        number=1,
        is_enabled=True,
        user_identifier=b"\x7e" + os.urandom(31),
        user_id=got_user5.did,
    )

    device = SoftWebauthnDevice()

    pkcco = cbor.decode(
        cbor.encode(
            {
                "publicKey": {
                    "rp": {"id": TestConfig.RP_ID, "name": "Demo server"},
                    "user": {
                        "id": webauthn_for_user5.user_identifier,
                        "icon": "https://example.com/image.png",
                        "name": got_user5.username,
                        "displayName": f"Tests - {got_user5.username}",
                    },
                    "timeout": 30000,
                    "challenge": (
                        b"\xcc\x8e\x03\x04\xdb6bd\xa0d\x98\xa9Vz0p.x"
                        b"\xa4\xf5\xd4\xf6%\xf8\x86zt\x1d\ny\xf9<"
                    ),
                    "pubKeyCredParams": [
                        {"alg": -7, "type": "public-key"},
                        {"alg": -8, "type": "public-key"},
                        {"alg": -37, "type": "public-key"},
                        {"alg": -257, "type": "public-key"},
                    ],
                    "excludeCredentials": [],
                    "authenticatorSelection": {
                        "userVerification": "discouraged",
                        "authenticatorAttachment": "cross-platform",
                    },
                }
            }
        )
    )
    attestation = device.create(pkcco, f"https://{TestConfig.RP_ID}")
    KeyList.priv_one = device.private_key

    att_obj = AttestationObject(attestation["response"]["attestationObject"])

    client_data = ClientData(attestation["response"]["clientDataJSON"])

    auth_data = att_obj.auth_data

    key_for_user5 = Key(
        name="Key 1",
        aaguid=auth_data.credential_data.aaguid,
        credential_id=auth_data.credential_data.credential_id,
        client_data_hash=hashlib.sha256(client_data).digest(),
        public_key=cbor.encode(auth_data.credential_data.public_key),
        counter=att_obj.auth_data.counter,
        attestation=attestation["response"]["attestationObject"],
        info="TODO",
        last_access=datetime.utcnow(),
        created=datetime.utcnow(),
        user_id=got_user5.did,
    )

    db.session.add(webauthn_for_user4)
    db.session.add(webauthn_for_user5)
    db.session.add(key_for_user5)

    # Users for activating Webauthn
    got_user6 = User.query.filter_by(username="******").first()
    webauthn_for_user6 = Webauthn(
        number=2, is_enabled=False, user_id=got_user6.did
    )

    got_user7 = User.query.filter_by(username="******").first()
    webauthn_for_user7 = Webauthn(
        number=1, is_enabled=False, user_id=got_user7.did
    )
    db.session.add(webauthn_for_user6)
    db.session.add(webauthn_for_user7)

    got_user8 = User.query.filter_by(username="******").first()
    webauthn_for_user8 = Webauthn(
        number=1, is_enabled=False, user_id=got_user8.did
    )
    first_key_for_user8 = Key(
        name="Key 1",
        aaguid=b"",
        credential_id=b"againnotrealbutrequiredtolistkeyproperly",
        client_data_hash=hashlib.sha256(b"a").digest(),
        public_key=b"",
        counter=0,
        attestation=b"",
        info="TODO",
        last_access=datetime.utcnow(),
        created=datetime.utcnow(),
        user_id=got_user8.did,
    )
    second_key_for_user8 = Key(
        name="Key 2",
        aaguid=b"",
        credential_id=b"notrealbutnecessarytodelete",
        client_data_hash=hashlib.sha256(b"a").digest(),
        public_key=b"",
        counter=0,
        attestation=b"",
        info="TODO",
        last_access=datetime.utcnow(),
        created=datetime.utcnow(),
        user_id=got_user8.did,
    )
    db.session.add(webauthn_for_user8)
    db.session.add(first_key_for_user8)
    db.session.add(second_key_for_user8)

    db.session.commit()

    yield db

    db.drop_all()