Example #1
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 #2
0
def fido2_login_complete(req):
    user = None
    logreq('fido2_login_complete', req)
    username = req.session.get(FIDO2_USER_KEY, None)
    if username:
        user = get_user_model().objects.get(username=username)
    if user:
        creds = get_fido2_credentials(user)
        data = cbor.decode(req.body)
        crid = data['credentialId']
        cdat = ClientData(data['clientDataJSON'])
        adat = AuthenticatorData(data['authenticatorData'])
        csig = data['signature']
        stat = get_fido2_state(req)
        try:
            SERVER.authenticate_complete(stat, creds, crid, cdat, adat, csig)
        except ValueError as e:
            logger.warn('Failed fido2 authentication', e)
            return HttpResponseForbidden()
        found = False
        for a in user.authenticators.all():
            if a.crid == crid:
                a.inc_counter()
                found = True
                break
        if not found:
            logger.warn(
                f'Failed to bump fido2 counter for cred-id "{crid}" owned by "{user.username}".'
            )
        auth.login(req, user)
        messages.info(
            req, f'Welcome back {user.get_full_name() or user.username}.')
        logger.info(f'login_complete successful for user "{user.username}".')
        return get_cbor_resp(redirect='/')
    return HttpResponseForbidden()
Example #3
0
def complete_reg(request):
    try:
        data = cbor.decode(request.body)

        client_data = ClientData(data['clientDataJSON'])
        att_obj = AttestationObject((data['attestationObject']))
        server = get_server()
        auth_data = server.register_complete(request.session['fido_state'],
                                             client_data, att_obj)
        encoded = websafe_encode(auth_data.credential_data)
        key = UserKey.objects.create(
            user=request.user,
            properties={
                "device": encoded,
                "type": att_obj.fmt,
                "domain": request.get_host(),
            },
            key_type=KEY_TYPE_FIDO2,
        )
        write_session(request, key)
        messages.success(request, 'FIDO2 Token added!')
        return JsonResponse({'status': 'OK'})

    except Exception:
        logger.exception("Error completing FIDO2 registration.")
        return JsonResponse({
            'status':
            'ERR',
            "message":
            "Error on server, please try again later",
        })
Example #4
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 #5
0
def fido2_keys_user_validate(user_id):
    keys = list_fido2_keys(user_id)
    credentials = list(map(lambda k: pickle.loads(base64.b64decode(k.key)), keys))

    data = request.get_json()
    cbor_data = cbor.decode(base64.b64decode(data["payload"]))

    credential_id = cbor_data['credentialId']
    client_data = ClientData(cbor_data['clientDataJSON'])
    auth_data = AuthenticatorData(cbor_data['authenticatorData'])
    signature = cbor_data['signature']

    Config.FIDO2_SERVER.authenticate_complete(
        get_fido2_session(user_id),
        credentials,
        credential_id,
        client_data,
        auth_data,
        signature
    )

    user_to_verify = get_user_by_id(user_id=user_id)
    user_to_verify.current_session_id = str(uuid.uuid4())
    user_to_verify.logged_in_at = datetime.utcnow()
    user_to_verify.failed_login_count = 0
    save_model_user(user_to_verify)

    return jsonify({'status': 'OK'})
Example #6
0
 def test_ES256_parse_verify(self):
     key = CoseKey.parse(cbor.decode(_ES256_KEY))
     self.assertIsInstance(key, ES256)
     self.assertEqual(
         key,
         {
             1:
             2,
             3:
             -7,
             -1:
             1,
             -2:
             a2b_hex(
                 b'A5FD5CE1B1C458C530A54FA61B31BF6B04BE8B97AFDE54DD8CBB69275A8A1BE1'
             ),  # noqa
             -3:
             a2b_hex(
                 b'FA3A3231DD9DEED9D1897BE5A6228C59501E4BCD12975D3DFF730F01278EA61C'
             )  # noqa
         })
     key.verify(
         a2b_hex(
             b'0021F5FC0B85CD22E60623BCD7D1CA48948909249B4776EB515154E57B66AE12010000002C'
             +  # noqa
             b'7B89F12A9088B0F5EE0EF8F6718BCCC374249C31AEEBAEB79BD0450132CD536C'
         ),  # noqa
         a2b_hex(
             b'304402202B3933FE954A2D29DE691901EB732535393D4859AAA80D58B08741598109516D0220236FBE6B52326C0A6B1CFDC6BF0A35BDA92A6C2E41E40C3A1643428D820941E0'
         )  # noqa
     )
