示例#1
0
文件: sso.py 项目: xingchuang/pritunl
def sso_authenticate_post():
    if settings.app.sso != DUO_AUTH or \
        settings.app.sso_duo_mode == 'passcode':
        return flask.abort(405)

    username = utils.json_filter_str('username')
    usernames = [username]
    email = None
    if '@' in username:
        email = username
        usernames.append(username.split('@')[0])

    valid = False
    for i, username in enumerate(usernames):
        try:
            duo_auth = sso.Duo(
                username=username,
                factor=settings.app.sso_duo_mode,
                remote_ip=utils.get_remote_addr(),
                auth_type='Key',
            )
            valid = duo_auth.authenticate()
            break
        except InvalidUser:
            if i == len(usernames) - 1:
                logger.warning(
                    'Invalid duo username',
                    'sso',
                    username=username,
                )

    if valid:
        valid, org_id, groups = sso.plugin_sso_authenticate(
            sso_type='duo',
            user_name=username,
            user_email=email,
            remote_ip=utils.get_remote_addr(),
        )
        if not valid:
            logger.warning(
                'Duo plugin authentication not valid',
                'sso',
                username=username,
            )
            return flask.abort(401)
        groups = set(groups or [])
    else:
        logger.warning(
            'Duo authentication not valid',
            'sso',
            username=username,
        )
        return flask.abort(401)

    if not org_id:
        org_id = settings.app.sso_org

    return _validate_user(username, email, DUO_AUTH, org_id, groups)
示例#2
0
文件: auth.py 项目: bogsi/pritunl
def _auth_radius(username, password):
    sso_mode = settings.app.sso

    valid, org_names, groups = sso.verify_radius(username, password)
    if not valid:
        return utils.jsonify({
            'error': AUTH_INVALID,
            'error_msg': AUTH_INVALID_MSG,
        }, 401)

    org_id = settings.app.sso_org
    if org_names:
        for org_name in org_names:
            org = organization.get_by_name(org_name, fields=('_id'))
            if org:
                org_id = org.id
                break

    valid, org_id_new, groups2 = sso.plugin_sso_authenticate(
        sso_type='radius',
        user_name=username,
        user_email=None,
        remote_ip=utils.get_remote_addr(),
    )
    if valid:
        org_id = org_id_new or org_id
    else:
        logger.error('Radius plugin authentication not valid', 'sso',
            username=username,
        )
        return utils.jsonify({
            'error': AUTH_INVALID,
            'error_msg': AUTH_INVALID_MSG,
        }, 401)

    groups = ((groups or set()) | (groups2 or set())) or None

    if DUO_AUTH in sso_mode:
        try:
            duo_auth = sso.Duo(
                username=username,
                factor=settings.app.sso_duo_mode,
                remote_ip=utils.get_remote_addr(),
                auth_type='Key',
            )
            valid = duo_auth.authenticate()
        except InvalidUser:
            logger.error('Duo authentication username not valid', 'sso',
                username=username,
            )
            return utils.jsonify({
                'error': AUTH_INVALID,
                'error_msg': AUTH_INVALID_MSG,
            }, 401)
        if valid:
            valid, org_id_new, groups2 = sso.plugin_sso_authenticate(
                sso_type='duo',
                user_name=username,
                user_email=None,
                remote_ip=utils.get_remote_addr(),
            )
            if valid:
                org_id = org_id_new or org_id
            else:
                logger.error('Duo plugin authentication not valid', 'sso',
                    username=username,
                )
                return utils.jsonify({
                    'error': AUTH_INVALID,
                    'error_msg': AUTH_INVALID_MSG,
                }, 401)

            groups = ((groups or set()) | (groups2 or set())) or None
        else:
            logger.error('Duo authentication not valid', 'sso',
                username=username,
            )
            return utils.jsonify({
                'error': AUTH_INVALID,
                'error_msg': AUTH_INVALID_MSG,
            }, 401)

    groups = ((groups or set()) | (groups2 or set())) or None

    org = organization.get_by_id(org_id)
    if not org:
        return flask.abort(405)

    usr = org.find_user(name=username)
    if not usr:
        usr = org.new_user(name=username, type=CERT_CLIENT,
            auth_type=sso_mode, groups=list(groups) if groups else None)

        usr.audit_event(
            'user_created',
            'User created with single sign-on',
            remote_addr=utils.get_remote_addr(),
        )

        event.Event(type=ORGS_UPDATED)
        event.Event(type=USERS_UPDATED, resource_id=org.id)
        event.Event(type=SERVERS_UPDATED)
    else:
        if usr.disabled:
            return utils.jsonify({
                'error': AUTH_DISABLED,
                'error_msg': AUTH_DISABLED_MSG,
            }, 403)

        if groups and groups - set(usr.groups or []):
            usr.groups = list(set(usr.groups or []) | groups)
            usr.commit('groups')

        if usr.auth_type != sso_mode:
            usr.auth_type = sso_mode
            usr.set_pin(None)
            usr.commit(('auth_type', 'pin'))

    key_link = org.create_user_key_link(usr.id, one_time=True)

    usr.audit_event('user_profile',
        'User profile viewed from single sign-on',
        remote_addr=utils.get_remote_addr(),
    )

    return utils.jsonify({
        'redirect': utils.get_url_root() + key_link['view_url'],
    }, 202)
示例#3
0
文件: sso.py 项目: xingchuang/pritunl
def sso_duo_post():
    sso_mode = settings.app.sso
    token = utils.filter_str(flask.request.json.get('token')) or None
    passcode = utils.filter_str(flask.request.json.get('passcode')) or ''

    if sso_mode not in (DUO_AUTH, AZURE_DUO_AUTH, GOOGLE_DUO_AUTH,
                        SLACK_DUO_AUTH, SAML_DUO_AUTH, SAML_OKTA_DUO_AUTH,
                        SAML_ONELOGIN_DUO_AUTH, RADIUS_DUO_AUTH):
        return flask.abort(404)

    if not token:
        return utils.jsonify(
            {
                'error': TOKEN_INVALID,
                'error_msg': TOKEN_INVALID_MSG,
            }, 401)

    tokens_collection = mongo.get_collection('sso_tokens')
    doc = tokens_collection.find_and_modify(query={
        '_id': token,
    },
                                            remove=True)
    if not doc or doc['_id'] != token or doc['type'] != DUO_AUTH:
        return utils.jsonify(
            {
                'error': TOKEN_INVALID,
                'error_msg': TOKEN_INVALID_MSG,
            }, 401)

    username = doc['username']
    email = doc['email']
    org_id = doc['org_id']
    groups = set(doc['groups'] or [])

    if settings.app.sso_duo_mode == 'passcode':
        duo_auth = sso.Duo(
            username=username,
            factor=settings.app.sso_duo_mode,
            remote_ip=utils.get_remote_addr(),
            auth_type='Key',
            passcode=passcode,
        )
        valid = duo_auth.authenticate()
        if not valid:
            logger.warning(
                'Duo authentication not valid',
                'sso',
                username=username,
            )
            return utils.jsonify(
                {
                    'error': PASSCODE_INVALID,
                    'error_msg': PASSCODE_INVALID_MSG,
                }, 401)
    else:
        duo_auth = sso.Duo(
            username=username,
            factor=settings.app.sso_duo_mode,
            remote_ip=utils.get_remote_addr(),
            auth_type='Key',
        )
        valid = duo_auth.authenticate()
        if not valid:
            logger.warning(
                'Duo authentication not valid',
                'sso',
                username=username,
            )
            return utils.jsonify(
                {
                    'error': DUO_FAILED,
                    'error_msg': DUO_FAILED_MSG,
                }, 401)

    valid, org_id_new, groups2 = sso.plugin_sso_authenticate(
        sso_type='duo',
        user_name=username,
        user_email=email,
        remote_ip=utils.get_remote_addr(),
    )
    if valid:
        org_id = org_id_new or org_id
    else:
        logger.warning(
            'Duo plugin authentication not valid',
            'sso',
            username=username,
        )
        return flask.abort(401)

    groups = groups | set(groups2 or [])

    return _validate_user(username, email, sso_mode, org_id, groups)
