コード例 #1
0
    def test_client_data(self):
        client_data = ClientData(
            b'{"typ":"navigator.id.finishEnrollment","challenge":"vqrS6WXDe1JUs5_c3i4-LkKIHRr-3XVb3azuA5TifHo","cid_pubkey":{"kty":"EC","crv":"P-256","x":"HzQwlfXX7Q4S5MtCCnZUNBw3RMzPO9tOyWjBqRl4tJ8","y":"XVguGFLIZx1fXg3wNqfdbn75hi4-_7-BxhMljw42Ht4"},"origin":"http://example.com"}'
        )  # noqa

        self.assertEqual(
            client_data.hash,
            a2b_hex(
                '4142d21c00d94ffb9d504ada8f99b721f4b191ae4e37ca0140f696b6983cfacb'
            ))  # noqa
        self.assertEqual(client_data.get('origin'), 'http://example.com')

        self.assertEqual(client_data, ClientData.from_b64(client_data.b64))

        self.assertEqual(
            client_data.data, {
                'typ': 'navigator.id.finishEnrollment',
                'challenge': 'vqrS6WXDe1JUs5_c3i4-LkKIHRr-3XVb3azuA5TifHo',
                'cid_pubkey': {
                    'kty': 'EC',
                    'crv': 'P-256',
                    'x': 'HzQwlfXX7Q4S5MtCCnZUNBw3RMzPO9tOyWjBqRl4tJ8',
                    'y': 'XVguGFLIZx1fXg3wNqfdbn75hi4-_7-BxhMljw42Ht4'
                },
                'origin': 'http://example.com'
            })
コード例 #2
0
    def test_client_data(self):
        client_data = ClientData(
            b'{"typ":"navigator.id.finishEnrollment","challenge":"vqrS6WXDe1JUs5_c3i4-LkKIHRr-3XVb3azuA5TifHo","cid_pubkey":{"kty":"EC","crv":"P-256","x":"HzQwlfXX7Q4S5MtCCnZUNBw3RMzPO9tOyWjBqRl4tJ8","y":"XVguGFLIZx1fXg3wNqfdbn75hi4-_7-BxhMljw42Ht4"},"origin":"http://example.com"}'  # noqa E501
        )

        self.assertEqual(
            client_data.hash,
            a2b_hex(
                "4142d21c00d94ffb9d504ada8f99b721f4b191ae4e37ca0140f696b6983cfacb"
            ),
        )
        self.assertEqual(client_data.get("origin"), "http://example.com")

        self.assertEqual(client_data, ClientData.from_b64(client_data.b64))

        self.assertEqual(
            client_data.data,
            {
                "typ": "navigator.id.finishEnrollment",
                "challenge": "vqrS6WXDe1JUs5_c3i4-LkKIHRr-3XVb3azuA5TifHo",
                "cid_pubkey": {
                    "kty": "EC",
                    "crv": "P-256",
                    "x": "HzQwlfXX7Q4S5MtCCnZUNBw3RMzPO9tOyWjBqRl4tJ8",
                    "y": "XVguGFLIZx1fXg3wNqfdbn75hi4-_7-BxhMljw42Ht4",
                },
                "origin": "http://example.com",
            },
        )
