예제 #1
0
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)
예제 #2
0
파일: u2f.py 프로젝트: SUNET/eduid-webapp
def bind(user, version, registration_data, client_data, description=''):
    security_user = SecurityUser.from_user(user, current_app.private_userdb)
    enrollment_data = session.pop('_u2f_enroll_', None)
    if not enrollment_data:
        current_app.logger.error('Found no U2F enrollment data in session.')
        return {'_error': True, 'message': 'security.u2f.missing_enrollment_data'}
    data = {
        'version': version,
        'registrationData': registration_data,
        'clientData': client_data
    }
    device, der_cert = complete_registration(enrollment_data, data, current_app.config['U2F_FACETS'])

    cert = x509.load_der_x509_certificate(der_cert, default_backend())
    pem_cert = crypto.dump_certificate(crypto.FILETYPE_PEM, cert)
    if not isinstance(pem_cert, six.string_types):
        pem_cert = pem_cert.decode('utf-8')

    u2f_token = U2F(version=device['version'], keyhandle=device['keyHandle'], app_id=device['appId'],
                    public_key=device['publicKey'], attest_cert=pem_cert, description=description,
                    application='eduid_security', created_ts=True)
    security_user.credentials.add(u2f_token)
    save_and_sync_user(security_user)
    current_app.stats.count(name='u2f_token_bind')
    return {
        'message': 'security.u2f_register_success',
        'credentials': compile_credential_list(security_user)
    }