Example #7
0
    def page(self) -> CBORPageResult:
        assert user.id is not None

        if not is_two_factor_login_enabled(user.id):
            raise MKGeneralException(
                _("Two-factor authentication not enabled"))

        data: dict[str, object] = cbor.decode(request.get_data())
        credential_id = data["credentialId"]
        client_data = ClientData(data["clientDataJSON"])
        auth_data = AuthenticatorData(data["authenticatorData"])
        signature = data["signature"]
        logger.debug("ClientData: %r", client_data)
        logger.debug("AuthenticatorData: %r", auth_data)

        make_fido2_server().authenticate_complete(
            session.session_info.webauthn_action_state,
            [
                AttestedCredentialData.unpack_from(v["credential_data"])[0]
                for v in load_two_factor_credentials(user.id)
                ["webauthn_credentials"].values()
            ],
            credential_id,
            client_data,
            auth_data,
            signature,
        )
        session.session_info.webauthn_action_state = None
        set_two_factor_completed()
        return {"status": "OK"}
Example #8
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"]')))
Example #9
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"]')
Example #10
0
def bench_recovery_makecredential(iterations=100, repeats=10, num_seeds=1):
    iterations = int(iterations)

    clientDataJSON_hash = os.urandom(32)
    primary_authnr = Authenticator()
    backup_authnr = Authenticator()
    basic_make_credential(primary_authnr, clientDataJSON_hash)
    allowList = [{
        'type': 'public-key',
        'id': i
    } for i in primary_authnr._credentials.keys()]

    for i in range(num_seeds - 1):
        primary_authnr.import_recovery_seed(
            Authenticator().export_recovery_seed([0]))
    primary_authnr.import_recovery_seed(backup_authnr.export_recovery_seed([0
                                                                            ]))

    recovery_allowCredentials = [{
        'id': ctap2.AttestedCredentialData(cred).credential_id,
        'type': 'public-key'
    } for cred in ctap2.AuthenticatorData(
        cbor.decode(
            generate_backups_get_assertion(primary_authnr, clientDataJSON_hash,
                                           allowList))
        [2]).extensions['recovery']['creds']]

    return iterations, repeats, timeit.repeat(
        stmt=lambda: recovery_make_credential(
            backup_authnr, clientDataJSON_hash, recovery_allowCredentials),
        number=iterations,
        repeat=repeats,
    )
Example #11
0
def complete_reg(request):
    try:
        data = cbor.decode(request.body)

        client_data = ClientData(data['clientDataJSON'])
        att_obj = AttestationObject((data['attestationObject']))
        server = get_server()
        auth_data = server.register_complete(request.session['fido_state'],
                                             client_data, att_obj)
        encoded = websafe_encode(auth_data.credential_data)
        UserKey.objects.create(
            username=request.user.get_username(),
            properties={
                "device": encoded,
                "type": att_obj.fmt
            },
            key_type="FIDO2",
        )
        return JsonResponse({'status': 'OK'})

    except:
        return JsonResponse({
            'status':
            'ERR',
            "message":
            "Error on server, please try again later",
        })
Example #12
0
def authenticate_complete(request):
    credentials = []
    username = request.session.get("base_username",
                                   request.user.get_username())
    server = get_server()
    credentials = get_user_credentials(username)
    data = cbor.decode(request.body)
    credential_id = data['credentialId']
    client_data = ClientData(data['clientDataJSON'])
    auth_data = AuthenticatorData(data['authenticatorData'])
    signature = data['signature']

    cred = server.authenticate_complete(request.session.pop('fido_state'),
                                        credentials, credential_id,
                                        client_data, auth_data, signature)

    for k in UserKey.objects.filter(username=username,
                                    key_type="FIDO2",
                                    enabled=1):
        if AttestedCredentialData(websafe_decode(
                k.properties["device"])).credential_id == cred.credential_id:
            k.last_used = timezone.now()
            k.save()
            mfa = {"verified": True, "method": "FIDO2", 'id': k.id}
            if getattr(settings, "MFA_RECHECK", False):
                mfa["next_check"] = next_check()
            request.session["mfa"] = mfa
            res = login(request)
            return JsonResponse({'status': "OK", "redirect": res["location"]})

    return JsonResponse({'status': "err"})
