Example #1
0
    def get_link_user(self, org_ids):
        from pritunl import organization

        for org_id in org_ids:
            org = organization.get_by_id(org_id)
            if not org:
                continue

            usr = org.find_user(resource_id=self.id)
            if not usr:
                logger.info('Creating host link user', 'host',
                    host_id=self.id,
                )

                usr = org.new_user(name=HOST_USER_PREFIX + str(self.id),
                    type=CERT_SERVER, resource_id=self.id)

                journal.entry(
                    journal.USER_CREATE,
                    usr.journal_data,
                    event_long='User created for host linking',
                )

                usr.audit_event('user_created',
                    'User created for host linking')

            return usr

        raise ValueError('No orgs exists in link server')
Example #2
0
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)
Example #3
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'])
    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
Example #4
0
def sso_callback_get():
    state = flask.request.args.get('state')
    user = flask.request.args.get('user')

    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)

    org_id = settings.app.sso_org
    if not org_id:
        return flask.abort(405)

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

    usr = org.find_user(name=user)
    if not usr:
        usr = org.new_user(name=user, email=user, type=CERT_CLIENT)

    key_link = org.create_user_key_link(usr.id)

    return flask.redirect(flask.request.url_root[:-1] + key_link['view_url'])
Example #5
0
def org_put(org_id):
    if settings.app.demo_mode:
        return utils.demo_blocked()

    org = organization.get_by_id(org_id)

    org.name = utils.filter_str(flask.request.json['name'])

    auth_api = flask.request.json.get('auth_api', False)
    if auth_api:
        org.auth_api = True
        if not org.auth_token:
            org.generate_auth_token()
        if not org.auth_secret:
            org.generate_auth_secret()
    else:
        org.auth_api = False
        org.auth_token = None
        org.auth_secret = None

    if flask.request.json.get('auth_token') == True:
        org.generate_auth_token()

    if flask.request.json.get('auth_secret') == True:
        org.generate_auth_secret()

    org.commit()
    event.Event(type=ORGS_UPDATED)
    return utils.jsonify(org.dict())
Example #6
0
File: key.py Project: kknet/pritunl
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(404)

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

    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 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:
        return utils.response(key_conf['conf'])
    return utils.response('')
Example #7
0
def org_put(org_id):
    org = organization.get_by_id(org_id)
    name = utils.filter_str(flask.request.json['name'])
    org.name = name
    org.commit(org.changed)
    event.Event(type=ORGS_UPDATED)
    return utils.jsonify(org.dict())
Example #8
0
def user_post(org_id):
    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]

    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')
        user = org.new_user(type=CERT_CLIENT, name=name, email=email,
            disabled=disabled)
        users.append(user.dict())

    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])
Example #9
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"])
    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
Example #10
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 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)
Example #11
0
def _get_onc_archive(org_id, user_id):
    org = organization.get_by_id(org_id)
    usr = org.get_user(user_id)
    key_archive = usr.build_onc_archive()
    response = flask.Response(response=key_archive, mimetype="application/octet-stream")
    response.headers.add("Content-Disposition", 'attachment; filename="%s.zip"' % usr.name)
    return (usr, response)
Example #12
0
def server_org_delete(server_id, org_id):
    if settings.app.demo_mode:
        return utils.demo_blocked()

    svr = server.get_by_id(server_id,
        fields=('_id', 'status', 'network', 'network_start',
            'network_end', 'primary_organization',
            'primary_user', 'organizations', 'routes', 'ipv6'))
    org = organization.get_by_id(org_id, fields=('_id'))

    if svr.status == ONLINE:
        return utils.jsonify({
            'error': SERVER_NOT_OFFLINE,
            'error_msg': SERVER_NOT_OFFLINE_DETACH_ORG_MSG,
        }, 400)

    svr.remove_org(org)
    svr.commit(svr.changed)

    event.Event(type=SERVERS_UPDATED)
    event.Event(type=SERVER_ROUTES_UPDATED, resource_id=svr.id)
    event.Event(type=SERVER_ORGS_UPDATED, resource_id=svr.id)
    event.Event(type=USERS_UPDATED, resource_id=org.id)

    return utils.jsonify({})
Example #13
0
def user_otp_secret_put(org_id, user_id):
    org = organization.get_by_id(org_id)
    user = org.get_user(user_id)
    user.generate_otp_secret()
    user.commit()
    event.Event(type=USERS_UPDATED, resource_id=org.id)
    return utils.jsonify(user.dict())
Example #14
0
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.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": flask.request.url_root[:-1] + key_link["view_url"]}, 202)
Example #15
0
def user_audit_get(org_id, user_id):
    if org_id == 'admin' and user_id == 'admin':
        return utils.jsonify(auth.get_audit_events())

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

    return utils.jsonify(user.get_audit_events())
Example #16
0
def org_get(org_id=None):
    if org_id:
        return utils.jsonify(organization.get_by_id(org_id).dict())

    orgs = []
    for org in organization.iter_orgs_dict():
        orgs.append(org)
    return utils.jsonify(orgs)
Example #17
0
File: key.py Project: kknet/pritunl
def _get_key_archive(org_id, user_id):
    org = organization.get_by_id(org_id)
    user = org.get_user(user_id)
    key_archive = user.build_key_archive()
    response = flask.Response(response=key_archive,
        mimetype='application/octet-stream')
    response.headers.add('Content-Disposition',
        'attachment; filename="%s.tar"' % user.name)
    return response
Example #18
0
def _get_onc_archive(org_id, user_id):
    org = organization.get_by_id(org_id)
    usr = org.get_user(user_id)
    onc_conf = usr.build_onc()
    response = flask.Response(response=onc_conf,
        mimetype='application/x-onc')
    response.headers.add('Content-Disposition',
        'attachment; filename="%s_%s.onc"' % (org.name, usr.name))
    return (usr, response)
Example #19
0
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))
Example #20
0
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({})
Example #21
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])
Example #22
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
Example #23
0
def user_put(org_id, user_id):
    org = organization.get_by_id(org_id)
    user = org.get_user(user_id)

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

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

    disabled = flask.request.json.get('disabled')
    if disabled is not None:
        user.disabled = disabled

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

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

        for svr in org.iter_servers(fields=server.dict_fields + \
                ['hosts', 'links',  'replica_count', 'tls_auth_key',
                    'ca_certificate']):
            for instance in svr.instances:
                for client in instance['clients']:
                    if client['id'] == user_id:
                        svr.restart()
                        break
                if user_id in instance['clients']:
                    svr.restart()
    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:
        try:
            user.send_key_email(send_key_email)
        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())