コード例 #3
0
    def test_u2f_facets(self):
        rp = RelyingParty("example.com", "Example",
                          "http://example.com/icon.svg")
        app_id = b"https://www.example.com/facets.json"

        def verify_u2f_origin(origin):
            return origin in ("https://oauth.example.com",
                              "https://admin.example.com")

        server = U2FFido2Server(app_id=app_id.decode("ascii"),
                                rp=rp,
                                verify_u2f_origin=verify_u2f_origin)

        state = {
            "challenge": "GAZPACHO!",
            "user_verification": USER_VERIFICATION.PREFERRED,
        }
        client_data_dict = {
            "challenge": "GAZPACHO!",
            "origin": "https://oauth.example.com",
            "type": WEBAUTHN_TYPE.GET_ASSERTION,
        }
        client_data = ClientData(json.dumps(client_data_dict).encode("utf-8"))

        param = b"TOMATO GIVES "

        device = U2FDevice(param, app_id)
        auth_data = AttestedCredentialData.from_ctap1(param,
                                                      device.public_key_bytes)
        authenticator_data, signature = device.sign(client_data)

        server.authenticate_complete(
            state,
            [auth_data],
            device.credential_id,
            client_data,
            authenticator_data,
            signature,
        )

        # Now with something not whitelisted
        client_data_dict = {
            "challenge": "GAZPACHO!",
            "origin": "https://publicthingy.example.com",
            "type": WEBAUTHN_TYPE.GET_ASSERTION,
        }
        client_data = ClientData(json.dumps(client_data_dict).encode("utf-8"))

        authenticator_data, signature = device.sign(client_data)

        with six.assertRaisesRegex(self, ValueError, "Invalid origin in "
                                   "ClientData."):
            server.authenticate_complete(
                state,
                [auth_data],
                device.credential_id,
                client_data,
                authenticator_data,
                signature,
            )
コード例 #4
0
    def test_u2f_facets(self):
        rp = RelyingParty('example.com', 'Example',
                          'http://example.com/icon.svg')
        app_id = b'https://www.example.com/facets.json'

        def verify_u2f_origin(origin):
            return origin in ('https://oauth.example.com',
                              'https://admin.example.com')

        server = U2FFido2Server(app_id=app_id.decode('ascii'),
                                rp=rp,
                                verify_u2f_origin=verify_u2f_origin)

        state = {
            'challenge': 'GAZPACHO!',
            'user_verification': USER_VERIFICATION.PREFERRED
        }
        client_data_dict = {
            'challenge': 'GAZPACHO!',
            'origin': 'https://oauth.example.com',
            'type': WEBAUTHN_TYPE.GET_ASSERTION
        }
        client_data = ClientData(json.dumps(client_data_dict).encode('utf-8'))

        param = b'TOMATO GIVES '

        device = U2FDevice(param, app_id)
        auth_data = AttestedCredentialData.from_ctap1(param,
                                                      device.public_key_bytes)
        authenticator_data, signature = device.sign(client_data)

        server.authenticate_complete(state, [auth_data], device.credential_id,
                                     client_data, authenticator_data,
                                     signature)

        # Now with something not whitelisted
        client_data_dict = {
            'challenge': 'GAZPACHO!',
            'origin': 'https://publicthingy.example.com',
            'type': WEBAUTHN_TYPE.GET_ASSERTION
        }
        client_data = ClientData(json.dumps(client_data_dict).encode('utf-8'))

        authenticator_data, signature = device.sign(client_data)

        with six.assertRaisesRegex(self, ValueError, 'Invalid origin in '
                                   'ClientData.'):
            server.authenticate_complete(state, [auth_data],
                                         device.credential_id, client_data,
                                         authenticator_data, signature)
コード例 #5
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)
コード例 #6
0
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"})
コード例 #7
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',
    )
コード例 #8
0
    def test_authenticate_complete_invalid_signature(self):
        rp = RelyingParty("example.com", "Example")
        server = Fido2Server(rp)

        state = {
            "challenge": "GAZPACHO!",
            "user_verification": USER_VERIFICATION.PREFERRED,
        }
        client_data_dict = {
            "challenge": "GAZPACHO!",
            "origin": "https://example.com",
            "type": WEBAUTHN_TYPE.GET_ASSERTION,
        }
        client_data = ClientData(json.dumps(client_data_dict).encode("utf-8"))
        _AUTH_DATA = a2b_hex(
            "A379A6F6EEAFB9A55E378C118034E2751E682FAB9F2D30AB13D2125586CE1947010000001D"
        )
        with six.assertRaisesRegex(self, ValueError, "Invalid signature."):
            server.authenticate_complete(
                state,
                [AttestedCredentialData(_ATT_CRED_DATA)],
                _CRED_ID,
                client_data,
                AuthenticatorData(_AUTH_DATA),
                b"INVALID",
            )