Example #13
0
def get_assertion(authenticator, request_json):
    request = json.loads(request_json)
    pkcro = request['publicKeyCredentialRequestOptions']
    collectedClientData = {
        'type': 'webauthn.get',
        'challenge': pkcro['challenge'],
        'origin': 'https://localhost:8443',
    }
    clientDataJSON = json.dumps(collectedClientData, indent=None).encode('utf-8')
    clientDataJSON_hash = sha256(clientDataJSON)
    authenticator_response = cbor.decode(authenticator.authenticator_get_assertion(cbor.encode({
        0x01: pkcro['rpId'],
        0x02: clientDataJSON_hash,
        0x03: [{'id': base64.urlsafe_b64decode(c['id']), 'type': 'public-key'} for c in pkcro['allowCredentials']],
        0x04: pkcro['extensions'],
    })))
    authenticatorData = authenticator_response[0x02]
    sig = authenticator_response[0x03]
    credential = {
        'type': 'public-key',
        'id': base64.urlsafe_b64encode(authenticator_response[0x01]['id']).decode('utf-8'),
        'response': {
            'authenticatorData': base64.urlsafe_b64encode(authenticatorData).decode('utf-8'),
            'clientDataJSON': base64.urlsafe_b64encode(clientDataJSON).decode('utf-8'),
            'signature': base64.urlsafe_b64encode(sig).decode('utf-8'),
        },
        'clientExtensionResults': {},
    }
    print(json.dumps(credential, indent=2))
Example #14
0
def ctap2_to_webauthn_attestation_object(attObj_cbor):
    attObj = cbor.decode(attObj_cbor)
    return cbor.encode({
        'fmt': attObj[0x01],
        'authData': attObj[0x02],
        'attStmt': attObj[0x03],
    })
Example #15
0
    def _call(
        self,
        cmd: int,
        data: bytes = b"",
        event: Event = None,
        on_keepalive: FunctionType = None,
    ):
        if cmd != hid.CTAPHID.CBOR:
            raise CtapError(CtapError.ERR.INVALID_COMMAND)

        if not data:
            raise CtapError(CtapError.ERR.INVALID_PARAMETER)

        ctap2_cmd = ctap2.Ctap2.CMD.from_bytes(data[:1], 'big')
        handler = self._ctap2_cmd_to_handler.get(ctap2_cmd)
        if not handler:
            raise CtapError(CtapError.ERR.INVALID_COMMAND)

        if len(data) == 1:
            return handler()

        # noinspection PyBroadException
        try:
            ctap2_req: dict = cbor.decode(data[1:])
        except Exception:
            raise CtapError(CtapError.ERR.INVALID_CBOR)

        if not isinstance(ctap2_req, dict):
            raise CtapError(CtapError.ERR.INVALID_CBOR)

        # noinspection PyArgumentList
        return handler(ctap2_req)
Example #16
0
def profile_webauthn_register_route():
    """register credential for current user"""

    user = User.query.get(current_user.id)
    form = WebauthnRegisterForm()
    if form.validate_on_submit():
        try:
            attestation = cbor.decode(b64decode(form.attestation.data))
            auth_data = webauthn.register_complete(
                session.pop('webauthn_register_state'),
                ClientData(attestation['clientDataJSON']),
                AttestationObject(attestation['attestationObject']))

            db.session.add(WebauthnCredential(
                user_id=user.id,
                user_handle=session.pop('webauthn_register_user_handle'),
                credential_data=cbor.encode(auth_data.credential_data.__dict__),
                name=form.name.data))
            db.session.commit()

            return redirect(url_for('auth.profile_route'))
        except (KeyError, ValueError) as e:
            current_app.logger.exception(e)
            flash('Error during registration.', 'error')

    return render_template('auth/profile/webauthn_register.html', form=form)