示例#4
0
def sso_authenticate_post():
    if settings.app.sso != DUO_AUTH or \
            settings.app.sso_duo_mode == 'passcode':
        return flask.abort(405)

    username = utils.json_filter_str('username')
    usernames = [username]
    email = None
    if '@' in username:
        email = username
        usernames.append(username.split('@')[0])

    valid = False
    for i, username in enumerate(usernames):
        try:
            duo_auth = sso.Duo(
                username=username,
                factor=settings.app.sso_duo_mode,
                remote_ip=utils.get_remote_addr(),
                auth_type='Key',
            )
            valid = duo_auth.authenticate()
            break
        except InvalidUser:
            if i == len(usernames) - 1:
                logger.error(
                    'Invalid duo username',
                    'sso',
                    username=username,
                )

    if valid:
        valid, org_id, groups = sso.plugin_sso_authenticate(
            sso_type='duo',
            user_name=username,
            user_email=email,
            remote_ip=utils.get_remote_addr(),
        )
        if not valid:
            logger.error(
                'Duo plugin authentication not valid',
                'sso',
                username=username,
            )
            return flask.abort(401)
    else:
        logger.error(
            'Duo authentication not valid',
            'sso',
            username=username,
        )
        return flask.abort(401)

    if not org_id:
        org_id = settings.app.sso_org

    org = organization.get_by_id(org_id)
    if not org:
        logger.error(
            'Organization for Duo sso does not exist',
            'sso',
            org_id=org_id,
        )
        return flask.abort(405)

    usr = org.find_user(name=username)
    if not usr:
        usr = org.new_user(name=username,
                           email=email,
                           type=CERT_CLIENT,
                           auth_type=DUO_AUTH,
                           groups=list(groups) if groups else None)
        usr.audit_event('user_created',
                        'User created with single sign-on',
                        remote_addr=utils.get_remote_addr())

        event.Event(type=ORGS_UPDATED)
        event.Event(type=USERS_UPDATED, resource_id=org.id)
        event.Event(type=SERVERS_UPDATED)
    else:
        if usr.disabled:
            return flask.abort(403)

        if groups and groups - set(usr.groups or []):
            usr.groups = list(set(usr.groups or []) | groups)
            usr.commit('groups')

        if usr.auth_type != DUO_AUTH:
            usr.auth_type = DUO_AUTH
            usr.commit('auth_type')
            event.Event(type=USERS_UPDATED, resource_id=org.id)

    key_link = org.create_user_key_link(usr.id, one_time=True)

    usr.audit_event(
        'user_profile',
        'User profile viewed from single sign-on',
        remote_addr=utils.get_remote_addr(),
    )

    return utils.get_url_root() + key_link['view_url']
示例#5
0
def sso_callback_get():
    sso_mode = settings.app.sso

    if sso_mode not in (GOOGLE_AUTH, GOOGLE_DUO_AUTH, GOOGLE_YUBICO_AUTH,
                        SLACK_AUTH, SLACK_DUO_AUTH, SLACK_YUBICO_AUTH,
                        SAML_AUTH, SAML_DUO_AUTH, SAML_YUBICO_AUTH,
                        SAML_OKTA_AUTH, SAML_OKTA_DUO_AUTH,
                        SAML_OKTA_YUBICO_AUTH, SAML_ONELOGIN_AUTH,
                        SAML_ONELOGIN_DUO_AUTH, SAML_ONELOGIN_YUBICO_AUTH):
        return flask.abort(405)

    state = flask.request.args.get('state')
    sig = flask.request.args.get('sig')

    tokens_collection = mongo.get_collection('sso_tokens')
    doc = tokens_collection.find_and_modify(query={
        '_id': state,
    },
                                            remove=True)

    if not doc:
        return flask.abort(404)

    query = flask.request.query_string.split('&sig=')[0]
    test_sig = base64.urlsafe_b64encode(
        hmac.new(str(doc['secret']), query, hashlib.sha512).digest())

    if sig != test_sig:
        return flask.abort(401)

    params = urlparse.parse_qs(query)

    if doc.get('type') == SAML_AUTH:
        username = params.get('username')[0]
        email = params.get('email', [None])[0]
        org_name = params.get('org', [None])[0]

        if not username:
            return flask.abort(406)

        valid, org_name = sso.verify_saml(username, email, org_name)
        if not valid:
            return flask.abort(401)

        org_id = settings.app.sso_org
        if org_name:
            org = organization.get_by_name(org_name, fields=('_id'))
            if org:
                org_id = org.id

        valid, org_id_new, groups = sso.plugin_sso_authenticate(
            sso_type='saml',
            user_name=username,
            user_email=email,
            remote_ip=utils.get_remote_addr(),
            sso_org_names=[org_name],
        )
        if valid:
            org_id = org_id_new or org_id
        else:
            logger.error(
                'Saml plugin authentication not valid',
                'sso',
                username=username,
            )
            return flask.abort(401)
    elif doc.get('type') == SLACK_AUTH:
        username = params.get('username')[0]
        email = None
        user_team = params.get('team')[0]
        org_names = params.get('orgs', [''])[0]
        org_names = org_names.split(',')

        valid, org_name = sso.verify_slack(username, user_team, org_names)
        if not valid:
            return flask.abort(401)

        if org_name:
            org_names = [org_name]

        org_id = settings.app.sso_org
        for org_name in org_names:
            org = organization.get_by_name(org_name, fields=('_id'))
            if org:
                org_id = org.id
                break

        valid, org_id_new, groups = sso.plugin_sso_authenticate(
            sso_type='slack',
            user_name=username,
            user_email=email,
            remote_ip=utils.get_remote_addr(),
            sso_org_names=org_names,
        )
        if valid:
            org_id = org_id_new or org_id
        else:
            logger.error(
                'Slack plugin authentication not valid',
                'sso',
                username=username,
            )
            return flask.abort(401)
    else:
        username = params.get('username')[0]
        email = username

        valid, org_name = sso.verify_google(username)
        if not valid:
            return flask.abort(401)

        org_id = settings.app.sso_org
        if org_name:
            org = organization.get_by_name(org_name, fields=('_id'))
            if org:
                org_id = org.id

        valid, org_id_new, groups = sso.plugin_sso_authenticate(
            sso_type='google',
            user_name=username,
            user_email=email,
            remote_ip=utils.get_remote_addr(),
        )
        if valid:
            org_id = org_id_new or org_id
        else:
            logger.error(
                'Google plugin authentication not valid',
                'sso',
                username=username,
            )
            return flask.abort(401)

    if DUO_AUTH in sso_mode:
        if settings.app.sso_duo_mode == 'passcode':
            token = utils.generate_secret()

            tokens_collection = mongo.get_collection('sso_tokens')
            tokens_collection.insert({
                '_id': token,
                'type': DUO_AUTH,
                'username': username,
                'email': email,
                'org_id': org_id,
                'groups': groups,
                'timestamp': utils.now(),
            })

            duo_page = static.StaticFile(settings.conf.www_path,
                                         'duo.html',
                                         cache=False,
                                         gzip=False)

            if settings.app.theme == 'dark':
                duo_page.data = duo_page.data.replace('<body>',
                                                      '<body class="dark">')
            duo_page.data = duo_page.data.replace('<%= token %>', token)

            return duo_page.get_response()
        else:
            duo_auth = sso.Duo(
                username=username,
                factor=settings.app.sso_duo_mode,
                remote_ip=utils.get_remote_addr(),
                auth_type='Key',
            )
            valid = duo_auth.authenticate()
            if valid:
                valid, org_id_new, groups2 = sso.plugin_sso_authenticate(
                    sso_type='duo',
                    user_name=username,
                    user_email=email,
                    remote_ip=utils.get_remote_addr(),
                )
                if valid:
                    org_id = org_id_new or org_id
                else:
                    logger.error(
                        'Duo plugin authentication not valid',
                        'sso',
                        username=username,
                    )
                    return flask.abort(401)

                groups = ((groups or set()) | (groups2 or set())) or None
            else:
                logger.error(
                    'Duo authentication not valid',
                    'sso',
                    username=username,
                )
                return flask.abort(401)

    if YUBICO_AUTH in sso_mode:
        token = utils.generate_secret()

        tokens_collection = mongo.get_collection('sso_tokens')
        tokens_collection.insert({
            '_id': token,
            'type': YUBICO_AUTH,
            'username': username,
            'email': email,
            'org_id': org_id,
            'groups': groups,
            'timestamp': utils.now(),
        })

        yubico_page = static.StaticFile(settings.conf.www_path,
                                        'yubico.html',
                                        cache=False,
                                        gzip=False)

        if settings.app.theme == 'dark':
            yubico_page.data = yubico_page.data.replace(
                '<body>', '<body class="dark">')
        yubico_page.data = yubico_page.data.replace('<%= token %>', token)

        return yubico_page.get_response()

    org = organization.get_by_id(org_id)
    if not org:
        return flask.abort(405)

    usr = org.find_user(name=username)
    if not usr:
        usr = org.new_user(name=username,
                           email=email,
                           type=CERT_CLIENT,
                           auth_type=sso_mode,
                           groups=list(groups) if groups else None)
        usr.audit_event('user_created',
                        'User created with single sign-on',
                        remote_addr=utils.get_remote_addr())

        event.Event(type=ORGS_UPDATED)
        event.Event(type=USERS_UPDATED, resource_id=org.id)
        event.Event(type=SERVERS_UPDATED)
    else:
        if usr.disabled:
            return flask.abort(403)

        if groups and groups - set(usr.groups or []):
            usr.groups = list(set(usr.groups or []) | groups)
            usr.commit('groups')

        if usr.auth_type != sso_mode:
            usr.auth_type = sso_mode
            usr.commit('auth_type')

    key_link = org.create_user_key_link(usr.id, one_time=True)

    usr.audit_event(
        'user_profile',
        'User profile viewed from single sign-on',
        remote_addr=utils.get_remote_addr(),
    )

    return utils.redirect(utils.get_url_root() + key_link['view_url'])
