Ejemplo n.º 1
0
def _get_user_credentials(user):
    res = {}
    for this in user.credentials.filter(U2F).to_list():
        acd = AttestedCredentialData.from_ctap1(websafe_decode(this.keyhandle),
                                                websafe_decode(this.public_key))
        res[this.key] = {'u2f': {'version': this.version,
                                 'keyHandle': this.keyhandle,
                                 'publicKey': this.public_key,
                                 },
                         'webauthn': acd,
                         'app_id': this.app_id,
                         }
    for this in user.credentials.filter(Webauthn).to_list():
        keyhandle = this.keyhandle
        cred_data = base64.urlsafe_b64decode(this.credential_data.encode('ascii'))
        credential_data, rest = AttestedCredentialData.unpack_from(cred_data)
        version = 'webauthn'
        res[this.key] = {'u2f': {'version': version,
                                 'keyHandle': keyhandle,
                                 'publicKey': credential_data.public_key,
                                 },
                         'webauthn': credential_data,
                         'app_id': '',
                         }
    return res
Ejemplo n.º 2
0
    def test_sign_await_touch(self):
        client = U2fClient(None, APP_ID)
        client.ctap = mock.MagicMock()
        client.ctap.get_version.return_value = "U2F_V2"
        client.ctap.authenticate.side_effect = [
            ApduError(APDU.USE_NOT_SATISFIED),
            ApduError(APDU.USE_NOT_SATISFIED),
            ApduError(APDU.USE_NOT_SATISFIED),
            ApduError(APDU.USE_NOT_SATISFIED),
            SIG_DATA,
        ]

        event = Event()
        event.wait = mock.MagicMock()

        resp = client.sign(
            APP_ID,
            "challenge",
            [{"version": "U2F_V2", "keyHandle": "a2V5"}],
            event=event,
        )

        event.wait.assert_called()

        client.ctap.get_version.assert_called_with()
        client.ctap.authenticate.assert_called()
        client_param, app_param, key_handle = client.ctap.authenticate.call_args[0]

        self.assertEqual(client_param, sha256(websafe_decode(resp["clientData"])))
        self.assertEqual(app_param, sha256(APP_ID.encode()))
        self.assertEqual(key_handle, b"key")
        self.assertEqual(websafe_decode(resp["signatureData"]), SIG_DATA)
Ejemplo n.º 3
0
    def test_register_await_touch(self):
        client = U2fClient(None, APP_ID)
        client.ctap = mock.MagicMock()
        client.ctap.get_version.return_value = "U2F_V2"
        client.ctap.authenticate.side_effect = ApduError(APDU.WRONG_DATA)
        client.ctap.register.side_effect = [
            ApduError(APDU.USE_NOT_SATISFIED),
            ApduError(APDU.USE_NOT_SATISFIED),
            ApduError(APDU.USE_NOT_SATISFIED),
            ApduError(APDU.USE_NOT_SATISFIED),
            REG_DATA,
        ]

        event = Event()
        event.wait = mock.MagicMock()
        resp = client.register(
            APP_ID,
            [{"version": "U2F_V2", "challenge": "foobar"}],
            [{"version": "U2F_V2", "keyHandle": "a2V5"}],
            event=event,
        )

        event.wait.assert_called()

        client.ctap.get_version.assert_called_with()
        client.ctap.authenticate.assert_called_once()
        client.ctap.register.assert_called()

        client_param, app_param = client.ctap.register.call_args[0]
        self.assertEqual(sha256(websafe_decode(resp["clientData"])), client_param)
        self.assertEqual(websafe_decode(resp["registrationData"]), REG_DATA)
        self.assertEqual(sha256(APP_ID.encode()), app_param)
Ejemplo n.º 4
0
Archivo: models.py Proyecto: g10f/sso
 def credentials(cls, user):
     u2f_devices = cls.objects.filter(user=user, confirmed=True)
     return [
         AttestedCredentialData.create(
             aaguid=websafe_decode(d.aaguid),
             credential_id=websafe_decode(d.credential_id),
             public_key=CoseKey.parse(
                 cbor.decode(websafe_decode(d.public_key))))
         for d in u2f_devices
     ]