Example #24
0
def get_by_id(id, fields=None, load_org=False):
    from pritunl import organization

    user = User(id=id, fields=fields)
    if not user:
        return None

    if load_org:
        user.org = organization.get_by_id(user.id)

    return user
Example #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
Example #26
0
def user_linked_key_page_get(short_code):
    utils.rand_sleep()

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

    if not doc:
        time.sleep(settings.app.rate_limit_sleep)
        return flask.abort(404)

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

    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_url %>', '/key/%s.tar' % (
        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 and settings.local.sub_plan == 'enterprise':
        conf_links += '<a class="btn btn-success" ' + \
            'style="margin-top: 7px;" ' + \
            'title="Download Chromebook Keys" ' + \
            'href="/key_onc/%s.zip">Download Chromebook Keys</a><br>\n' % (
                doc['key_id'])

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

    return key_page
Example #27
0
def org_delete(org_id):
    org = organization.get_by_id(org_id)
    name = org.name
    server_ids = org.remove()

    logger.LogEntry(message='Deleted organization "%s".' % name)

    for server_id in server_ids:
        event.Event(type=SERVER_ORGS_UPDATED, resource_id=server_id)
    event.Event(type=SERVERS_UPDATED)
    event.Event(type=ORGS_UPDATED)

    return utils.jsonify({})
Example #28
0
def user_audit_get(org_id, user_id):
    if settings.app.demo_mode:
        resp = utils.demo_get_cache()
        if resp:
            return utils.jsonify(resp)

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

    resp = user.get_audit_events()
    if settings.app.demo_mode:
        utils.demo_set_cache(resp)
    return utils.jsonify(resp)
Example #29
0
def key_sync_get(org_id, user_id, server_id):
    org = organization.get_by_id(org_id)
    user = org.get_user(id=user_id)
    sync_key = flask.request.json['sync_key']
    key_hash = flask.request.json['key_hash']

    if sync_key != user.sync_key:
        raise flask.abort(401)

    key_conf = user.sync_conf(server_id, key_hash)
    if key_conf:
        return key_conf['conf']
    return ''
Example #30
0
def user_delete(org_id, user_id):
    org = organization.get_by_id(org_id)
    user = org.get_user(user_id)
    name = user.name
    user.remove()

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

    user.disconnect()

    logger.LogEntry(message='Deleted user "%s".' % name)

    return utils.jsonify({})
Example #31
0
def key_sync_get(org_id, user_id, server_id, key_hash):
    org_id = org_id
    user_id = user_id
    server_id = server_id
    key_hash = key_hash[:256]
    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_token = auth_token[:256]
    auth_timestamp = auth_timestamp[:256]
    auth_nonce = auth_nonce[:32]
    auth_signature = auth_signature[:512]

    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({})