示例#6
0
文件: auth.py 项目: so-jelly/pritunl
def _auth_radius(username, password, remote_addr):
    sso_mode = settings.app.sso

    valid, org_names, groups = sso.verify_radius(username, password)
    if not valid:
        journal.entry(
            journal.SSO_AUTH_FAILURE,
            user_name=username,
            remote_address=remote_addr,
            reason=journal.SSO_AUTH_REASON_RADIUS_FAILED,
            reason_long='Radius authentication failed',
        )
        return utils.jsonify(
            {
                'error': AUTH_INVALID,
                'error_msg': AUTH_INVALID_MSG,
            }, 401)

    org_id = settings.app.sso_org
    if org_names:
        not_found = False
        for org_name in org_names:
            org = organization.get_by_name(org_name, fields=('_id'))
            if org:
                not_found = False
                org_id = org.id
                break
            else:
                not_found = True

        if not_found:
            logger.warning(
                'Supplied org names do not exist',
                'sso',
                sso_type='radius',
                user_name=username,
                org_names=org_names,
            )

    valid, org_id_new, groups2 = sso.plugin_sso_authenticate(
        sso_type='radius',
        user_name=username,
        user_email=None,
        remote_ip=utils.get_remote_addr(),
    )
    if valid:
        org_id = org_id_new or org_id
    else:
        journal.entry(
            journal.SSO_AUTH_FAILURE,
            user_name=username,
            remote_address=remote_addr,
            reason=journal.SSO_AUTH_REASON_PLUGIN_FAILED,
            reason_long='Radius plugin authentication failed',
        )
        logger.error(
            'Radius plugin authentication not valid',
            'sso',
            username=username,
        )
        return utils.jsonify(
            {
                'error': AUTH_INVALID,
                'error_msg': AUTH_INVALID_MSG,
            }, 401)

    groups = ((groups or set()) | (groups2 or set())) or None

    if DUO_AUTH in sso_mode:
        try:
            duo_auth = sso.Duo(
                username=username,
                factor=settings.app.sso_duo_mode,
                remote_ip=utils.get_remote_addr(),
                auth_type='Key',
            )
            valid = duo_auth.authenticate()
        except InvalidUser:
            logger.error(
                'Duo authentication username not valid',
                'sso',
                username=username,
            )
            journal.entry(
                journal.SSO_AUTH_FAILURE,
                user_name=username,
                remote_address=remote_addr,
                reason=journal.SSO_AUTH_REASON_DUO_FAILED,
                reason_long='Duo authentication invalid username',
            )
            return utils.jsonify(
                {
                    'error': AUTH_INVALID,
                    'error_msg': AUTH_INVALID_MSG,
                }, 401)
        if valid:
            valid, org_id_new, groups2 = sso.plugin_sso_authenticate(
                sso_type='duo',
                user_name=username,
                user_email=None,
                remote_ip=utils.get_remote_addr(),
            )
            if valid:
                org_id = org_id_new or org_id
            else:
                journal.entry(
                    journal.SSO_AUTH_FAILURE,
                    user_name=username,
                    remote_address=remote_addr,
                    reason=journal.SSO_AUTH_REASON_PLUGIN_FAILED,
                    reason_long='Duo plugin authentication failed',
                )
                logger.error(
                    'Duo plugin authentication not valid',
                    'sso',
                    username=username,
                )
                return utils.jsonify(
                    {
                        'error': AUTH_INVALID,
                        'error_msg': AUTH_INVALID_MSG,
                    }, 401)

            groups = ((groups or set()) | (groups2 or set())) or None
        else:
            logger.error(
                'Duo authentication not valid',
                'sso',
                username=username,
            )
            journal.entry(
                journal.SSO_AUTH_FAILURE,
                user_name=username,
                remote_address=remote_addr,
                reason=journal.SSO_AUTH_REASON_DUO_FAILED,
                reason_long='Duo authentication failed',
            )
            return utils.jsonify(
                {
                    'error': AUTH_INVALID,
                    'error_msg': AUTH_INVALID_MSG,
                }, 401)

    groups = ((groups or set()) | (groups2 or set())) or None

    org = organization.get_by_id(org_id)
    if not org:
        logger.error(
            'Organization for sso does not exist',
            'auth',
            org_id=org_id,
        )
        return flask.abort(405)

    usr = org.find_user(name=username)
    if not usr:
        usr = org.new_user(name=username,
                           type=CERT_CLIENT,
                           auth_type=sso_mode,
                           groups=list(groups) if groups else None)

        usr.audit_event(
            'user_created',
            'User created with single sign-on',
            remote_addr=remote_addr,
        )

        journal.entry(
            journal.USER_CREATE,
            usr.journal_data,
            event_long='User created with single sign-on',
            remote_address=remote_addr,
        )

        event.Event(type=ORGS_UPDATED)
        event.Event(type=USERS_UPDATED, resource_id=org.id)
        event.Event(type=SERVERS_UPDATED)
    else:
        if usr.disabled:
            return utils.jsonify(
                {
                    'error': AUTH_DISABLED,
                    'error_msg': AUTH_DISABLED_MSG,
                }, 403)

        if groups and groups - set(usr.groups or []):
            usr.groups = list(set(usr.groups or []) | groups)
            usr.commit('groups')

        if usr.auth_type != sso_mode:
            usr.auth_type = sso_mode
            usr.set_pin(None)
            usr.commit(('auth_type', 'pin'))

    key_link = org.create_user_key_link(usr.id, one_time=True)

    journal.entry(
        journal.SSO_AUTH_SUCCESS,
        usr.journal_data,
        key_id_hash=hashlib.md5(key_link['id'].encode()).hexdigest(),
        remote_address=remote_addr,
    )

    usr.audit_event(
        'user_profile',
        'User profile viewed from single sign-on',
        remote_addr=utils.get_remote_addr(),
    )

    journal.entry(
        journal.USER_PROFILE_SUCCESS,
        usr.journal_data,
        event_long='User profile viewed from single sign-on',
        remote_address=remote_addr,
    )

    return utils.jsonify(
        {
            'redirect': utils.get_url_root() + key_link['view_url'],
        }, 202)