Ejemplo n.º 5
0
def makeSignature(challenge,cred_id,rp_id):
	allow_list = [{
    	'type': 'public-key',
    	'id': websafe_decode(cred_id)
	}]
	sys.stderr.write('\nTouch your authenticator device now...\n')
	# sys.stderr.write(challenge+"\n")
	# sys.stderr.write(cred_id+"\n")
	# sys.stderr.write(rp_id+"\n")

	try:
	    assertions, client_data = client.get_assertion(
	    	rp_id, challenge, allow_list)
	except ValueError:
	    assertions, client_data = client.get_assertion(
	    	rp_id, challenge, allow_list)

	sys.stderr.write('Credential authenticated!')

	assertion = assertions[0]  # Only one cred in allowList, only one response.
	# print('ASSERTIONS : ', assertions)

	# print()
	# print('CLIENT DATA:', client_data)
	# print()
	# print('ASSERTION DATA:', assertion)
	# print()

	return str(cbor.decode_from(assertion.signature))
Ejemplo n.º 6
0
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"}))
Ejemplo n.º 7
0
def authenticate_begin(username, **_):
    """
    Begin authentication procedure

    Variables:
    username     user name of the user you want to login with

    Arguments:
    None

    Data Block:
    None

    Result example:
    <WEBAUTHN_AUTHENTICATION_DATA>
    """
    user = STORAGE.user.get(username, as_obj=False)
    if not user:
        return make_api_response({'success': False}, err="Bad Request", status_code=400)

    session.pop('state', None)
    security_tokens = user.get('security_tokens', {}) or {}
    credentials = [AttestedCredentialData(websafe_decode(x)) for x in security_tokens.values()]

    auth_data, state = server.authenticate_begin(credentials)
    session['state'] = state

    return make_api_response(list(cbor.encode(auth_data)))
Ejemplo n.º 8
0
 def work(self, client):
     try:
         pin = None
         if client.info.options.get("clientPin"):
             # Prompt for PIN if needed
             pin = getpass("Please enter PIN: ")
         request_options = PublicKeyCredentialRequestOptions(
             challenge=utils.websafe_decode(self._challenge),
             rp_id=self._rp['id'],
             allow_credentials=self._allow_list)
         self._assertions, self._client_data = client.get_assertion(
             request_options,
             on_keepalive=self.on_keepalive,
             event=self._cancel,
             pin=pin)
     except ClientError as e:
         if e.code == ClientError.ERR.DEVICE_INELIGIBLE:
             self.ui.info(
                 'Security key is ineligible')  # TODO extract key info
             return
         elif e.code != ClientError.ERR.TIMEOUT:
             raise
         else:
             return
     self._cancel.set()
Ejemplo n.º 9
0
    def test_get_by_username(self):
        Authenticator.objects.create(user=self.user,
                                     attestation_data=ATTESTATION_OBJECT)

        response = self.client.get(self.url,
                                   data={'username': self.user.username})

        self.assertEqual(response.status_code, 200)
        # Check response
        state = self.client.session[FIDO2_REQUEST_SESSION_KEY]
        challenge = websafe_decode(state['challenge'])
        fido2_request = {
            'publicKey': {
                'rpId': 'testserver',
                'challenge': base64.b64encode(challenge).decode('utf-8'),
                'allowCredentials': [{
                    'id': CREDENTIAL_ID,
                    'type': 'public-key'
                }],
                'timeout': 30000
            }
        }
        if fido2.__version__ < '0.8':
            fido2_request['publicKey']['userVerification'] = 'preferred'
        self.assertEqual(response.json(), fido2_request)
