예제 #1
0
파일: auth.py 프로젝트: liinnux/pritunl
def _auth_radius(username, password):
    valid, org_id = sso.verify_radius(username, password)
    if not valid:
        return utils.jsonify({
            'error': AUTH_INVALID,
            'error_msg': AUTH_INVALID_MSG,
        }, 401)

    if not org_id:
        org_id = settings.app.sso_org

    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=RADIUS_AUTH)
        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 usr.auth_type != RADIUS_AUTH:
            usr.auth_type = RADIUS_AUTH
            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': flask.request.url_root[:-1] + key_link['view_url'],
    }, 202)
예제 #2
0
파일: app.py 프로젝트: ampg99/pritunl
def after_request(response):
    if not flask.g.authed:
        raise ValueError('Request not authorized')

    resp_time = int((time.time() - flask.g.start) * 1000)
    db_time = int(flask.g.query_time * 1000)
    db_reads = flask.g.query_count
    db_writes = flask.g.write_count

    response.headers.add('Execution-Time', resp_time)
    response.headers.add('Query-Time', db_time)
    response.headers.add('Query-Count', db_reads)
    response.headers.add('Write-Count', db_writes)

    if not flask.request.path.startswith('/event'):
        monitoring.insert_point('requests', {
            'host': settings.local.host.name,
        }, {
            'path': flask.request.path,
            'remote_ip': utils.get_remote_addr(),
            'response_time': resp_time,
            'db_time': db_time,
            'db_reads': db_reads,
            'db_writes': db_writes,
        })

    return response
예제 #3
0
def user_post(org_id):
    if settings.app.demo_mode:
        return utils.demo_blocked()

    remote_addr = utils.get_remote_addr()

    if isinstance(flask.request.json, list):
        users_data = flask.request.json
    else:
        users_data = [flask.request.json]

    if len(users_data) > 10:
        if _users_background:
            return utils.jsonify({
                'error': USERS_BACKGROUND_BUSY,
                'error_msg': USERS_BACKGROUND_BUSY_MSG,
            }, 429)

        thread = threading.Thread(
            target=_create_users,
            args=(org_id, users_data, remote_addr, True),
        )
        thread.daemon = True
        thread.start()

        return utils.jsonify({
            'status': USERS_BACKGROUND,
            'status_msg': USERS_BACKGROUND_MSG,
        }, 202)

    return _create_users(org_id, users_data, remote_addr, False)
예제 #4
0
파일: admin.py 프로젝트: nclements/pritunl
def admin_post():
    if settings.app.demo_mode:
        return utils.demo_blocked()

    if not flask.g.administrator.super_user:
        return utils.jsonify({"error": REQUIRES_SUPER_USER, "error_msg": REQUIRES_SUPER_USER_MSG}, 400)

    username = utils.filter_str(flask.request.json["username"])
    password = flask.request.json["password"]
    otp_auth = flask.request.json.get("otp_auth", False)
    auth_api = flask.request.json.get("auth_api", False)
    disabled = flask.request.json.get("disabled", False)
    super_user = flask.request.json.get("super_user", False)

    try:
        admin = auth.new_admin(
            username=username,
            password=password,
            default=True,
            otp_auth=otp_auth,
            auth_api=auth_api,
            disabled=disabled,
            super_user=super_user,
        )
    except pymongo.errors.DuplicateKeyError:
        return utils.jsonify({"error": ADMIN_USERNAME_EXISTS, "error_msg": ADMIN_USERNAME_EXISTS_MSG}, 400)

    admin.audit_event("admin_created", "Administrator created", remote_addr=utils.get_remote_addr())

    event.Event(type=ADMINS_UPDATED)

    return utils.jsonify(admin.dict())
예제 #5
0
파일: key.py 프로젝트: animefreak93/pritunl
def user_linked_key_conf_get(key_id, server_id):
    doc = _find_doc({
        'key_id': key_id,
    })
    if not doc:
        return flask.abort(404)

    org = organization.get_by_id(doc['org_id'])
    if not org:
        return flask.abort(404)

    user = org.get_user(id=doc['user_id'])
    if not user:
        return flask.abort(404)

    if user.disabled:
        return flask.abort(403)

    key_conf = user.build_key_conf(server_id)

    user.audit_event('user_profile',
        'User profile downloaded with temporary profile link',
        remote_addr=utils.get_remote_addr(),
    )

    response = flask.Response(response=key_conf['conf'],
        mimetype='application/ovpn')
    response.headers.add('Content-Disposition',
        'attachment; filename="%s"' % key_conf['name'])

    return response
예제 #6
0
파일: key.py 프로젝트: pritunl/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 None

    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:
        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)
예제 #7
0
파일: auth.py 프로젝트: teddywest32/pritunl
def auth_session_post():
    username = flask.request.json["username"]
    password = flask.request.json["password"]
    otp_code = flask.request.json.get("otp_code")
    remote_addr = utils.get_remote_addr()

    admin = auth.get_by_username(username, remote_addr)
    if not admin:
        if settings.app.sso == RADIUS_AUTH:
            return _auth_radius(username, password)

        time.sleep(random.randint(0, 100) / 1000.0)
        return utils.jsonify({"error": AUTH_INVALID, "error_msg": AUTH_INVALID_MSG}, 401)

    if not otp_code and admin.otp_auth:
        return utils.jsonify({"error": AUTH_OTP_REQUIRED, "error_msg": AUTH_OTP_REQUIRED_MSG}, 402)

    if not admin.auth_check(password, otp_code, remote_addr):
        time.sleep(random.randint(0, 100) / 1000.0)
        return utils.jsonify({"error": AUTH_INVALID, "error_msg": AUTH_INVALID_MSG}, 401)

    flask.session["session_id"] = admin.new_session()
    flask.session["admin_id"] = str(admin.id)
    flask.session["timestamp"] = int(utils.time_now())
    if not settings.conf.ssl:
        flask.session["source"] = remote_addr

    return utils.jsonify({"authenticated": True, "default": admin.default or False})
예제 #8
0
파일: admin.py 프로젝트: pritunl/pritunl
def admin_delete(admin_id):
    if settings.app.demo_mode:
        return utils.demo_blocked()

    if not flask.g.administrator.super_user:
        return utils.jsonify({
            'error': REQUIRES_SUPER_USER,
            'error_msg': REQUIRES_SUPER_USER_MSG,
        }, 400)

    admin = auth.get_by_id(admin_id)
    remote_addr = utils.get_remote_addr()

    if admin.super_user and auth.super_user_count() < 2:
        return utils.jsonify({
            'error': NO_ADMINS,
            'error_msg': NO_ADMINS_MSG,
        }, 400)

    journal.entry(
        journal.ADMIN_DELETE,
        admin.journal_data,
        event_long='Administrator deleted',
        remote_addr=remote_addr,
    )

    admin.remove()
    event.Event(type=ADMINS_UPDATED)

    return utils.jsonify({})
예제 #9
0
파일: key.py 프로젝트: pritunl/pritunl
def user_uri_key_page_get(short_code):
    remote_addr = utils.get_remote_addr()

    doc = _find_doc({
        'short_id': short_code,
    }, one_time=True)
    if not doc:
        return flask.abort(404)

    org = organization.get_by_id(doc['org_id'])
    usr = org.get_user(id=doc['user_id'])
    if usr.disabled:
        return flask.abort(403)

    journal.entry(
        journal.USER_PROFILE_SUCCESS,
        usr.journal_data,
        remote_address=remote_addr,
        event_long='User temporary profile downloaded from pritunl client',
    )

    usr.audit_event('user_profile',
        'User temporary profile downloaded from pritunl client',
        remote_addr=remote_addr,
    )

    keys = {}
    for server in usr.iter_servers():
        key = usr.build_key_conf(server.id)
        keys[key['name']] = key['conf']

    return utils.jsonify(keys)
예제 #10
0
파일: app.py 프로젝트: pritunl/pritunl
def after_request(response):
    if settings.app.check_requests and not flask.g.valid:
        raise ValueError("Request not authorized")

    resp_time = int((time.time() - flask.g.start) * 1000)
    db_time = int(flask.g.query_time * 1000)
    db_reads = flask.g.query_count
    db_writes = flask.g.write_count

    response.headers.add("Execution-Time", resp_time)
    response.headers.add("Query-Time", db_time)
    response.headers.add("Query-Count", db_reads)
    response.headers.add("Write-Count", db_writes)

    response.headers.add("X-Frame-Options", "DENY")

    if not flask.request.path.startswith("/event"):
        monitoring.insert_point(
            "requests",
            {"host": settings.local.host.name},
            {
                "path": flask.request.path,
                "remote_ip": utils.get_remote_addr(),
                "response_time": resp_time,
                "db_time": db_time,
                "db_reads": db_reads,
                "db_writes": db_writes,
            },
        )

    return response