示例#7
0
def sso_duo_post():
    sso_mode = settings.app.sso
    token = utils.filter_str(flask.request.json.get('token')) or None
    passcode = utils.filter_str(flask.request.json.get('passcode')) or None

    if sso_mode not in (DUO_AUTH, GOOGLE_DUO_AUTH, SLACK_DUO_AUTH,
                        SAML_DUO_AUTH, SAML_OKTA_DUO_AUTH,
                        SAML_ONELOGIN_DUO_AUTH, RADIUS_DUO_AUTH):
        return flask.abort(404)

    if not token or not passcode:
        return utils.jsonify(
            {
                'error': TOKEN_INVALID,
                'error_msg': TOKEN_INVALID_MSG,
            }, 401)

    tokens_collection = mongo.get_collection('sso_tokens')
    doc = tokens_collection.find_one({
        '_id': token,
    })
    if not doc or doc['_id'] != token or doc['type'] != DUO_AUTH:
        return utils.jsonify(
            {
                'error': TOKEN_INVALID,
                'error_msg': TOKEN_INVALID_MSG,
            }, 401)

    username = doc['username']
    email = doc['email']
    org_id = doc['org_id']
    groups = doc['groups']

    duo_auth = sso.Duo(
        username=username,
        factor=settings.app.sso_duo_mode,
        remote_ip=utils.get_remote_addr(),
        auth_type='Key',
        passcode=passcode,
    )
    valid = duo_auth.authenticate()
    if not valid:
        return utils.jsonify(
            {
                'error': PASSCODE_INVALID,
                'error_msg': PASSCODE_INVALID_MSG,
            }, 401)

    org = organization.get_by_id(org_id)
    if not org:
        return flask.abort(405)

    usr = org.find_user(name=username)
    if not usr:
        usr = org.new_user(name=username,
                           email=email,
                           type=CERT_CLIENT,
                           auth_type=sso_mode,
                           groups=list(groups) if groups else None)
        usr.audit_event('user_created',
                        'User created with single sign-on',
                        remote_addr=utils.get_remote_addr())

        event.Event(type=ORGS_UPDATED)
        event.Event(type=USERS_UPDATED, resource_id=org.id)
        event.Event(type=SERVERS_UPDATED)
    else:
        if usr.disabled:
            return flask.abort(403)

        if groups and groups - set(usr.groups or []):
            usr.groups = list(set(usr.groups or []) | groups)
            usr.commit('groups')

        if usr.auth_type != sso_mode:
            usr.auth_type = sso_mode
            usr.commit('auth_type')

    key_link = org.create_user_key_link(usr.id, one_time=True)

    usr.audit_event(
        'user_profile',
        'User profile viewed from single sign-on',
        remote_addr=utils.get_remote_addr(),
    )

    return utils.jsonify(
        {
            'redirect': utils.get_url_root() + key_link['view_url'],
        }, 200)
示例#8
0
    def _auth_push_thread(self):
        info = {
            'Server': self.server.name,
        }

        platform_name = None
        if self.platform == 'linux':
            platform_name = 'Linux'
        elif self.platform == 'mac':
            platform_name = 'macOS'
        elif self.platform == 'ios':
            platform_name = 'iOS'
        elif self.platform == 'win':
            platform_name = 'Windows'
        elif self.platform == 'chrome':
            platform_name = 'Chrome OS'

        if self.device_name:
            info['Device'] = '%s (%s)' % (self.device_name, platform_name)

        onelogin_mode = utils.get_onelogin_mode()
        okta_mode = utils.get_okta_mode()

        if self.push_type == DUO_AUTH:
            duo_auth = sso.Duo(
                username=self.user.name,
                factor=settings.app.sso_duo_mode,
                remote_ip=self.remote_ip,
                auth_type='Connection',
                info=info,
            )
            allow = duo_auth.authenticate()
        elif self.push_type == SAML_ONELOGIN_AUTH:
            allow = sso.auth_onelogin_secondary(
                username=self.user.name,
                passcode=None,
                remote_ip=self.remote_ip,
                onelogin_mode=onelogin_mode,
            )
        elif self.push_type == SAML_OKTA_AUTH:
            allow = sso.auth_okta_secondary(
                username=self.user.name,
                passcode=None,
                remote_ip=self.remote_ip,
                okta_mode=okta_mode,
            )
        else:
            raise ValueError('Unkown push auth type')

        if not allow:
            self.user.audit_event(
                'user_connection',
                ('User connection to "%s" denied. ' +
                 'Push authentication failed') % (self.server.name),
                remote_addr=self.remote_ip,
            )
            raise AuthError('User failed push authentication')

        if settings.app.sso_cache and not self.server_auth_token:
            self.sso_push_cache_collection.update(
                {
                    'user_id': self.user.id,
                    'server_id': self.server.id,
                    'mac_addr': self.mac_addr,
                    'device_id': self.device_id,
                    'device_name': self.device_name,
                }, {
                    'user_id': self.user.id,
                    'server_id': self.server.id,
                    'remote_ip': self.remote_ip,
                    'mac_addr': self.mac_addr,
                    'platform': self.platform,
                    'device_id': self.device_id,
                    'device_name': self.device_name,
                    'timestamp': utils.now(),
                },
                upsert=True)