Ejemplo n.º 10
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"})
Ejemplo n.º 11
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"})
Ejemplo n.º 12
0
    def _build_factor_name(self, factor):
        """ Build the display name for a MFA factor based on the factor type"""
        if factor['provider'] == 'DUO':
            return factor['factorType'] + ": " + factor['provider'].capitalize()
        elif factor['factorType'] == 'push':
            return "Okta Verify App: " + factor['profile']['deviceType'] + ": " + factor['profile']['name']
        elif factor['factorType'] == 'sms':
            return factor['factorType'] + ": " + factor['profile']['phoneNumber']
        elif factor['factorType'] == 'call':
            return factor['factorType'] + ": " + factor['profile']['phoneNumber']
        elif factor['factorType'] == 'token:software:totp':
            return factor['factorType'] + "( " + factor['provider'] + " ) : " + factor['profile']['credentialId']
        elif factor['factorType'] == 'token':
            return factor['factorType'] + ": " + factor['profile']['credentialId']
        elif factor['factorType'] == 'u2f':
            return factor['factorType'] + ": " + factor['factorType']
        elif factor['factorType'] == 'webauthn':
            factor_name = None
            try:
                registered_authenticators = RegisteredAuthenticators(self.ui)
                credential_id = websafe_decode(factor['profile']['credentialId'])
                factor_name = registered_authenticators.get_authenticator_user(credential_id)
            except Exception:
                pass

            default_factor_name = factor['profile'].get('authenticatorName') or factor['factorType']
            factor_name = factor_name or default_factor_name

            return factor['factorType'] + ": " + factor_name
        elif factor['factorType'] == 'token:hardware':
            return factor['factorType'] + ": " + factor['provider']

        else:
            return "Unknown MFA type: " + factor['factorType']
Ejemplo n.º 13
0
 def try_enroll(
     self, enrollment_data, response_data, has_webauthn_register, device_name=None, state=None
 ):
     if has_webauthn_register:
         data = json.loads(response_data)
         client_data = ClientData(websafe_decode(data["response"]["clientDataJSON"]))
         att_obj = base.AttestationObject(websafe_decode(data["response"]["attestationObject"]))
         binding = self.webauthn_registration_server.register_complete(
             state, client_data, att_obj
         )
     else:
         data, cert = u2f.complete_registration(enrollment_data, response_data, self.u2f_facets)
         binding = dict(data)
     devices = self.config.setdefault("devices", [])
     devices.append(
         {"name": device_name or "Security Key", "ts": int(time()), "binding": binding}
     )
Ejemplo n.º 14
0
def okta_mfa_webauthn(conf, s, factor, state_token):
    # type: (Conf, requests.Session, Dict[str, str], str) -> Optional[Dict[str, Any]]
    if not have_fido:
        err('Need fido2 package(s) for webauthn. Consider doing `pip install fido2` (or similar)'
            )
    devices = list(CtapHidDevice.list_devices())
    if not devices:
        err('webauthn configured, but no U2F devices found')
    provider = factor.get('provider', '')
    log('mfa {0} challenge request [okta_url]'.format(provider))
    data = {'stateToken': state_token}
    _, _h, j = send_json_req(conf,
                             s,
                             'webauthn mfa challenge',
                             factor.get('url', ''),
                             data,
                             expected_url=conf.okta_url,
                             verify=conf.get_cert('okta_url', True))
    rfactor = j['_embedded']['factor']
    profile = rfactor['profile']
    purl = parse_url(conf.okta_url)
    origin = '{0}://{1}'.format(purl[0], purl[1])
    challenge = rfactor['_embedded']['challenge']['challenge']
    credentialId = websafe_decode(profile['credentialId'])
    allow_list = [{'type': 'public-key', 'id': credentialId}]
    for dev in devices:
        client = Fido2Client(dev, origin)
        print('!!! Touch the flashing U2F device to authenticate... !!!')
        try:
            result = client.get_assertion(purl[1], challenge, allow_list)
            dbg(conf.debug, 'assertion.result', result)
            break
        except Exception:
            traceback.print_exc(file=sys.stderr)
            result = None
    if not result:
        return None
    assertion, client_data = result[0][0], result[
        1]  # only one cred in allowList, so only one response.
    data = {
        'stateToken':
        state_token,
        'clientData':
        to_n((base64.b64encode(client_data)).decode('ascii')),
        'signatureData':
        to_n((base64.b64encode(assertion.signature)).decode('ascii')),
        'authenticatorData':
        to_n((base64.b64encode(assertion.auth_data)).decode('ascii'))
    }
    log('mfa {0} signature request [okta_url]'.format(provider))
    _, _h, j = send_json_req(conf,
                             s,
                             'uf2 mfa signature',
                             j['_links']['next']['href'],
                             data,
                             expected_url=conf.okta_url,
                             verify=conf.get_cert('okta_url', True))
    return j