Example #32
0
File: auth.py Project: ijat/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)
Example #33
0
def key_wg_post(org_id, user_id, server_id):
    org_id = org_id
    user_id = user_id
    server_id = server_id
    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)

    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_WG_FAILURE,
            remote_address=remote_addr,
            event_long='Missing auth header',
        )
        return flask.abort(406)
    auth_token = auth_token[:256]
    auth_timestamp = auth_timestamp[:256]
    auth_nonce = auth_nonce[:32]
    auth_signature = auth_signature[:512]

    try:
        if abs(int(auth_timestamp) - int(utils.time_now())) > \
            settings.app.auth_time_window:
            journal.entry(
                journal.USER_WG_FAILURE,
                remote_address=remote_addr,
                event_long='Expired auth timestamp',
            )
            return flask.abort(408)
    except ValueError:
        journal.entry(
            journal.USER_WG_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_WG_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_WG_FAILURE,
            remote_address=remote_addr,
            event_long='User not found',
        )
        return flask.abort(404)
    elif not usr.sync_secret:
        journal.entry(
            journal.USER_WG_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_WG_FAILURE,
            usr.journal_data,
            remote_address=remote_addr,
            event_long='Sync token mismatch',
        )
        return flask.abort(411)

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

    cipher_data64 = flask.request.json.get('data')
    box_nonce64 = flask.request.json.get('nonce')
    public_key64 = flask.request.json.get('public_key')
    signature64 = flask.request.json.get('signature')

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

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

    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_WG_FAILURE,
            usr.journal_data,
            remote_address=remote_addr,
            event_long='Auth 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_WG_FAILURE,
            usr.journal_data,
            remote_address=remote_addr,
            event_long='Duplicate nonce',
        )
        return flask.abort(409)

    data_hash = hashlib.sha512('&'.join(
        [cipher_data64, box_nonce64, public_key64])).digest()
    try:
        usr.verify_sig(
            data_hash,
            base64.b64decode(signature64),
        )
    except InvalidSignature:
        journal.entry(
            journal.USER_WG_FAILURE,
            usr.journal_data,
            remote_address=remote_addr,
            event_long='Invalid rsa signature',
        )
        return flask.abort(412)

    svr = usr.get_server(server_id)

    sender_pub_key = nacl.public.PublicKey(base64.b64decode(public_key64))
    box_nonce = base64.b64decode(box_nonce64)

    priv_key = nacl.public.PrivateKey(
        base64.b64decode(svr.auth_box_private_key))

    cipher_data = base64.b64decode(cipher_data64)
    nacl_box = nacl.public.Box(priv_key, sender_pub_key)
    plaintext = nacl_box.decrypt(cipher_data, box_nonce).decode('utf-8')

    try:
        nonces_collection.insert({
            'token': auth_token,
            'nonce': box_nonce64,
            'timestamp': utils.now(),
        })
    except pymongo.errors.DuplicateKeyError:
        journal.entry(
            journal.USER_WG_FAILURE,
            usr.journal_data,
            remote_address=remote_addr,
            event_long='Duplicate secondary nonce',
        )
        return flask.abort(415)

    key_data = json.loads(plaintext)

    client_platform = key_data['platform']
    client_device_id = key_data['device_id']
    client_device_name = key_data['device_name']
    client_mac_addr = key_data['mac_addr']
    client_auth_token = key_data['token']
    client_auth_nonce = key_data['nonce']
    client_auth_password = key_data['password']
    client_auth_timestamp = key_data['timestamp']
    client_wg_public_key = key_data['wg_public_key']

    if len(client_wg_public_key) < 32:
        journal.entry(
            journal.USER_WG_FAILURE,
            usr.journal_data,
            remote_address=remote_addr,
            event_long='Public key too short',
        )
        return flask.abort(416)

    try:
        client_wg_public_key = base64.b64decode(client_wg_public_key)
        if len(client_wg_public_key) != 32:
            raise ValueError('Invalid length')
        client_wg_public_key = base64.b64encode(client_wg_public_key)
    except:
        journal.entry(
            journal.USER_WG_FAILURE,
            usr.journal_data,
            remote_address=remote_addr,
            event_long='Public key invalid',
        )
        return flask.abort(417)

    wg_keys_collection = mongo.get_collection('wg_keys')
    try:
        wg_keys_collection.insert({
            '_id': client_wg_public_key,
            'timestamp': utils.now(),
        })
    except pymongo.errors.DuplicateKeyError:
        journal.entry(
            journal.USER_WG_FAILURE,
            usr.journal_data,
            remote_address=remote_addr,
            event_long='Duplicate wg public key',
        )
        return flask.abort(413)

    instance = server.get_instance(server_id)
    if not instance or instance.state != 'running':
        return flask.abort(429)

    if not instance.server.wg:
        return flask.abort(429)

    clients = instance.instance_com.clients

    event = threading.Event()
    send_data = {
        'allow': None,
        'configuration': None,
        'reason': None,
    }

    def callback(allow, data):
        send_data['allow'] = allow
        if allow:
            send_data['configuration'] = data
        else:
            send_data['reason'] = data
        event.set()

    clients.connect_wg(
        user=usr,
        org=org,
        wg_public_key=client_wg_public_key,
        auth_password=client_auth_password,
        auth_token=client_auth_token,
        auth_nonce=client_auth_nonce,
        auth_timestamp=client_auth_timestamp,
        platform=client_platform,
        device_id=client_device_id,
        device_name=client_device_name,
        mac_addr=client_mac_addr,
        remote_ip=remote_addr,
        connect_callback=callback,
    )

    event.wait()

    send_nonce = nacl.utils.random(nacl.public.Box.NONCE_SIZE)
    nacl_box = nacl.public.Box(priv_key, sender_pub_key)
    send_cipher_data = nacl_box.encrypt(json.dumps(send_data), send_nonce)
    send_cipher_data = send_cipher_data[nacl.public.Box.NONCE_SIZE:]

    send_nonce64 = base64.b64encode(send_nonce)
    send_cipher_data64 = base64.b64encode(send_cipher_data)

    usr.audit_event(
        'user_profile',
        'User retrieved wg public key from pritunl client',
        remote_addr=remote_addr,
    )

    journal.entry(
        journal.USER_WG_SUCCESS,
        usr.journal_data,
        remote_address=remote_addr,
        event_long='User retrieved wg public key from pritunl client',
    )

    sync_signature = base64.b64encode(
        hmac.new(usr.sync_secret.encode(),
                 send_cipher_data64 + '&' + send_nonce64,
                 hashlib.sha512).digest())

    return utils.jsonify({
        'data': send_cipher_data64,
        'nonce': send_nonce64,
        'signature': sync_signature,
    })
Example #34
0
def _auth_plugin(username, password, remote_addr):
    if not settings.local.sub_plan or \
            'enterprise' not in settings.local.sub_plan:
        journal.entry(
            journal.ADMIN_AUTH_FAILURE,
            user_name=username,
            remote_address=remote_addr,
            reason=journal.ADMIN_AUTH_REASON_INVALID_USERNAME,
            reason_long='Invalid username',
        )
        return utils.jsonify(
            {
                'error': AUTH_INVALID,
                'error_msg': AUTH_INVALID_MSG,
            }, 401)

    has_plugin, valid, org_id, groups = sso.plugin_login_authenticate(
        user_name=username,
        password=password,
        remote_ip=remote_addr,
    )

    if not has_plugin:
        journal.entry(
            journal.ADMIN_AUTH_FAILURE,
            user_name=username,
            remote_address=remote_addr,
            reason=journal.ADMIN_AUTH_REASON_INVALID_USERNAME,
            reason_long='Invalid username',
        )
        return utils.jsonify(
            {
                'error': AUTH_INVALID,
                'error_msg': AUTH_INVALID_MSG,
            }, 401)

    if not valid:
        journal.entry(
            journal.SSO_AUTH_REASON_PLUGIN_FAILED,
            user_name=username,
            remote_address=remote_addr,
            reason=journal.SSO_AUTH_REASON_PLUGIN_FAILED,
            reason_long='Plugin authentication failed',
        )
        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:
        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=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(),
        )

        journal.entry(
            journal.USER_CREATE,
            usr.journal_data,
            event_long='User created with plugin authentication',
            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 != 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(),
    )

    journal.entry(
        journal.USER_PROFILE_SUCCESS,
        usr.journal_data,
        event_long='User profile viewed from plugin authentication',
        remote_address=remote_addr,
    )

    return utils.jsonify(
        {
            'redirect': utils.get_url_root() + key_link['view_url'],
        }, 202)
Example #35
0
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 'undefined'

        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'] or None

        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'] or []:
            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 = True if flask.request.json.get('disabled') else False
    if disabled != user.disabled:
        user.audit_event(
            'user_updated',
            'User %s' % ('disabled' if disabled else 'enabled'),
            remote_addr=utils.get_remote_addr(),
        )
        if disabled:
            reset_user = True
    user.disabled = disabled

    user.bypass_secondary = True if flask.request.json.get(
        'bypass_secondary') else False

    user.client_to_client = True if flask.request.json.get(
        '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:
        user.disconnect()

    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())