Example #17
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"]')))
Example #18
0
    def _add_token_to_user(self, registration_data, state):
        data = registration_data + (b'=' * (len(registration_data) % 4))
        data = base64.urlsafe_b64decode(data)
        data = cbor.decode(data)
        client_data = ClientData(data['clientDataJSON'])
        attestation = data['attestationObject']
        att_obj = AttestationObject(attestation)
        server = get_webauthn_server(self.app.config.fido2_rp_id)
        auth_data = server.register_complete(state, client_data, att_obj)
        cred_data = auth_data.credential_data
        cred_id = cred_data.credential_id

        credential = Webauthn.from_dict(
            dict(
                keyhandle=cred_id.hex(),
                credential_data=base64.urlsafe_b64encode(cred_data).decode(
                    'ascii'),
                app_id=self.app.config.fido2_rp_id,
                attest_obj=base64.b64encode(attestation).decode('ascii'),
                description='ctap1 token',
                created_by='test_security',
            ))
        self.test_user.credentials.add(credential)
        self.app.central_userdb.save(self.test_user, check_sync=False)
        return credential
Example #19
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 #20
0
    def page(self) -> CBORPageResult:
        assert user.id is not None
        user.need_permission("general.manage_2fa")

        raw_data = request.get_data()
        logger.debug("Raw request: %r", raw_data)
        data: dict[str, object] = cbor.decode(raw_data)
        client_data = ClientData(data["clientDataJSON"])
        att_obj = AttestationObject(data["attestationObject"])
        logger.debug("Client data: %r", client_data)
        logger.debug("Attestation object: %r", att_obj)

        auth_data = make_fido2_server().register_complete(
            session.session_info.webauthn_action_state, client_data, att_obj
        )

        ident = auth_data.credential_data.credential_id.hex()
        credentials = load_two_factor_credentials(user.id, lock=True)

        if ident in credentials["webauthn_credentials"]:
            raise MKGeneralException(_("Your WebAuthn credetial is already in use"))

        credentials["webauthn_credentials"][ident] = WebAuthnCredential(
            {
                "credential_id": ident,
                "registered_at": int(time.time()),
                "alias": "",
                "credential_data": bytes(auth_data.credential_data),
            }
        )
        save_two_factor_credentials(user.id, credentials)

        flash(_("Registration successful"))
        return {"status": "OK"}
Example #21
0
 def test_EdDSA_parse_verify(self):
     key = CoseKey.parse(cbor.decode(_EdDSA_KEY))
     self.assertIsInstance(key, EdDSA)
     self.assertEqual(
         key,
         {
             1:
             1,
             3:
             -8,
             -1:
             6,
             -2:
             a2b_hex(
                 'EE9B21803405D3CF45601E58B6F4C06EA93862DE87D3AF903C5870A5016E86F5'
             )  # noqa
         })
     key.verify(
         a2b_hex(
             b'a379a6f6eeafb9a55e378c118034e2751e682fab9f2d30ab13d2125586ce1947010000000500a11a323057d1103784ddff99a354ddd42348c2f00e88d8977b916cabf92268'
         ),  # noqa
         a2b_hex(
             b'e8c927ef1a57c738ff4ba8d6f90e06d837a5219eee47991f96b126b0685d512520c9c2eedebe4b88ff2de2b19cb5f8686efc7c4261e9ed1cb3ac5de50869be0a'
         )  # noqa
     )
Example #22
0
def complete_reg(request):
    """Completes the registeration, called by API"""
    try:
        data = cbor.decode(request.body)

        client_data = ClientData(data['clientDataJSON'])
        att_obj = AttestationObject((data['attestationObject']))
        server = getServer()
        auth_data = server.register_complete(request.session['fido_state'],
                                             client_data, att_obj)
        encoded = websafe_encode(auth_data.credential_data)
        uk = User_Keys()
        uk.username = request.user.username
        uk.properties = {
            "device": encoded,
            "type": att_obj.fmt,
        }
        uk.owned_by_enterprise = getattr(settings, "MFA_OWNED_BY_ENTERPRISE",
                                         False)
        uk.key_type = "FIDO2"
        uk.save()
        return HttpResponse(simplejson.dumps({'status': 'OK'}))
    except Exception as exp:
        try:
            from raven.contrib.django.raven_compat.models import client
            client.captureException()
        except:
            pass
        return HttpResponse(
            simplejson.dumps({
                'status':
                'ERR',
                "message":
                "Error on server, please try again later"
            }))