예제 #11
0
파일: key.py 프로젝트: animefreak93/pritunl
def user_key_tar_archive_get(org_id, user_id):
    usr, resp = _get_key_tar_archive(org_id, user_id)

    usr.audit_event('user_profile',
        'User tar profile downloaded from web console',
        remote_addr=utils.get_remote_addr(),
    )

    return resp
예제 #12
0
파일: sso.py 프로젝트: pritunl/pritunl
def sso_yubico_post():
    remote_addr = utils.get_remote_addr()
    sso_mode = settings.app.sso
    token = utils.filter_str(flask.request.json.get('token')) or None
    key = utils.filter_str(flask.request.json.get('key')) or None

    if sso_mode not in (GOOGLE_YUBICO_AUTH, SLACK_YUBICO_AUTH,
            SAML_YUBICO_AUTH, SAML_OKTA_YUBICO_AUTH,
            SAML_ONELOGIN_YUBICO_AUTH):
        return flask.abort(404)

    if not token or not key:
        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'] != YUBICO_AUTH:
        journal.entry(
            journal.SSO_AUTH_FAILURE,
            remote_address=remote_addr,
            reason=journal.SSO_AUTH_REASON_INVALID_TOKEN,
            reason_long='Invalid Yubikey authentication token',
        )

        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 [])

    valid, yubico_id = sso.auth_yubico(key)
    if not valid or not yubico_id:
        journal.entry(
            journal.SSO_AUTH_FAILURE,
            username=username,
            remote_address=remote_addr,
            reason=journal.SSO_AUTH_REASON_YUBIKEY_FAILED,
            reason_long='Yubikey authentication failed',
        )

        return utils.jsonify({
            'error': YUBIKEY_INVALID,
            'error_msg': YUBIKEY_INVALID_MSG,
        }, 401)

    return _validate_user(username, email, sso_mode, org_id, groups,
        remote_addr, yubico_id=yubico_id)
예제 #13
0
파일: key.py 프로젝트: animefreak93/pritunl
def user_key_link_get(org_id, user_id):
    org = organization.get_by_id(org_id)
    usr = org.get_user(user_id)

    usr.audit_event('user_profile',
        'User temporary profile links created from web console',
        remote_addr=utils.get_remote_addr(),
    )

    return utils.jsonify(org.create_user_key_link(user_id))
예제 #14
0
파일: key.py 프로젝트: liinnux/pritunl
def user_key_pin_put(key_id):
    doc = _find_doc({
        'key_id': key_id,
    })
    if not doc:
        return flask.abort(404)

    if settings.app.demo_mode:
        return utils.demo_blocked()

    org = organization.get_by_id(doc['org_id'])
    usr = org.get_user(doc['user_id'])
    if usr.disabled:
        return flask.abort(403)

    if RADIUS_AUTH in usr.auth_type:
        return utils.jsonify({
            'error': PIN_RADIUS,
            'error_msg': PIN_RADIUS_MSG,
        }, 400)

    current_pin = utils.filter_str(
        flask.request.json.get('current_pin')) or None
    pin = utils.filter_str(flask.request.json.get('pin')) or None

    if pin:
        if not pin.isdigit():
            return utils.jsonify({
                'error': PIN_NOT_DIGITS,
                'error_msg': PIN_NOT_DIGITS_MSG,
            }, 400)

        if len(pin) < settings.user.pin_min_length:
            return utils.jsonify({
                'error': PIN_TOO_SHORT,
                'error_msg': PIN_TOO_SHORT_MSG,
            }, 400)

    if usr.pin and not usr.check_pin(current_pin):
        return utils.jsonify({
            'error': PIN_INVALID,
            'error_msg': PIN_INVALID_MSG,
        }, 400)

    if usr.set_pin(pin):
        usr.audit_event('user_updated',
            'User pin changed with temporary profile link',
            remote_addr=utils.get_remote_addr(),
        )

    usr.commit()

    event.Event(type=USERS_UPDATED, resource_id=org.id)

    return utils.jsonify({})
예제 #15
0
def user_post(org_id):
    if settings.app.demo_mode:
        return utils.demo_blocked()

    org = organization.get_by_id(org_id)
    users = []

    if isinstance(flask.request.json, list):
        users_data = flask.request.json
    else:
        users_data = [flask.request.json]

    try:
        for user_data in users_data:
            name = utils.filter_str(user_data['name'])
            email = utils.filter_str(user_data.get('email'))
            disabled = user_data.get('disabled')
            network_links = user_data.get('network_links')
            bypass_secondary = user_data.get('bypass_secondary')
            dns_servers = user_data.get('dns_servers') or None
            dns_suffix = utils.filter_str(user_data.get('dns_suffix')) or None

            user = org.new_user(type=CERT_CLIENT, name=name, email=email,
                disabled=disabled, bypass_secondary=bypass_secondary,
                dns_servers=dns_servers, dns_suffix=dns_suffix)
            user.audit_event('user_created',
                'User created from web console',
                remote_addr=utils.get_remote_addr(),
            )

            if network_links:
                for network_link in network_links:
                    try:
                        user.add_network_link(network_link)
                    except (ipaddress.AddressValueError, ValueError):
                        return _network_link_invalid()
                    except ServerOnlineError:
                        return utils.jsonify({
                            'error': NETWORK_LINK_NOT_OFFLINE,
                            'error_msg': NETWORK_LINK_NOT_OFFLINE_MSG,
                        }, 400)

            users.append(user.dict())
    finally:
        event.Event(type=ORGS_UPDATED)
        event.Event(type=USERS_UPDATED, resource_id=org.id)
        event.Event(type=SERVERS_UPDATED)

    if isinstance(flask.request.json, list):
        logger.LogEntry(message='Created %s new users.' % len(
            flask.request.json))
        return utils.jsonify(users)
    else:
        logger.LogEntry(message='Created new user "%s".' % users[0]['name'])
        return utils.jsonify(users[0])
예제 #16
0
def user_linked_key_page_get(short_code):
    doc = _find_doc({
        'short_id': short_code,
    }, one_time=True)
    if not doc:
        return flask.abort(404)

    org = organization.get_by_id(doc['org_id'])
    user = org.get_user(id=doc['user_id'])

    user.audit_event('user_profile',
        'User temporary profile link viewed',
        remote_addr=utils.get_remote_addr(),
    )

    if settings.local.sub_active and settings.app.theme == 'dark':
        view_name = KEY_VIEW_DARK_NAME
    else:
        view_name = KEY_VIEW_NAME

    key_page = static.StaticFile(settings.conf.www_path, view_name,
        cache=False).data
    key_page = key_page.replace('<%= user_name %>', '%s - %s' % (
        org.name, user.name))
    key_page = key_page.replace('<%= user_key_tar_url %>', '/key/%s.tar' % (
        doc['key_id']))
    key_page = key_page.replace('<%= user_key_zip_url %>', '/key/%s.zip' % (
        doc['key_id']))

    if org.otp_auth:
        key_page = key_page.replace('<%= user_otp_key %>', user.otp_secret)
        key_page = key_page.replace('<%= user_otp_url %>',
            'otpauth://totp/%s@%s?secret=%s' % (
                user.name, org.name, user.otp_secret))
    else:
        key_page = key_page.replace('<%= user_otp_key %>', '')
        key_page = key_page.replace('<%= user_otp_url %>', '')

    key_page = key_page.replace('<%= short_id %>', doc['short_id'])

    conf_links = ''

    if settings.local.sub_active:
        conf_links += '<a class="btn btn-success" ' + \
            'title="Download Chromebook Profiles" ' + \
            'href="/key_onc/%s.zip">Download Chromebook Profiles</a><br>\n' % (
                doc['key_id'])

    for server in org.iter_servers():
        conf_links += '<a class="btn btn-sm" title="Download Profile" ' + \
            'href="/key/%s/%s.key">Download Profile (%s)</a><br>\n' % (
                doc['key_id'], server.id, server.name)
    key_page = key_page.replace('<%= conf_links %>', conf_links)

    return key_page
예제 #17
0
파일: admin.py 프로젝트: pritunl/pritunl
def admin_post():
    if settings.app.demo_mode:
        return utils.demo_blocked()

    if not flask.g.administrator.super_user:
        return utils.jsonify({
            'error': REQUIRES_SUPER_USER,
            'error_msg': REQUIRES_SUPER_USER_MSG,
        }, 400)

    username = utils.filter_str(flask.request.json['username']).lower()
    password = flask.request.json['password']
    yubikey_id = flask.request.json.get('yubikey_id') or None
    yubikey_id = yubikey_id[:12] if yubikey_id else None
    otp_auth = flask.request.json.get('otp_auth', False)
    auth_api = flask.request.json.get('auth_api', False)
    disabled = flask.request.json.get('disabled', False)
    super_user = flask.request.json.get('super_user', False)
    remote_addr = utils.get_remote_addr()

    try:
        admin = auth.new_admin(
            username=username,
            password=password,
            yubikey_id=yubikey_id,
            default=True,
            otp_auth=otp_auth,
            auth_api=auth_api,
            disabled=disabled,
            super_user=super_user,
        )
    except pymongo.errors.DuplicateKeyError:
        return utils.jsonify({
            'error': ADMIN_USERNAME_EXISTS,
            'error_msg': ADMIN_USERNAME_EXISTS_MSG,
        }, 400)

    admin.audit_event('admin_created',
        'Administrator created',
        remote_addr=remote_addr,
    )

    journal.entry(
        journal.ADMIN_CREATE,
        admin.journal_data,
        event_long='Administrator created',
        remote_addr=remote_addr,
    )

    event.Event(type=ADMINS_UPDATED)

    return utils.jsonify(admin.dict())