Example #36
0
def _validate_user(username,
                   email,
                   sso_mode,
                   org_id,
                   groups,
                   remote_addr,
                   http_redirect=False,
                   yubico_id=None):
    usr = user.find_user_auth(name=username, auth_type=sso_mode)
    if not usr:
        org = organization.get_by_id(org_id)
        if not org:
            logger.error(
                'Organization for sso does not exist',
                'sso',
                org_id=org_id,
            )
            return flask.abort(405)

        usr = org.find_user(name=username)
    else:
        if usr.org_id != org_id:
            logger.info(
                'User organization changed, moving user',
                'sso',
                user_name=username,
                user_email=email,
                remote_ip=remote_addr,
                cur_org_id=usr.org_id,
                new_org_id=org_id,
            )

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

            usr.remove()
            old_org_id = usr.org_id

            usr = org.new_user(
                name=usr.name,
                email=usr.email,
                type=usr.type,
                groups=usr.groups,
                auth_type=usr.auth_type,
                yubico_id=usr.yubico_id,
                disabled=usr.disabled,
                bypass_secondary=usr.bypass_secondary,
                client_to_client=usr.client_to_client,
                dns_servers=usr.dns_servers,
                dns_suffix=usr.dns_suffix,
                port_forwarding=usr.port_forwarding,
            )

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

        org = usr.org

    if not usr:
        usr = org.new_user(name=username,
                           email=email,
                           type=CERT_CLIENT,
                           auth_type=sso_mode,
                           yubico_id=yubico_id,
                           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 yubico_id and usr.yubico_id and yubico_id != usr.yubico_id:
            journal.entry(
                journal.SSO_AUTH_FAILURE,
                user_name=username,
                remote_address=remote_addr,
                reason=journal.SSO_AUTH_REASON_INVALID_YUBIKEY,
                reason_long='Invalid username',
            )

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

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

        changed = False

        if yubico_id and not usr.yubico_id:
            changed = True
            usr.yubico_id = yubico_id
            usr.commit('yubico_id')

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

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

        if changed:
            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=remote_addr,
    )

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

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

    if http_redirect:
        return utils.redirect(utils.get_url_root() + key_link['view_url'])
    else:
        return utils.jsonify(
            {
                'redirect': utils.get_url_root() + key_link['view_url'],
            }, 200)
Example #37
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 ''

    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:
        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 = 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.error(
                '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.error(
                '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.error(
            'Duo plugin authentication not valid',
            'sso',
            username=username,
        )
        return flask.abort(401)

    groups = groups | set(groups2 or [])

    usr = user.find_user_auth(name=username, auth_type=sso_mode)
    if not usr:
        org = organization.get_by_id(org_id)
        if not org:
            return flask.abort(405)

        usr = org.find_user(name=username)
    else:
        org = usr.org

    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)
Example #38
0
def key_sync_get(org_id, user_id, server_id, key_hash):
    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:
        return flask.abort(406)
    auth_nonce = auth_nonce[:32]

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

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

    usr = org.get_user(id=user_id)
    if not usr:
        return flask.abort(404)
    elif not usr.sync_secret:
        return flask.abort(410)

    if auth_token != usr.sync_token:
        return flask.abort(410)

    if usr.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:
        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):
        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:
        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=utils.get_remote_addr(),
        )

        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({})
Example #39
0
def user_key_link_get(org_id, user_id):
    org = organization.get_by_id(org_id)
    return utils.jsonify(org.create_user_key_link(user_id))
Example #40
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 settings.user.pin_digits_only and 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:
        if not limiter.auth_check(usr.id):
            return utils.jsonify(
                {
                    'error': AUTH_TOO_MANY,
                    'error_msg': AUTH_TOO_MANY_MSG,
                }, 400)

        if 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({})
Example #41
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'])
    usr = org.get_user(id=doc['user_id'])
    if usr.disabled:
        return flask.abort(403)

    usr.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 RADIUS_AUTH in usr.auth_type 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

    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
Example #42
0
 def get_org(self, org_id, fields=None):
     if org_id in self.organizations:
         return organization.get_by_id(org_id, fields=fields)
Example #43
0
def user_get(org_id, user_id=None, page=None):
    org = organization.get_by_id(org_id)
    if user_id:
        return utils.jsonify(org.get_user(user_id).dict())

    page = flask.request.args.get('page', None)
    page = int(page) if page else page
    search = flask.request.args.get('search', None)
    limit = int(flask.request.args.get('limit', settings.user.page_count))
    otp_auth = False
    server_count = 0
    servers = []

    for svr in org.iter_servers(fields=('name', 'otp_auth')):
        servers.append(svr)
        server_count += 1
        if svr.otp_auth:
            otp_auth = True

    users = []
    users_id = []
    users_data = {}
    users_servers = {}
    fields = (
        'organization',
        'organization_name',
        'name',
        'email',
        'type',
        'otp_secret',
        'disabled',
    )
    for usr in org.iter_users(page=page, search=search,
            search_limit=limit, fields=fields):
        users_id.append(usr.id)

        user_dict = usr.dict()
        user_dict['status'] = False
        user_dict['otp_auth'] = otp_auth

        users_data[usr.id] = user_dict
        users_servers[usr.id] = {}

        server_data = []
        for svr in servers:
            data = {
                'id': svr.id,
                'name': svr.name,
                'status': False,
                'client_id': None,
                'device_name': None,
                'platform': None,
                'real_address': None,
                'virt_address': None,
                'connected_since': None
            }
            server_data.append(data)
            users_servers[usr.id][svr.id] = data

        user_dict['servers'] = sorted(server_data, key=lambda x: x['name'])

        users.append(user_dict)

    clients_collection = mongo.get_collection('clients')
    for doc in clients_collection.find({
                'user_id': {'$in': users_id},
            }):
        server_data = users_servers[doc['user_id']].get(doc['server_id'])
        if not server_data:
            continue

        users_data[doc['user_id']]['status'] = True

        server_data['status'] = True
        server_data['client_id'] = doc['_id']
        server_data['device_name'] = doc['device_name']
        server_data['platform'] = doc['platform']
        server_data['real_address'] = doc['real_address']
        server_data['virt_address'] = doc['virt_address'].split('/')[0]
        server_data['connected_since'] = doc['connected_since']

    ip_addrs_iter = server.multi_get_ip_addr(org_id, users_id)
    for user_id, server_id, ip_add in ip_addrs_iter:
        server_data = users_servers[user_id].get(server_id)
        if server_data and not server_data['virt_address']:
            server_data['virt_address'] = ip_add

    if page is not None:
        return utils.jsonify({
            'page': page,
            'page_total': org.page_total,
            'server_count': server_count,
            'users': users,
        })
    elif search is not None:
        return utils.jsonify({
            'search': search,
            'search_more': limit < org.last_search_count,
            'search_limit': limit,
            'search_count': org.last_search_count,
            'search_time':  round((time.time() - flask.g.start), 4),
            'server_count': server_count,
            'users': users,
        })
    else:
        return utils.jsonify(users)