Example #23
0
 def test_RS256_parse_verify(self):
     key = CoseKey.parse(cbor.decode(_RS256_KEY))
     self.assertIsInstance(key, RS256)
     self.assertEqual(
         key,
         {
             1:
             3,
             3:
             -257,
             -1:
             a2b_hex(
                 b'B610DCE84B65029FAE24F7BF8A1730D37BC91435642A628E691E9B030BF3F7CEC59FF91CBE82C54DE16C136FA4FA8A58939B5A950B32E03073592FEC8D8B33601C04F70E5E2D5CF7B4E805E1990EA5A86928A1B390EB9026527933ACC03E6E41DC0BE40AA5EB7B9B460743E4DD80895A758FB3F3F794E5E9B8310D3A60C28F2410D95CF6E732749A243A30475267628B456DE770BC2185BBED1D451ECB0062A3D132C0E4D842E0DDF93A444A3EE33A85C2E913156361713155F1F1DC64E8E68ED176466553BBDE669EB82810B104CB4407D32AE6316C3BD6F382EC3AE2C5FD49304986D64D92ED11C25B6C5CF1287233545A987E9A3E169F99790603DBA5C8AD'
             ),  # noqa
             -2:
             a2b_hex(b'010001')  # noqa
         })
     key.verify(
         a2b_hex(
             b'0021F5FC0B85CD22E60623BCD7D1CA48948909249B4776EB515154E57B66AE12010000002E'
             +  # noqa
             b'CC9340FD84950987BA667DBE9B2C97C7241E15E2B54869A0DD1CE2013C4064B8'
         ),  # noqa
         a2b_hex(
             b'071B707D11F0E7F62861DFACA89C4E674321AD8A6E329FDD40C7D6971348FBB0514E7B2B0EFE215BAAC0365C4124A808F8180D6575B710E7C01DAE8F052D0C5A2CE82F487C656E7AD824F3D699BE389ADDDE2CBF39E87A8955E93202BAE8830AB4139A7688DFDAD849F1BB689F3852BA05BED70897553CC44704F6941FD1467AD6A46B4DAB503716D386FE7B398E78E0A5A8C4040539D2C9BFA37E4D94F96091FFD1D194DE2CA58E9124A39757F013801421E09BD261ADA31992A8B0386A80AF51A87BD0CEE8FDAB0D4651477670D4C7B245489BED30A57B83964DB79418D5A4F5F2E5ABCA274426C9F90B007A962AE15DFF7343AF9E110746E2DB9226D785C6'
         )  # noqa
     )
Example #24
0
def login_webauthn_route():
    """login webauthn route"""

    user = User.query.filter(
        User.id == session.get('webauthn_login_user_id')).one_or_none()
    if not user:
        return login_manager.unauthorized()

    form = WebauthnLoginForm()
    if form.validate_on_submit():
        try:
            assertion = cbor.decode(b64decode(form.assertion.data))
            webauthn.authenticate_complete(
                session.pop('webauthn_login_state'),
                webauthn_credentials(user), assertion['credentialRawId'],
                ClientData(assertion['clientDataJSON']),
                AuthenticatorData(assertion['authenticatorData']),
                assertion['signature'])
            regenerate_session()
            login_user(user)
            return redirect_after_login()

        except (KeyError, ValueError) as e:
            current_app.logger.exception(e)
            flash('Login error during Webauthn authentication.', 'error')

    return render_template('auth/login_webauthn.html', form=form)
Example #25
0
def assertion_response():
    app.logger.debug("/assertion/response")
    data = cbor.decode(request.get_data())
    app.logger.debug('post_data:\n%s', pp.pformat(data))
    credential_id = data['id']
    raw_id = data['rawId']
    client_data = ClientData(data['clientDataJSON'])
    app.logger.debug('client_data:\n%s', pp.pformat(client_data))
    auth_data = AuthenticatorData(data['authenticatorData'])
    app.logger.debug('auth_data:\n%s', pp.pformat(auth_data))
    signature = data['signature']
    credential = Credential.get(credential_id)
    if not credential:
        abort(404)
    credential_data = credential.to_credential_data()
    server.authenticate_complete(session.pop('state'), [credential_data],
                                 raw_id, client_data, auth_data, signature)
    # Checking signCount
    if auth_data.counter > credential.counter:
        # TODO: flask_ldapconn is not allow to store integer value
        credential.counter = str(auth_data.counter)
        credential.save()
    else:
        app.logger.warn('wrong counter: stored counter=%d but %d asserted',
                        credential.counter, auth_data.counter)
        abort(404)
    user = credential.user
    if not user:
        abort(404)
    login_user(user)
    return cbor.encode({'status': 'OK'})