예제 #18
0
파일: auth.py 프로젝트: ogrishman/pritunl
def auth_token_post():
    username = flask.request.json['username']
    password = flask.request.json['password']
    remote_addr = utils.get_remote_addr()

    if not utils.check_auth(username, password, remote_addr):
        return utils.jsonify({
            'error': AUTH_INVALID,
            'error_msg': AUTH_INVALID_MSG,
        }, 401)

    auth_token = AuthToken()
    return utils.jsonify({
        'auth_token': auth_token.id,
    })
예제 #19
0
def user_linked_key_onc_archive_get(key_id):
    doc = _find_doc({
        'key_id': key_id,
    })
    if not doc:
        return flask.abort(404)

    usr, resp = _get_onc_archive(doc['org_id'], doc['user_id'])

    usr.audit_event('user_profile',
        'User onc profile downloaded with temporary profile link',
        remote_addr=utils.get_remote_addr(),
    )

    return resp
예제 #20
0
def user_otp_secret_put(org_id, user_id):
    if settings.app.demo_mode:
        return utils.demo_blocked()

    org = organization.get_by_id(org_id)
    user = org.get_user(user_id)

    user.audit_event('user_updated',
        'User two step secret reset',
        remote_addr=utils.get_remote_addr(),
    )

    user.generate_otp_secret()
    user.commit()
    event.Event(type=USERS_UPDATED, resource_id=org.id)
    return utils.jsonify(user.dict())
예제 #21
0
파일: key.py 프로젝트: animefreak93/pritunl
def user_linked_key_conf_get(org_id, user_id, server_id):
    org = organization.get_by_id(org_id)
    usr = org.get_user(user_id)
    key_conf = usr.build_key_conf(server_id)

    usr.audit_event('user_profile',
        'User key profile downloaded from web console',
        remote_addr=utils.get_remote_addr(),
    )

    response = flask.Response(response=key_conf['conf'],
        mimetype='application/ovpn')
    response.headers.add('Content-Disposition',
        'attachment; filename="%s"' % key_conf['name'])

    return response
예제 #22
0
파일: key.py 프로젝트: pritunl/pritunl
def user_linked_key_page_delete(short_code):
    utils.rand_sleep()
    remote_addr = utils.get_remote_addr()

    journal.entry(
        journal.USER_PROFILE_DELETE,
        remote_address=remote_addr,
        event_long='Temporary profile link deleted',
    )

    collection = mongo.get_collection('users_key_link')
    collection.remove({
        'short_id': short_code,
    })

    return utils.jsonify({})
예제 #23
0
def user_key_tar_archive_get(org_id, user_id):
    remote_addr = utils.get_remote_addr()
    usr, resp = _get_key_tar_archive(org_id, user_id)

    usr.audit_event('user_profile',
        'User tar profile downloaded from web console',
        remote_addr=remote_addr,
    )

    journal.entry(
        journal.USER_PROFILE_SUCCESS,
        usr.journal_data,
        remote_address=remote_addr,
        event_long='User tar profile downloaded from web console',
    )

    return resp
예제 #24
0
파일: user.py 프로젝트: pichuang/pritunl
def user_otp_secret_put(org_id, user_id):
    if settings.app.demo_mode:
        return utils.demo_blocked()

    org = organization.get_by_id(org_id)
    user = org.get_user(user_id)

    user.audit_event(
        'user_updated',
        'User two step secret reset',
        remote_addr=utils.get_remote_addr(),
    )

    user.generate_otp_secret()
    user.commit()
    event.Event(type=USERS_UPDATED, resource_id=org.id)
    return utils.jsonify(user.dict())
예제 #25
0
def user_linked_key_conf_get(org_id, user_id, server_id):
    org = organization.get_by_id(org_id)
    usr = org.get_user(user_id)
    key_conf = usr.build_key_conf(server_id)

    usr.audit_event(
        'user_profile',
        'User key profile downloaded from web console',
        remote_addr=utils.get_remote_addr(),
    )

    response = flask.Response(response=key_conf['conf'],
                              mimetype='application/ovpn')
    response.headers.add('Content-Disposition',
                         'attachment; filename="%s"' % key_conf['name'])

    return response
예제 #26
0
파일: key.py 프로젝트: satnami/pritunl
def user_linked_key_zip_archive_get(key_id):
    doc = _find_doc({
        'key_id': key_id,
    })
    if not doc:
        return flask.abort(404)

    usr, resp = _get_key_zip_archive(doc['org_id'], doc['user_id'])
    if usr.disabled:
        return flask.abort(403)

    usr.audit_event('user_profile',
        'User zip profile downloaded with temporary profile link',
        remote_addr=utils.get_remote_addr(),
    )

    return resp
예제 #27
0
def user_linked_key_page_delete(short_code):
    utils.rand_sleep()
    short_code = short_code[:128]
    remote_addr = utils.get_remote_addr()

    journal.entry(
        journal.USER_PROFILE_DELETE,
        remote_address=remote_addr,
        event_long='Temporary profile link deleted',
    )

    collection = mongo.get_collection('users_key_link')
    collection.remove({
        'short_id': short_code,
    })

    return utils.jsonify({})
예제 #28
0
def auth_session_post():
    username = utils.json_filter_str('username')
    password = utils.json_str('password')
    otp_code = utils.json_opt_filter_str('otp_code')
    yubico_key = utils.json_opt_filter_str('yubico_key')
    remote_addr = utils.get_remote_addr()

    time.sleep(random.randint(50, 100) / 1000.)

    admin = auth.get_by_username(username, remote_addr)
    if not admin:
        if settings.app.sso and RADIUS_AUTH in settings.app.sso:
            return _auth_radius(username, password)

        time.sleep(random.randint(0, 100) / 1000.)
        return _auth_plugin(username, password)

    if (not otp_code and admin.otp_auth) or \
            (not yubico_key and admin.yubikey_id):
        return utils.jsonify({
            'error': AUTH_OTP_REQUIRED,
            'error_msg': AUTH_OTP_REQUIRED_MSG,
            'otp_auth': admin.otp_auth,
            'yubico_auth': bool(admin.yubikey_id),
        }, 402)

    if not admin.auth_check(password, otp_code, yubico_key, remote_addr):
        time.sleep(random.randint(0, 100) / 1000.)
        return utils.jsonify({
            'error': AUTH_INVALID,
            'error_msg': AUTH_INVALID_MSG,
        }, 401)

    flask.session['session_id'] = admin.new_session()
    flask.session['admin_id'] = str(admin.id)
    flask.session['timestamp'] = int(utils.time_now())
    if not settings.app.server_ssl:
        flask.session['source'] = remote_addr

    utils.set_flask_sig()

    return utils.jsonify({
        'authenticated': True,
        'default': admin.default or False,
    })
예제 #29
0
def auth_session_post():
    username = utils.json_filter_str('username')
    password = utils.json_str('password')
    otp_code = utils.json_opt_filter_str('otp_code')
    yubico_key = utils.json_opt_filter_str('yubico_key')
    remote_addr = utils.get_remote_addr()

    time.sleep(random.randint(50, 100) / 1000.)

    admin = auth.get_by_username(username, remote_addr)
    if not admin:
        if settings.app.sso and RADIUS_AUTH in settings.app.sso:
            return _auth_radius(username, password)

        time.sleep(random.randint(0, 100) / 1000.)
        return _auth_plugin(username, password)

    if (not otp_code and admin.otp_auth) or \
            (not yubico_key and admin.yubikey_id):
        return utils.jsonify({
            'error': AUTH_OTP_REQUIRED,
            'error_msg': AUTH_OTP_REQUIRED_MSG,
            'otp_auth': admin.otp_auth,
            'yubico_auth': bool(admin.yubikey_id),
        }, 402)

    if not admin.auth_check(password, otp_code, yubico_key, remote_addr):
        time.sleep(random.randint(0, 100) / 1000.)
        return utils.jsonify({
            'error': AUTH_INVALID,
            'error_msg': AUTH_INVALID_MSG,
        }, 401)

    flask.session['session_id'] = admin.new_session()
    flask.session['admin_id'] = str(admin.id)
    flask.session['timestamp'] = int(utils.time_now())
    if not settings.app.server_ssl:
        flask.session['source'] = remote_addr

    utils.set_flask_sig()

    return utils.jsonify({
        'authenticated': True,
        'default': admin.default or False,
    })