Example #44
0
    def assign_ip_pool_org(self, org_id):
        org = organization.get_by_id(org_id)
        network = self.server.network
        server_id = self.server.id
        org_id = org.id
        ip_pool_avial = True
        pool_end = False

        ip_network = ipaddress.IPv4Network(network)
        ip_pool = ip_network.iterhosts()
        ip_pool.next()

        try:
            doc = self.collection.find({
                'network': network,
                'server_id': server_id,
            }).sort('_id', pymongo.DESCENDING)[0]
            if doc:
                last_addr = doc['_id']
                for remote_ip_addr in ip_pool:
                    if int(remote_ip_addr) == last_addr:
                        break
        except IndexError:
            pass

        if mongo.has_bulk:
            bulk = self.collection.initialize_unordered_bulk_op()
            bulk_empty = True
        else:
            bulk = None
            bulk_empty = None

        for user in org.iter_users(include_pool=True):
            if ip_pool_avial:
                response = self.collection.update(
                    {
                        'network': network,
                        'server_id': server_id,
                        'user_id': {
                            '$exists': False
                        },
                    }, {'$set': {
                        'org_id': org_id,
                        'user_id': user.id,
                    }})
                if response['updatedExisting']:
                    continue
                ip_pool_avial = False

            try:
                remote_ip_addr = ip_pool.next()
            except StopIteration:
                pool_end = True
                break
            doc_id = int(remote_ip_addr)

            spec = {
                '_id': doc_id,
            }
            doc = {
                '$set': {
                    '_id': doc_id,
                    'network': network,
                    'server_id': server_id,
                    'org_id': org_id,
                    'user_id': user.id,
                    'address':
                    '%s/%s' % (remote_ip_addr, ip_network.prefixlen),
                }
            }

            if bulk:
                bulk.find(spec).upsert().update(doc)
                bulk_empty = False
            else:
                self.collection.update(spec, doc, upsert=True)

        if bulk and not bulk_empty:
            bulk.execute()

        if pool_end:
            logger.warning(
                'Failed to assign ip addresses ' + 'to org, ip pool empty',
                'server',
                org_id=org_id,
            )
Example #45
0
def user_linked_key_conf_get(key_id, server_id):
    key_id = key_id[:128]
    server_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
Example #46
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)
        groups = set(groups or [])
    else:
        logger.error(
            'Duo authentication not valid',
            'sso',
            username=username,
        )
        return flask.abort(401)

    if not org_id:
        org_id = settings.app.sso_org

    usr = user.find_user_auth(name=username, auth_type=DUO_AUTH)
    if not usr:
        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)
    else:
        org = usr.org

    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']
Example #47
0
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

    valid, org_id_new = 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)

    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.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)
Example #48
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'))
            pin = utils.filter_str(user_data.get('pin')) or None
            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
            port_forwarding_in = user_data.get('port_forwarding')
            port_forwarding = []

            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)

                pin = auth.generate_hash_pin_v2(pin)

            if port_forwarding_in:
                for data in port_forwarding_in:
                    port_forwarding.append({
                        'protocol':
                        utils.filter_str(data.get('protocol')),
                        'port':
                        utils.filter_str(data.get('port')),
                        'dport':
                        utils.filter_str(data.get('dport')),
                    })

            user = org.new_user(type=CERT_CLIENT,
                                name=name,
                                email=email,
                                pin=pin,
                                disabled=disabled,
                                bypass_secondary=bypass_secondary,
                                dns_servers=dns_servers,
                                dns_suffix=dns_suffix,
                                port_forwarding=port_forwarding)
            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])
Example #49
0
def sso_yubico_post():
    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_one({
        '_id': token,
    })
    if not doc or doc['_id'] != token or doc['type'] != YUBICO_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 [])

    valid, yubico_id = sso.auth_yubico(key)
    if not valid:
        return utils.jsonify(
            {
                'error': YUBIKEY_INVALID,
                'error_msg': YUBIKEY_INVALID_MSG,
            }, 401)

    usr = user.find_user_auth(name=username, auth_type=sso_mode)
    if not usr:
        org = organization.get_by_id(org_id)
        if not org:
            return flask.abort(405)

        usr = org.find_user(name=username)
    else:
        org = usr.org

    if not usr:
        usr = org.new_user(name=username,
                           email=email,
                           type=CERT_CLIENT,
                           auth_type=sso_mode,
                           yubico_id=yubico_id,
                           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 yubico_id != usr.yubico_id:
            return utils.jsonify(
                {
                    'error': YUBIKEY_INVALID,
                    'error_msg': YUBIKEY_INVALID_MSG,
                }, 401)

        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)