Example #26
0
def authenticate_complete(request):
    data = cbor.decode(request.body)
    credential_id = data["credentialId"]
    client_data = ClientData(data["clientDataJSON"])
    auth_data = AuthenticatorData(data["authenticatorData"])
    signature = data["signature"]
    credentials = [
        row.credential for row in User.objects.get(
            pk=request.session['user']).fidocredential_set.all()
    ]

    fido_server.authenticate_complete(
        request.session.pop("state"),
        credentials,
        credential_id,
        client_data,
        auth_data,
        signature,
    )

    try:
        user = User.objects.get(pk=request.session.pop('user'))
    except User.DoesNotExist:
        raise Http404
    else:
        # If we're here, we've already confirmed the user has the
        # username and the password.
        login(request, user)

    return HttpResponse(
        cbor.encode({"status": "OK"}),
        content_type='application/cbor',
    )
Example #27
0
def authenticate_complete(request):
    server = get_server()
    data = cbor.decode(request.body)
    credential_id = data['credentialId']
    client_data = ClientData(data['clientDataJSON'])
    auth_data = AuthenticatorData(data['authenticatorData'])
    signature = data['signature']

    cred = server.authenticate_complete(request.session.pop('fido_state'),
                                        get_user_credentials(request),
                                        credential_id, client_data, auth_data,
                                        signature)

    keys = UserKey.objects.filter(
        user=request.user,
        key_type=KEY_TYPE_FIDO2,
        enabled=True,
    )

    for key in keys:
        if AttestedCredentialData(websafe_decode(
                key.properties["device"])).credential_id == cred.credential_id:
            write_session(request, key)
            res = login(request)
            return JsonResponse({'status': "OK", "redirect": res["location"]})

    return JsonResponse({'status': "err"})
Example #28
0
    def test_parse_bytes(self):
        info = Info.from_dict(cbor.decode(_INFO))

        self.assertEqual(info.versions, ["U2F_V2", "FIDO_2_0"])
        self.assertEqual(info.extensions, ["uvm", "hmac-secret"])
        self.assertEqual(info.aaguid, _AAGUID)
        self.assertEqual(info.options, {
            "rk": True,
            "up": True,
            "plat": False,
            "clientPin": False
        })
        self.assertEqual(info.max_msg_size, 1200)
        self.assertEqual(info.pin_uv_protocols, [1])
        assert info[0x01] == ["U2F_V2", "FIDO_2_0"]
        assert info[0x02] == ["uvm", "hmac-secret"]
        assert info[0x03] == _AAGUID
        assert info[0x04] == {
            "clientPin": False,
            "plat": False,
            "rk": True,
            "up": True,
        }
        assert info[0x05] == 1200
        assert info[0x06] == [1]
Example #29
0
def complete_reg(request):
    try:
        data = cbor.decode(request.body)

        client_data = ClientData(data['clientDataJSON'])
        att_obj = AttestationObject((data['attestationObject']))
        server = getServer()
        auth_data = server.register_complete(request.session['fido_state'],
                                             client_data, att_obj)
        encoded = websafe_encode(auth_data.credential_data)
        uk = User_Keys()
        uk.username = request.user.username
        uk.properties = {
            "device": encoded,
            "type": att_obj.fmt,
        }
        uk.key_type = "FIDO2"
        uk.save()
        return HttpResponse(simplejson.dumps({'status': 'OK'}))
    except Exception as exp:
        from raven.contrib.django.raven_compat.models import client
        import traceback
        client.captureException()
        return HttpResponse(
            simplejson.dumps({
                'status':
                'ERR',
                "message":
                "Error on server, please try again later"
            }))
def authenticate_complete():
    if not User.query.count():
        abort(404)

    try:
        data = cbor.decode(request.get_data())
        credential_id = data["credentialId"]
        client_data = ClientData(data["clientDataJSON"])
        auth_data = AuthenticatorData(data["authenticatorData"])
        signature = data["signature"]
    except IndexError:
        abort(400)

    user = User.get_by(credential_id)
    if user is None:
        abort(401)

    server.authenticate_complete(
        session.pop("state"),
        [user.create_data],
        credential_id,
        client_data,
        auth_data,
        signature,
    )
    return cbor.encode({"status": "OK"})