示例#9
0
    def _check_password(self):
        if settings.vpn.stress_test or self.user.link_server_id:
            return

        if self.user.bypass_secondary:
            logger.info(
                'Bypass secondary enabled, skipping password',
                'sso',
                user_name=self.user.name,
                org_name=self.user.org.name,
                server_name=self.server.name,
            )
            return

        if self.has_token:
            logger.info(
                'Client authentication cached, skipping password',
                'sso',
                user_name=self.user.name,
                org_name=self.user.org.name,
                server_name=self.server.name,
            )
            return

        if self.whitelisted:
            logger.info(
                'Client network whitelisted, skipping password',
                'sso',
                user_name=self.user.name,
                org_name=self.user.org.name,
                server_name=self.server.name,
            )
            return

        if not limiter.auth_check(self.user.id):
            self.user.audit_event(
                'user_connection',
                ('User connection to "%s" denied. Too many ' +
                 'authentication attempts') % (self.server.name),
                remote_addr=self.remote_ip,
            )
            raise AuthError('Too many authentication attempts')

        sso_mode = settings.app.sso or ''
        duo_mode = settings.app.sso_duo_mode
        onelogin_mode = utils.get_onelogin_mode()
        okta_mode = utils.get_okta_mode()
        auth_type = self.user.auth_type or ''

        has_duo_passcode = DUO_AUTH in sso_mode and \
            DUO_AUTH in auth_type and duo_mode == 'passcode'
        has_onelogin_passcode = SAML_ONELOGIN_AUTH == sso_mode and \
            SAML_ONELOGIN_AUTH in auth_type and onelogin_mode == 'passcode'
        has_okta_passcode = SAML_OKTA_AUTH == sso_mode and \
            SAML_OKTA_AUTH in auth_type and okta_mode == 'passcode'

        if has_duo_passcode or has_onelogin_passcode or has_okta_passcode:
            if not self.password and self.has_challenge() and \
                    self.user.has_pin():
                self.user.audit_event(
                    'user_connection',
                    ('User connection to "%s" denied. ' +
                     'User failed pin authentication') % (self.server.name),
                    remote_addr=self.remote_ip,
                )
                self.set_challenge(None, 'Enter Pin', False)
                raise AuthError('Challenge pin')

            challenge = self.get_challenge()
            if challenge:
                self.password = challenge + self.password

            passcode_len = settings.app.sso_duo_passcode_length
            orig_password = self.password
            passcode = self.password[-passcode_len:]
            self.password = self.password[:-passcode_len]

            allow = False
            if settings.app.sso_cache and not self.server_auth_token:
                doc = self.sso_passcode_cache_collection.find_one({
                    'user_id':
                    self.user.id,
                    'server_id':
                    self.server.id,
                    'remote_ip':
                    self.remote_ip,
                    'mac_addr':
                    self.mac_addr,
                    'platform':
                    self.platform,
                    'device_id':
                    self.device_id,
                    'device_name':
                    self.device_name,
                    'passcode':
                    passcode,
                })
                if doc:
                    self.sso_passcode_cache_collection.update(
                        {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': passcode,
                        }, {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': passcode,
                            'timestamp': utils.now(),
                        })
                    allow = True

                    logger.info(
                        'Authentication cached, skipping secondary passcode',
                        'sso',
                        user_name=self.user.name,
                        org_name=self.user.org.name,
                        server_name=self.server.name,
                    )

            if not allow:
                if DUO_AUTH in sso_mode:
                    label = 'Duo'
                    duo_auth = sso.Duo(
                        username=self.user.name,
                        factor=duo_mode,
                        remote_ip=self.remote_ip,
                        auth_type='Connection',
                        passcode=passcode,
                    )
                    allow = duo_auth.authenticate()
                elif SAML_ONELOGIN_AUTH == sso_mode:
                    label = 'OneLogin'
                    allow = sso.auth_onelogin_secondary(
                        username=self.user.name,
                        passcode=passcode,
                        remote_ip=self.remote_ip,
                        onelogin_mode=onelogin_mode,
                    )
                elif SAML_OKTA_AUTH == sso_mode:
                    label = 'Okta'
                    allow = sso.auth_okta_secondary(
                        username=self.user.name,
                        passcode=passcode,
                        remote_ip=self.remote_ip,
                        okta_mode=okta_mode,
                    )
                else:
                    raise AuthError('Unknown secondary passcode challenge')

                if not allow:
                    self.user.audit_event(
                        'user_connection',
                        ('User connection to "%s" denied. ' +
                         'User failed %s passcode authentication') %
                        (self.server.name, label),
                        remote_addr=self.remote_ip,
                    )

                    if self.has_challenge():
                        if self.user.has_password(self.server):
                            self.set_challenge(orig_password,
                                               'Enter %s Passcode' % label,
                                               True)
                        else:
                            self.set_challenge(None,
                                               'Enter %s Passcode' % label,
                                               True)
                        raise AuthError('Challenge secondary passcode')
                    raise AuthError('Invalid secondary passcode')

                if settings.app.sso_cache and not self.server_auth_token:
                    self.sso_passcode_cache_collection.update(
                        {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'mac_addr': self.mac_addr,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                        }, {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': passcode,
                            'timestamp': utils.now(),
                        },
                        upsert=True)

        elif YUBICO_AUTH in sso_mode and YUBICO_AUTH in auth_type:
            if not self.password and self.has_challenge() and \
                    self.user.has_pin():
                self.user.audit_event(
                    'user_connection',
                    ('User connection to "%s" denied. ' +
                     'User failed pin authentication') % (self.server.name),
                    remote_addr=self.remote_ip,
                )
                self.set_challenge(None, 'Enter Pin', False)
                raise AuthError('Challenge pin')

            challenge = self.get_challenge()
            if challenge:
                self.password = challenge + self.password

            orig_password = self.password
            yubikey = self.password[-44:]
            self.password = self.password[:-44]

            yubikey_hash = hashlib.sha512()
            yubikey_hash.update(yubikey)
            yubikey_hash = base64.b64encode(yubikey_hash.digest())

            allow = False
            if settings.app.sso_cache and not self.server_auth_token:
                doc = self.sso_passcode_cache_collection.find_one({
                    'user_id':
                    self.user.id,
                    'server_id':
                    self.server.id,
                    'remote_ip':
                    self.remote_ip,
                    'mac_addr':
                    self.mac_addr,
                    'platform':
                    self.platform,
                    'device_id':
                    self.device_id,
                    'device_name':
                    self.device_name,
                    'passcode':
                    yubikey_hash,
                })
                if doc:
                    self.sso_passcode_cache_collection.update(
                        {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': yubikey_hash,
                        }, {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': yubikey_hash,
                            'timestamp': utils.now(),
                        })
                    allow = True

                    logger.info(
                        'Authentication cached, skipping Yubikey',
                        'sso',
                        user_name=self.user.name,
                        org_name=self.user.org.name,
                        server_name=self.server.name,
                    )

            if not allow:
                valid, yubico_id = sso.auth_yubico(yubikey)
                if yubico_id != self.user.yubico_id:
                    valid = False

                if not valid:
                    self.user.audit_event(
                        'user_connection',
                        ('User connection to "%s" denied. ' +
                         'User failed Yubico authentication') %
                        (self.server.name),
                        remote_addr=self.remote_ip,
                    )

                    if self.has_challenge():
                        if self.user.has_password(self.server):
                            self.set_challenge(orig_password, 'YubiKey', True)
                        else:
                            self.set_challenge(None, 'YubiKey', True)
                        raise AuthError('Challenge YubiKey')
                    raise AuthError('Invalid YubiKey')

                if settings.app.sso_cache and not self.server_auth_token:
                    self.sso_passcode_cache_collection.update(
                        {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'mac_addr': self.mac_addr,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                        }, {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': yubikey_hash,
                            'timestamp': utils.now(),
                        },
                        upsert=True)

        elif self.server.otp_auth and self.user.type == CERT_CLIENT:
            if not self.password and self.has_challenge() and \
                    self.user.has_pin():
                self.user.audit_event(
                    'user_connection',
                    ('User connection to "%s" denied. ' +
                     'User failed pin authentication') % (self.server.name),
                    remote_addr=self.remote_ip,
                )
                self.set_challenge(None, 'Enter Pin', False)
                raise AuthError('Challenge pin')

            challenge = self.get_challenge()
            if challenge:
                self.password = challenge + self.password

            orig_password = self.password
            otp_code = self.password[-6:]
            self.password = self.password[:-6]

            allow = False
            if settings.app.sso_cache and not self.server_auth_token:
                doc = self.otp_cache_collection.find_one({
                    'user_id':
                    self.user.id,
                    'server_id':
                    self.server.id,
                    'remote_ip':
                    self.remote_ip,
                    'mac_addr':
                    self.mac_addr,
                    'platform':
                    self.platform,
                    'device_id':
                    self.device_id,
                    'device_name':
                    self.device_name,
                    'passcode':
                    otp_code,
                })
                if doc:
                    self.otp_cache_collection.update(
                        {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': otp_code,
                        }, {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': otp_code,
                            'timestamp': utils.now(),
                        })
                    allow = True

                    logger.info(
                        'Authentication cached, skipping OTP',
                        'sso',
                        user_name=self.user.name,
                        org_name=self.user.org.name,
                        server_name=self.server.name,
                    )

            if not allow:
                if not self.user.verify_otp_code(otp_code):
                    self.user.audit_event(
                        'user_connection',
                        ('User connection to "%s" denied. ' +
                         'User failed two-step authentication') %
                        (self.server.name),
                        remote_addr=self.remote_ip,
                    )

                    if self.has_challenge():
                        if self.user.has_password(self.server):
                            self.set_challenge(orig_password, 'Enter OTP Code',
                                               True)
                        else:
                            self.set_challenge(None, 'Enter OTP Code', True)
                        raise AuthError('Challenge OTP code')
                    raise AuthError('Invalid OTP code')

                if settings.app.sso_cache and not self.server_auth_token:
                    self.otp_cache_collection.update(
                        {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'mac_addr': self.mac_addr,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                        }, {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': otp_code,
                            'timestamp': utils.now(),
                        },
                        upsert=True)

        if self.user.has_pin():
            if not self.user.check_pin(self.password):
                self.user.audit_event(
                    'user_connection',
                    ('User connection to "%s" denied. ' +
                     'User failed pin authentication') % (self.server.name),
                    remote_addr=self.remote_ip,
                )

                if self.has_challenge():
                    self.set_challenge(None, 'Enter Pin', False)
                    raise AuthError('Challenge pin')
                raise AuthError('Invalid pin')
        elif settings.user.pin_mode == PIN_REQUIRED:
            self.user.audit_event(
                'user_connection',
                ('User connection to "%s" denied. ' +
                 'User does not have a pin set') % (self.server.name),
                remote_addr=self.remote_ip,
            )
            raise AuthError('User does not have a pin set')