Example #50
0
def user_get(org_id, user_id=None, page=None):
    if settings.app.demo_mode and user_id:
        resp = utils.demo_get_cache()
        if resp:
            return utils.jsonify(resp)

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

    if user_id:
        resp = org.get_user(user_id).dict()
        if settings.app.demo_mode:
            utils.demo_set_cache(resp)
        return utils.jsonify(resp)

    page = flask.request.args.get('page', page)
    page = int(page) if page else page
    search = flask.request.args.get('search', None)
    limit = int(flask.request.args.get('limit', settings.user.page_count))
    otp_auth = False
    dns_mapping = False
    server_count = 0
    servers = []

    if settings.app.demo_mode:
        resp = utils.demo_get_cache(page, search, limit)
        if resp:
            return utils.jsonify(resp)

    for svr in org.iter_servers(fields=('name', 'otp_auth', 'dns_mapping',
                                        'groups')):
        servers.append(svr)
        server_count += 1
        if svr.otp_auth:
            otp_auth = True
        if svr.dns_mapping:
            dns_mapping = True

    users = []
    users_id = []
    users_data = {}
    users_servers = {}
    fields = (
        'organization',
        'organization_name',
        'name',
        'email',
        'groups',
        'pin',
        'type',
        'auth_type',
        'otp_secret',
        'disabled',
        'bypass_secondary',
        'client_to_client',
        'dns_servers',
        'dns_suffix',
        'port_forwarding',
    )
    for usr in org.iter_users(page=page,
                              search=search,
                              search_limit=limit,
                              fields=fields):
        users_id.append(usr.id)

        user_dict = usr.dict()
        user_dict['gravatar'] = settings.user.gravatar
        user_dict['audit'] = settings.app.auditing == ALL
        user_dict['status'] = False
        user_dict['sso'] = settings.app.sso

        if otp_auth and not usr.has_duo_passcode and not usr.has_yubikey:
            user_dict['otp_auth'] = True
        else:
            user_dict['otp_auth'] = False

        if dns_mapping:
            user_dict['dns_mapping'] = (
                '%s.%s.vpn' % (str(usr.name).split('@')[0], org.name)).lower()
        else:
            user_dict['dns_mapping'] = None
        user_dict['network_links'] = []

        users_data[usr.id] = user_dict
        users_servers[usr.id] = {}

        server_data = []
        for svr in servers:
            if not svr.check_groups(usr.groups):
                continue
            data = {
                'id': svr.id,
                'name': svr.name,
                'status': False,
                'server_id': svr.id,
                'device_name': None,
                'platform': None,
                'real_address': None,
                'virt_address': None,
                'virt_address6': None,
                'connected_since': None,
            }
            server_data.append(data)
            users_servers[usr.id][svr.id] = data

        user_dict['servers'] = sorted(server_data, key=lambda x: x['name'])
        users.append(user_dict)

    clients_collection = mongo.get_collection('clients')
    for doc in clients_collection.find({
            'user_id': {
                '$in': users_id
            },
    }):
        server_data = users_servers[doc['user_id']].get(doc['server_id'])
        if not server_data:
            continue

        users_data[doc['user_id']]['status'] = True

        if server_data['status']:
            server_data = {
                'name': server_data['name'],
            }
            append = True
        else:
            append = False

        virt_address6 = doc.get('virt_address6')
        if virt_address6:
            server_data['virt_address6'] = virt_address6.split('/')[0]

        server_data['id'] = doc['_id']
        server_data['status'] = True
        server_data['server_id'] = server_data['id']
        server_data['device_name'] = doc['device_name']
        server_data['platform'] = doc['platform']
        server_data['real_address'] = doc['real_address']
        server_data['virt_address'] = doc['virt_address'].split('/')[0]
        server_data['connected_since'] = doc['connected_since']

        if append:
            svrs = users_data[doc['user_id']]['servers']
            svrs.append(server_data)
            users_data[doc['user_id']]['servers'] = sorted(
                svrs, key=lambda x: x['name'])

    net_link_collection = mongo.get_collection('users_net_link')
    for doc in net_link_collection.find({
            'user_id': {
                '$in': users_id
            },
    }):
        users_data[doc['user_id']]['network_links'].append(doc['network'])

    ip_addrs_iter = server.multi_get_ip_addr(org_id, users_id)
    for user_id, server_id, addr, addr6 in ip_addrs_iter:
        server_data = users_servers[user_id].get(server_id)
        if server_data:
            if not server_data['virt_address']:
                server_data['virt_address'] = addr
            if not server_data['virt_address6']:
                server_data['virt_address6'] = addr6

    if page is not None:
        resp = {
            'page': page,
            'page_total': org.page_total,
            'server_count': server_count,
            'users': users,
        }
    elif search is not None:
        resp = {
            'search': search,
            'search_more': limit < org.last_search_count,
            'search_limit': limit,
            'search_count': org.last_search_count,
            'search_time': round((time.time() - flask.g.start), 4),
            'server_count': server_count,
            'users': users,
        }
    else:
        resp = users

    if settings.app.demo_mode and not search:
        utils.demo_set_cache(resp, page, search, limit)
    return utils.jsonify(resp)
Example #51
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 not utils.const_compare(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]
        groups = set(params.get('groups') or [])
        org_name = params.get('org', [None])[0]

        if not username:
            return flask.abort(406)

        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, groups2 = 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)

        groups = groups | set(groups2 or [])
    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(',')

        if user_team != settings.app.sso_match[0]:
            return flask.abort(401)

        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)
        groups = set(groups or [])
    else:
        username = params.get('username')[0]
        email = username

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

        org_id = settings.app.sso_org

        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)
        groups = set(groups or [])

        if settings.app.sso_google_mode == 'groups':
            groups = groups | set(google_groups)
        else:
            for org_name in sorted(google_groups):
                org = organization.get_by_name(org_name, fields=('_id'))
                if org:
                    org_id = org.id
                    break

    if DUO_AUTH in sso_mode:
        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': list(groups) if groups else None,
            'timestamp': utils.now(),
        })

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

        sso_duo_mode = settings.app.sso_duo_mode
        if sso_duo_mode == 'passcode':
            duo_mode = 'passcode'
        elif sso_duo_mode == 'phone':
            duo_mode = 'phone'
        else:
            duo_mode = 'push'

        body_class = duo_mode
        if settings.app.theme == 'dark':
            body_class += ' dark'

        duo_page.data = duo_page.data.replace('<%= body_class %>', body_class)
        duo_page.data = duo_page.data.replace('<%= token %>', token)
        duo_page.data = duo_page.data.replace('<%= duo_mode %>', duo_mode)

        return duo_page.get_response()

    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': list(groups) if groups else None,
            '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()

    usr = user.find_user_auth(name=username, auth_type=sso_mode)
    if not usr:
        org = organization.get_by_id(org_id)
        if not org:
            return flask.abort(405)

        usr = org.find_user(name=username)
    else:
        org = usr.org

    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'])
Example #52
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 flask.request.url_root[:-1] + key_link['view_url']
Example #53
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'])
    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)
    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
Example #54
0
File: auth.py Project: ijat/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)
Example #55
0
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 exists',
                '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']).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)