예제 #30
0
파일: key.py 프로젝트: pritunl/pritunl
def user_key_link_get(org_id, user_id):
    remote_addr = utils.get_remote_addr()
    org = organization.get_by_id(org_id)
    usr = org.get_user(user_id)

    usr.audit_event('user_profile',
        'User temporary profile links created from web console',
        remote_addr=remote_addr,
    )

    journal.entry(
        journal.USER_PROFILE_SUCCESS,
        usr.journal_data,
        remote_address=remote_addr,
        event_long='User temporary profile links created from web console',
    )

    return utils.jsonify(org.create_user_key_link(user_id))
예제 #31
0
def user_key_link_get(org_id, user_id):
    remote_addr = utils.get_remote_addr()
    org = organization.get_by_id(org_id)
    usr = org.get_user(user_id)

    usr.audit_event('user_profile',
        'User temporary profile links created from web console',
        remote_addr=remote_addr,
    )

    journal.entry(
        journal.USER_PROFILE_SUCCESS,
        usr.journal_data,
        remote_address=remote_addr,
        event_long='User temporary profile links created from web console',
    )

    return utils.jsonify(org.create_user_key_link(user_id))
예제 #32
0
파일: admin.py 프로젝트: ijat/pritunl
def admin_post():
    if settings.app.demo_mode:
        return utils.demo_blocked()

    if not flask.g.administrator.super_user:
        return utils.jsonify(
            {
                'error': REQUIRES_SUPER_USER,
                'error_msg': REQUIRES_SUPER_USER_MSG,
            }, 400)

    username = utils.filter_str(flask.request.json['username']).lower()
    password = flask.request.json['password']
    otp_auth = flask.request.json.get('otp_auth', False)
    auth_api = flask.request.json.get('auth_api', False)
    disabled = flask.request.json.get('disabled', False)
    super_user = flask.request.json.get('super_user', False)

    try:
        admin = auth.new_admin(
            username=username,
            password=password,
            default=True,
            otp_auth=otp_auth,
            auth_api=auth_api,
            disabled=disabled,
            super_user=super_user,
        )
    except pymongo.errors.DuplicateKeyError:
        return utils.jsonify(
            {
                'error': ADMIN_USERNAME_EXISTS,
                'error_msg': ADMIN_USERNAME_EXISTS_MSG,
            }, 400)

    admin.audit_event(
        'admin_created',
        'Administrator created',
        remote_addr=utils.get_remote_addr(),
    )

    event.Event(type=ADMINS_UPDATED)

    return utils.jsonify(admin.dict())
예제 #33
0
def after_request(response):
    if settings.app.check_requests and not flask.g.valid:
        raise ValueError('Request not authorized')

    response.headers.add('X-Frame-Options', 'DENY')

    if settings.app.server_ssl:
        response.headers.add('Strict-Transport-Security', 'max-age=31536000')

    if not flask.request.path.startswith('/event'):
        monitoring.insert_point('requests', {
            'host': settings.local.host.name,
        }, {
            'path': flask.request.path,
            'remote_ip': utils.get_remote_addr(),
            'response_time': int((time.time() - flask.g.start) * 1000),
        })

    return response
예제 #34
0
def auth_session_post():
    username = flask.request.json['username']
    password = flask.request.json['password']
    otp_code = flask.request.json.get('otp_code')
    remote_addr = utils.get_remote_addr()

    admin = auth.get_by_username(username, remote_addr)
    if not admin:
        if settings.app.sso == RADIUS_AUTH:
            return _auth_radius(username, password)

        time.sleep(random.randint(0, 100) / 1000.)
        return utils.jsonify(
            {
                'error': AUTH_INVALID,
                'error_msg': AUTH_INVALID_MSG,
            }, 401)

    if not otp_code and admin.otp_auth:
        return utils.jsonify(
            {
                'error': AUTH_OTP_REQUIRED,
                'error_msg': AUTH_OTP_REQUIRED_MSG,
            }, 402)

    if not admin.auth_check(password, otp_code, remote_addr):
        time.sleep(random.randint(0, 100) / 1000.)
        return utils.jsonify(
            {
                'error': AUTH_INVALID,
                'error_msg': AUTH_INVALID_MSG,
            }, 401)

    flask.session['session_id'] = admin.new_session()
    flask.session['admin_id'] = str(admin.id)
    flask.session['timestamp'] = int(utils.time_now())
    if not settings.conf.ssl:
        flask.session['source'] = remote_addr

    return utils.jsonify({
        'authenticated': True,
        'default': admin.default or False,
    })
예제 #35
0
def auth_delete():
    admin_id = utils.session_opt_str('admin_id')
    session_id = utils.session_opt_str('session_id')
    remote_addr = utils.get_remote_addr()

    journal.entry(
        journal.ADMIN_SESSION_END,
        admin_id=admin_id,
        session_id=session_id,
        remote_address=remote_addr,
    )

    if admin_id and session_id:
        admin_id = utils.ObjectId(admin_id)
        auth.clear_session(admin_id, str(session_id))
    flask.session.clear()

    return utils.jsonify({
        'authenticated': False,
    })
예제 #36
0
def user_linked_key_onc_archive_get(key_id):
    key_id = key_id[:128]
    remote_addr = utils.get_remote_addr()
    doc = _find_doc({
        'key_id': key_id,
    })
    if not doc:
        journal.entry(
            journal.USER_PROFILE_FAILURE,
            remote_address=remote_addr,
            event_long='Key ID not found',
        )
        return flask.abort(404)

    if settings.user.restrict_import:
        return flask.abort(404)

    usr, resp = _get_onc_archive(doc['org_id'], doc['user_id'])
    if usr.disabled:
        journal.entry(
            journal.USER_PROFILE_FAILURE,
            usr.journal_data,
            remote_address=remote_addr,
            event_long='User disabled',
        )
        return flask.abort(403)

    journal.entry(
        journal.USER_PROFILE_SUCCESS,
        usr.journal_data,
        remote_address=remote_addr,
        event_long='User onc profile downloaded with temporary profile link',
    )

    usr.audit_event(
        'user_profile',
        'User onc profile downloaded with temporary profile link',
        remote_addr=remote_addr,
    )

    return resp
예제 #37
0
def auth_session_post():
    username = flask.request.json['username']
    password = flask.request.json['password']
    remote_addr = utils.get_remote_addr()
    admin = auth.check_auth(username, password, remote_addr)

    if not admin:
        return utils.jsonify({
            'error': AUTH_INVALID,
            'error_msg': AUTH_INVALID_MSG,
        }, 401)

    flask.session['admin_id'] = str(admin.id)
    flask.session['timestamp'] = int(time.time())
    if not settings.conf.ssl:
        flask.session['source'] = remote_addr

    return utils.jsonify({
        'authenticated': True,
        'default': admin.default,
    })
예제 #38
0
파일: auth.py 프로젝트: bashajan/pritunl
def auth_session_post():
    username = flask.request.json['username']
    password = flask.request.json['password']
    remote_addr = utils.get_remote_addr()
    admin = auth.check_auth(username, password, remote_addr)

    if not admin:
        return utils.jsonify({
            'error': AUTH_INVALID,
            'error_msg': AUTH_INVALID_MSG,
        }, 401)

    flask.session['admin_id'] = str(admin.id)
    flask.session['timestamp'] = int(time.time())
    if not settings.conf.ssl:
        flask.session['source'] = remote_addr

    return utils.jsonify({
        'authenticated': True,
        'default': admin.default,
    })
예제 #39
0
파일: auth.py 프로젝트: liinnux/pritunl
def auth_session_post():
    username = flask.request.json['username']
    password = flask.request.json['password']
    otp_code = flask.request.json.get('otp_code')
    remote_addr = utils.get_remote_addr()

    admin = auth.get_by_username(username, remote_addr)
    if not admin:
        if settings.app.sso == RADIUS_AUTH:
            return _auth_radius(username, password)

        time.sleep(random.randint(0, 100) / 1000.)
        return utils.jsonify({
            'error': AUTH_INVALID,
            'error_msg': AUTH_INVALID_MSG,
        }, 401)

    if not otp_code and admin.otp_auth:
        return utils.jsonify({
            'error': AUTH_OTP_REQUIRED,
            'error_msg': AUTH_OTP_REQUIRED_MSG,
        }, 402)

    if not admin.auth_check(password, otp_code, remote_addr):
        time.sleep(random.randint(0, 100) / 1000.)
        return utils.jsonify({
            'error': AUTH_INVALID,
            'error_msg': AUTH_INVALID_MSG,
        }, 401)

    flask.session['session_id'] = admin.new_session()
    flask.session['admin_id'] = str(admin.id)
    flask.session['timestamp'] = int(utils.time_now())
    if not settings.conf.ssl:
        flask.session['source'] = remote_addr

    return utils.jsonify({
        'authenticated': True,
        'default': admin.default or False,
    })