示例#10
0
    def _check_password(self):
        if self.user.bypass_secondary or self.user.link_server_id or \
                settings.vpn.stress_test or self.has_token:
            return

        sso_mode = settings.app.sso or ''
        duo_mode = settings.app.sso_duo_mode
        auth_type = self.user.auth_type or ''
        if DUO_AUTH in sso_mode and DUO_AUTH in auth_type and \
                duo_mode == 'passcode':
            if not self.password and self.has_challenge() and \
                self.user.has_pin():
                self.set_challenge(None, 'Enter Pin', False)
                raise AuthError('Challenge pin')

            challenge = self.get_challenge()
            if challenge:
                self.password = challenge + self.password

            passcode_len = settings.app.sso_duo_passcode_length
            orig_password = self.password
            passcode = self.password[-passcode_len:]
            self.password = self.password[:-passcode_len]

            allow = False
            if settings.app.sso_cache:
                doc = self.sso_passcode_cache_collection.find_one({
                    'user_id':
                    self.user.id,
                    'server_id':
                    self.server.id,
                    'remote_ip':
                    self.remote_ip,
                    'mac_addr':
                    self.mac_addr,
                    'platform':
                    self.platform,
                    'device_id':
                    self.device_id,
                    'device_name':
                    self.device_name,
                    'passcode':
                    passcode,
                })
                if doc:
                    self.sso_passcode_cache_collection.update(
                        {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': passcode,
                        }, {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': passcode,
                            'timestamp': utils.now(),
                        })
                    allow = True

            if not allow:
                duo_auth = sso.Duo(
                    username=self.user.name,
                    factor=duo_mode,
                    remote_ip=self.remote_ip,
                    auth_type='Connection',
                    passcode=passcode,
                )
                allow = duo_auth.authenticate()

                if not allow:
                    if self.has_challenge():
                        if self.user.has_password(self.server):
                            self.set_challenge(orig_password,
                                               'Enter Duo Passcode', True)
                        else:
                            self.set_challenge(None, 'Enter Duo Passcode',
                                               True)
                        raise AuthError('Challenge Duo code')

                    self.user.audit_event(
                        'user_connection',
                        ('User connection to "%s" denied. ' +
                         'User failed Duo passcode authentication') %
                        (self.server.name),
                        remote_addr=self.remote_ip,
                    )
                    raise AuthError('Invalid OTP code')

                if settings.app.sso_cache:
                    self.sso_passcode_cache_collection.update(
                        {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'mac_addr': self.mac_addr,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                        }, {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': passcode,
                            'timestamp': utils.now(),
                        },
                        upsert=True)

        elif YUBICO_AUTH in sso_mode and YUBICO_AUTH in auth_type:
            if not self.password and self.has_challenge() and \
                    self.user.has_pin():
                self.set_challenge(None, 'Enter Pin', False)
                raise AuthError('Challenge pin')

            challenge = self.get_challenge()
            if challenge:
                self.password = challenge + self.password

            orig_password = self.password
            yubikey = self.password[-44:]
            self.password = self.password[:-44]

            yubikey_hash = hashlib.sha512()
            yubikey_hash.update(yubikey)
            yubikey_hash = base64.b64encode(yubikey_hash.digest())

            allow = False
            if settings.app.sso_cache:
                doc = self.sso_passcode_cache_collection.find_one({
                    'user_id':
                    self.user.id,
                    'server_id':
                    self.server.id,
                    'remote_ip':
                    self.remote_ip,
                    'mac_addr':
                    self.mac_addr,
                    'platform':
                    self.platform,
                    'device_id':
                    self.device_id,
                    'device_name':
                    self.device_name,
                    'passcode':
                    yubikey_hash,
                })
                if doc:
                    self.sso_passcode_cache_collection.update(
                        {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': yubikey_hash,
                        }, {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': yubikey_hash,
                            'timestamp': utils.now(),
                        })
                    allow = True

            if not allow:
                valid, yubico_id = sso.auth_yubico(yubikey)
                if yubico_id != self.user.yubico_id:
                    valid = False

                if not valid:
                    if self.has_challenge():
                        if self.user.has_password(self.server):
                            self.set_challenge(orig_password, 'YubiKey', True)
                        else:
                            self.set_challenge(None, 'YubiKey', True)
                        raise AuthError('Challenge YubiKey')

                    self.user.audit_event(
                        'user_connection',
                        ('User connection to "%s" denied. ' +
                         'User failed Yubico authentication') %
                        (self.server.name),
                        remote_addr=self.remote_ip,
                    )
                    raise AuthError('Invalid YubiKey')

                if settings.app.sso_cache:
                    self.sso_passcode_cache_collection.update(
                        {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'mac_addr': self.mac_addr,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                        }, {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': yubikey_hash,
                            'timestamp': utils.now(),
                        },
                        upsert=True)

        elif self.server.otp_auth and self.user.type == CERT_CLIENT:
            if not self.password and self.has_challenge() and \
                    self.user.has_pin():
                self.set_challenge(None, 'Enter Pin', False)
                raise AuthError('Challenge pin')

            challenge = self.get_challenge()
            if challenge:
                self.password = challenge + self.password

            orig_password = self.password
            otp_code = self.password[-6:]
            self.password = self.password[:-6]

            allow = False
            if settings.vpn.otp_cache:
                doc = self.otp_cache_collection.find_one({
                    'user_id':
                    self.user.id,
                    'server_id':
                    self.server.id,
                    'remote_ip':
                    self.remote_ip,
                    'mac_addr':
                    self.mac_addr,
                    'platform':
                    self.platform,
                    'device_id':
                    self.device_id,
                    'device_name':
                    self.device_name,
                    'passcode':
                    otp_code,
                })
                if doc:
                    self.otp_cache_collection.update(
                        {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': otp_code,
                        }, {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': otp_code,
                            'timestamp': utils.now(),
                        })
                    allow = True

            if not allow:
                if not self.user.verify_otp_code(otp_code):
                    if self.has_challenge():
                        if self.user.has_password(self.server):
                            self.set_challenge(orig_password, 'Enter OTP Code',
                                               True)
                        else:
                            self.set_challenge(None, 'Enter OTP Code', True)
                        raise AuthError('Challenge OTP code')

                    self.user.audit_event(
                        'user_connection',
                        ('User connection to "%s" denied. ' +
                         'User failed two-step authentication') %
                        (self.server.name),
                        remote_addr=self.remote_ip,
                    )
                    raise AuthError('Invalid OTP code')

                if settings.vpn.otp_cache:
                    self.otp_cache_collection.update(
                        {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'mac_addr': self.mac_addr,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                        }, {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': otp_code,
                            'timestamp': utils.now(),
                        },
                        upsert=True)

        if self.user.has_pin():
            if not self.user.check_pin(self.password):
                if self.has_challenge():
                    self.set_challenge(None, 'Enter Pin', False)
                    raise AuthError('Challenge pin')

                self.user.audit_event(
                    'user_connection',
                    ('User connection to "%s" denied. ' +
                     'User failed pin authentication') % (self.server.name),
                    remote_addr=self.remote_ip,
                )
                raise AuthError('Invalid pin')
        elif settings.user.pin_mode == PIN_REQUIRED:
            self.user.audit_event(
                'user_connection',
                ('User connection to "%s" denied. ' +
                 'User does not have a pin set') % (self.server.name),
                remote_addr=self.remote_ip,
            )
            raise AuthError('User does not have a pin set')