예제 #3
0
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(
        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,
        application = '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))
    return {
        'message': 'security.webauthn_register_success',
        'credentials': compile_credential_list(security_user)
    }
예제 #4
0
def get_credentials(user):
    """
    View to get credentials for the logged user.
    """
    current_app.logger.debug('Trying to get the credentials '
                             'for user {}'.format(user))

    credentials = {'credentials': compile_credential_list(user)}

    return credentials
예제 #5
0
파일: u2f.py 프로젝트: SUNET/eduid-webapp
def remove(user, credential_key):
    security_user = SecurityUser.from_user(user, current_app.private_userdb)
    token_to_remove = security_user.credentials.filter(U2F).find(credential_key)
    if token_to_remove:
        security_user.credentials.remove(credential_key)
        save_and_sync_user(security_user)
        current_app.stats.count(name='u2f_token_remove')
    return {
        'message': 'security.u2f-token-removed',
        'credentials': compile_credential_list(security_user)
    }
예제 #6
0
def get_credentials(user):
    """
    View to get credentials for the logged user.
    """
    current_app.logger.debug('Trying to get the credentials '
                             'for user {}'.format(user))

    credentials = {
        'credentials': compile_credential_list(user)
        }

    return CredentialList().dump(credentials).data
예제 #7
0
def remove(user, credential_key):
    security_user = SecurityUser.from_user(user, current_app.private_userdb)
    token_to_remove = security_user.credentials.filter(U2F).find(
        credential_key)
    if token_to_remove:
        security_user.credentials.remove(credential_key)
        save_and_sync_user(security_user)
        current_app.stats.count(name='u2f_token_remove')

    credentials = compile_credential_list(security_user)
    return success_response(payload=dict(credentials=credentials),
                            message=SecurityMsg.rm_u2f_success)
예제 #8
0
파일: u2f.py 프로젝트: SUNET/eduid-webapp
def modify(user, credential_key, description):
    security_user = SecurityUser.from_user(user, current_app.private_userdb)
    token_to_modify = security_user.credentials.filter(U2F).find(credential_key)
    if not token_to_modify:
        current_app.logger.error('Did not find requested U2F token for user.')
        return {'_error': True, 'message': 'security.u2f.missing_token'}
    if len(description) > current_app.config['U2F_MAX_DESCRIPTION_LENGTH']:
        current_app.logger.error('User tried to set a U2F token description longer than {}.'.format(
            current_app.config['U2F_MAX_DESCRIPTION_LENGTH']))
        return {'_error': True, 'message': 'security.u2f.description_to_long'}
    token_to_modify.description = description
    save_and_sync_user(security_user)
    current_app.stats.count(name='u2f_token_modify')
    return {
        'credentials': compile_credential_list(security_user)
    }
예제 #9
0
def modify(user, credential_key, description):
    security_user = SecurityUser.from_user(user, current_app.private_userdb)
    token_to_modify = security_user.credentials.filter(U2F).find(
        credential_key)
    if not token_to_modify:
        current_app.logger.error('Did not find requested U2F token for user.')
        return error_response(message=SecurityMsg.no_token)

    if len(description) > current_app.config.u2f_max_description_length:
        current_app.logger.error(
            'User tried to set a U2F token description longer than {}.'.format(
                current_app.config.u2f_max_description_length))
        return error_response(message=SecurityMsg.long_desc)

    token_to_modify.description = description
    save_and_sync_user(security_user)
    current_app.stats.count(name='u2f_token_modify')
    return {'credentials': compile_credential_list(security_user)}
예제 #10
0
def remove(user, credential_key):
    security_user = SecurityUser.from_user(user, current_app.private_userdb)
    tokens = security_user.credentials.filter(FidoCredential)
    if tokens.count <= 1:
        return {'_error': True, 'message': 'security.webauthn-noremove-last'}
    token_to_remove = security_user.credentials.find(credential_key)
    if token_to_remove:
        security_user.credentials.remove(credential_key)
        save_and_sync_user(security_user)
        current_app.stats.count(name='webauthn_token_remove')
        current_app.logger.info(f'User {security_user} has removed a security token: {credential_key}')
        message = 'security.webauthn-token-removed'
    else:
        current_app.logger.info(f'User {security_user} has tried to remove a'
                                f' missing security token: {credential_key}')
        message = 'security.webauthn-token-notfound'
    return {
        'message': message,
        'credentials': compile_credential_list(security_user)
    }
예제 #11
0
def change_password(user, old_password, new_password):
    """
    View to change the password
    """
    security_user = SecurityUser.from_user(user, current_app.private_userdb)
    authn_ts = session.get('reauthn-for-chpass', None)
    if authn_ts is None:
        return error_message('chpass.no_reauthn')

    now = datetime.utcnow()
    delta = now - datetime.fromtimestamp(authn_ts)
    timeout = current_app.config.get('CHPASS_TIMEOUT', 600)
    if int(delta.total_seconds()) > timeout:
        return error_message('chpass.stale_reauthn')

    vccs_url = current_app.config.get('VCCS_URL')
    added = add_credentials(vccs_url, old_password, new_password, security_user, source='security')

    if not added:
        current_app.logger.debug('Problem verifying the old credentials for {}'.format(user))
        return error_message('chpass.unable-to-verify-old-password')

    security_user.terminated = False
    try:
        save_and_sync_user(security_user)
    except UserOutOfSync:
        return error_message('user-out-of-sync')

    del session['reauthn-for-chpass']

    current_app.stats.count(name='security_password_changed', value=1)
    current_app.logger.info('Changed password for user {}'.format(security_user.eppn))

    next_url = current_app.config.get('DASHBOARD_URL', '/profile')
    credentials = {
        'next_url': next_url,
        'credentials': compile_credential_list(security_user),
        'message': 'chpass.password-changed'
        }

    return CredentialList().dump(credentials).data
예제 #12
0
def change_password(user, old_password, new_password):
    """
    View to change the password
    """
    security_user = SecurityUser.from_user(user, current_app.private_userdb)
    authn_ts = session.get('reauthn-for-chpass', None)
    if authn_ts is None:
        return error_message('chpass.no_reauthn')

    now = datetime.utcnow()
    delta = now - datetime.fromtimestamp(authn_ts)
    timeout = current_app.config.get('CHPASS_TIMEOUT', 600)
    if int(delta.total_seconds()) > timeout:
        return error_message('chpass.stale_reauthn')

    vccs_url = current_app.config.get('VCCS_URL')
    added = add_credentials(vccs_url, old_password, new_password, security_user, source='security')

    if not added:
        current_app.logger.debug('Problem verifying the old credentials for {}'.format(user))
        return error_message('chpass.unable-to-verify-old-password')

    security_user.terminated = False
    try:
        save_and_sync_user(security_user)
    except UserOutOfSync:
        return error_message('user-out-of-sync')

    del session['reauthn-for-chpass']

    current_app.stats.count(name='security_password_changed', value=1)
    current_app.logger.info('Changed password for user {}'.format(security_user.eppn))

    next_url = current_app.config.get('DASHBOARD_URL', '/profile')
    credentials = {
        'next_url': next_url,
        'credentials': compile_credential_list(security_user),
        'message': 'chpass.password-changed'
        }

    return CredentialList().dump(credentials).data
예제 #13
0
def remove(user, credential_key):
    security_user = SecurityUser.from_user(user, current_app.private_userdb)
    tokens = security_user.credentials.filter(FidoCredential)
    if tokens.count <= 1:
        return {'_error': True, 'message': SecurityMsg.no_last.value}

    token_to_remove = security_user.credentials.find(credential_key)
    if token_to_remove:
        security_user.credentials.remove(credential_key)
        save_and_sync_user(security_user)
        current_app.stats.count(name='webauthn_token_remove')
        current_app.logger.info(f'User {security_user} has removed a security token: {credential_key}')
        message = SecurityMsg.rm_webauthn
    else:
        current_app.logger.info(
            f'User {security_user} has tried to remove a' f' missing security token: {credential_key}'
        )
        message = SecurityMsg.no_webauthn

    credentials = compile_credential_list(security_user)
    return {'message': message, 'credentials': credentials}
예제 #14
0
def bind(user, version, registration_data, client_data, description=''):
    security_user = SecurityUser.from_user(user, current_app.private_userdb)
    enrollment_data = session.pop('_u2f_enroll_', None)
    if not enrollment_data:
        current_app.logger.error('Found no U2F enrollment data in session.')
        return error_response(message=SecurityMsg.missing_data)

    data = {
        'version': version,
        'registrationData': registration_data,
        'clientData': client_data
    }
    device, der_cert = complete_registration(enrollment_data, data,
                                             current_app.config.u2f_facets)

    cert = x509.load_der_x509_certificate(der_cert, default_backend())
    pem_cert = crypto.dump_certificate(crypto.FILETYPE_PEM, cert)
    if not isinstance(pem_cert, six.string_types):
        pem_cert = pem_cert.decode('utf-8')

    u2f_token = U2F.from_dict(
        dict(
            version=device['version'],
            keyhandle=device['keyHandle'],
            app_id=device['appId'],
            public_key=device['publicKey'],
            attest_cert=pem_cert,
            description=description,
            created_by='eduid_security',
            created_ts=True,
        ))
    security_user.credentials.add(u2f_token)
    save_and_sync_user(security_user)
    current_app.stats.count(name='u2f_token_bind')
    credentials = compile_credential_list(security_user)
    return success_response(payload=dict(credentials=credentials),
                            message=SecurityMsg.u2f_registered)
예제 #15
0
def change_password(user):
    """
    View to change the password
    """
    security_user = SecurityUser.from_user(user, current_app.private_userdb)
    min_entropy = current_app.config.password_entropy
    schema = ChangePasswordSchema(zxcvbn_terms=get_zxcvbn_terms(
        security_user.eppn),
                                  min_entropy=int(min_entropy))

    if not request.data:
        return error_response(message='chpass.no-data')

    try:
        form = schema.load(json.loads(request.data))
        current_app.logger.debug(form)
    except ValidationError as e:
        current_app.logger.error(e)
        return error_response(message='chpass.weak-password')
    else:
        old_password = form.get('old_password')
        new_password = form.get('new_password')

    if session.get_csrf_token() != form['csrf_token']:
        return error_response(message='csrf.try_again')

    authn_ts = session.get('reauthn-for-chpass', None)
    if authn_ts is None:
        return error_response(message='chpass.no_reauthn')

    now = datetime.utcnow()
    delta = now - datetime.fromtimestamp(authn_ts)
    timeout = current_app.config.chpass_timeout
    if int(delta.total_seconds()) > timeout:
        return error_response(message='chpass.stale_reauthn')

    vccs_url = current_app.config.vccs_url
    added = add_credentials(vccs_url,
                            old_password,
                            new_password,
                            security_user,
                            source='security')

    if not added:
        current_app.logger.debug(
            'Problem verifying the old credentials for {}'.format(user))
        return error_response(message='chpass.unable-to-verify-old-password')

    security_user.terminated = False
    try:
        save_and_sync_user(security_user)
    except UserOutOfSync:
        return error_response(message='user-out-of-sync')

    del session['reauthn-for-chpass']

    current_app.stats.count(name='security_password_changed', value=1)
    current_app.logger.info('Changed password for user {}'.format(
        security_user.eppn))

    next_url = current_app.config.dashboard_url
    credentials = {
        'next_url': next_url,
        'credentials': compile_credential_list(security_user),
        'message': 'chpass.password-changed',
    }

    return credentials