Ejemplo n.º 15
0
    def test_sign(self):
        client = U2fClient(None, APP_ID)
        client.ctap = mock.MagicMock()
        client.ctap.get_version.return_value = "U2F_V2"
        client.ctap.authenticate.return_value = SIG_DATA

        resp = client.sign(
            APP_ID, "challenge", [{"version": "U2F_V2", "keyHandle": "a2V5"}]
        )

        client.ctap.get_version.assert_called_with()
        client.ctap.authenticate.assert_called_once()
        client_param, app_param, key_handle = client.ctap.authenticate.call_args[0]

        self.assertEqual(client_param, sha256(websafe_decode(resp["clientData"])))
        self.assertEqual(app_param, sha256(APP_ID.encode()))
        self.assertEqual(key_handle, b"key")
        self.assertEqual(websafe_decode(resp["signatureData"]), SIG_DATA)
Ejemplo n.º 16
0
 def test_websafe_decode(self):
     self.assertEqual(websafe_decode(b''), b'')
     self.assertEqual(websafe_decode(b'Zg'), b'f')
     self.assertEqual(websafe_decode(b'Zm8'), b'fo')
     self.assertEqual(websafe_decode(b'Zm9v'), b'foo')
     self.assertEqual(websafe_decode(b'Zm9vYg'), b'foob')
     self.assertEqual(websafe_decode(b'Zm9vYmE'), b'fooba')
     self.assertEqual(websafe_decode(b'Zm9vYmFy'), b'foobar')
Ejemplo n.º 17
0
 def test_websafe_decode(self):
     self.assertEqual(websafe_decode(b""), b"")
     self.assertEqual(websafe_decode(b"Zg"), b"f")
     self.assertEqual(websafe_decode(b"Zm8"), b"fo")
     self.assertEqual(websafe_decode(b"Zm9v"), b"foo")
     self.assertEqual(websafe_decode(b"Zm9vYg"), b"foob")
     self.assertEqual(websafe_decode(b"Zm9vYmE"), b"fooba")
     self.assertEqual(websafe_decode(b"Zm9vYmFy"), b"foobar")
Ejemplo n.º 18
0
    def test_get(self):
        self.client.force_login(self.user)

        response = self.client.get(self.url)

        self.assertEqual(response.status_code, 200)
        # Check response
        state = self.client.session[FIDO2_REQUEST_SESSION_KEY]
        challenge = websafe_decode(state['challenge'])
        self.assertEqual(response.json(), self._get_fido2_request(challenge, []))
Ejemplo n.º 19
0
def get_user_credentials(request):
    return [
        AttestedCredentialData(websafe_decode(uk.properties["device"]))
        for uk in UserKey.objects.filter(
            user=request.user,
            key_type=KEY_TYPE_FIDO2,
            properties__contains=f'"domain":"{request.get_host()}"',
            enabled=True,
        )
    ]
Ejemplo n.º 20
0
 def validate_response(self, request: Request, challenge, response):
     try:
         credentials = []
         for device in self.get_u2f_devices():
             if type(device) == AuthenticatorData:
                 credentials.append(device.credential_data)
             else:
                 credentials.append(create_credential_object(device))
         self.webauthn_authentication_server.authenticate_complete(
             state=request.session["webauthn_authentication_state"],
             credentials=credentials,
             credential_id=websafe_decode(response["keyHandle"]),
             client_data=ClientData(websafe_decode(response["clientData"])),
             auth_data=AuthenticatorData(
                 websafe_decode(response["authenticatorData"])),
             signature=websafe_decode(response["signatureData"]),
         )
     except (InvalidSignature, InvalidKey, StopIteration):
         return False
     return True
Ejemplo n.º 21
0
def forwards_func(apps, schema_editor):
    # We get the model from the versioned app registry;
    U2FDevice = apps.get_model("sso_auth", "U2FDevice")
    db_alias = schema_editor.connection.alias
    for d in U2FDevice.objects.using(db_alias).all():
        credential_data = AttestedCredentialData.from_ctap1(websafe_decode(d.key_handle), websafe_decode(d.public_key_old))

        d.public_key = websafe_encode(cbor.encode(credential_data.public_key))
        d.aaguid = websafe_encode(credential_data.aaguid)
        d.credential_id = websafe_encode(credential_data.credential_id)
        d.save()