示例#11
0
    def _check_password(self):
        if settings.vpn.stress_test or self.user.link_server_id:
            return

        if self.user.bypass_secondary:
            logger.info(
                'Bypass secondary enabled, skipping password',
                'sso',
                username=self.user.name,
            )
            return

        if self.has_token:
            logger.info(
                'Client authentication cached, skipping password',
                'sso',
                username=self.user.name,
            )
            return

        if self.whitelisted:
            logger.info(
                'Client network whitelisted, skipping password',
                'sso',
                username=self.user.name,
            )
            return

        doc = self.limiter_collection.find_and_modify({
            '_id': self.user.id,
        }, {
            '$inc': {
                'count': 1
            },
            '$setOnInsert': {
                'timestamp': utils.now()
            },
        },
                                                      new=True,
                                                      upsert=True)

        if utils.now() > doc['timestamp'] + datetime.timedelta(
                seconds=settings.app.auth_limiter_ttl):
            doc = {
                'count': 1,
                'timestamp': utils.now(),
            }
            self.limiter_collection.update({
                '_id': self.user.id,
            },
                                           doc,
                                           upsert=True)

        if doc['count'] > settings.app.auth_limiter_count_max:
            self.user.audit_event(
                'user_connection',
                ('User connection to "%s" denied. Too many ' +
                 'authentication attempts') % (self.server.name),
                remote_addr=self.remote_ip,
            )
            raise AuthError('Too many authentication attempts')

        sso_mode = settings.app.sso or ''
        duo_mode = settings.app.sso_duo_mode
        auth_type = self.user.auth_type or ''
        if DUO_AUTH in sso_mode and DUO_AUTH in auth_type and \
                duo_mode == 'passcode':
            if not self.password and self.has_challenge() and \
                    self.user.has_pin():
                self.user.audit_event(
                    'user_connection',
                    ('User connection to "%s" denied. ' +
                     'User failed pin authentication') % (self.server.name),
                    remote_addr=self.remote_ip,
                )
                self.set_challenge(None, 'Enter Pin', False)
                raise AuthError('Challenge pin')

            challenge = self.get_challenge()
            if challenge:
                self.password = challenge + self.password

            passcode_len = settings.app.sso_duo_passcode_length
            orig_password = self.password
            passcode = self.password[-passcode_len:]
            self.password = self.password[:-passcode_len]

            allow = False
            if settings.app.sso_cache:
                doc = self.sso_passcode_cache_collection.find_one({
                    'user_id':
                    self.user.id,
                    'server_id':
                    self.server.id,
                    'remote_ip':
                    self.remote_ip,
                    'mac_addr':
                    self.mac_addr,
                    'platform':
                    self.platform,
                    'device_id':
                    self.device_id,
                    'device_name':
                    self.device_name,
                    'passcode':
                    passcode,
                })
                if doc:
                    self.sso_passcode_cache_collection.update(
                        {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': passcode,
                        }, {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': passcode,
                            'timestamp': utils.now(),
                        })
                    allow = True

                    logger.info(
                        'Authentication cached, skipping Duo',
                        'sso',
                        username=self.user.name,
                    )

            if not allow:
                duo_auth = sso.Duo(
                    username=self.user.name,
                    factor=duo_mode,
                    remote_ip=self.remote_ip,
                    auth_type='Connection',
                    passcode=passcode,
                )
                allow = duo_auth.authenticate()

                if not allow:
                    self.user.audit_event(
                        'user_connection',
                        ('User connection to "%s" denied. ' +
                         'User failed Duo passcode authentication') %
                        (self.server.name),
                        remote_addr=self.remote_ip,
                    )

                    if self.has_challenge():
                        if self.user.has_password(self.server):
                            self.set_challenge(orig_password,
                                               'Enter Duo Passcode', True)
                        else:
                            self.set_challenge(None, 'Enter Duo Passcode',
                                               True)
                        raise AuthError('Challenge Duo code')
                    raise AuthError('Invalid OTP code')

                if settings.app.sso_cache:
                    self.sso_passcode_cache_collection.update(
                        {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'mac_addr': self.mac_addr,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                        }, {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': passcode,
                            'timestamp': utils.now(),
                        },
                        upsert=True)

        elif YUBICO_AUTH in sso_mode and YUBICO_AUTH in auth_type:
            if not self.password and self.has_challenge() and \
                    self.user.has_pin():
                self.user.audit_event(
                    'user_connection',
                    ('User connection to "%s" denied. ' +
                     'User failed pin authentication') % (self.server.name),
                    remote_addr=self.remote_ip,
                )
                self.set_challenge(None, 'Enter Pin', False)
                raise AuthError('Challenge pin')

            challenge = self.get_challenge()
            if challenge:
                self.password = challenge + self.password

            orig_password = self.password
            yubikey = self.password[-44:]
            self.password = self.password[:-44]

            yubikey_hash = hashlib.sha512()
            yubikey_hash.update(yubikey)
            yubikey_hash = base64.b64encode(yubikey_hash.digest())

            allow = False
            if settings.app.sso_cache:
                doc = self.sso_passcode_cache_collection.find_one({
                    'user_id':
                    self.user.id,
                    'server_id':
                    self.server.id,
                    'remote_ip':
                    self.remote_ip,
                    'mac_addr':
                    self.mac_addr,
                    'platform':
                    self.platform,
                    'device_id':
                    self.device_id,
                    'device_name':
                    self.device_name,
                    'passcode':
                    yubikey_hash,
                })
                if doc:
                    self.sso_passcode_cache_collection.update(
                        {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': yubikey_hash,
                        }, {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': yubikey_hash,
                            'timestamp': utils.now(),
                        })
                    allow = True

                    logger.info(
                        'Authentication cached, skipping Yubikey',
                        'sso',
                        username=self.user.name,
                    )

            if not allow:
                valid, yubico_id = sso.auth_yubico(yubikey)
                if yubico_id != self.user.yubico_id:
                    valid = False

                if not valid:
                    self.user.audit_event(
                        'user_connection',
                        ('User connection to "%s" denied. ' +
                         'User failed Yubico authentication') %
                        (self.server.name),
                        remote_addr=self.remote_ip,
                    )

                    if self.has_challenge():
                        if self.user.has_password(self.server):
                            self.set_challenge(orig_password, 'YubiKey', True)
                        else:
                            self.set_challenge(None, 'YubiKey', True)
                        raise AuthError('Challenge YubiKey')
                    raise AuthError('Invalid YubiKey')

                if settings.app.sso_cache:
                    self.sso_passcode_cache_collection.update(
                        {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'mac_addr': self.mac_addr,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                        }, {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': yubikey_hash,
                            'timestamp': utils.now(),
                        },
                        upsert=True)

        elif self.server.otp_auth and self.user.type == CERT_CLIENT:
            if not self.password and self.has_challenge() and \
                    self.user.has_pin():
                self.user.audit_event(
                    'user_connection',
                    ('User connection to "%s" denied. ' +
                     'User failed pin authentication') % (self.server.name),
                    remote_addr=self.remote_ip,
                )
                self.set_challenge(None, 'Enter Pin', False)
                raise AuthError('Challenge pin')

            challenge = self.get_challenge()
            if challenge:
                self.password = challenge + self.password

            orig_password = self.password
            otp_code = self.password[-6:]
            self.password = self.password[:-6]

            allow = False
            if settings.vpn.otp_cache:
                doc = self.otp_cache_collection.find_one({
                    'user_id':
                    self.user.id,
                    'server_id':
                    self.server.id,
                    'remote_ip':
                    self.remote_ip,
                    'mac_addr':
                    self.mac_addr,
                    'platform':
                    self.platform,
                    'device_id':
                    self.device_id,
                    'device_name':
                    self.device_name,
                    'passcode':
                    otp_code,
                })
                if doc:
                    self.otp_cache_collection.update(
                        {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': otp_code,
                        }, {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': otp_code,
                            'timestamp': utils.now(),
                        })
                    allow = True

                    logger.info(
                        'Authentication cached, skipping OTP',
                        'sso',
                        username=self.user.name,
                    )

            if not allow:
                if not self.user.verify_otp_code(otp_code):
                    self.user.audit_event(
                        'user_connection',
                        ('User connection to "%s" denied. ' +
                         'User failed two-step authentication') %
                        (self.server.name),
                        remote_addr=self.remote_ip,
                    )

                    if self.has_challenge():
                        if self.user.has_password(self.server):
                            self.set_challenge(orig_password, 'Enter OTP Code',
                                               True)
                        else:
                            self.set_challenge(None, 'Enter OTP Code', True)
                        raise AuthError('Challenge OTP code')
                    raise AuthError('Invalid OTP code')

                if settings.vpn.otp_cache:
                    self.otp_cache_collection.update(
                        {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'mac_addr': self.mac_addr,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                        }, {
                            'user_id': self.user.id,
                            'server_id': self.server.id,
                            'remote_ip': self.remote_ip,
                            'mac_addr': self.mac_addr,
                            'platform': self.platform,
                            'device_id': self.device_id,
                            'device_name': self.device_name,
                            'passcode': otp_code,
                            'timestamp': utils.now(),
                        },
                        upsert=True)

        if self.user.has_pin():
            if not self.user.check_pin(self.password):
                self.user.audit_event(
                    'user_connection',
                    ('User connection to "%s" denied. ' +
                     'User failed pin authentication') % (self.server.name),
                    remote_addr=self.remote_ip,
                )

                if self.has_challenge():
                    self.set_challenge(None, 'Enter Pin', False)
                    raise AuthError('Challenge pin')
                raise AuthError('Invalid pin')
        elif settings.user.pin_mode == PIN_REQUIRED:
            self.user.audit_event(
                'user_connection',
                ('User connection to "%s" denied. ' +
                 'User does not have a pin set') % (self.server.name),
                remote_addr=self.remote_ip,
            )
            raise AuthError('User does not have a pin set')