コード例 #9
0
ファイル: __init__.py プロジェクト: NereuOliveira/sner4
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)
コード例 #10
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"}
コード例 #11
0
    def test_authenticate(self):
        ctap = CTAP1(mock.MagicMock())
        ctap.device.call.return_value = a2b_hex('0100000001304402204b5f0cd17534cedd8c34ee09570ef542a353df4436030ce43d406de870b847780220267bb998fac9b7266eb60e7cb0b5eabdfd5ba9614f53c7b22272ec10047a923f') + b'\x90\x00'  # noqa

        client_param = a2b_hex(b'ccd6ee2e47baef244d49a222db496bad0ef5b6f93aa7cc4d30c4821b3b9dbc57')  # noqa
        app_param = a2b_hex(b'4b0be934baebb5d12d26011b69227fa5e86df94e7d94aa2949a89f2d493992ca')  # noqa
        key_handle = b'\3'*64

        resp = ctap.authenticate(client_param, app_param, key_handle)
        ctap.device.call.assert_called_with(0x03, b'\0\2\3\0\0\0\x81' +
                                            client_param + app_param + b'\x40' +
                                            key_handle + b'\0\0')

        self.assertEqual(resp.user_presence, 1)
        self.assertEqual(resp.counter, 1)
        self.assertEqual(resp.signature, a2b_hex('304402204b5f0cd17534cedd8c34ee09570ef542a353df4436030ce43d406de870b847780220267bb998fac9b7266eb60e7cb0b5eabdfd5ba9614f53c7b22272ec10047a923f'))  # noqa

        public_key = a2b_hex(b'04d368f1b665bade3c33a20f1e429c7750d5033660c019119d29aa4ba7abc04aa7c80a46bbe11ca8cb5674d74f31f8a903f6bad105fb6ab74aefef4db8b0025e1d')  # noqa
        client_data = ClientData(b'{"typ":"navigator.id.getAssertion","challenge":"opsXqUifDriAAmWclinfbS0e-USY0CgyJHe_Otd7z8o","cid_pubkey":{"kty":"EC","crv":"P-256","x":"HzQwlfXX7Q4S5MtCCnZUNBw3RMzPO9tOyWjBqRl4tJ8","y":"XVguGFLIZx1fXg3wNqfdbn75hi4-_7-BxhMljw42Ht4"},"origin":"http://example.com"}')  # noqa
        resp.verify(app_param, client_param, public_key)

        key_handle = b'\4'*8
        ctap.authenticate(client_param, app_param, key_handle)
        ctap.device.call.assert_called_with(0x03, b'\0\2\3\0\0\0\x49' +
                                            client_param + app_param + b'\x08' +
                                            key_handle + b'\0\0')

        ctap.authenticate(client_param, app_param, key_handle, True)
        ctap.device.call.assert_called_with(0x03, b'\0\2\7\0\0\0\x49' +
                                            client_param + app_param + b'\x08' +
                                            key_handle + b'\0\0')
コード例 #12
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"}
コード例 #13
0
    def verify_token(self, token):
        data = cbor2.loads(base64.b64decode(token["token"]))
        credential_id = data["credentialId"]
        client_data = ClientData(data["clientDataJSON"])
        auth_data = AuthenticatorData(data["authenticatorData"])
        signature = data["signature"]
        state = token["state"]
        domain = token["domain"]

        credentials_query = Fido2Device.objects.filter(user=self.user)
        credentials = [
            AttestedCredentialData(cbor2.loads(c.authenticator_data))
            for c in credentials_query
        ]

        rp = PublicKeyCredentialRpEntity(domain, settings.FIDO2_RP_NAME)
        fido2 = Fido2Server(rp)

        try:
            fido2.authenticate_complete(
                state,
                credentials,
                credential_id,
                client_data,
                auth_data,
                signature,
            )

            return True
        except ValueError:
            logger.exception("Error in FIDO2 final authentication")
            return False