Ejemplo n.º 22
0
    def test_get_registered_keys(self):
        Authenticator.objects.create(user=self.user, attestation_data=ATTESTATION_OBJECT)
        self.client.force_login(self.user)

        response = self.client.get(self.url)

        self.assertEqual(response.status_code, 200)
        # Check response contains the same request as session
        state = self.client.session[FIDO2_REQUEST_SESSION_KEY]
        challenge = websafe_decode(state['challenge'])
        credentials = [{'id': CREDENTIAL_ID, 'type': 'public-key'}]
        self.assertEqual(response.json(), self._get_fido2_request(challenge, credentials))
Ejemplo n.º 23
0
    def __init__(self, ui, okta_org_url, challenge, credential_id=None, timeout_ms=30_000):
        """
        :param okta_org_url: Base URL string for Okta IDP.
        :param challenge: Challenge
        :param credential_id: FIDO credential ID
        """
        self.ui = ui
        self._okta_org_url = okta_org_url
        self._clients = None
        self._has_prompted = False
        self._challenge = websafe_decode(challenge)
        self._timeout_ms = timeout_ms
        self._event = Event()
        self._assertions = None
        self._client_data = None
        self._rp = {'id': okta_org_url[8:], 'name': okta_org_url[8:]}

        if credential_id:
            self._allow_list = [
                PublicKeyCredentialDescriptor(PublicKeyCredentialType.PUBLIC_KEY, websafe_decode(credential_id))
            ]
Ejemplo n.º 24
0
def u2f_complete():
    data = cbor.decode(request.get_data())
    reg_data = RegistrationData.from_b64(data["registrationData"])
    print("clientData", websafe_decode(data["clientData"]))
    print("U2F RegistrationData:", reg_data)
    att_obj = AttestationObject.from_ctap1(sha256(b"https://localhost:5000"),
                                           reg_data)
    print("AttestationObject:", att_obj)

    auth_data = att_obj.auth_data

    credentials.append(auth_data.credential_data)
    print("REGISTERED U2F CREDENTIAL:", auth_data.credential_data)
    return cbor.encode({"status": "OK"})
Ejemplo n.º 25
0
    def test_register(self):
        client = U2fClient(None, APP_ID)
        client.ctap = mock.MagicMock()
        client.ctap.get_version.return_value = 'U2F_V2'
        client.ctap.authenticate.side_effect = ApduError(APDU.WRONG_DATA)
        client.ctap.register.return_value = REG_DATA

        resp = client.register(APP_ID, [{
            'version': 'U2F_V2',
            'challenge': 'foobar'
        }], [{
            'version': 'U2F_V2',
            'keyHandle': 'a2V5'
        }])

        client.ctap.get_version.assert_called_with()
        client.ctap.authenticate.assert_called_once()
        client.ctap.register.assert_called_once()

        client_param, app_param = client.ctap.register.call_args[0]
        self.assertEqual(sha256(websafe_decode(resp['clientData'])),
                         client_param)
        self.assertEqual(websafe_decode(resp['registrationData']), REG_DATA)
        self.assertEqual(sha256(APP_ID.encode()), app_param)
Ejemplo n.º 26
0
 def __init__(self, ui, appId, nonce, credentialId):
     """
     :param appId: Base URL string for Okta IDP e.g. https://xxxx.okta.com'
     :param nonce: nonce
     :param credentialid: credentialid
     """
     self.ui = ui
     self._clients = None
     self._has_prompted = False
     self._cancel = Event()
     self._credentialId = websafe_decode(credentialId)
     self._appId = sha256(appId.encode())
     self._version = 'U2F_V2'
     self._signature = None
     self._clientData = json.dumps({
         "challenge": nonce,
         "origin": appId,
         "typ": "navigator.id.getAssertion"
     }).encode()
     self._nonce = sha256(self._clientData)
Ejemplo n.º 27
0
def register_begin(**kwargs):
    """
    Begin registration of a security token

    Variables:
    None

    Arguments:
    None

    Data Block:
    None

    Result example:
    <WEBAUTHN_REGISTRATION_DATA>
    """
    uname = kwargs['user']['uname']
    user = STORAGE.user.get(uname, as_obj=False)

    if user['otp_sk'] is None:
        return make_api_response(None, err="OTP must be setup before adding security tokens", status_code=403)

    session.pop('state', None)
    security_tokens = user.get('security_tokens', {}) or {}

    registration_data, state = server.register_begin(
        dict(
            id=user['uname'].encode('utf-8'),
            name=user['uname'],
            displayName=user['name'],
            icon=f"https://{config.ui.fqdn}/static/images/favicon.ico"
        ),
        credentials=[AttestedCredentialData(websafe_decode(x)) for x in security_tokens.values()]
    )

    session['state'] = state

    return make_api_response(list(cbor.encode(registration_data)))