示例#12
0
    def _check_password(self):
        if self.user.bypass_secondary or self.user.link_server_id or \
                settings.vpn.stress_test:
            return

        duo_mode = settings.app.sso_duo_mode
        if DUO_AUTH in self.user.auth_type and duo_mode == 'passcode':
            if not self.password and self.has_challenge() and \
                self.user.has_pin():
                self.set_challenge(None, 'Enter Pin', False)
                raise AuthError('Challenge pin')

            challenge = self.get_challenge()
            if challenge:
                self.password = challenge + self.password

            passcode_len = settings.app.sso_duo_passcode_length
            orig_password = self.password
            passcode = self.password[-passcode_len:]
            self.password = self.password[:-passcode_len]

            allow = False
            if settings.app.sso_passcode_cache:
                doc = self.sso_passcode_cache_collection.find_one({
                    'user_id': self.user.id,
                    'server_id': self.server.id,
                    'remote_ip': self.remote_ip,
                    'mac_addr': self.mac_addr,
                    'platform': self.platform,
                    'device_id': self.device_id,
                    'device_name': self.device_name,
                    'passcode': passcode,
                })
                if doc:
                    self.sso_passcode_cache_collection.update({
                        'user_id': self.user.id,
                        'server_id': self.server.id,
                        'remote_ip': self.remote_ip,
                        'mac_addr': self.mac_addr,
                        'platform': self.platform,
                        'device_id': self.device_id,
                        'device_name': self.device_name,
                        'passcode': passcode,
                    }, {
                        'user_id': self.user.id,
                        'server_id': self.server.id,
                        'remote_ip': self.remote_ip,
                        'mac_addr': self.mac_addr,
                        'platform': self.platform,
                        'device_id': self.device_id,
                        'device_name': self.device_name,
                        'passcode': passcode,
                        'timestamp': utils.now(),
                    })
                    allow = True

            if not allow:
                duo_auth = sso.Duo(
                    username=self.user.name,
                    factor=duo_mode,
                    remote_ip=self.remote_ip,
                    auth_type='Connection',
                    passcode=passcode,
                )
                allow = duo_auth.authenticate()

                if not allow:
                    if self.has_challenge():
                        if self.user.has_password(self.server):
                            self.set_challenge(
                                orig_password, 'Enter Duo Passcode', True)
                        else:
                            self.set_challenge(
                                None, 'Enter Duo Passcode', True)
                        raise AuthError('Challenge otp code')

                    self.user.audit_event('user_connection',
                        ('User connection to "%s" denied. ' +
                         'User failed Duo passcode authentication') % (
                            self.server.name),
                        remote_addr=self.remote_ip,
                    )
                    raise AuthError('Invalid OTP code')

                if settings.app.sso_passcode_cache:
                    self.sso_passcode_cache_collection.update({
                        'user_id': self.user.id,
                        'server_id': self.server.id,
                        'remote_ip': self.remote_ip,
                        'mac_addr': self.mac_addr,
                        'platform': self.platform,
                        'device_id': self.device_id,
                        'device_name': self.device_name,
                    }, {
                        'user_id': self.user.id,
                        'server_id': self.server.id,
                        'remote_ip': self.remote_ip,
                        'mac_addr': self.mac_addr,
                        'platform': self.platform,
                        'device_id': self.device_id,
                        'device_name': self.device_name,
                        'passcode': passcode,
                        'timestamp': utils.now(),
                    }, upsert=True)

        elif self.server.otp_auth and self.user.type == CERT_CLIENT:
            if not self.password and self.has_challenge() and \
                    self.user.has_pin():
                self.set_challenge(None, 'Enter Pin', False)
                raise AuthError('Challenge pin')

            challenge = self.get_challenge()
            if challenge:
                self.password = challenge + self.password

            orig_password = self.password
            otp_code = self.password[-6:]
            self.password = self.password[:-6]

            if not self.user.verify_otp_code(otp_code, self.remote_ip):
                if self.has_challenge():
                    if self.user.has_password(self.server):
                        self.set_challenge(
                            orig_password, 'Enter OTP Code', True)
                    else:
                        self.set_challenge(None, 'Enter OTP Code', True)
                    raise AuthError('Challenge otp code')

                self.user.audit_event('user_connection',
                    ('User connection to "%s" denied. ' +
                     'User failed two-step authentication') % (
                        self.server.name),
                    remote_addr=self.remote_ip,
                )
                raise AuthError('Invalid OTP code')

        if self.user.has_pin():
            if not self.user.check_pin(self.password):
                if self.has_challenge():
                    self.set_challenge(None, 'Enter Pin', False)
                    raise AuthError('Challenge pin')

                self.user.audit_event('user_connection',
                    ('User connection to "%s" denied. ' +
                     'User failed pin authentication') % (
                        self.server.name),
                    remote_addr=self.remote_ip,
                )
                raise AuthError('Invalid pin')
        elif settings.user.pin_mode == PIN_REQUIRED:
            self.user.audit_event('user_connection',
                ('User connection to "%s" denied. ' +
                 'User does not have a pin set') % (
                    self.server.name),
                remote_addr=self.remote_ip,
            )
            raise AuthError('User does not have a pin set')