コード例 #14
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
コード例 #15
0
ファイル: FIDO2.py プロジェクト: changchiajung/fingerprint
def authenticate_complete(request):
    credentials = []
    username=request.session.get("base_username",request.user.username)
    server=getServer()
    credentials=getUserCredentials(username)
    data = cbor.loads(request.body)[0]
    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
    )
    keys = User_Keys.objects.filter(username=username, key_type="FIDO2",enabled=1)
    import random
    for k in keys:
        if AttestedCredentialData(websafe_decode(k.properties["device"])).credential_id == cred.credential_id:
            k.last_used = timezone.now()
            k.save()
            mfa = {"verified": True, "method": "FIDO2"}
            if getattr(settings, "MFA_RECHECK", False):
                mfa["next_check"] = int((datetime.datetime.now()+ datetime.timedelta(
                seconds=random.randint(settings.MFA_RECHECK_MIN, settings.MFA_RECHECK_MAX))).strftime("%s"))
            request.session["mfa"] = mfa
            res=login(request)
            return HttpResponse(simplejson.dumps({'status':"OK","redirect":res["location"]}),content_type="application/json")
    return HttpResponse(simplejson.dumps({'status': "err"}))
コード例 #16
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",
        })
コード例 #17
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"})
コード例 #18
0
ファイル: views.py プロジェクト: cvolny/django-restauthn
 def post(self, request, format=None):
     logger.info(f'webauthn-register.{format}: {request.data}')
     clientData = request.data.get("clientDataJSON", None)
     attestationData = request.data.get("attestationObject", None)
     if clientData and attestationData:
         client = ClientData(clientData)
         attestation = AttestationObject(attestationData)
         state = request.session.get(settings.FIDO2.SESSION_STATE_KEY)
         if client and attestation and state:
             try:
                 auth_data = SERVER.register_complete(
                     state, client, attestation)
                 cred_data = auth_data.credential_data
                 authenticator = Authenticator.objects.create(
                     user=request.user, credential=cred_data)
                 logger.info(
                     f'register fido2 for "{request.user.username}": {cred_data.credential_id}'
                 )
                 return Response(
                     dict(detail="OK", user=getuser(request.user)))
             except Exception as e:
                 logger.warn(
                     f'Exception webauthn-register.{format} {request.user.username}: {e}'
                 )
     return Response(dict(detail="Bad request"),
                     status=status.HTTP_400_BAD_REQUEST)
コード例 #19
0
    def test_u2f(self):
        rp = RelyingParty("example.com", "Example",
                          "http://example.com/icon.svg")
        app_id = b"https://example.com"
        server = U2FFido2Server(app_id=app_id.decode("ascii"), rp=rp)

        state = {
            "challenge": "GAZPACHO!",
            "user_verification": USER_VERIFICATION.PREFERRED,
        }
        client_data_dict = {
            "challenge": "GAZPACHO!",
            "origin": "https://example.com",
            "type": WEBAUTHN_TYPE.GET_ASSERTION,
        }
        client_data = ClientData(json.dumps(client_data_dict).encode("utf-8"))

        param = b"TOMATO GIVES "

        device = U2FDevice(param, app_id)
        auth_data = AttestedCredentialData.from_ctap1(param,
                                                      device.public_key_bytes)
        authenticator_data, signature = device.sign(client_data)

        server.authenticate_complete(
            state,
            [auth_data],
            device.credential_id,
            client_data,
            authenticator_data,
            signature,
        )
コード例 #20
0
ファイル: webauthn.py プロジェクト: lamlion/eduid-webapp
def registration_complete(user, credential_id, attestation_object, client_data, description):
    security_user = SecurityUser.from_user(user, current_app.private_userdb)
    server = get_webauthn_server(current_app.config.fido2_rp_id)
    att_obj = AttestationObject(urlsafe_b64decode(attestation_object))
    cdata_obj = ClientData(urlsafe_b64decode(client_data))
    state = session['_webauthn_state_']
    auth_data = server.register_complete(state, cdata_obj, att_obj)

    cred_data = auth_data.credential_data
    current_app.logger.debug('Proccessed Webauthn credential data: {}.'.format(cred_data))

    credential = Webauthn.from_dict(
        dict(
            keyhandle=credential_id,
            credential_data=base64.urlsafe_b64encode(cred_data).decode('ascii'),
            app_id=current_app.config.fido2_rp_id,
            attest_obj=base64.b64encode(attestation_object.encode('utf-8')).decode('ascii'),
            description=description,
            created_by='security',
        )
    )

    security_user.credentials.add(credential)
    save_and_sync_user(security_user)
    current_app.stats.count(name='webauthn_register_complete')
    current_app.logger.info('User {} has completed registration of a webauthn token'.format(security_user))
    credentials = compile_credential_list(security_user)
    return success_response(payload=dict(credentials=credentials), message=SecurityMsg.webauthn_success)