예제 #40
0
def user_uri_key_page_get(short_code):
    doc = _find_doc({
        'short_id': short_code,
    }, one_time=True)

    if not doc:
        return flask.abort(404)

    org = organization.get_by_id(doc['org_id'])
    user = org.get_user(id=doc['user_id'])

    user.audit_event('user_profile',
        'User temporary profile downloaded from pritunl client',
        remote_addr=utils.get_remote_addr(),
    )

    keys = {}
    for server in org.iter_servers():
        key = user.build_key_conf(server.id)
        keys[key['name']] = key['conf']

    return utils.jsonify(keys)
예제 #41
0
파일: auth.py 프로젝트: monsterChen/pritunl
def auth_session_post():
    username = flask.request.json['username']
    password = flask.request.json['password']
    remote_addr = utils.get_remote_addr()

    if not utils.check_auth(username, password, remote_addr):
        return utils.jsonify({
            'error': AUTH_INVALID,
            'error_msg': AUTH_INVALID_MSG,
        }, 401)

    flask.session['auth'] = True
    flask.session['timestamp'] = int(time.time())
    if not app_server.ssl:
        flask.session['source'] = remote_addr

    data = {
        'authenticated': True,
    }
    if password == DEFAULT_PASSWORD:
        data['default_password'] = True
    return utils.jsonify(data)
예제 #42
0
def user_uri_key_page_get(short_code):
    doc = _find_doc({
        'short_id': short_code,
    }, one_time=True)
    if not doc:
        return flask.abort(404)

    org = organization.get_by_id(doc['org_id'])
    user = org.get_user(id=doc['user_id'])

    user.audit_event(
        'user_profile',
        'User temporary profile downloaded from pritunl client',
        remote_addr=utils.get_remote_addr(),
    )

    keys = {}
    for server in org.iter_servers():
        key = user.build_key_conf(server.id)
        keys[key['name']] = key['conf']

    return utils.jsonify(keys)
예제 #43
0
def user_linked_key_conf_get(key_id, server_id):
    doc = _find_doc({
        'key_id': key_id,
    })
    if not doc:
        return flask.abort(404)

    org = organization.get_by_id(doc['org_id'])
    user = org.get_user(id=doc['user_id'])
    key_conf = user.build_key_conf(server_id)

    user.audit_event(
        'user_profile',
        'User profile downloaded with temporary profile link',
        remote_addr=utils.get_remote_addr(),
    )

    response = flask.Response(response=key_conf['conf'],
                              mimetype='application/ovpn')
    response.headers.add('Content-Disposition',
                         'attachment; filename="%s"' % key_conf['name'])

    return response
예제 #44
0
def after_request(response):
    resp_time = int((time.time() - flask.g.start) * 1000)
    db_time = int(flask.g.query_time * 1000)
    db_reads = flask.g.query_count
    db_writes = flask.g.write_count

    response.headers.add('Execution-Time', resp_time)
    response.headers.add('Query-Time', db_time)
    response.headers.add('Query-Count', db_reads)
    response.headers.add('Write-Count', db_writes)

    if not flask.request.path.startswith('/event'):
        monitoring.insert_point('requests', {
            'host': settings.local.host.name,
        }, {
            'path': flask.request.path,
            'remote_ip': utils.get_remote_addr(),
            'response_time': resp_time,
            'db_time': db_time,
            'db_reads': db_reads,
            'db_writes': db_writes,
        })

    return response
예제 #45
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)
예제 #46
0
파일: user.py 프로젝트: fanduel/pritunl
def user_put(org_id, user_id):
    if settings.app.demo_mode:
        return utils.demo_blocked()

    org = organization.get_by_id(org_id)
    user = org.get_user(user_id)
    reset_user = False
    port_forwarding_event = False

    if 'name' in flask.request.json:
        name = utils.filter_str(flask.request.json['name']) or None

        if name != user.name:
            user.audit_event(
                'user_updated',
                'User name changed',
                remote_addr=utils.get_remote_addr(),
            )

        user.name = name

    if 'email' in flask.request.json:
        email = utils.filter_str(flask.request.json['email']) or None

        if email != user.email:
            user.audit_event(
                'user_updated',
                'User email changed',
                remote_addr=utils.get_remote_addr(),
            )

        user.email = email

    if 'groups' in flask.request.json:
        groups = flask.request.json['groups'] or []
        for i, group in enumerate(groups):
            groups[i] = utils.filter_str(group)
        groups = set(groups)

        if groups != set(user.groups or []):
            user.audit_event(
                'user_updated',
                'User groups changed',
                remote_addr=utils.get_remote_addr(),
            )

        user.groups = list(groups)

    if 'pin' in flask.request.json:
        pin = flask.request.json['pin']

        if pin is not True:
            if pin:
                if settings.user.pin_mode == PIN_DISABLED:
                    return utils.jsonify(
                        {
                            'error': PIN_IS_DISABLED,
                            'error_msg': PIN_IS_DISABLED_MSG,
                        }, 400)

                if RADIUS_AUTH in user.auth_type:
                    return utils.jsonify(
                        {
                            'error': PIN_RADIUS,
                            'error_msg': PIN_RADIUS_MSG,
                        }, 400)

                if not pin.isdigit():
                    return utils.jsonify(
                        {
                            'error': PIN_NOT_DIGITS,
                            'error_msg': PIN_NOT_DIGITS_MSG,
                        }, 400)

                if len(pin) < settings.user.pin_min_length:
                    return utils.jsonify(
                        {
                            'error': PIN_TOO_SHORT,
                            'error_msg': PIN_TOO_SHORT_MSG,
                        }, 400)

            if user.set_pin(pin):
                user.audit_event(
                    'user_updated',
                    'User pin changed',
                    remote_addr=utils.get_remote_addr(),
                )

    if 'network_links' in flask.request.json:
        network_links_cur = set(user.get_network_links())
        network_links_new = set()

        for network_link in flask.request.json['network_links']:
            try:
                network_link = str(ipaddress.IPNetwork(network_link))
            except (ipaddress.AddressValueError, ValueError):
                return _network_link_invalid()
            network_links_new.add(network_link)

        network_links_add = network_links_new - network_links_cur
        network_links_rem = network_links_cur - network_links_new

        if len(network_links_add) or len(network_links_rem):
            reset_user = True
            user.audit_event(
                'user_updated',
                'User network links updated',
                remote_addr=utils.get_remote_addr(),
            )

        try:
            for network_link in network_links_add:
                user.add_network_link(network_link)
        except ServerOnlineError:
            return utils.jsonify(
                {
                    'error': NETWORK_LINK_NOT_OFFLINE,
                    'error_msg': NETWORK_LINK_NOT_OFFLINE_MSG,
                }, 400)

        for network_link in network_links_rem:
            user.remove_network_link(network_link)

    if 'port_forwarding' in flask.request.json:
        port_forwarding = []
        for data in flask.request.json['port_forwarding'] or []:
            port_forwarding.append({
                'protocol':
                utils.filter_str(data.get('protocol')),
                'port':
                utils.filter_str(data.get('port')),
                'dport':
                utils.filter_str(data.get('dport')),
            })

        if port_forwarding != user.port_forwarding:
            port_forwarding_event = True
            user.audit_event(
                'user_updated',
                'User port forwarding changed',
                remote_addr=utils.get_remote_addr(),
            )

        user.port_forwarding = port_forwarding

    disabled = flask.request.json.get('disabled')
    if disabled is not None:
        if disabled != user.disabled:
            user.audit_event(
                'user_updated',
                'User %s' % ('disabled' if disabled else 'enabled'),
                remote_addr=utils.get_remote_addr(),
            )

        user.disabled = disabled

    bypass_secondary = flask.request.json.get('bypass_secondary')
    if bypass_secondary is not None:
        user.bypass_secondary = True if bypass_secondary else False

    client_to_client = flask.request.json.get('client_to_client')
    if client_to_client is not None:
        user.client_to_client = True if client_to_client else False

    if 'dns_servers' in flask.request.json:
        dns_servers = flask.request.json['dns_servers'] or None
        if user.dns_servers != dns_servers:
            user.audit_event(
                'user_updated',
                'User dns servers changed',
                remote_addr=utils.get_remote_addr(),
            )
            reset_user = True
        user.dns_servers = dns_servers

    if 'dns_suffix' in flask.request.json:
        dns_suffix = utils.filter_str(flask.request.json['dns_suffix']) or None
        if user.dns_suffix != dns_suffix:
            user.audit_event(
                'user_updated',
                'User dns suffix changed',
                remote_addr=utils.get_remote_addr(),
            )
            reset_user = True
        user.dns_suffix = dns_suffix

    user.commit()
    event.Event(type=USERS_UPDATED, resource_id=user.org.id)
    if port_forwarding_event:
        messenger.publish('port_forwarding', {
            'org_id': org.id,
            'user_id': user.id,
        })

    if reset_user or disabled:
        user.disconnect()

    if disabled:
        if user.type == CERT_CLIENT:
            logger.LogEntry(message='Disabled user "%s".' % user.name)
    elif disabled == False and user.type == CERT_CLIENT:
        logger.LogEntry(message='Enabled user "%s".' % user.name)

    send_key_email = flask.request.json.get('send_key_email')
    if send_key_email and user.email:
        user.audit_event(
            'user_emailed',
            'User key email sent to "%s"' % user.email,
            remote_addr=utils.get_remote_addr(),
        )

        try:
            user.send_key_email(utils.get_url_root())
        except EmailNotConfiguredError:
            return utils.jsonify(
                {
                    'error': EMAIL_NOT_CONFIGURED,
                    'error_msg': EMAIL_NOT_CONFIGURED_MSG,
                }, 400)
        except EmailFromInvalid:
            return utils.jsonify(
                {
                    'error': EMAIL_FROM_INVALID,
                    'error_msg': EMAIL_FROM_INVALID_MSG,
                }, 400)
        except EmailAuthInvalid:
            return utils.jsonify(
                {
                    'error': EMAIL_AUTH_INVALID,
                    'error_msg': EMAIL_AUTH_INVALID_MSG,
                }, 400)

    return utils.jsonify(user.dict())
