def validate_2fa(name): form = forms.SignTokenForm() if form.validate_on_submit(): errorCode = json.loads(form.response.data)['errorCode'] if errorCode != 0: flash("Token authentication failed", "error") return redirect(url_for('select_2fa')) device, c, t = complete_authentication(session['u2f_sign'], form.response.data, app_id) if t != 1: flash("Token authentication failed", "error") return redirect(url_for('select_2fa')) # Log in the user user = load_user(session['user']) flask_login.login_user(user) flash("Login complete", "success") return redirect(url_for('index')) key = models.U2FCredentials.query.filter_by(owner=session['user'], name=name).first() sign = begin_authentication(app_id, [key.device]) session['u2f_sign'] = sign.json challenge = sign['challenge'] registeredKeys = json.loads(sign['registeredKeys'][0]) version = registeredKeys['version'] keyHandle = registeredKeys['keyHandle'] return render_template('validate_2fa.html', challenge=challenge, version=version, keyHandle=keyHandle, app_id=app_id, form=form, key=key)
def login(): devices = [doc['device'] for doc in DB.u2f.find()] u2f_enabled = True if devices else False if request.method == 'POST': csrf.protect() pwd = request.form.get('pass') if pwd and verify_pass(pwd): if devices: resp = json.loads(request.form.get('resp')) print(resp) try: u2f.complete_authentication(session['challenge'], resp) except ValueError as exc: print('failed', exc) abort(401) return finally: session['challenge'] = None session['logged_in'] = True return redirect(request.args.get('redirect') or '/admin') else: abort(401) payload = None if devices: payload = u2f.begin_authentication(ID, devices) session['challenge'] = payload return render_template( 'login.html', u2f_enabled=u2f_enabled, me=ME, payload=payload, )
def login(request): username = request.data.get('username') password = request.data.get('password') user = authenticate(username=username, password=password) if not user: return Response( {"error": "Login failed"}, status=HTTP_401_UNAUTHORIZED ) if user.u2f_key.exists(): if user.u2f_authentication_request.exists(): user.u2f_authentication_request.first().delete() serializer = U2FKeySerializer(user.u2f_key.first()) sign_request = u2f.begin_authentication( settings.APP_ID, [serializer.data]) U2FAuthenticationRequest.objects.create( user=user, body=json.dumps(sign_request)) return Response(sign_request.data_for_client) else: token, _ = Token.objects.get_or_create(user=user) return Response({"token": token.key})
def __init__(self, user, initial_device, request, **kwargs): """ `initial_device` is either the user's default device, or the backup device when the user chooses to enter a backup token. The token will be verified against all devices, it is not limited to the given device. """ super(AuthenticationTokenForm, self).__init__(**kwargs) self.user = user self.request = request self.initial_device = initial_device if request.META['HTTP_X_FORWARDED_HOST']: self.appId = '{scheme}://{host}'.format(scheme='https' if self.request.is_secure() else 'http', host=request.META['HTTP_X_FORWARDED_HOST']).rstrip('/') else: self.appId = '{scheme}://{host}'.format( scheme='https' if self.request.is_secure() else 'http', host=self.request.get_host()).rstrip('/') # YubiKey generates a OTP of 44 characters (not digits). So if the # user's primary device is a YubiKey, replace the otp_token # IntegerField with a CharField. if RemoteYubikeyDevice and YubikeyDevice and \ isinstance(initial_device, (RemoteYubikeyDevice, YubikeyDevice)): self.fields['otp_token'] = forms.CharField(label=_('YubiKey'), widget=forms.PasswordInput()) elif isinstance(initial_device, U2FDevice): self.fields['otp_token'] = forms.CharField(label=_('Token')) if self.data: self.sign_request = self.request.session['u2f_sign_request'] else: self.sign_request = u2f.begin_authentication(self.appId, [key.to_json() for key in user.u2f_keys.all()]) self.request.session['u2f_sign_request'] = self.sign_request
def sign(username): u2f_devices = [ d.properties["device"] for d in User_Keys.objects.filter(username=username, key_type="U2F") ] challenge = begin_authentication(settings.U2F_APPID, u2f_devices) return [challenge.json, simplejson.dumps(challenge.data_for_client)]
def activate(self, request: Request, is_webauthn_signin_ff_enabled): if not is_webauthn_signin_ff_enabled: challenge = dict(u2f.begin_authentication(self.u2f_app_id, self.get_u2f_devices())) # XXX: Upgrading python-u2flib-server to 5.0.0 changes the response # format. Our current js u2f library expects the old format, so # massaging the data to include the old `authenticateRequests` key here. authenticate_requests = [] for registered_key in challenge["registeredKeys"]: authenticate_requests.append( { "challenge": challenge["challenge"], "version": registered_key["version"], "keyHandle": registered_key["keyHandle"], "appId": registered_key["appId"], } ) challenge["authenticateRequests"] = authenticate_requests return ActivationChallengeResult(challenge=challenge) credentials = [] for device in self.get_u2f_devices(): if type(device) == AuthenticatorData: credentials.append(device.credential_data) else: credentials.append(create_credential_object(device)) challenge, state = self.webauthn_authentication_server.authenticate_begin( credentials=credentials ) request.session["webauthn_authentication_state"] = state return ActivationChallengeResult(challenge=cbor.encode(challenge["publicKey"]))
def sign(self, username): if username not in self.users: return json.dumps(False) user = self.users[username] challenge = begin_authentication(self.app_id, user.get('_u2f_devices_', [])) user['_u2f_challenge_'] = challenge.json return json.dumps(challenge.data_for_client)
def __init__(self, *args, **kwargs): super(KeyResponseForm, self).__init__(*args, **kwargs) if self.data: self.sign_request = self.request.session['u2f_sign_request'] else: self.sign_request = u2f.begin_authentication( self.appId, [d.to_json() for d in self.user.u2f_keys.all()]) self.request.session['u2f_sign_request'] = self.sign_request
def set_u2f_challenge(self): user_devices = [ud.device for ud in self.user.useru2f_set.all()] if user_devices: authentication_request = begin_authentication( zentral_settings["api"]["tls_hostname"], user_devices) u2f_challenge = self.session["u2f_challenge"] = dict( authentication_request) return u2f_challenge
def _get_u2f_request(request, u2f_key): origin = get_origin(request) u2f_request = u2f.begin_authentication(u2f_key.app_id, [{ 'publicKey': u2f_key.public_key, 'keyHandle': u2f_key.key_handle, 'appId': u2f_key.app_id, 'version': 'U2F_V2'}]) return u2f_request
def sign(): app_id = get_origin(request.environ) username = request.args.get('username', 'user') data = request.data.decode() user = users[username] challenge = begin_authentication(app_id, user.get('_u2f_devices_', []), data) user['_u2f_challenge_'] = challenge.json return json.dumps(challenge.data_for_client)
def _u2f_get_login_challenge(self): self.ensure_one() icp = self.env['ir.config_parameter'].sudo() baseurl = icp.get_param('web.base.url') devices = self._u2f_get_device() if devices: challenge = u2f.begin_authentication(baseurl, [devices.json]) return challenge return False
def __init__(self, *args, **kwargs): self.user = kwargs.pop('user') super(U2FTokenAuthenticationForm, self).__init__(*args, **kwargs) self.helper.form_class = 'u2f-challenge' challenge = begin_authentication(APP_ID, get_user_devices(self.user)) self.fields['u2f_challenge'].initial = json.dumps( challenge.data_for_client) self.fields['u2f_challenge_signed'].initial = signing.dumps( challenge, salt=self._get_sign_salt())
def __init__(self, *args, **kwargs): super(KeyResponseForm, self).__init__(*args, **kwargs) if self.data: self.sign_request = self.request.session['u2f_sign_request'] else: self.sign_request = u2f.begin_authentication(self.appId, [ d.to_json() for d in self.user.u2f_keys.all() ]) self.request.session['u2f_sign_request'] = self.sign_request
def generate_challenge(self): challenge = begin_authentication( settings.OTP_U2F_APP_ID, [key.as_device_registration() for key in self.u2fkey_set.all()]) U2FChallenge.objects.create( device=self, challenge=challenge.data_for_client['challenge'], challenge_data=challenge.json) return challenge.data_for_client
def get_context_data(self, **kwargs): challenge = u2f.begin_authentication( mf_settings['U2F_APPID'], list(self.keys.values_list("properties__device", flat=True))) self.request.session["_u2f_challenge_"] = challenge.json return { 'token': json.dumps(challenge.data_for_client), }
def sign(user): user_u2f_tokens = user.credentials.filter(U2F) if not user_u2f_tokens.count: current_app.logger.error('Found no U2F token for user.') return {'_error': True, 'message': 'security.u2f.no_token_found'} registered_keys = credentials_to_registered_keys(user_u2f_tokens) challenge = begin_authentication(current_app.config['U2F_APP_ID'], registered_keys) session['_u2f_challenge_'] = challenge.json current_app.stats.count(name='u2f_sign') return U2FSignResponseSchema().load(challenge.data_for_client).data
def sign(user): user_u2f_tokens = user.credentials.filter(U2F) if not user_u2f_tokens.count: current_app.logger.error('Found no U2F token for user.') return error_response(message=SecurityMsg.no_u2f) registered_keys = credentials_to_registered_keys(user_u2f_tokens) challenge = begin_authentication(current_app.config.u2f_app_id, registered_keys) session['_u2f_challenge_'] = challenge.json current_app.stats.count(name='u2f_sign') return U2FSignResponseSchema().load(challenge.data_for_client)
def test_authenticate_single_soft_u2f(self): # Register device, token = register_token() # Authenticate request = begin_authentication(APP_ID, [device]) data = request.data_for_client response = token.getAssertion(FACET, data['appId'], data['challenge'], data['registeredKeys'][0]) complete_authentication(request.json, response)
def sign(self, user_name, object_dn): # Do we have read permissions for the requested attribute self.__check_acl(user_name, object_dn, "r") uuid = self.__dn_to_uuid(object_dn) user_settings = self.__settings[uuid] if uuid in self.__settings else {} devices = [DeviceRegistration.wrap(device) for device in user_settings.get('_u2f_devices_', [])] challenge = begin_authentication(self.app_id, devices) user_settings['_u2f_challenge_'] = challenge.json self.__save_settings() return challenge.json
def sign(self, user_name, object_dn): # Do we have read permissions for the requested attribute self.__check_acl(user_name, object_dn, "r") uuid = self.__dn_to_uuid(object_dn) user_settings = self.__settings[ uuid] if uuid in self.__settings else {} devices = [ DeviceRegistration.wrap(device) for device in user_settings.get('_u2f_devices_', []) ] challenge = begin_authentication(self.app_id, devices) user_settings['_u2f_challenge_'] = challenge.json self.__save_settings() return challenge.json
def activate(self, request): challenge = dict(u2f.begin_authentication(self.u2f_app_id, self.get_u2f_devices())) # XXX: Upgrading python-u2flib-server to 5.0.0 changes the response # format. Our current js u2f library expects the old format, so # massaging the data to include the old `authenticateRequests` key here. authenticate_requests = [] for registered_key in challenge['registeredKeys']: authenticate_requests.append({ 'challenge': challenge['challenge'], 'version': registered_key['version'], 'keyHandle': registered_key['keyHandle'], 'appId': registered_key['appId'], }) challenge['authenticateRequests'] = authenticate_requests return ActivationChallengeResult(challenge=challenge)
def test_authenticate_single_soft_u2f(self): # Register device, token = register_token() # Authenticate request = begin_authentication(APP_ID, [device]) data = request.data_for_client response = token.getAssertion( FACET, data['appId'], data['challenge'], data['registeredKeys'][0] ) complete_authentication(request.json, response)
def admin_login() -> _Response: if session.get("logged_in") is True: return redirect(url_for("admin.admin_notifications")) devices = [doc["device"] for doc in DB.u2f.find()] u2f_enabled = True if devices else False if request.method == "POST": csrf.protect() # 1. Check regular password login flow pwd = request.form.get("pass") if pwd: if verify_pass(pwd): session.permanent = True session["logged_in"] = True return redirect( request.args.get("redirect") or url_for("admin.admin_notifications")) else: abort(403) # 2. Check for U2F payload, if any elif devices: resp = json.loads(request.form.get("resp")) # type: ignore try: u2f.complete_authentication(session["challenge"], resp) except ValueError as exc: print("failed", exc) abort(403) return finally: session["challenge"] = None session.permanent = True session["logged_in"] = True return redirect( request.args.get("redirect") or url_for("admin.admin_notifications")) else: abort(401) payload = None if devices: payload = u2f.begin_authentication(ID, devices) session["challenge"] = payload return htmlify( render_template("login.html", u2f_enabled=u2f_enabled, payload=payload))
def _sign_request(user_id, challenge, handles, properties): client = get_client() user = get_user(user_id) if user is None or len(user.devices) == 0: app.logger.info('User "%s" has no devices registered', user_id) raise exc.NoEligibleDevicesException('No devices registered', []) registered_keys = [] descriptors = [] handle_map = {} if not handles: handles = user.devices.keys() for handle in handles: try: dev = user.devices[handle] except KeyError: raise exc.BadInputException('Invalid device handle: ' + handle) if not dev.compromised: descriptor = dev.get_descriptor(get_metadata(dev)) descriptors.append(descriptor) key = _get_registered_key(dev, descriptor) registered_keys.append(key) handle_map[key['keyHandle']] = dev.handle if not registered_keys: raise exc.NoEligibleDevicesException( 'All devices compromised', [d.get_descriptor() for d in user.devices.values()] ) request_data = begin_authentication( client.app_id, registered_keys, challenge ) request_data['handleMap'] = handle_map request_data['properties'] = properties store.store(client.id, user_id, challenge, request_data.json) data = SignRequestData.wrap(request_data.data_for_client) data['descriptors'] = descriptors return data
def sign(username, **_): """ Start signin in procedure Variables: username user name of the user you want to login with Arguments: None Data Block: None Result example: <U2F_SIGN_IN_CHALLENGE_BLOCK> """ user = STORAGE.get_user(username) if not user: return make_api_response({'success': False}, err="Bad Request", status_code=400) challenge = begin_authentication(APP_ID, user.get('u2f_devices', [])) session['_u2f_challenge_'] = challenge.json return make_api_response(challenge.data_for_client)
def get_config_for_bundle(self, action): if action.old_format: userid = action.user_id user = current_app.central_userdb.get_user_by_id( userid, raise_on_missing=False) else: eppn = action.eppn user = current_app.central_userdb.get_user_by_eppn( eppn, raise_on_missing=False) current_app.logger.debug('Loaded User {} from db'.format(user)) if not user: raise self.ActionError('mfa.user-not-found') credentials = _get_user_credentials(user) current_app.logger.debug('FIDO credentials for user {}:\n{}'.format(user, pprint.pformat(credentials))) # CTAP1/U2F # TODO: Only make U2F challenges for U2F tokens? challenge = None if current_app.config.get('GENERATE_U2F_CHALLENGES') is True: u2f_tokens = [v['u2f'] for v in credentials.values()] try: challenge = begin_authentication(current_app.config['U2F_APP_ID'], u2f_tokens) current_app.logger.debug('U2F challenge:\n{}'.format(pprint.pformat(challenge))) except ValueError: # there is no U2F key registered for this user pass # CTAP2/Webauthn # TODO: Only make Webauthn challenges for Webauthn tokens? webauthn_credentials = [v['webauthn'] for v in credentials.values()] fido2rp = RelyingParty(current_app.config['FIDO2_RP_ID'], 'eduID') fido2server = _get_fido2server(credentials, fido2rp) raw_fido2data, fido2state = fido2server.authenticate_begin(webauthn_credentials) current_app.logger.debug('FIDO2 authentication data:\n{}'.format(pprint.pformat(raw_fido2data))) fido2data = base64.urlsafe_b64encode(cbor.dumps(raw_fido2data)).decode('ascii') fido2data = fido2data.rstrip('=') config = {'u2fdata': '{}', 'webauthn_options': fido2data} # Save the challenge to be used when validating the signature in perform_action() below if challenge is not None: session[self.PACKAGE_NAME + '.u2f.challenge'] = challenge.json config['u2fdata'] = json.dumps(challenge.data_for_client) current_app.logger.debug(f'FIDO1/U2F challenge for user {user}: {challenge.data_for_client}') current_app.logger.debug(f'FIDO2/Webauthn state for user {user}: {fido2state}') session[self.PACKAGE_NAME + '.webauthn.state'] = json.dumps(fido2state) # Explicit check for boolean True if current_app.config.get('MFA_TESTING') is True: current_app.logger.info('MFA test mode is enabled') config['testing'] = True else: config['testing'] = False # Add config for external mfa auth config['eidas_url'] = current_app.config['EIDAS_URL'] config['mfa_authn_idp'] = current_app.config['MFA_AUTHN_IDP'] return config
def sign(self, username): user = self.users[username] challenge = begin_authentication( self.app_id, user.get('_u2f_devices_', [])) user['_u2f_challenge_'] = challenge.json return json.dumps(challenge.data_for_client)
def _u2f_get_login_challenge(self): baseurl = self.env['ir.config_parameter'].sudo().get_param( 'web.base.url') challenge = begin_authentication(baseurl, [self._u2f_get_device().json]) return challenge
def get_config_for_bundle(self, action): if action.old_format: userid = action.user_id user = current_app.central_userdb.get_user_by_id( userid, raise_on_missing=False) else: eppn = action.eppn user = current_app.central_userdb.get_user_by_eppn( eppn, raise_on_missing=False) current_app.logger.debug('Loaded User {} from db'.format(user)) if not user: raise self.ActionError('mfa.user-not-found') credentials = _get_user_credentials(user) current_app.logger.debug('FIDO credentials for user {}:\n{}'.format( user, pprint.pformat(credentials))) # CTAP1/U2F # TODO: Only make U2F challenges for U2F tokens? challenge = None if current_app.config.get('GENERATE_U2F_CHALLENGES') is True: u2f_tokens = [v['u2f'] for v in credentials.values()] try: challenge = begin_authentication( current_app.config['U2F_APP_ID'], u2f_tokens) current_app.logger.debug('U2F challenge:\n{}'.format( pprint.pformat(challenge))) except ValueError: # there is no U2F key registered for this user pass # CTAP2/Webauthn # TODO: Only make Webauthn challenges for Webauthn tokens? webauthn_credentials = [v['webauthn'] for v in credentials.values()] fido2rp = RelyingParty(current_app.config['FIDO2_RP_ID'], 'eduID') fido2server = _get_fido2server(credentials, fido2rp) raw_fido2data, fido2state = fido2server.authenticate_begin( webauthn_credentials) current_app.logger.debug('FIDO2 authentication data:\n{}'.format( pprint.pformat(raw_fido2data))) fido2data = base64.urlsafe_b64encode( cbor.dumps(raw_fido2data)).decode('ascii') fido2data = fido2data.rstrip('=') config = {'u2fdata': '{}', 'webauthn_options': fido2data} # Save the challenge to be used when validating the signature in perform_action() below if challenge is not None: session[self.PACKAGE_NAME + '.u2f.challenge'] = challenge.json config['u2fdata'] = json.dumps(challenge.data_for_client) current_app.logger.debug( f'FIDO1/U2F challenge for user {user}: {challenge.data_for_client}' ) current_app.logger.debug( f'FIDO2/Webauthn state for user {user}: {fido2state}') session[self.PACKAGE_NAME + '.webauthn.state'] = json.dumps(fido2state) # Explicit check for boolean True if current_app.config.get('MFA_TESTING') is True: current_app.logger.info('MFA test mode is enabled') config['testing'] = True else: config['testing'] = False # Add config for external mfa auth config['eidas_url'] = current_app.config['EIDAS_URL'] config['mfa_authn_idp'] = current_app.config['MFA_AUTHN_IDP'] return config