コード例 #21
0
def authenticate():
    global credential, last_challenge
    if not credential:
        return HTML.format(content='No credential registered!')

    if request.method == 'POST':
        data = request.get_json(force=True)
        client_data = ClientData(from_js_array(data['clientData']))
        auth_data = AuthenticatorData(from_js_array(data['authenticatorData']))
        signature = from_js_array(data['signature'])
        print('clientData', client_data)
        print('AuthenticatorData', auth_data)

        # Verify the challenge
        if client_data.challenge != last_challenge:
            raise ValueError('Challenge mismatch!')

        # Verify the signature
        credential.public_key.verify(auth_data + client_data.hash, signature)
        print('ASSERTION OK')
        return 'OK'

    last_challenge = os.urandom(32)
    return AUTH_HTML.format(challenge=to_js_array(last_challenge),
                            credential_id=to_js_array(
                                credential.credential_id))
コード例 #22
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",
        })
コード例 #23
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'})
コード例 #24
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()
コード例 #25
0
ファイル: views.py プロジェクト: osstech-jp/fido2-ldap-demo
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'})
コード例 #26
0
    def test_u2f(self):
        rp = RelyingParty('example.com', 'Example',
                          'http://example.com/icon.svg')
        app_id = b'https://example.com'
        server = U2FFido2Server(app_id=app_id.decode('ascii'), rp=rp)

        state = {
            'challenge': 'GAZPACHO!',
            'user_verification': USER_VERIFICATION.PREFERRED
        }
        client_data_dict = {
            'challenge': 'GAZPACHO!',
            'origin': 'https://example.com',
            'type': WEBAUTHN_TYPE.GET_ASSERTION
        }
        client_data = ClientData(json.dumps(client_data_dict).encode('utf-8'))

        param = b'TOMATO GIVES '

        device = U2FDevice(param, app_id)
        auth_data = AttestedCredentialData.from_ctap1(param,
                                                      device.public_key_bytes)
        authenticator_data, signature = device.sign(client_data)

        server.authenticate_complete(state, [auth_data], device.credential_id,
                                     client_data, authenticator_data,
                                     signature)
コード例 #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"})
コード例 #28
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"
            }))
コード例 #29
0
def complete_reg(request):
    try:
        data = cbor.loads(request.body)[0]

        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"
            }))
コード例 #30
0
    def _get_assertion_request(
        rp_id: str = 'pasten.com',
        client_data: Optional[ClientData] = None,
        allowed_cred_ids: Optional[List[bytes]] = None,
        user_verification_required=False,
    ) -> dict:

        client_data = client_data or ClientData.build(
            typ=WEBAUTHN_TYPE.GET_ASSERTION,
            origin=rp_id,
            challenge=websafe_encode(b'pasten-challenge'),
        )
        req = {
            CtapGetAssertionRequest.RP_ID_KEY: rp_id,
            CtapGetAssertionRequest.CLIENT_DATA_HASH_KEY: client_data.hash,
        }

        if user_verification_required:
            req[CtapGetAssertionRequest.OPTIONS_KEY] = {
                CtapOptions.USER_VERIFICATION: True
            }

        if allowed_cred_ids:
            req[CtapGetAssertionRequest.ALLOW_LIST_KEY] = [
                PublicKeyCredentialDescriptor(
                    PublicKeyCredentialType.PUBLIC_KEY, cred_id
                )
                for cred_id in allowed_cred_ids
            ]

        return req