예제 #47
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)
예제 #48
0
파일: auth.py 프로젝트: bogsi/pritunl
def _auth_plugin(username, password):
    if settings.local.sub_plan != 'enterprise':
        return utils.jsonify({
            'error': AUTH_INVALID,
            'error_msg': AUTH_INVALID_MSG,
        }, 401)

    valid, org_id, groups = sso.plugin_login_authenticate(
        user_name=username,
        password=password,
        remote_ip=utils.get_remote_addr(),
    )

    if not valid:
        return utils.jsonify({
            'error': AUTH_INVALID,
            'error_msg': AUTH_INVALID_MSG,
        }, 401)

    if not org_id:
        logger.error(
            'Login plugin did not return valid organization name',
            'auth',
            org_name=org_id,
            user_name=username,
        )
        return utils.jsonify({
            'error': AUTH_INVALID,
            'error_msg': AUTH_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, type=CERT_CLIENT,
            auth_type=PLUGIN_AUTH, groups=list(groups) if groups else None)
        usr.audit_event(
            'user_created',
            'User created with plugin authentication',
            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 != PLUGIN_AUTH:
            usr.auth_type = PLUGIN_AUTH
            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 plugin authentication',
        remote_addr=utils.get_remote_addr(),
    )

    return utils.jsonify({
        'redirect': utils.get_url_root() + key_link['view_url'],
    }, 202)
예제 #49
0
파일: user.py 프로젝트: fanduel/pritunl
def auth_user_post():
    if settings.app.demo_mode:
        return utils.demo_blocked()

    auth_token = flask.request.headers.get('Auth-Token', None)
    auth_timestamp = flask.request.headers.get('Auth-Timestamp', None)
    auth_nonce = flask.request.headers.get('Auth-Nonce', None)
    auth_signature = flask.request.headers.get('Auth-Signature', None)

    if not auth_token or not auth_timestamp or not auth_nonce or \
            not auth_signature:
        return utils.jsonify(
            {
                'error': AUTH_INVALID,
                'error_msg': AUTH_INVALID_MSG,
            }, 401)
    auth_nonce = auth_nonce[:32]

    try:
        if abs(int(auth_timestamp) - int(utils.time_now())) > \
                settings.app.auth_time_window:
            return utils.jsonify(
                {
                    'error': AUTH_INVALID,
                    'error_msg': AUTH_INVALID_MSG,
                }, 401)
    except ValueError:
        return utils.jsonify(
            {
                'error': AUTH_INVALID,
                'error_msg': AUTH_INVALID_MSG,
            }, 401)

    org = organization.get_by_token(auth_token)
    if not org:
        return utils.jsonify(
            {
                'error': AUTH_INVALID,
                'error_msg': AUTH_INVALID_MSG,
            }, 401)

    auth_string = '&'.join([
        auth_token,
        auth_timestamp,
        auth_nonce,
        flask.request.method,
        flask.request.path,
    ] + ([flask.request.data] if flask.request.data else []))

    if len(auth_string) > AUTH_SIG_STRING_MAX_LEN:
        return utils.jsonify(
            {
                'error': AUTH_INVALID,
                'error_msg': AUTH_INVALID_MSG,
            }, 401)

    if not org.auth_secret or len(org.auth_secret) < 8:
        return utils.jsonify(
            {
                'error': AUTH_INVALID,
                'error_msg': AUTH_INVALID_MSG,
            }, 401)

    auth_test_signature = base64.b64encode(
        hmac.new(org.auth_secret.encode(), auth_string,
                 hashlib.sha256).digest())
    if auth_signature != auth_test_signature:
        return utils.jsonify(
            {
                'error': AUTH_INVALID,
                'error_msg': AUTH_INVALID_MSG,
            }, 401)

    try:
        org.nonces_collection.insert({
            'token': auth_token,
            'nonce': auth_nonce,
            'timestamp': utils.now(),
        })
    except pymongo.errors.DuplicateKeyError:
        return utils.jsonify(
            {
                'error': AUTH_INVALID,
                'error_msg': AUTH_INVALID_MSG,
            }, 401)

    username = flask.request.json['username']
    network_links = flask.request.json.get('network_links')

    usr = org.find_user(name=username)
    if usr:
        usr.remove()

    usr = org.new_user(name=username, type=CERT_CLIENT)
    usr.audit_event('user_created',
                    'User created with authentication token',
                    remote_addr=utils.get_remote_addr())

    if network_links:
        for network_link in network_links:
            try:
                usr.add_network_link(network_link, force=True)
            except (ipaddress.AddressValueError, ValueError):
                return _network_link_invalid()

    event.Event(type=ORGS_UPDATED)
    event.Event(type=USERS_UPDATED, resource_id=org.id)
    event.Event(type=SERVERS_UPDATED)

    keys = {}
    for svr in org.iter_servers():
        key = usr.build_key_conf(svr.id)
        keys[key['name']] = key['conf']

    return utils.jsonify(keys)
예제 #50
0
def sso_authenticate_post():
    if settings.app.sso != DUO_AUTH:
        return flask.abort(405)

    username = flask.request.json['username']
    usernames = [username]
    email = None
    if '@' in username:
        email = username
        usernames.append(username.split('@')[0])

    valid = False
    for i, username in enumerate(usernames):
        try:
            valid, org_id = sso.auth_duo(
                username,
                strong=True,
                ipaddr=flask.request.remote_addr,
                type='Key',
            )
            break
        except InvalidUser:
            if i == len(usernames) - 1:
                logger.error('Invalid duo username', 'sso',
                    username=username,
                )

    if not valid:
        logger.error('Invalid duo username', '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)
        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 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()[:-1] + key_link['view_url']
예제 #51
0
def key_sync_get(org_id, user_id, server_id, key_hash):
    utils.rand_sleep()

    if not settings.local.sub_active:
        return utils.response('', status_code=480)

    auth_token = flask.request.headers.get('Auth-Token', None)
    auth_timestamp = flask.request.headers.get('Auth-Timestamp', None)
    auth_nonce = flask.request.headers.get('Auth-Nonce', None)
    auth_signature = flask.request.headers.get('Auth-Signature', None)
    if not auth_token or not auth_timestamp or not auth_nonce or \
            not auth_signature:
        return flask.abort(401)
    auth_nonce = auth_nonce[:32]

    try:
        if abs(int(auth_timestamp) - int(utils.time_now())) > \
                settings.app.auth_time_window:
            return flask.abort(401)
    except ValueError:
        return flask.abort(401)

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

    user = org.get_user(id=user_id)
    if not user:
        return flask.abort(401)
    elif not user.sync_secret:
        return flask.abort(401)

    if user.disabled:
        return flask.abort(403)

    auth_string = '&'.join([
        user.sync_token, auth_timestamp, auth_nonce, flask.request.method,
        flask.request.path] +
        ([flask.request.data] if flask.request.data else []))

    if len(auth_string) > AUTH_SIG_STRING_MAX_LEN:
        return flask.abort(401)

    auth_test_signature = base64.b64encode(hmac.new(
        user.sync_secret.encode(), auth_string,
        hashlib.sha256).digest())
    if auth_signature != auth_test_signature:
        return flask.abort(401)

    nonces_collection = mongo.get_collection('auth_nonces')
    try:
        nonces_collection.insert({
            'token': auth_token,
            'nonce': auth_nonce,
            'timestamp': utils.now(),
        }, w=0)
    except pymongo.errors.DuplicateKeyError:
        return flask.abort(401)

    key_conf = user.sync_conf(server_id, key_hash)
    if key_conf:
        user.audit_event('user_profile',
            'User profile synced from pritunl client',
            remote_addr=utils.get_remote_addr(),
        )

        return utils.response(key_conf['conf'])
    return utils.response('')
예제 #52
0
def user_linked_key_page_get(short_code):
    doc = _find_doc({
        'short_id': short_code,
    }, one_time=True, one_time_new=True)
    if not doc:
        return flask.abort(404)

    org = organization.get_by_id(doc['org_id'])
    user = org.get_user(id=doc['user_id'])
    if user.disabled:
        return flask.abort(403)

    user.audit_event('user_profile',
        'User temporary profile link viewed',
        remote_addr=utils.get_remote_addr(),
    )

    if settings.local.sub_active and settings.app.theme == 'dark':
        view_name = KEY_VIEW_DARK_NAME
    else:
        view_name = KEY_VIEW_NAME

    if user.auth_type == RADIUS_AUTH or \
            settings.user.pin_mode == PIN_DISABLED:
        header_class = 'pin-disabled'
    else:
        header_class = ''

    key_page = static.StaticFile(settings.conf.www_path, view_name,
        cache=False, gzip=False).data
    key_page = key_page.replace('<%= header_class %>', header_class)

    uri_url = (utils.get_url_root()[:-1] + '/ku/' + doc['short_id']).encode()
    if uri_url.startswith('https'):
        uri_url = uri_url.replace('https', 'pritunl', 1)
    else:
        uri_url = uri_url.replace('http', 'pritunl', 1)
    key_page = key_page.replace('<%= uri_url %>', uri_url)

    key_page = key_page.replace('<%= user_name %>', '%s - %s' % (
        org.name, user.name))
    key_page = key_page.replace('<%= user_key_tar_url %>', '/key/%s.tar' % (
        doc['key_id']))
    key_page = key_page.replace('<%= user_key_zip_url %>', '/key/%s.zip' % (
        doc['key_id']))

    if org.otp_auth:
        key_page = key_page.replace('<%= user_otp_key %>', user.otp_secret)
        key_page = key_page.replace('<%= user_otp_url %>',
            'otpauth://totp/%s@%s?secret=%s' % (
                user.name, org.name, user.otp_secret))
    else:
        key_page = key_page.replace('<%= user_otp_key %>', '')
        key_page = key_page.replace('<%= user_otp_url %>', '')

    if user.pin:
        key_page = key_page.replace('<%= cur_pin_display %>', 'block')
    else:
        key_page = key_page.replace('<%= cur_pin_display %>', 'none')

    key_page = key_page.replace('<%= key_id %>', doc['key_id'])
    key_page = key_page.replace('<%= short_id %>', doc['short_id'])

    conf_links = ''

    if settings.local.sub_active:
        conf_links += '<a class="btn btn-success" ' + \
            'title="Download Chromebook Profiles" ' + \
            'href="/key_onc/%s.zip">Download Chromebook Profiles</a><br>\n' % (
                doc['key_id'])

    for server in org.iter_servers():
        conf_links += '<a class="btn btn-sm" title="Download Profile" ' + \
            'href="/key/%s/%s.key">Download Profile (%s)</a><br>\n' % (
                doc['key_id'], server.id, server.name)
    key_page = key_page.replace('<%= conf_links %>', conf_links)

    return key_page
예제 #53
0
def user_key_pin_put(key_id):
    if settings.app.demo_mode:
        return utils.demo_blocked()

    doc = _find_doc({
        'key_id': key_id,
    })
    if not doc:
        return flask.abort(404)

    if settings.app.demo_mode:
        return utils.demo_blocked()

    if settings.user.pin_mode == PIN_DISABLED:
        return utils.jsonify({
            'error': PIN_IS_DISABLED,
            'error_msg': PIN_IS_DISABLED_MSG,
        }, 400)

    org = organization.get_by_id(doc['org_id'])
    usr = org.get_user(doc['user_id'])
    if usr.disabled:
        return flask.abort(403)

    if RADIUS_AUTH in usr.auth_type:
        return utils.jsonify({
            'error': PIN_RADIUS,
            'error_msg': PIN_RADIUS_MSG,
        }, 400)

    current_pin = utils.filter_str(
        flask.request.json.get('current_pin')) or None
    pin = utils.filter_str(flask.request.json.get('pin')) or None

    if pin:
        if not pin.isdigit():
            return utils.jsonify({
                'error': PIN_NOT_DIGITS,
                'error_msg': PIN_NOT_DIGITS_MSG,
            }, 400)

        if len(pin) < settings.user.pin_min_length:
            return utils.jsonify({
                'error': PIN_TOO_SHORT,
                'error_msg': PIN_TOO_SHORT_MSG,
            }, 400)

    if usr.pin and not usr.check_pin(current_pin):
        return utils.jsonify({
            'error': PIN_INVALID,
            'error_msg': PIN_INVALID_MSG,
        }, 400)

    if usr.set_pin(pin):
        usr.audit_event('user_updated',
            'User pin changed with temporary profile link',
            remote_addr=utils.get_remote_addr(),
        )

    usr.commit()

    event.Event(type=USERS_UPDATED, resource_id=org.id)

    return utils.jsonify({})
예제 #54
0
def check_session():
    auth_token = flask.request.headers.get('Auth-Token', None)
    if auth_token:
        auth_timestamp = flask.request.headers.get('Auth-Timestamp', None)
        auth_nonce = flask.request.headers.get('Auth-Nonce', None)
        auth_signature = flask.request.headers.get('Auth-Signature', None)
        if not auth_token or not auth_timestamp or not auth_nonce or \
                not auth_signature:
            return False
        auth_nonce = auth_nonce[:32]

        try:
            if abs(int(auth_timestamp) - int(utils.time_now())) > \
                    settings.app.auth_time_window:
                return False
        except ValueError:
            return False

        administrator = find_user(token=auth_token)
        if not administrator:
            return False

        auth_string = '&'.join([
            auth_token, auth_timestamp, auth_nonce, flask.request.method,
            flask.request.path
        ] + ([flask.request.data] if flask.request.data else []))

        if len(auth_string) > AUTH_SIG_STRING_MAX_LEN:
            return False

        auth_test_signature = base64.b64encode(
            hmac.new(administrator.secret.encode(), auth_string,
                     hashlib.sha256).digest())
        if auth_signature != auth_test_signature:
            return False

        try:
            Administrator.nonces_collection.insert(
                {
                    'token': auth_token,
                    'nonce': auth_nonce,
                    'timestamp': utils.now(),
                },
                w=0)
        except pymongo.errors.DuplicateKeyError:
            return False
    else:
        if not flask.session:
            return False

        admin_id = flask.session.get('admin_id')
        if not admin_id:
            return False
        admin_id = bson.ObjectId(admin_id)
        session_id = flask.session.get('session_id')

        administrator = get_user(admin_id, session_id)
        if not administrator:
            return False

        if not settings.conf.ssl and flask.session.get(
                'source') != utils.get_remote_addr():
            flask.session.clear()
            return False

        session_timeout = settings.app.session_timeout
        if session_timeout and int(utils.time_now()) - \
                flask.session['timestamp'] > session_timeout:
            flask.session.clear()
            return False

        flask.session['timestamp'] = int(utils.time_now())

    flask.g.administrator = administrator
    return True
예제 #55
0
def key_sync_get(org_id, user_id, server_id, key_hash):
    remote_addr = utils.get_remote_addr()

    if not settings.user.conf_sync:
        return utils.jsonify({})

    if not settings.local.sub_active:
        return utils.jsonify({}, status_code=480)

    utils.rand_sleep()

    auth_token = flask.request.headers.get('Auth-Token', None)
    auth_timestamp = flask.request.headers.get('Auth-Timestamp', None)
    auth_nonce = flask.request.headers.get('Auth-Nonce', None)
    auth_signature = flask.request.headers.get('Auth-Signature', None)
    if not auth_token or not auth_timestamp or not auth_nonce or \
            not auth_signature:
        journal.entry(
            journal.USER_SYNC_FAILURE,
            remote_address=remote_addr,
            event_long='Missing auth header',
        )
        return flask.abort(406)
    auth_nonce = auth_nonce[:32]

    try:
        if abs(int(auth_timestamp) - int(utils.time_now())) > \
                settings.app.auth_time_window:
            journal.entry(
                journal.USER_SYNC_FAILURE,
                remote_address=remote_addr,
                event_long='Expired auth timestamp',
            )
            return flask.abort(408)
    except ValueError:
        journal.entry(
            journal.USER_SYNC_FAILURE,
            remote_address=remote_addr,
            event_long='Invalid auth timestamp',
        )
        return flask.abort(405)

    org = organization.get_by_id(org_id)
    if not org:
        journal.entry(
            journal.USER_SYNC_FAILURE,
            remote_address=remote_addr,
            event_long='Organization not found',
        )
        return flask.abort(404)

    usr = org.get_user(id=user_id)
    if not usr:
        journal.entry(
            journal.USER_SYNC_FAILURE,
            remote_address=remote_addr,
            event_long='User not found',
        )
        return flask.abort(404)
    elif not usr.sync_secret:
        journal.entry(
            journal.USER_SYNC_FAILURE,
            usr.journal_data,
            remote_address=remote_addr,
            event_long='User missing sync secret',
        )
        return flask.abort(410)

    if auth_token != usr.sync_token:
        journal.entry(
            journal.USER_SYNC_FAILURE,
            usr.journal_data,
            remote_address=remote_addr,
            event_long='Sync token mismatch',
        )
        return flask.abort(410)

    if usr.disabled:
        journal.entry(
            journal.USER_SYNC_FAILURE,
            usr.journal_data,
            remote_address=remote_addr,
            event_long='User disabled',
        )
        return flask.abort(403)

    auth_string = '&'.join([
        usr.sync_token, auth_timestamp, auth_nonce, flask.request.method,
        flask.request.path
    ])

    if len(auth_string) > AUTH_SIG_STRING_MAX_LEN:
        journal.entry(
            journal.USER_SYNC_FAILURE,
            usr.journal_data,
            remote_address=remote_addr,
            event_long='Auth string len limit exceeded',
        )
        return flask.abort(413)

    auth_test_signature = base64.b64encode(
        hmac.new(usr.sync_secret.encode(), auth_string,
                 hashlib.sha512).digest())
    if not utils.const_compare(auth_signature, auth_test_signature):
        journal.entry(
            journal.USER_SYNC_FAILURE,
            usr.journal_data,
            remote_address=remote_addr,
            event_long='Sync signature mismatch',
        )
        return flask.abort(401)

    nonces_collection = mongo.get_collection('auth_nonces')
    try:
        nonces_collection.insert({
            'token': auth_token,
            'nonce': auth_nonce,
            'timestamp': utils.now(),
        })
    except pymongo.errors.DuplicateKeyError:
        journal.entry(
            journal.USER_SYNC_FAILURE,
            usr.journal_data,
            remote_address=remote_addr,
            event_long='Duplicate key',
        )
        return flask.abort(409)

    key_conf = usr.sync_conf(server_id, key_hash)
    if key_conf:
        usr.audit_event(
            'user_profile',
            'User profile synced from pritunl client',
            remote_addr=remote_addr,
        )

        journal.entry(
            journal.USER_SYNC_SUCCESS,
            usr.journal_data,
            remote_address=remote_addr,
            event_long='User profile synced from pritunl client',
        )

        sync_signature = base64.b64encode(
            hmac.new(usr.sync_secret.encode(), key_conf['conf'],
                     hashlib.sha512).digest())

        return utils.jsonify({
            'signature': sync_signature,
            'conf': key_conf['conf'],
        })

    return utils.jsonify({})
예제 #56
0
def sso_callback_get():
    sso_mode = settings.app.sso

    if sso_mode not in (GOOGLE_AUTH, GOOGLE_DUO_AUTH, SLACK_AUTH,
            SLACK_DUO_AUTH, SAML_AUTH, SAML_DUO_AUTH, SAML_OKTA_AUTH,
            SAML_OKTA_DUO_AUTH, SAML_ONELOGIN_AUTH, SAML_ONELOGIN_DUO_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
    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
    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
    if DUO_AUTH in sso_mode:
        valid, _ = sso.auth_duo(
            username,
            ipaddr=flask.request.remote_addr,
            type='Key',
        )
        if not valid:
            return flask.abort(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)
        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 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()[:-1] + key_link['view_url'])
예제 #57
0
def user_linked_key_conf_get(key_id, server_id):
    remote_addr = utils.get_remote_addr()

    doc = _find_doc({
        'key_id': key_id,
    })
    if not doc:
        journal.entry(
            journal.USER_PROFILE_FAILURE,
            remote_address=remote_addr,
            event_long='Key ID not found',
        )
        return flask.abort(404)

    if settings.user.restrict_import:
        return flask.abort(404)

    org = organization.get_by_id(doc['org_id'])
    if not org:
        journal.entry(
            journal.USER_PROFILE_FAILURE,
            remote_address=remote_addr,
            event_long='Organization not found',
        )
        return flask.abort(404)

    usr = org.get_user(id=doc['user_id'])
    if not usr:
        journal.entry(
            journal.USER_PROFILE_FAILURE,
            remote_address=remote_addr,
            event_long='User not found',
        )
        return flask.abort(404)

    if usr.disabled:
        journal.entry(
            journal.USER_PROFILE_FAILURE,
            usr.journal_data,
            remote_address=remote_addr,
            event_long='User disabled',
        )
        return flask.abort(403)

    key_conf = usr.build_key_conf(server_id)

    journal.entry(
        journal.USER_PROFILE_SUCCESS,
        usr.journal_data,
        remote_address=remote_addr,
        event_long='User profile downloaded with temporary profile link',
    )

    usr.audit_event(
        'user_profile',
        'User profile downloaded with temporary profile link',
        remote_addr=remote_addr,
    )

    response = flask.Response(response=key_conf['conf'],
                              mimetype='application/ovpn')
    response.headers.add('Content-Disposition',
                         'attachment; filename="%s"' % key_conf['name'])

    return response
예제 #58
0
def user_linked_key_page_get(short_code):
    remote_addr = utils.get_remote_addr()

    doc = _find_doc({
        'short_id': short_code,
    },
                    one_time=True,
                    one_time_new=True)
    if not doc:
        journal.entry(
            journal.USER_PROFILE_FAILURE,
            remote_address=remote_addr,
            event_long='Key ID not found',
        )
        return flask.abort(404)

    org = organization.get_by_id(doc['org_id'])
    usr = org.get_user(id=doc['user_id'])
    if usr.disabled:
        journal.entry(
            journal.USER_PROFILE_FAILURE,
            usr.journal_data,
            remote_address=remote_addr,
            event_long='User disabled',
        )
        return flask.abort(403)

    journal.entry(
        journal.USER_PROFILE_SUCCESS,
        usr.journal_data,
        remote_address=remote_addr,
        event_long='User temporary profile link viewed',
    )

    usr.audit_event(
        'user_profile',
        'User temporary profile link viewed',
        remote_addr=remote_addr,
    )

    if settings.local.sub_active and settings.app.theme == 'dark':
        view_name = KEY_VIEW_DARK_NAME
    else:
        view_name = KEY_VIEW_NAME

    if RADIUS_AUTH in usr.auth_type or \
            settings.user.pin_mode == PIN_DISABLED:
        header_class = 'pin-disabled'
    else:
        header_class = ''

    if settings.user.restrict_import:
        header_class += ' restrict-import'

    key_page = static.StaticFile(settings.conf.www_path,
                                 view_name,
                                 cache=False,
                                 gzip=False).data

    uri_url = (utils.get_url_root() + '/ku/' + doc['short_id']).encode()
    if uri_url.startswith('https'):
        uri_url = uri_url.replace('https', 'pritunl', 1)
    else:
        uri_url = uri_url.replace('http', 'pritunl', 1)
    key_page = key_page.replace('<%= uri_url %>', uri_url)

    key_page = key_page.replace('<%= user_name %>',
                                '%s - %s' % (org.name, usr.name))
    key_page = key_page.replace('<%= user_key_tar_url %>',
                                '/key/%s.tar' % (doc['key_id']))
    key_page = key_page.replace('<%= user_key_zip_url %>',
                                '/key/%s.zip' % (doc['key_id']))

    if org.otp_auth and not usr.has_duo_passcode and not usr.has_yubikey:
        key_page = key_page.replace('<%= user_otp_key %>', usr.otp_secret)
        key_page = key_page.replace(
            '<%= user_otp_url %>', 'otpauth://totp/%s@%s?secret=%s' %
            (usr.name, org.name, usr.otp_secret))
    else:
        key_page = key_page.replace('<%= user_otp_key %>', '')
        key_page = key_page.replace('<%= user_otp_url %>', '')

    if usr.pin:
        key_page = key_page.replace('<%= cur_pin_display %>', 'block')
    else:
        key_page = key_page.replace('<%= cur_pin_display %>', 'none')

    key_page = key_page.replace('<%= key_id %>', doc['key_id'])
    key_page = key_page.replace('<%= short_id %>', doc['short_id'])

    conf_links = ''

    if settings.local.sub_active:
        conf_links += '<a class="btn btn-success download-chrome" ' + \
            'title="Download Chrome OS Profile" ' + \
            'href="/key_onc/%s.onc">Download Chrome OS Profile</a>\n' % (
                doc['key_id'])

    has_servers = False
    for server in usr.iter_servers():
        has_servers = True
        conf_links += '<a class="btn btn-sm download-profile" ' + \
            'title="Download Profile" ' + \
            'href="/key/%s/%s.key">Download Profile (%s)</a>\n' % (
                doc['key_id'], server.id, server.name)
    key_page = key_page.replace('<%= conf_links %>', conf_links)

    if not has_servers:
        header_class += ' no-servers'
    key_page = key_page.replace('<%= header_class %>', header_class)

    return key_page