Ejemplo n.º 28
0
    def test_get(self):
        Authenticator.objects.create(user=self.user,
                                     attestation_data=ATTESTATION_OBJECT)
        session = self.client.session
        session[AUTHENTICATION_USER_SESSION_KEY] = self.user.pk
        session.save()

        response = self.client.get(self.url)

        self.assertEqual(response.status_code, 200)
        # Check response
        state = self.client.session[FIDO2_REQUEST_SESSION_KEY]
        challenge = websafe_decode(state['challenge'])
        fido2_request = {
            'publicKey': {
                'rpId': 'testserver',
                'challenge': base64.b64encode(challenge).decode('utf-8'),
                'allowCredentials': [{
                    'id': CREDENTIAL_ID,
                    'type': 'public-key'
                }]
            }
        }
        self.assertEqual(response.json(), fido2_request)
Ejemplo n.º 29
0
def getUserCredentials(username):
    credentials = []
    for uk in User_Keys.objects.filter(username=username, key_type="FIDO2"):
        credentials.append(
            AttestedCredentialData(websafe_decode(uk.properties["device"])))
    return credentials
Ejemplo n.º 30
0
argv = sys.argv[1:]
try:
    opts, args = getopt.getopt(argv, "i:n:s:c:", [])
except getopt.GetoptError:
    print('test.py -i <inputfile> -o <outputfile>')
    sys.exit(2)
for opt, arg in opts:
    if opt in ("-i"):
        user_id = arg
    elif opt in ("-n"):
        user_name = arg
    elif opt in ("-s"):
        salt = bytes(arg, encoding='utf-8')
    elif opt in ("-c"):
        credential = AttestedCredentialData(websafe_decode(arg))

try:
    from fido2.pcsc import CtapPcscDevice
except ImportError:
    CtapPcscDevice = None


def enumerate_devices():
    for dev in CtapHidDevice.list_devices():
        yield dev
    if CtapPcscDevice:
        for dev in CtapPcscDevice.list_devices():
            yield dev

Ejemplo n.º 31
0
def authenticate_complete(request):
    try:
        credentials = []
        username = request.session.get("base_username", request.user.username)
        server = getServer()
        credentials = getUserCredentials(username)
        data = cbor.decode(request.body)
        credential_id = data['credentialId']
        client_data = ClientData(data['clientDataJSON'])
        auth_data = AuthenticatorData(data['authenticatorData'])
        signature = data['signature']
        try:
            cred = server.authenticate_complete(
                request.session.pop('fido_state'), credentials, credential_id,
                client_data, auth_data, signature)
        except ValueError:
            return HttpResponse(simplejson.dumps({
                'status':
                "ERR",
                "message":
                "Wrong challenge received, make sure that this is your security and try again."
            }),
                                content_type="application/json")
        except Exception as excep:
            try:
                from raven.contrib.django.raven_compat.models import client
                client.captureException()
            except:
                pass
            return HttpResponse(simplejson.dumps({
                'status': "ERR",
                "message": excep.message
            }),
                                content_type="application/json")

        if request.session.get("mfa_recheck", False):
            import time
            request.session["mfa"]["rechecked_at"] = time.time()
            return HttpResponse(simplejson.dumps({'status': "OK"}),
                                content_type="application/json")
        else:
            import random
            keys = User_Keys.objects.filter(username=username,
                                            key_type="FIDO2",
                                            enabled=1)
            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", 'id': k.id}
                    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
                    try:
                        authenticated = request.user.is_authenticated
                    except:
                        authenticated = request.user.is_authenticated()
                    if not authenticated:
                        res = login(request)
                        if not "location" in res: return reset_cookie(request)
                        return HttpResponse(simplejson.dumps({
                            'status':
                            "OK",
                            "redirect":
                            res["location"]
                        }),
                                            content_type="application/json")
                    return HttpResponse(simplejson.dumps({'status': "OK"}),
                                        content_type="application/json")
    except Exception as exp:
        return HttpResponse(simplejson.dumps({
            'status': "ERR",
            "message": exp.message
        }),
                            content_type="application/json")