Example #56
0
def sso_callback_get():
    sso_mode = settings.app.sso

    if sso_mode not in (GOOGLE_AUTH, GOOGLE_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

    else:
        username = params.get('username', [None])[0]
        email = username

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

        if not org_id:
            org_id = settings.app.sso_org

    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 flask.redirect(flask.request.url_root[:-1] + key_link['view_url'])
Example #57
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(404)

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

    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 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:
        return utils.response(key_conf['conf'])
    return utils.response('')
Example #58
0
    def generate_ovpn_conf(self):
        logger.debug(
            'Generating server ovpn conf',
            'server',
            server_id=self.server.id,
        )

        if not self.server.primary_organization or \
                not self.server.primary_user:
            self.server.create_primary_user()

        if self.server.primary_organization not in self.server.organizations:
            self.server.remove_primary_user()
            self.server.create_primary_user()

        primary_org = organization.get_by_id(self.server.primary_organization)
        if not primary_org:
            self.server.create_primary_user()
            primary_org = organization.get_by_id(
                id=self.server.primary_organization)

        self.primary_user = primary_org.get_user(self.server.primary_user)
        if not self.primary_user:
            self.server.create_primary_user()
            primary_org = organization.get_by_id(
                id=self.server.primary_organization)
            self.primary_user = primary_org.get_user(self.server.primary_user)

        push = ''
        if self.server.mode == LOCAL_TRAFFIC:
            for network in self.server.local_networks:
                push += 'push "route %s %s"\n' % utils.parse_network(network)
        elif self.server.mode == VPN_TRAFFIC:
            pass

        for link_svr in self.server.iter_links(fields=('_id', 'network',
                                                       'local_networks',
                                                       'network_start',
                                                       'network_end')):
            if self.server.id < link_svr.id:
                gateway = utils.get_network_gateway(self.server.network)
                push += 'route %s %s %s\n' % (
                    utils.parse_network(link_svr.network) + (gateway, ))
                for local_network in link_svr.local_networks:
                    push += 'route %s %s %s\n' % (
                        utils.parse_network(local_network) + (gateway, ))

        if self.server.network_mode == BRIDGE:
            host_int_data = self.host_interface_data
            host_address = host_int_data['address']
            host_netmask = host_int_data['netmask']

            server_line = 'server-bridge %s %s %s %s' % (
                host_address,
                host_netmask,
                self.server.network_start,
                self.server.network_end,
            )
        else:
            server_line = 'server %s %s' % utils.parse_network(
                self.server.network)

        server_conf = OVPN_INLINE_SERVER_CONF % (
            self.server.port,
            self.server.protocol,
            self.interface,
            server_line,
            self.management_socket_path,
            self.server.max_clients,
            self.server.ping_interval,
            self.server.ping_timeout + 20,
            self.server.ping_interval,
            self.server.ping_timeout,
            CIPHERS[self.server.cipher],
            4 if self.server.debug else 1,
            8 if self.server.debug else 3,
        )

        if self.server.bind_address:
            server_conf += 'local %s\n' % self.server.bind_address

        if self.server.inter_client:
            server_conf += 'client-to-client\n'

        if self.server.multi_device:
            server_conf += 'duplicate-cn\n'

        # Pritunl v0.10.x did not include comp-lzo in client conf
        # if lzo_compression is adaptive dont include comp-lzo in server conf
        if self.server.lzo_compression == ADAPTIVE:
            pass
        elif self.server.lzo_compression:
            server_conf += 'comp-lzo yes\npush "comp-lzo yes"\n'
        else:
            server_conf += 'comp-lzo no\npush "comp-lzo no"\n'

        server_conf += JUMBO_FRAMES[self.server.jumbo_frames]

        if push:
            server_conf += push

        if self.server.debug:
            self.server.output.push_message('Server conf:')
            for conf_line in server_conf.split('\n'):
                if conf_line:
                    self.server.output.push_message('  ' + conf_line)

        server_conf += '<ca>\n%s\n</ca>\n' % self.server.ca_certificate

        if self.server.tls_auth:
            server_conf += 'key-direction 0\n<tls-auth>\n%s\n</tls-auth>\n' % (
                self.server.tls_auth_key)

        server_conf += '<cert>\n%s\n</cert>\n' % utils.get_cert_block(
            self.primary_user.certificate)
        server_conf += '<key>\n%s\n</key>\n' % self.primary_user.private_key
        server_conf += '<dh>\n%s\n</dh>\n' % self.server.dh_params

        with open(self.ovpn_conf_path, 'w') as ovpn_conf:
            os.chmod(self.ovpn_conf_path, 0600)
            ovpn_conf.write(server_conf)
Example #59
0
    def generate_ovpn_conf(self):
        if not self.server.primary_organization or \
                not self.server.primary_user:
            self.server.create_primary_user()

        if self.server.primary_organization not in self.server.organizations:
            self.server.remove_primary_user()
            self.server.create_primary_user()

        primary_org = organization.get_by_id(self.server.primary_organization)
        if not primary_org:
            self.server.create_primary_user()
            primary_org = organization.get_by_id(
                id=self.server.primary_organization)

        self.primary_user = primary_org.get_user(self.server.primary_user)
        if not self.primary_user:
            self.server.create_primary_user()
            primary_org = organization.get_by_id(
                id=self.server.primary_organization)
            self.primary_user = primary_org.get_user(self.server.primary_user)

        gateway = utils.get_network_gateway(self.server.network)
        gateway6 = utils.get_network_gateway(self.server.network6)

        push = ''
        routes = []
        for route in self.server.get_routes(include_default=False):
            routes.append(route['network'])
            if route['virtual_network']:
                continue

            metric = route.get('metric')
            if metric:
                metric_def = ' default %s' % metric
                metric = ' %s' % metric
            else:
                metric_def = ''
                metric = ''

            network = route['network']
            if route['net_gateway']:
                if ':' in network:
                    push += 'push "route-ipv6 %s net_gateway%s"\n' % (network,
                                                                      metric)
                else:
                    push += 'push "route %s %s net_gateway%s"\n' % (
                        utils.parse_network(network) + (metric, ))
            elif not route.get('network_link'):
                if ':' in network:
                    push += 'push "route-ipv6 %s%s"\n' % (network, metric_def)
                else:
                    push += 'push "route %s %s%s"\n' % (
                        utils.parse_network(network) + (metric_def, ))
            else:
                if ':' in network:
                    push += 'route-ipv6 %s %s%s\n' % (network, gateway6,
                                                      metric)
                else:
                    push += 'route %s %s %s%s\n' % (
                        utils.parse_network(network) + (gateway, metric))

        for link_svr in self.server.iter_links(
                fields=('_id', 'network', 'local_networks', 'network_start',
                        'network_end', 'organizations', 'routes', 'links',
                        'ipv6', 'replica_count', 'network_mode')):
            if self.server.id < link_svr.id:
                for route in link_svr.get_routes(include_default=False):
                    network = route['network']
                    metric = route.get('metric')
                    if metric:
                        metric = ' %s' % metric
                    else:
                        metric = ''

                    if route['net_gateway']:
                        continue

                    if ':' in network:
                        push += 'route-ipv6 %s %s%s\n' % (network, gateway6,
                                                          metric)
                    else:
                        push += 'route %s %s %s%s\n' % (
                            utils.parse_network(network) + (gateway, metric))

        if self.vxlan:
            push += 'push "route %s %s"\n' % utils.parse_network(
                self.vxlan.vxlan_net)
            if self.server.ipv6:
                push += 'push "route-ipv6 %s"\n' % self.vxlan.vxlan_net6

        if self.server.network_mode == BRIDGE:
            host_int_data = self.host_interface_data
            host_address = host_int_data['address']
            host_netmask = host_int_data['netmask']

            server_line = 'server-bridge %s %s %s %s' % (
                host_address,
                host_netmask,
                self.server.network_start,
                self.server.network_end,
            )
        else:
            server_line = 'server %s %s' % utils.parse_network(
                self.server.network)

            if self.server.ipv6:
                server_line += '\nserver-ipv6 ' + self.server.network6

        if self.server.protocol == 'tcp':
            if (self.server.ipv6 or settings.vpn.ipv6) and \
                    not self.server.bind_address:
                protocol = 'tcp6-server'
            else:
                protocol = 'tcp-server'
        elif self.server.protocol == 'udp':
            if (self.server.ipv6 or settings.vpn.ipv6) and \
                    not self.server.bind_address:
                protocol = 'udp6'
            else:
                protocol = 'udp'
        else:
            raise ValueError('Unknown protocol')

        if utils.check_openvpn_ver():
            server_ciphers = SERVER_CIPHERS
            server_conf_template = OVPN_INLINE_SERVER_CONF
        else:
            server_ciphers = SERVER_CIPHERS_OLD
            server_conf_template = OVPN_INLINE_SERVER_CONF_OLD

        server_conf = server_conf_template % (
            self.server.port,
            protocol,
            self.interface,
            server_line,
            self.management_socket_path,
            self.server.max_clients,
            self.server.ping_interval,
            self.server.ping_timeout + 20,
            self.server.ping_interval,
            self.server.ping_timeout,
            server_ciphers[self.server.cipher],
            HASHES[self.server.hash],
            4 if self.server.debug else 1,
            8 if self.server.debug else 3,
        )

        if self.server.bind_address:
            server_conf += 'local %s\n' % self.server.bind_address

        if self.server.inter_client:
            server_conf += 'client-to-client\n'

        if self.server.multi_device:
            server_conf += 'duplicate-cn\n'

        if self.server.protocol == 'udp':
            server_conf += 'replay-window 128\n'

        if self.server.mss_fix:
            server_conf += 'mssfix %s\n' % self.server.mss_fix

        # Pritunl v0.10.x did not include comp-lzo in client conf
        # if lzo_compression is adaptive dont include comp-lzo in server conf
        if self.server.lzo_compression == ADAPTIVE:
            pass
        elif self.server.lzo_compression:
            server_conf += 'comp-lzo yes\npush "comp-lzo yes"\n'
        else:
            server_conf += 'comp-lzo no\npush "comp-lzo no"\n'

        server_conf += JUMBO_FRAMES[self.server.jumbo_frames]

        if push:
            server_conf += push

        if self.server.debug:
            self.server.output.push_message('Server conf:')
            for conf_line in server_conf.split('\n'):
                if conf_line:
                    self.server.output.push_message('  ' + conf_line)

        if settings.local.sub_plan and \
                'enterprise' in settings.local.sub_plan:
            returns = plugins.caller(
                'server_config',
                host_id=settings.local.host_id,
                host_name=settings.local.host.name,
                server_id=self.server.id,
                server_name=self.server.name,
                port=self.server.port,
                protocol=self.server.protocol,
                ipv6=self.server.ipv6,
                ipv6_firewall=self.server.ipv6_firewall,
                network=self.server.network,
                network6=self.server.network6,
                network_mode=self.server.network_mode,
                network_start=self.server.network_start,
                network_stop=self.server.network_end,
                restrict_routes=self.server.restrict_routes,
                bind_address=self.server.bind_address,
                onc_hostname=None,
                dh_param_bits=self.server.dh_param_bits,
                multi_device=self.server.multi_device,
                dns_servers=self.server.dns_servers,
                search_domain=self.server.search_domain,
                otp_auth=self.server.otp_auth,
                cipher=self.server.cipher,
                hash=self.server.hash,
                inter_client=self.server.inter_client,
                ping_interval=self.server.ping_interval,
                ping_timeout=self.server.ping_timeout,
                link_ping_interval=self.server.link_ping_interval,
                link_ping_timeout=self.server.link_ping_timeout,
                allowed_devices=self.server.allowed_devices,
                max_clients=self.server.max_clients,
                replica_count=self.server.replica_count,
                dns_mapping=self.server.dns_mapping,
                debug=self.server.debug,
                routes=routes,
                interface=self.interface,
                bridge_interface=self.bridge_interface,
                vxlan=self.vxlan,
            )

            if returns:
                for return_val in returns:
                    if not return_val:
                        continue
                    server_conf += return_val.strip() + '\n'

        server_conf += '<ca>\n%s\n</ca>\n' % self.server.ca_certificate

        if self.server.tls_auth:
            server_conf += \
                'key-direction 0\n<tls-auth>\n%s\n</tls-auth>\n' % (
                self.server.tls_auth_key)

        server_conf += '<cert>\n%s\n</cert>\n' % utils.get_cert_block(
            self.primary_user.certificate)
        server_conf += '<key>\n%s\n</key>\n' % self.primary_user.private_key
        server_conf += '<dh>\n%s\n</dh>\n' % self.server.dh_params

        with open(self.ovpn_conf_path, 'w') as ovpn_conf:
            os.chmod(self.ovpn_conf_path, 0600)
            ovpn_conf.write(server_conf)
Example #60
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

        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:
        valid, _ = sso.auth_duo(
            username,
            ipaddr=utils.get_remote_addr(),
            type='Key',
        )
        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)

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