예제 #1
0
    def __new__(cls, id=None, doc=None, spec=None, fields=None,
            upsert=False, **kwargs):
        from pritunl import utils
        fields = fields or cls.fields

        mongo_object = object.__new__(cls)
        mongo_object.changed = set()
        mongo_object.unseted = set()
        mongo_object.id = id
        mongo_object.loaded_fields = fields

        if id or doc or spec:
            mongo_object.exists = True
            try:
                mongo_object.load(doc=doc, spec=spec, fields=fields)
            except NotFound:
                if not upsert:
                    return None
                mongo_object.exists = False
                if not id:
                    mongo_object.id = utils.ObjectId()
        else:
            mongo_object.exists = False
            mongo_object.id = utils.ObjectId()
        return mongo_object
예제 #2
0
    def connected(self, client):
        client_id = client['client_id']
        user_id = utils.ObjectId(client['user_id'])
        org_id = utils.ObjectId(client['org_id'])
        device = self.devices[user_id].get(client_id)

        if not device:
            self.instance_com.push_output(
                'ERROR Unknown client connected org_id=%s user_id=%s' % (
                    org_id, user_id))
            return

        domain = device['user'] + '.' + device['org']
        timestamp = utils.now()

        domain_hash = hashlib.md5()
        domain_hash.update(domain)
        domain_hash = bson.binary.Binary(domain_hash.digest(),
            subtype=bson.binary.MD5_SUBTYPE)

        try:
            id = self.collection.insert({
                'user_id': user_id,
                'server_id': self.server.id,
                'domain': domain_hash,
                'timestamp': timestamp,
                'platform': device['platform'],
                'type': device['type'],
                'device_name': device['device_name'],
                'mac_addr': device['mac_addr'],
                'network': self.server.network,
                'real_address': device['real_address'],
                'virt_address': device['virt_address'],
                'connected_since': int(timestamp.strftime('%s')),
            })
        except:
            logger.exception('Error adding client', 'server',
                server_id=self.server.id,
            )
            self.instance_com.client_kill(device)
            return

        device['id'] = id

        self.clients.append({
            'id': id,
            'client_id': client_id,
            'user_id': user_id,
            'org_id': org_id,
            'virt_address': device['virt_address'],
            'timestamp': timestamp,
        })

        self.instance_com.push_output('User connected org_id=%s user_id=%s' % (
            org_id, user_id))
        self.send_event()
예제 #3
0
def publish(channels, message, extra=None, transaction=None):
    if cache.has_cache:
        return cache.publish(channels, message, extra=extra)

    collection = mongo.get_collection('messages')
    doc = {
        'message': message,
        'timestamp': utils.now(),
    }

    if extra:
        for key, val in list(extra.items()):
            doc[key] = val

    # ObjectId must be set by server and ObjectId order must match $natural
    # order. Docs sent in order on client are not guaranteed to match $natural
    # order on server. Nonce is added to force an insert from upsert where
    # insert is not supported.
    # When using inserts manipulate=False must be set to prevent pymongo
    # from setting ObjectId locally.
    if transaction:
        tran_collection = transaction.collection(collection.name_str)

        if isinstance(channels, str):
            doc['channel'] = channels
            tran_collection.update({
                'nonce': utils.ObjectId(),
            }, {
                '$set': doc,
            },
                                   upsert=True)
        else:
            for channel in channels:
                doc_copy = doc.copy()
                doc_copy['channel'] = channel

                tran_collection.bulk().find({
                    'nonce': utils.ObjectId(),
                }).upsert().update({
                    '$set': doc_copy,
                })
            tran_collection.bulk_execute()
    else:
        if isinstance(channels, str):
            doc['channel'] = channels
            collection.insert(doc, manipulate=False)
        else:
            docs = []
            for channel in channels:
                doc_copy = doc.copy()
                doc_copy['channel'] = channel
                docs.append(doc_copy)
            collection.insert(docs, manipulate=False)
예제 #4
0
def _upgrade_org(org_id, org_path):
    organizations_db = get_collection('organizations')
    org_conf_path = os.path.join(org_path, 'ca.conf')

    spec = {
        '_id': utils.ObjectId(org_id),
    }

    update_doc = {
        'name': None,
        'type': ORG_DEFAULT,
        'ca_certificate': None,
        'ca_private_key': None,
    }

    with open(org_conf_path, 'r') as conf_file:
        for line in conf_file.readlines():
            line = line.strip()
            name, value = line.split('=', 1)
            if name == 'name':
                update_doc['name'] = value
            elif name == 'pool' and value == 'true':
                update_doc['type'] = ORG_POOL

    org_ca_cert_path = os.path.join(org_path, 'certs', 'ca.crt')
    with open(org_ca_cert_path, 'r') as org_cert_file:
        update_doc['ca_certificate'] = org_cert_file.read().rstrip('\n')

    org_ca_key_path = os.path.join(org_path, 'keys', 'ca.key')
    with open(org_ca_key_path, 'r') as org_key_file:
        update_doc['ca_private_key'] = org_key_file.read().rstrip('\n')

    organizations_db.update(spec, update_doc, upsert=True)
예제 #5
0
def link_location_exclude_post(link_id, location_id):
    if not settings.local.sub_plan or \
            'enterprise' not in settings.local.sub_plan:
        return flask.abort(404)

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

    lnk = link.get_by_id(link_id)
    if not lnk or lnk.type == DIRECT:
        return flask.abort(404)

    loc = lnk.get_location(location_id)
    if not loc:
        return flask.abort(404)

    exclude_id = utils.ObjectId(flask.request.json.get('exclude_id'))
    loc.add_exclude(exclude_id)

    lnk.commit('excludes')

    event.Event(type=LINKS_UPDATED)

    return utils.jsonify({
        'location_id': exclude_id,
    })
예제 #6
0
def parse_object_id(_, values):
    if values:
        for key in values:
            if key.endswith('_id'):
                val = values[key]
                if len(val) > 10:
                    values[key] = utils.ObjectId(val)
예제 #7
0
def event_get(cursor=None):
    if check_global_interrupt():
        raise flask.abort(500)

    if cursor is not None:
        cursor = utils.ObjectId(cursor)

    return utils.jsonify(event.get_events(cursor=cursor))
예제 #8
0
파일: link.py 프로젝트: sha1/pritunl
def link_state_delete():
    if settings.app.demo_mode:
        return utils.demo_blocked()

    auth_token = flask.request.headers.get('Auth-Token', None)
    auth_timestamp = flask.request.headers.get('Auth-Timestamp', None)
    auth_nonce = flask.request.headers.get('Auth-Nonce', None)
    auth_signature = flask.request.headers.get('Auth-Signature', None)
    if not auth_token or not auth_timestamp or not auth_nonce or \
            not auth_signature:
        return flask.abort(406)
    auth_token = auth_token[:256]
    auth_timestamp = auth_timestamp[:64]
    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:
            return flask.abort(408)
    except ValueError:
        return flask.abort(405)

    host = link.get_host(utils.ObjectId(auth_token))
    if not host:
        return flask.abort(404)

    auth_string = '&'.join([
        auth_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(host.secret.encode(), auth_string.encode(),
                 hashlib.sha512).digest()).decode()
    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)

    host.set_inactive()

    return utils.jsonify({})
예제 #9
0
def auth_delete():
    admin_id = flask.session.get('admin_id')
    session_id = flask.session.get('session_id')
    if admin_id and session_id:
        admin_id = utils.ObjectId(admin_id)
        auth.clear_session(admin_id, session_id)
    flask.session.clear()

    return utils.jsonify({
        'authenticated': False,
    })
예제 #10
0
    def disconnected(self, client):
        client_id = client.get('client_id')
        user_id = client.get('user_id')
        user_id = utils.ObjectId(user_id) if user_id else None
        org_id = client.get('org_id')
        org_id = utils.ObjectId(org_id) if org_id else None

        devices = self.devices[user_id]
        device = devices.get(client_id)
        devices.pop(client_id, None)

        if device:
            virt_address = device['virt_address']
            if self.ips.get(virt_address) == client_id:
                self.ips.pop(virt_address, None)

            if virt_address in self.dyn_ips:
                try:
                    self.dyn_ips.remove(virt_address)
                except KeyError:
                    pass
                self.ip_pool.append(virt_address.split('/')[0])

            id = device.get('id')
            if id:
                try:
                    self.collection.remove({
                        '_id': id,
                    })
                except:
                    logger.exception(
                        'Error removing client',
                        'server',
                        server_id=self.server.id,
                    )

        self.instance_com.push_output(
            'User disconnected org_id=%s user_id=%s' % (org_id, user_id))
        self.send_event()
예제 #11
0
    def __init__(self, priority=None, retry=None, **kwargs):
        mongo.MongoObject.__init__(self, **kwargs)
        self.type = self.type
        self.reserve_id = self.reserve_id
        self.runner_id = utils.ObjectId()
        self.claimed = False
        self.queue_com = QueueCom()
        self.keep_alive_thread = None

        if priority is not None:
            self.priority = priority
        if retry is not None:
            self.retry = retry
예제 #12
0
    def client_connected(self, client):
        client_id = client['client_id']
        org_id = utils.ObjectId(client['org_id'])
        user_id = utils.ObjectId(client['user_id'])
        devices = self.client_devices[user_id]
        data = None

        for device in devices:
            if device['client_id'] == client_id:
                data = device
                break

        if not data:
            self.push_output(
                'ERROR Unknown client connected org_id=%s user_id=%s' %
                (org_id, user_id))
            return

        self.clients.append({
            'id': user_id,
            'client_id': client_id,
            'device_id': data['device_id'],
            'device_name': data['device_name'],
            'platform': data['platform'],
            'type': data['type'],
            'real_address': data['real_address'],
            'virt_address': data['virt_address'],
            'connected_since': int(utils.now().strftime('%s')),
        })

        if data['type'] == CERT_CLIENT:
            self.clients_active += 1

        self.update_clients()

        self.push_output('User connected org_id=%s user_id=%s' %
                         (org_id, user_id))
예제 #13
0
def event_get(cursor=None):
    if settings.app.demo_mode:
        time.sleep(0.1)
        return utils.jsonify([{
            'id': 'demo',
        }])

    if check_global_interrupt():
        raise flask.abort(500)

    if cursor is not None:
        cursor = utils.ObjectId(cursor)

    return utils.jsonify(event.get_events(cursor=cursor,
                                          yield_app_server=True))
예제 #14
0
 def __init__(self, server):
     self.server = server
     self.id = utils.ObjectId()
     self.resource_lock = None
     self.interrupt = False
     self.sock_interrupt = False
     self.clean_exit = False
     self.interface = None
     self.primary_user = None
     self.process = None
     self.auth_log_process = None
     self.iptables_rules = []
     self.server_links = []
     self._temp_path = utils.get_temp_path()
     self.ovpn_conf_path = os.path.join(self._temp_path, OVPN_CONF_NAME)
     self.management_socket_path = os.path.join(
         settings.conf.var_run_path, MANAGEMENT_SOCKET_NAME % self.id)
예제 #15
0
def auth_delete():
    admin_id = utils.session_opt_str('admin_id')
    session_id = utils.session_opt_str('session_id')
    remote_addr = utils.get_remote_addr()

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

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

    return utils.jsonify({
        'authenticated': False,
    })
예제 #16
0
    def __init__(self, lock_id=None, priority=None, ttl=None, **kwargs):
        mongo.MongoObject.__init__(self, **kwargs)

        if lock_id is not None:
            self.lock_id = lock_id
        if self.lock_id is None:
            self.lock_id = utils.ObjectId()

        if priority is not None:
            self.priority = priority

        if ttl is not None:
            self.ttl = ttl

        if self.actions:
            actions_json = zlib.decompress(self.actions)
            self.action_sets = json.loads(
                actions_json, object_hook=utils.json_object_hook_handler)
        else:
            self.action_sets = []
예제 #17
0
 def __init__(self, server):
     self.server = server
     self.id = utils.ObjectId()
     self.interrupt = False
     self.sock_interrupt = False
     self.clean_exit = False
     self.interface = None
     self.bridge_interface = None
     self.primary_user = None
     self.process = None
     self.vxlan = None
     self.iptables = iptables.Iptables()
     self.iptables_lock = threading.Lock()
     self.tun_nat = False
     self.server_links = []
     self.route_advertisements = set()
     self._temp_path = utils.get_temp_path()
     self.ovpn_conf_path = os.path.join(self._temp_path, OVPN_CONF_NAME)
     self.management_socket_path = os.path.join(
         settings.conf.var_run_path,
         MANAGEMENT_SOCKET_NAME % self.id,
     )
예제 #18
0
def publish(channels, message, extra=None, cap=50, ttl=300):
    if isinstance(channels, str):
        channels = [channels]

    for channel in channels:
        doc = {
            '_id': utils.ObjectId(),
            'message': message,
            'timestamp': utils.now(),
        }
        if extra:
            for key, val in extra.items():
                doc[key] = val

        doc = json.dumps(doc, default=utils.json_default)

        pipe = _client.pipeline()
        pipe.lpush(channel, doc)
        pipe.ltrim(channel, 0, cap)
        if ttl:
            pipe.expire(channel, ttl)
        pipe.publish(channel, doc)
        pipe.execute()
예제 #19
0
    def client_disconnect(self, client):
        client_id = client.get('client_id')
        user_id = client.get('user_id')
        user_id = utils.ObjectId(user_id) if user_id else None
        user_type = None
        virt_address = None
        devices = self.client_devices[user_id]

        for i, device in enumerate(devices):
            if device['client_id'] == client_id:
                virt_address = device['virt_address']
                del devices[i]
                break

        for i, clt in enumerate(self.clients):
            if clt['client_id'] == client_id:
                user_type = clt['type']
                virt_address = clt['virt_address']
                del self.clients[i]
                break

        if virt_address:
            if virt_address in self.client_ips:
                self.client_ips.remove(virt_address)

            if virt_address in self.client_dyn_ips:
                self.client_dyn_ips.remove(virt_address)
                self.ip_pool.append(virt_address.split('/')[0])

        if user_type == CERT_CLIENT:
            self.clients_active -= 1

        self.update_clients()

        self.push_output('User disconnected org_id=%s user_id=%s' %
                         (client.get('org_id'), user_id))
예제 #20
0
파일: task.py 프로젝트: sha1/pritunl
 def __init__(self, run_id=None, **kwargs):
     mongo.MongoObject.__init__(self)
     self.type = self.type
     self.runner_id = utils.ObjectId()
예제 #21
0
파일: demo.py 프로젝트: thaihust/fVPN
    def thread():
        platforms = list(DESKTOP_PLATFORMS)
        start_timestamp = datetime.datetime(2015, 12, 28, 4, 1, 0)
        hosts_collection = mongo.get_collection('hosts')
        servers_collection = mongo.get_collection('servers')
        clients_collection = mongo.get_collection('clients')

        clients_collection.remove({})

        for hst in host.iter_hosts():
            hosts_collection.update({
                '_id': hst.id,
            }, {
                '$set': {
                    'server_count': 0,
                    'device_count': 0,
                    'cpu_usage': 0,
                    'mem_usage': 0,
                    'thread_count': 0,
                    'open_file_count': 0,
                    'status': ONLINE,
                    'start_timestamp': start_timestamp,
                    'ping_timestamp': start_timestamp,
                    'auto_public_address': None,
                    'auto_public_address6': None,
                    'auto_public_host': hst.name + '.pritunl.com',
                    'auto_public_host6': hst.name + '.pritunl.com',
                }
            })

        for svr in server.iter_servers():
            prefered_hosts = host.get_prefered_hosts(svr.hosts,
                                                     svr.replica_count)

            instances = []
            for hst in prefered_hosts:
                instances.append({
                    'instance_id': utils.ObjectId(),
                    'host_id': hst,
                    'ping_timestamp': utils.now(),
                })

            servers_collection.update({
                '_id': svr.id,
            }, {
                '$set': {
                    'status': ONLINE,
                    'pool_cursor': None,
                    'start_timestamp': start_timestamp,
                    'availability_group': DEFAULT,
                    'instances': instances,
                    'instances_count': len(instances),
                }
            })

            for org in svr.iter_orgs():
                for usr in org.iter_users():
                    if usr.type != CERT_CLIENT:
                        continue

                    virt_address = svr.get_ip_addr(org.id, usr.id)
                    virt_address6 = svr.ip4to6(virt_address)

                    doc = {
                        '_id':
                        utils.ObjectId(),
                        'user_id':
                        usr.id,
                        'server_id':
                        svr.id,
                        'host_id':
                        settings.local.host_id,
                        'timestamp':
                        start_timestamp,
                        'platform':
                        random.choice(platforms),
                        'type':
                        CERT_CLIENT,
                        'device_name':
                        utils.random_name(),
                        'mac_addr':
                        utils.rand_str(16),
                        'network':
                        svr.network,
                        'real_address':
                        str(
                            ipaddress.IPAddress(
                                100000000 + random.randint(0, 1000000000))),
                        'virt_address':
                        virt_address,
                        'virt_address6':
                        virt_address6,
                        'host_address':
                        settings.local.host.local_addr,
                        'host_address6':
                        settings.local.host.local_addr6,
                        'dns_servers': [],
                        'dns_suffix':
                        None,
                        'connected_since':
                        int(start_timestamp.strftime('%s')),
                    }

                    clients_collection.insert(doc)

        for lnk in link.iter_links():
            lnk.status = ONLINE
            lnk.commit()

            for location in lnk.iter_locations():
                active = False
                for hst in location.iter_hosts():
                    if not active:
                        hst.active = True
                        active = True
                    hst.status = AVAILABLE
                    hst.commit(('active', 'status'))

        logger.info('Demo initiated', 'demo')
예제 #22
0
    def parse_line(self, line):
        if self.client:
            if line == '>CLIENT:ENV,END':
                cmd = self.client['cmd']
                if cmd == 'connect':
                    self.clients.connect(self.client)
                elif cmd == 'reauth':
                    self.clients.connect(self.client, reauth=True)
                elif cmd == 'connected':
                    self.clients.connected(self.client.get('client_id'))
                elif cmd == 'disconnected':
                    self.clients.disconnected(self.client.get('client_id'))
                self.client = None
            elif line.startswith('>CLIENT:ENV'):
                env_key, env_val = line[12:].split('=', 1)
                if env_key == 'tls_id_0':
                    tls_env = ''.join(x for x in env_val if x in VALID_CHARS)
                    o_index = tls_env.find('O=')
                    cn_index = tls_env.find('CN=')

                    if o_index < 0 or cn_index < 0:
                        self.send_client_deny(
                            self.client, 'Failed to parse org_id and user_id')
                        self.client = None
                        return

                    if o_index > cn_index:
                        org_id = tls_env[o_index + 2:]
                        user_id = tls_env[3:o_index]
                    else:
                        org_id = tls_env[2:cn_index]
                        user_id = tls_env[cn_index + 3:]

                    self.client['org_id'] = utils.ObjectId(org_id)
                    self.client['user_id'] = utils.ObjectId(user_id)
                elif env_key == 'IV_HWADDR':
                    self.client['mac_addr'] = env_val
                elif env_key == 'untrusted_ip':
                    self.client['remote_ip'] = env_val
                elif env_key == 'untrusted_ip6':
                    remote_ip = env_val
                    if remote_ip.startswith('::ffff:'):
                        remote_ip = remote_ip.split(':')[-1]
                    self.client['remote_ip'] = remote_ip
                elif env_key == 'IV_PLAT' and not self.client.get('platform'):
                    if 'chrome' in env_val.lower():
                        env_val = 'chrome'
                        self.client['device_id'] = uuid.uuid4().hex
                        self.client['device_name'] = 'chrome-os'
                    self.client['platform'] = env_val
                elif env_key == 'UV_ID':
                    self.client['device_id'] = env_val
                elif env_key == 'UV_NAME':
                    self.client['device_name'] = env_val
                elif env_key == 'UV_PLATFORM':
                    self.client['platform'] = env_val
                elif env_key == 'password':
                    self.client['password'] = env_val
            else:
                self.push_output('CCOM> %s' % line[1:])
        elif line.startswith('>BYTECOUNT_CLI'):
            client_id, bytes_recv, bytes_sent = line.split(',')
            client_id = client_id.split(':')[1]
            self.parse_bytecount(client_id, int(bytes_recv), int(bytes_sent))
        elif line.startswith('>CLIENT:CONNECT'):
            _, client_id, key_id = line.split(',')
            self.client = {
                'cmd': 'connect',
                'client_id': client_id,
                'key_id': key_id,
            }
        elif line.startswith('>CLIENT:REAUTH'):
            _, client_id, key_id = line.split(',')
            self.client = {
                'cmd': 'reauth',
                'client_id': client_id,
                'key_id': key_id,
            }
        elif line.startswith('>CLIENT:ESTABLISHED'):
            _, client_id = line.split(',')
            self.client = {
                'cmd': 'connected',
                'client_id': client_id,
            }
        elif line.startswith('>CLIENT:DISCONNECT'):
            _, client_id = line.split(',')
            self.client = {
                'cmd': 'disconnected',
                'client_id': client_id,
            }
        elif line.startswith('SUCCESS:'):
            self.push_output('COM> %s' % line)
예제 #23
0
def settings_put():
    if settings.app.demo_mode:
        return utils.demo_blocked()

    org_event = False
    admin_event = False
    admin = flask.g.administrator
    changes = set()

    settings_commit = False
    update_server = False
    update_acme = False
    update_cert = False

    if 'username' in flask.request.json and flask.request.json['username']:
        username = utils.filter_str(flask.request.json['username']).lower()
        if username != admin.username:
            changes.add('username')
        admin.username = username

    if 'password' in flask.request.json and flask.request.json['password']:
        password = flask.request.json['password']
        changes.add('password')
        admin.password = password

    if 'server_cert' in flask.request.json:
        settings_commit = True
        server_cert = flask.request.json['server_cert']
        if server_cert:
            server_cert = server_cert.strip()
        else:
            server_cert = None

        if server_cert != settings.app.server_cert:
            update_server = True

        settings.app.server_cert = server_cert

    if 'server_key' in flask.request.json:
        settings_commit = True
        server_key = flask.request.json['server_key']
        if server_key:
            server_key = server_key.strip()
        else:
            server_key = None

        if server_key != settings.app.server_key:
            update_server = True

        settings.app.server_key = server_key

    if 'server_port' in flask.request.json:
        settings_commit = True

        server_port = flask.request.json['server_port']
        if not server_port:
            server_port = 443

        try:
            server_port = int(server_port)
            if server_port < 1 or server_port > 65535:
                raise ValueError('Port invalid')
        except ValueError:
            return utils.jsonify(
                {
                    'error': PORT_INVALID,
                    'error_msg': PORT_INVALID_MSG,
                }, 400)

        if settings.app.redirect_server and server_port == 80:
            return utils.jsonify(
                {
                    'error': PORT_RESERVED,
                    'error_msg': PORT_RESERVED_MSG,
                }, 400)

        if server_port != settings.app.server_port:
            update_server = True

        settings.app.server_port = server_port

    if 'acme_domain' in flask.request.json:
        settings_commit = True

        acme_domain = utils.filter_str(flask.request.json['acme_domain']
                                       or None)
        if acme_domain:
            acme_domain = acme_domain.replace('https://', '')
            acme_domain = acme_domain.replace('http://', '')
            acme_domain = acme_domain.replace('/', '')

        if acme_domain != settings.app.acme_domain:
            if not acme_domain:
                settings.app.acme_key = None
                settings.app.acme_timestamp = None
                settings.app.server_key = None
                settings.app.server_cert = None
                update_server = True
                update_cert = True
            else:
                update_acme = True
        settings.app.acme_domain = acme_domain

    if 'auditing' in flask.request.json:
        settings_commit = True
        auditing = flask.request.json['auditing'] or None

        if settings.app.auditing != auditing:
            if not flask.g.administrator.super_user:
                return utils.jsonify(
                    {
                        'error': REQUIRES_SUPER_USER,
                        'error_msg': REQUIRES_SUPER_USER_MSG,
                    }, 400)
            admin_event = True
            org_event = True

        settings.app.auditing = auditing

    if 'monitoring' in flask.request.json:
        settings_commit = True
        monitoring = flask.request.json['monitoring'] or None
        settings.app.monitoring = monitoring

    if 'influxdb_uri' in flask.request.json:
        settings_commit = True
        influxdb_uri = flask.request.json['influxdb_uri'] or None
        settings.app.influxdb_uri = influxdb_uri

    if 'email_from' in flask.request.json:
        settings_commit = True
        email_from = flask.request.json['email_from'] or None
        if email_from != settings.app.email_from:
            changes.add('smtp')
        settings.app.email_from = email_from

    if 'email_server' in flask.request.json:
        settings_commit = True
        email_server = flask.request.json['email_server'] or None
        if email_server != settings.app.email_server:
            changes.add('smtp')
        settings.app.email_server = email_server

    if 'email_username' in flask.request.json:
        settings_commit = True
        email_username = flask.request.json['email_username'] or None
        if email_username != settings.app.email_username:
            changes.add('smtp')
        settings.app.email_username = email_username

    if 'email_password' in flask.request.json:
        settings_commit = True
        email_password = flask.request.json['email_password'] or None
        if email_password != settings.app.email_password:
            changes.add('smtp')
        settings.app.email_password = email_password

    if 'pin_mode' in flask.request.json:
        settings_commit = True
        pin_mode = flask.request.json['pin_mode'] or None
        if pin_mode != settings.user.pin_mode:
            changes.add('pin_mode')
        settings.user.pin_mode = pin_mode

    if 'sso' in flask.request.json:
        org_event = True
        settings_commit = True
        sso = flask.request.json['sso'] or None
        if sso != settings.app.sso:
            changes.add('sso')
        settings.app.sso = sso

    if 'sso_match' in flask.request.json:
        settings_commit = True
        sso_match = flask.request.json['sso_match'] or None

        if sso_match != settings.app.sso_match:
            changes.add('sso')

        if isinstance(sso_match, list):
            settings.app.sso_match = sso_match
        else:
            settings.app.sso_match = None

    if 'sso_duo_token' in flask.request.json:
        settings_commit = True
        sso_duo_token = flask.request.json['sso_duo_token'] or None
        if sso_duo_token != settings.app.sso_duo_token:
            changes.add('sso')
        settings.app.sso_duo_token = sso_duo_token

    if 'sso_duo_secret' in flask.request.json:
        settings_commit = True
        sso_duo_secret = flask.request.json['sso_duo_secret'] or None
        if sso_duo_secret != settings.app.sso_duo_secret:
            changes.add('sso')
        settings.app.sso_duo_secret = sso_duo_secret

    if 'sso_duo_host' in flask.request.json:
        settings_commit = True
        sso_duo_host = flask.request.json['sso_duo_host'] or None
        if sso_duo_host != settings.app.sso_duo_host:
            changes.add('sso')
        settings.app.sso_duo_host = sso_duo_host

    if 'sso_duo_mode' in flask.request.json:
        settings_commit = True
        sso_duo_mode = flask.request.json['sso_duo_mode'] or None
        if sso_duo_mode != settings.app.sso_duo_mode:
            changes.add('sso')
        settings.app.sso_duo_mode = sso_duo_mode

    if 'sso_radius_secret' in flask.request.json:
        settings_commit = True
        sso_radius_secret = flask.request.json['sso_radius_secret'] or None
        if sso_radius_secret != settings.app.sso_radius_secret:
            changes.add('sso')
        settings.app.sso_radius_secret = sso_radius_secret

    if 'sso_radius_host' in flask.request.json:
        settings_commit = True
        sso_radius_host = flask.request.json['sso_radius_host'] or None
        if sso_radius_host != settings.app.sso_radius_host:
            changes.add('sso')
        settings.app.sso_radius_host = sso_radius_host

    if 'sso_org' in flask.request.json:
        settings_commit = True
        sso_org = flask.request.json['sso_org'] or None

        if sso_org:
            sso_org = utils.ObjectId(sso_org)
        else:
            sso_org = None

        if sso_org != settings.app.sso_org:
            changes.add('sso')

        if settings.app.sso and not sso_org:
            return utils.jsonify(
                {
                    'error': SSO_ORG_NULL,
                    'error_msg': SSO_ORG_NULL_MSG,
                }, 400)

        settings.app.sso_org = sso_org

    if 'sso_saml_url' in flask.request.json:
        settings_commit = True
        sso_saml_url = flask.request.json['sso_saml_url'] or None
        if sso_saml_url != settings.app.sso_saml_url:
            changes.add('sso')
        settings.app.sso_saml_url = sso_saml_url

    if 'sso_saml_issuer_url' in flask.request.json:
        settings_commit = True
        sso_saml_issuer_url = flask.request.json['sso_saml_issuer_url'] or None
        if sso_saml_issuer_url != settings.app.sso_saml_issuer_url:
            changes.add('sso')
        settings.app.sso_saml_issuer_url = sso_saml_issuer_url

    if 'sso_saml_cert' in flask.request.json:
        settings_commit = True
        sso_saml_cert = flask.request.json['sso_saml_cert'] or None
        if sso_saml_cert != settings.app.sso_saml_cert:
            changes.add('sso')
        settings.app.sso_saml_cert = sso_saml_cert

    if 'sso_okta_token' in flask.request.json:
        settings_commit = True
        sso_okta_token = flask.request.json['sso_okta_token'] or None
        if sso_okta_token != settings.app.sso_okta_token:
            changes.add('sso')
        settings.app.sso_okta_token = sso_okta_token

    if 'sso_onelogin_id' in flask.request.json:
        settings_commit = True
        sso_onelogin_id = flask.request.json['sso_onelogin_id'] or None
        if sso_onelogin_id != settings.app.sso_onelogin_id:
            changes.add('sso')
        settings.app.sso_onelogin_id = sso_onelogin_id

    if 'sso_onelogin_secret' in flask.request.json:
        settings_commit = True
        sso_onelogin_secret = \
            flask.request.json['sso_onelogin_secret'] or None
        if sso_onelogin_secret != settings.app.sso_onelogin_secret:
            changes.add('sso')
        settings.app.sso_onelogin_secret = sso_onelogin_secret

    if 'sso_client_cache' in flask.request.json:
        settings_commit = True
        sso_client_cache = True if \
            flask.request.json['sso_client_cache'] else False
        if sso_client_cache != settings.app.sso_client_cache:
            changes.add('sso')
        settings.app.sso_client_cache = sso_client_cache

    if 'sso_yubico_client' in flask.request.json:
        settings_commit = True
        sso_yubico_client = \
            flask.request.json['sso_yubico_client'] or None
        if sso_yubico_client != settings.app.sso_yubico_client:
            changes.add('sso')
        settings.app.sso_yubico_client = sso_yubico_client

    if 'sso_yubico_secret' in flask.request.json:
        settings_commit = True
        sso_yubico_secret = \
            flask.request.json['sso_yubico_secret'] or None
        if sso_yubico_secret != settings.app.sso_yubico_secret:
            changes.add('sso')
        settings.app.sso_yubico_secret = sso_yubico_secret

    if flask.request.json.get('theme'):
        settings_commit = True
        theme = 'light' if flask.request.json['theme'] == 'light' else 'dark'

        if theme != settings.app.theme:
            if theme == 'dark':
                event.Event(type=THEME_DARK)
            else:
                event.Event(type=THEME_LIGHT)

        settings.app.theme = theme

    if 'public_address' in flask.request.json:
        public_address = flask.request.json['public_address'] or None

        if public_address != settings.local.host.public_addr:
            settings.local.host.public_address = public_address
            settings.local.host.commit('public_address')

    if 'public_address6' in flask.request.json:
        public_address6 = flask.request.json['public_address6'] or None

        if public_address6 != settings.local.host.public_addr6:
            settings.local.host.public_address6 = public_address6
            settings.local.host.commit('public_address6')

    if 'routed_subnet6' in flask.request.json:
        routed_subnet6 = flask.request.json['routed_subnet6']
        if routed_subnet6:
            try:
                routed_subnet6 = ipaddress.IPv6Network(
                    flask.request.json['routed_subnet6'])
            except (ipaddress.AddressValueError, ValueError):
                return utils.jsonify(
                    {
                        'error': IPV6_SUBNET_INVALID,
                        'error_msg': IPV6_SUBNET_INVALID_MSG,
                    }, 400)

            if routed_subnet6.prefixlen > 64:
                return utils.jsonify(
                    {
                        'error': IPV6_SUBNET_SIZE_INVALID,
                        'error_msg': IPV6_SUBNET_SIZE_INVALID_MSG,
                    }, 400)

            routed_subnet6 = str(routed_subnet6)
        else:
            routed_subnet6 = None

        if settings.local.host.routed_subnet6 != routed_subnet6:
            if server.get_online_ipv6_count():
                return utils.jsonify(
                    {
                        'error': IPV6_SUBNET_ONLINE,
                        'error_msg': IPV6_SUBNET_ONLINE_MSG,
                    }, 400)
            settings.local.host.routed_subnet6 = routed_subnet6
            settings.local.host.commit('routed_subnet6')

    if 'reverse_proxy' in flask.request.json:
        settings_commit = True
        reverse_proxy = flask.request.json['reverse_proxy']
        settings.app.reverse_proxy = True if reverse_proxy else False

    if 'cloud_provider' in flask.request.json:
        settings_commit = True
        cloud_provider = flask.request.json['cloud_provider'] or None
        settings.app.cloud_provider = cloud_provider

    if 'route53_region' in flask.request.json:
        settings_commit = True
        settings.app.route53_region = utils.filter_str(
            flask.request.json['route53_region']) or None

    if 'route53_zone' in flask.request.json:
        settings_commit = True
        settings.app.route53_zone = utils.filter_str(
            flask.request.json['route53_zone']) or None

    for aws_key in (
            'us_east_1_access_key',
            'us_east_1_secret_key',
            'us_east_2_access_key',
            'us_east_2_secret_key',
            'us_west_1_access_key',
            'us_west_1_secret_key',
            'us_west_2_access_key',
            'us_west_2_secret_key',
            'eu_west_1_access_key',
            'eu_west_1_secret_key',
            'eu_central_1_access_key',
            'eu_central_1_secret_key',
            'ap_northeast_1_access_key',
            'ap_northeast_1_secret_key',
            'ap_northeast_2_access_key',
            'ap_northeast_2_secret_key',
            'ap_southeast_1_access_key',
            'ap_southeast_1_secret_key',
            'ap_southeast_2_access_key',
            'ap_southeast_2_secret_key',
            'ap_south_1_access_key',
            'ap_south_1_secret_key',
            'sa_east_1_access_key',
            'sa_east_1_secret_key',
    ):
        if aws_key in flask.request.json:
            settings_commit = True
            aws_value = flask.request.json[aws_key]

            if aws_value:
                setattr(settings.app, aws_key, utils.filter_str(aws_value))
            else:
                setattr(settings.app, aws_key, None)

    if not settings.app.sso:
        settings.app.sso_host = None
        settings.app.sso_token = None
        settings.app.sso_secret = None
        settings.app.sso_match = None
        settings.app.sso_duo_token = None
        settings.app.sso_duo_secret = None
        settings.app.sso_duo_host = None
        settings.app.sso_yubico_client = None
        settings.app.sso_yubico_secret = None
        settings.app.sso_org = None
        settings.app.sso_saml_url = None
        settings.app.sso_saml_issuer_url = None
        settings.app.sso_saml_cert = None
        settings.app.sso_okta_token = None
        settings.app.sso_onelogin_key = None
        settings.app.sso_onelogin_id = None
        settings.app.sso_onelogin_secret = None
        settings.app.sso_radius_secret = None
        settings.app.sso_radius_host = None
    else:
        if RADIUS_AUTH in settings.app.sso and \
                settings.app.sso_duo_mode == 'passcode':
            return utils.jsonify(
                {
                    'error': RADIUS_DUO_PASSCODE,
                    'error_msg': RADIUS_DUO_PASSCODE_MSG,
                }, 400)

        if settings.app.sso == DUO_AUTH and \
                settings.app.sso_duo_mode == 'passcode':
            return utils.jsonify(
                {
                    'error': DUO_PASSCODE,
                    'error_msg': DUO_PASSCODE_MSG,
                }, 400)

    for change in changes:
        flask.g.administrator.audit_event(
            'admin_settings',
            _changes_audit_text[change],
            remote_addr=utils.get_remote_addr(),
        )

    if settings_commit:
        settings.commit()

    admin.commit(admin.changed)

    if admin_event:
        event.Event(type=ADMINS_UPDATED)

    if org_event:
        for org in organization.iter_orgs(fields=('_id')):
            event.Event(type=USERS_UPDATED, resource_id=org.id)

    event.Event(type=SETTINGS_UPDATED)

    if update_acme:
        try:
            acme.update_acme_cert()
            app.update_server(0.5)
        except:
            logger.exception(
                'Failed to get LetsEncrypt cert',
                'handler',
                acme_domain=settings.app.acme_domain,
            )
            settings.app.acme_domain = None
            settings.app.acme_key = None
            settings.app.acme_timestamp = None
            settings.commit()
            return utils.jsonify(
                {
                    'error': ACME_ERROR,
                    'error_msg': ACME_ERROR_MSG,
                }, 400)
    elif update_cert:
        logger.info('Regenerating server certificate...', 'handler')
        utils.create_server_cert()
        app.update_server(0.5)
    elif update_server:
        app.update_server(0.5)

    response = flask.g.administrator.dict()
    response.update(_dict())
    return utils.jsonify(response)
예제 #24
0
def link_state_put():
    if settings.app.demo_mode:
        return utils.demo_blocked()

    auth_token = flask.request.headers.get('Auth-Token', None)
    auth_timestamp = flask.request.headers.get('Auth-Timestamp', None)
    auth_nonce = flask.request.headers.get('Auth-Nonce', None)
    auth_signature = flask.request.headers.get('Auth-Signature', None)
    if not auth_token or not auth_timestamp or not auth_nonce or \
            not auth_signature:
        return 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)

    host = link.get_host(utils.ObjectId(auth_token))
    if not host:
        return flask.abort(404)

    auth_string = '&'.join([
        auth_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(host.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)

    host.load_link()

    host.version = flask.request.json.get('version')
    host.public_address = flask.request.json.get('public_address')
    host.local_address = flask.request.json.get('local_address')
    host.address6 = flask.request.json.get('address6')

    data = json.dumps(host.get_state(), default=lambda x: str(x))
    data += (16 - len(data) % 16) * '\x00'

    iv = os.urandom(16)
    key = hashlib.sha256(host.secret).digest()
    cipher = Cipher(algorithms.AES(key),
                    modes.CBC(iv),
                    backend=default_backend()).encryptor()
    enc_data = base64.b64encode(cipher.update(data) + cipher.finalize())

    enc_signature = base64.b64encode(
        hmac.new(host.secret.encode(), enc_data, hashlib.sha512).digest())

    resp = flask.Response(response=enc_data, mimetype='application/base64')
    resp.headers.add('Cache-Control', 'no-cache, no-store, must-revalidate')
    resp.headers.add('Pragma', 'no-cache')
    resp.headers.add('Expires', 0)
    resp.headers.add('Cipher-IV', base64.b64encode(iv))
    resp.headers.add('Cipher-Signature', enc_signature)

    return resp
예제 #25
0
    def iter_users(self,
                   page=None,
                   search=None,
                   search_limit=None,
                   fields=None,
                   include_pool=False):
        spec = {
            'org_id': self.id,
            'type': CERT_CLIENT,
        }
        searched = False
        type_search = False
        limit = None
        skip = None
        page_count = settings.user.page_count

        if fields:
            fields = {key: True for key in fields}

        if search is not None:
            searched = True

            n = search.find('id:')
            if n != -1:
                user_id = search[n + 3:].split(None, 1)
                user_id = user_id[0] if user_id else ''
                if user_id:
                    type_search = True
                    spec['_id'] = utils.ObjectId(user_id)
                search = search[:n] + search[n + 3 + len(user_id):].strip()

            n = search.find('type:')
            if n != -1:
                user_type = search[n + 5:].split(None, 1)
                user_type = user_type[0] if user_type else ''
                if user_type:
                    type_search = True
                    spec['type'] = user_type
                search = search[:n] + search[n + 5 + len(user_type):].strip()

            n = search.find('group:')
            if n != -1:
                user_group = search[n + 6:].split(None, 1)
                user_group = user_group[0] if user_group else ''
                if user_group:
                    spec['groups'] = user_group
                search = search[:n] + search[n + 6 + len(user_group):].strip()

            n = search.find('email:')
            if n != -1:
                email = search[n + 6:].split(None, 1)
                email = email[0] if email else ''
                if email:
                    spec['email'] = {
                        '$regex': '.*%s.*' % email,
                        '$options': 'i',
                    }
                search = search[:n] + search[n + 6 + len(email):].strip()

            n = search.find('status:')
            if n != -1:
                status = search[n + 7:].split(None, 1)
                status = status[0] if status else ''
                search = search[:n] + search[n + 7 + len(status):].strip()

                if status not in (ONLINE, OFFLINE):
                    return

                user_ids = self.clients_collection.find(
                    None, {
                        '_id': True,
                        'user_id': True,
                    }).distinct('user_id')

                if status == ONLINE:
                    spec['_id'] = {'$in': user_ids}
                else:
                    spec['_id'] = {'$nin': user_ids}

            spec['name'] = {
                '$regex': '.*%s.*' % search.strip(),
                '$options': 'i',
            }

            limit = search_limit or page_count
        elif page is not None:
            limit = page_count
            skip = page * page_count if page else 0

        cursor = user.User.collection.find(spec, fields).sort(
            'name', pymongo.ASCENDING)

        if skip is not None:
            cursor = cursor.skip(page * page_count if page else 0)
        if limit is not None:
            cursor = cursor.limit(limit + 1)

        if searched:
            self.last_search_count = cursor.count()

        if limit is None:
            for doc in cursor:
                yield user.User(self, doc=doc, fields=fields)
        else:
            count = 0
            for doc in cursor:
                count += 1
                if count > limit:
                    return
                yield user.User(self, doc=doc, fields=fields)

        if type_search:
            return

        if include_pool:
            spec['type'] = {
                '$in': [CERT_SERVER, CERT_CLIENT_POOL, CERT_SERVER_POOL]
            }
        else:
            spec['type'] = CERT_SERVER

        cursor = user.User.collection.find(spec, fields).sort(
            'name', pymongo.ASCENDING)

        for doc in cursor:
            yield user.User(self, doc=doc, fields=fields)
예제 #26
0
def settings_put():
    admin = flask.g.administrator

    if 'username' in flask.request.json and flask.request.json['username']:
        admin.username = utils.filter_str(
            flask.request.json['username']).lower()
    if 'password' in flask.request.json and flask.request.json['password']:
        admin.password = flask.request.json['password']
    if 'token' in flask.request.json and flask.request.json['token']:
        admin.generate_token()
    if 'secret' in flask.request.json and flask.request.json['secret']:
        admin.generate_secret()

    settings_commit = False
    if 'email_from' in flask.request.json:
        settings_commit = True
        email_from = flask.request.json['email_from']
        settings.app.email_from = email_from or None

    if 'email_server' in flask.request.json:
        settings_commit = True
        email_server = flask.request.json['email_server']
        settings.app.email_server = email_server or None

    if 'email_username' in flask.request.json:
        settings_commit = True
        email_username = flask.request.json['email_username']
        settings.app.email_username = email_username or None

    if 'email_password' in flask.request.json:
        settings_commit = True
        email_password = flask.request.json['email_password']
        settings.app.email_password = email_password or None

    if 'sso' in flask.request.json:
        settings_commit = True
        sso = flask.request.json['sso']
        settings.app.sso = sso or None

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

        if isinstance(sso_match, list):
            settings_commit = True
            settings.app.sso_match = sso_match or None

    if 'sso_token' in flask.request.json:
        sso_token = flask.request.json['sso_token']
        settings_commit = True
        settings.app.sso_token = sso_token or None

    if 'sso_secret' in flask.request.json:
        sso_secret = flask.request.json['sso_secret']
        settings_commit = True
        settings.app.sso_secret = sso_secret or None

    if 'sso_host' in flask.request.json:
        sso_host = flask.request.json['sso_host']
        settings_commit = True
        settings.app.sso_host = sso_host or None

    if 'sso_admin' in flask.request.json:
        sso_admin = flask.request.json['sso_admin']
        settings_commit = True
        settings.app.sso_admin = sso_admin or None

    if 'sso_org' in flask.request.json:
        settings_commit = True
        sso_org = flask.request.json['sso_org']
        if sso_org:
            settings.app.sso_org = utils.ObjectId(sso_org)
        else:
            settings.app.sso_org = None

    if 'theme' in flask.request.json:
        settings_commit = True
        theme = 'dark' if flask.request.json['theme'] == 'dark' else 'light'

        if theme != settings.app.theme:
            if theme == 'dark':
                event.Event(type=THEME_DARK)
            else:
                event.Event(type=THEME_LIGHT)

        settings.app.theme = theme

    if 'public_address' in flask.request.json:
        public_address = flask.request.json['public_address']
        settings.local.host.public_address = public_address
        settings.local.host.commit('public_address')

    if 'public_address6' in flask.request.json:
        public_address6 = flask.request.json['public_address6']
        settings.local.host.public_address6 = public_address6
        settings.local.host.commit('public_address6')

    if 'routed_subnet6' in flask.request.json:
        routed_subnet6 = flask.request.json['routed_subnet6']
        if routed_subnet6:
            try:
                routed_subnet6 = ipaddress.IPv6Network(
                    flask.request.json['routed_subnet6'])
            except (ipaddress.AddressValueError, ValueError):
                return utils.jsonify(
                    {
                        'error': IPV6_SUBNET_INVALID,
                        'error_msg': IPV6_SUBNET_INVALID_MSG,
                    }, 400)

            if routed_subnet6.prefixlen > 64:
                return utils.jsonify(
                    {
                        'error': IPV6_SUBNET_SIZE_INVALID,
                        'error_msg': IPV6_SUBNET_SIZE_INVALID_MSG,
                    }, 400)

            routed_subnet6 = str(routed_subnet6)
        else:
            routed_subnet6 = None

        if settings.local.host.routed_subnet6 != routed_subnet6:
            if server.get_online_ipv6_count():
                return utils.jsonify(
                    {
                        'error': IPV6_SUBNET_ONLINE,
                        'error_msg': IPV6_SUBNET_ONLINE_MSG,
                    }, 400)
            settings.local.host.routed_subnet6 = routed_subnet6
            settings.local.host.commit('routed_subnet6')

    if 'server_cert' in flask.request.json:
        settings_commit = True
        server_cert = flask.request.json['server_cert']
        if server_cert:
            settings.app.server_cert = server_cert.strip()
        else:
            settings.app.server_cert = None

    if 'server_key' in flask.request.json:
        settings_commit = True
        server_key = flask.request.json['server_key']
        if server_key:
            settings.app.server_key = server_key.strip()
        else:
            settings.app.server_key = None

    if not settings.app.sso:
        settings.app.sso_match = None
        settings.app.sso_token = None
        settings.app.sso_secret = None
        settings.app.sso_host = None
        settings.app.sso_admin = None
        settings.app.sso_org = None

    if settings_commit:
        settings.commit()

    admin.commit(admin.changed)

    response = flask.g.administrator.dict()
    response.update({
        'theme': settings.app.theme,
        'email_from': settings.app.email_from,
        'email_server': settings.app.email_server,
        'email_username': settings.app.email_username,
        'email_password': bool(settings.app.email_password),
        'sso': settings.app.sso,
        'sso_match': settings.app.sso_match,
        'sso_token': settings.app.sso_token,
        'sso_secret': settings.app.sso_secret,
        'sso_host': settings.app.sso_host,
        'sso_admin': settings.app.sso_admin,
        'sso_org': settings.app.sso_org,
        'public_address': settings.local.host.public_addr,
    })
    return utils.jsonify(response)
예제 #27
0
def settings_put():
    if settings.app.demo_mode:
        return utils.demo_blocked()

    org_event = False
    admin = flask.g.administrator
    changes = set()

    if 'username' in flask.request.json and flask.request.json['username']:
        username = utils.filter_str(flask.request.json['username']).lower()
        if username != admin.username:
            changes.add('username')
        admin.username = username
    if 'password' in flask.request.json and flask.request.json['password']:
        password = flask.request.json['password']
        changes.add('password')
        admin.password = password
    if 'token' in flask.request.json and flask.request.json['token']:
        admin.generate_token()
        changes.add('token')
    if 'secret' in flask.request.json and flask.request.json['secret']:
        admin.generate_secret()
        changes.add('token')

    settings_commit = False
    if 'auditing' in flask.request.json:
        settings_commit = True
        auditing = flask.request.json['auditing'] or None

        if settings.app.auditing != auditing:
            org_event = True

        settings.app.auditing = auditing

    if 'monitoring' in flask.request.json:
        settings_commit = True
        monitoring = flask.request.json['monitoring'] or None
        settings.app.monitoring = monitoring

    if 'datadog_api_key' in flask.request.json:
        settings_commit = True
        datadog_api_key = flask.request.json['datadog_api_key'] or None
        settings.app.datadog_api_key = datadog_api_key

    if 'email_from' in flask.request.json:
        settings_commit = True
        email_from = flask.request.json['email_from'] or None
        if email_from != settings.app.email_from:
            changes.add('smtp')
        settings.app.email_from = email_from

    if 'email_server' in flask.request.json:
        settings_commit = True
        email_server = flask.request.json['email_server'] or None
        if email_server != settings.app.email_server:
            changes.add('smtp')
        settings.app.email_server = email_server

    if 'email_username' in flask.request.json:
        settings_commit = True
        email_username = flask.request.json['email_username'] or None
        if email_username != settings.app.email_username:
            changes.add('smtp')
        settings.app.email_username = email_username

    if 'email_password' in flask.request.json:
        settings_commit = True
        email_password = flask.request.json['email_password'] or None
        if email_password != settings.app.email_password:
            changes.add('smtp')
        settings.app.email_password = email_password

    if 'pin_mode' in flask.request.json:
        settings_commit = True
        pin_mode = flask.request.json['pin_mode'] or None
        if pin_mode != settings.user.pin_mode:
            changes.add('pin_mode')
        settings.user.pin_mode = pin_mode

    if 'sso' in flask.request.json:
        org_event = True
        settings_commit = True
        sso = flask.request.json['sso'] or None
        if sso != settings.app.sso:
            changes.add('sso')
        settings.app.sso = sso

    if 'sso_match' in flask.request.json:
        settings_commit = True
        sso_match = flask.request.json['sso_match'] or None

        if sso_match != settings.app.sso_match:
            changes.add('sso')

        if isinstance(sso_match, list):
            settings.app.sso_match = sso_match
        else:
            settings.app.sso_match = None

    if 'sso_token' in flask.request.json:
        settings_commit = True
        sso_token = flask.request.json['sso_token'] or None
        if sso_token != settings.app.sso_token:
            changes.add('sso')
        settings.app.sso_token = sso_token

    if 'sso_secret' in flask.request.json:
        settings_commit = True
        sso_secret = flask.request.json['sso_secret'] or None
        if sso_secret != settings.app.sso_secret:
            changes.add('sso')
        settings.app.sso_secret = sso_secret

    if 'sso_host' in flask.request.json:
        settings_commit = True
        sso_host = flask.request.json['sso_host'] or None
        if sso_host != settings.app.sso_host:
            changes.add('sso')
        settings.app.sso_host = sso_host

    if 'sso_admin' in flask.request.json:
        settings_commit = True
        sso_admin = flask.request.json['sso_admin'] or None
        if sso_admin != settings.app.sso_admin:
            changes.add('sso')
        settings.app.sso_admin = sso_admin

    if 'sso_org' in flask.request.json:
        settings_commit = True
        sso_org = flask.request.json['sso_org']

        if sso_org:
            sso_org = utils.ObjectId(sso_org)
        else:
            sso_org = None

        if sso_org != settings.app.sso_org:
            changes.add('sso')

        settings.app.sso_org = sso_org

    if 'sso_saml_url' in flask.request.json:
        settings_commit = True
        sso_saml_url = flask.request.json['sso_saml_url'] or None
        if sso_saml_url != settings.app.sso_saml_url:
            changes.add('sso')
        settings.app.sso_saml_url = sso_saml_url

    if 'sso_saml_issuer_url' in flask.request.json:
        settings_commit = True
        sso_saml_issuer_url = flask.request.json['sso_saml_issuer_url'] or None
        if sso_saml_issuer_url != settings.app.sso_saml_issuer_url:
            changes.add('sso')
        settings.app.sso_saml_issuer_url = sso_saml_issuer_url

    if 'sso_saml_cert' in flask.request.json:
        settings_commit = True
        sso_saml_cert = flask.request.json['sso_saml_cert'] or None
        if sso_saml_cert != settings.app.sso_saml_cert:
            changes.add('sso')
        settings.app.sso_saml_cert = sso_saml_cert

    if 'sso_okta_token' in flask.request.json:
        settings_commit = True
        sso_okta_token = flask.request.json['sso_okta_token'] or None
        if sso_okta_token != settings.app.sso_okta_token:
            changes.add('sso')
        settings.app.sso_okta_token = sso_okta_token

    if 'sso_onelogin_key' in flask.request.json:
        settings_commit = True
        sso_onelogin_key = flask.request.json['sso_onelogin_key'] or None
        if sso_onelogin_key != settings.app.sso_onelogin_key:
            changes.add('sso')
        settings.app.sso_onelogin_key = sso_onelogin_key

    if 'theme' in flask.request.json:
        settings_commit = True
        theme = 'dark' if flask.request.json['theme'] == 'dark' else 'light'

        if theme != settings.app.theme:
            if theme == 'dark':
                event.Event(type=THEME_DARK)
            else:
                event.Event(type=THEME_LIGHT)

        settings.app.theme = theme

    if 'public_address' in flask.request.json:
        public_address = flask.request.json['public_address']
        settings.local.host.public_address = public_address
        settings.local.host.commit('public_address')

    if 'public_address6' in flask.request.json:
        public_address6 = flask.request.json['public_address6']
        settings.local.host.public_address6 = public_address6
        settings.local.host.commit('public_address6')

    if 'routed_subnet6' in flask.request.json:
        routed_subnet6 = flask.request.json['routed_subnet6']
        if routed_subnet6:
            try:
                routed_subnet6 = ipaddress.IPv6Network(
                    flask.request.json['routed_subnet6'])
            except (ipaddress.AddressValueError, ValueError):
                return utils.jsonify(
                    {
                        'error': IPV6_SUBNET_INVALID,
                        'error_msg': IPV6_SUBNET_INVALID_MSG,
                    }, 400)

            if routed_subnet6.prefixlen > 64:
                return utils.jsonify(
                    {
                        'error': IPV6_SUBNET_SIZE_INVALID,
                        'error_msg': IPV6_SUBNET_SIZE_INVALID_MSG,
                    }, 400)

            routed_subnet6 = str(routed_subnet6)
        else:
            routed_subnet6 = None

        if settings.local.host.routed_subnet6 != routed_subnet6:
            if server.get_online_ipv6_count():
                return utils.jsonify(
                    {
                        'error': IPV6_SUBNET_ONLINE,
                        'error_msg': IPV6_SUBNET_ONLINE_MSG,
                    }, 400)
            settings.local.host.routed_subnet6 = routed_subnet6
            settings.local.host.commit('routed_subnet6')

    if 'server_cert' in flask.request.json:
        settings_commit = True
        server_cert = flask.request.json['server_cert']
        if server_cert:
            settings.app.server_cert = server_cert.strip()
        else:
            settings.app.server_cert = None

    if 'server_key' in flask.request.json:
        settings_commit = True
        server_key = flask.request.json['server_key']
        if server_key:
            settings.app.server_key = server_key.strip()
        else:
            settings.app.server_key = None

    if not settings.app.sso:
        settings.app.sso_match = None
        settings.app.sso_token = None
        settings.app.sso_secret = None
        settings.app.sso_host = None
        settings.app.sso_admin = None
        settings.app.sso_org = None
        settings.app.sso_saml_url = None
        settings.app.sso_saml_issuer_url = None
        settings.app.sso_saml_cert = None
        settings.app.sso_okta_token = None
        settings.app.sso_onelogin_key = None

    for change in changes:
        auth.audit_event(
            'admin_settings',
            _changes_audit_text[change],
            remote_addr=utils.get_remote_addr(),
        )

    if settings_commit:
        settings.commit()

    admin.commit(admin.changed)

    if org_event:
        for org in organization.iter_orgs(fields=('_id')):
            event.Event(type=USERS_UPDATED, resource_id=org.id)

    event.Event(type=SETTINGS_UPDATED)

    response = flask.g.administrator.dict()
    response.update({
        'theme': settings.app.theme,
        'auditing': settings.app.auditing,
        'monitoring': settings.app.monitoring,
        'datadog_api_key': settings.app.datadog_api_key,
        'email_from': settings.app.email_from,
        'email_server': settings.app.email_server,
        'email_username': settings.app.email_username,
        'email_password': bool(settings.app.email_password),
        'pin_mode': settings.user.pin_mode,
        'sso': settings.app.sso,
        'sso_match': settings.app.sso_match,
        'sso_token': settings.app.sso_token,
        'sso_secret': settings.app.sso_secret,
        'sso_host': settings.app.sso_host,
        'sso_admin': settings.app.sso_admin,
        'sso_org': settings.app.sso_org,
        'sso_saml_url': settings.app.sso_saml_url,
        'sso_saml_issuer_url': settings.app.sso_saml_issuer_url,
        'sso_saml_cert': settings.app.sso_saml_cert,
        'sso_okta_token': settings.app.sso_okta_token,
        'sso_onelogin_key': settings.app.sso_onelogin_key,
        'public_address': settings.local.host.public_addr,
    })
    return utils.jsonify(response)
예제 #28
0
def check_session():
    auth_token = flask.request.headers.get('Auth-Token', None)
    if auth_token:
        auth_timestamp = flask.request.headers.get('Auth-Timestamp', None)
        auth_nonce = flask.request.headers.get('Auth-Nonce', None)
        auth_signature = flask.request.headers.get('Auth-Signature', None)
        if not auth_token or not auth_timestamp or not auth_nonce or \
                not auth_signature:
            return False
        auth_nonce = auth_nonce[:32]

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

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

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

        if len(auth_string) > AUTH_SIG_STRING_MAX_LEN:
            return False

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

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

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

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

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

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

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

    flask.g.administrator = administrator
    return True
예제 #29
0
    def connect(self, client):
        try:
            client_id = client['client_id']
            org_id = utils.ObjectId(client['org_id'])
            user_id = utils.ObjectId(client['user_id'])
            device_id = client.get('device_id')
            device_name = client.get('device_name')
            platform = client.get('platform')
            mac_addr = client.get('mac_addr')
            otp_code = client.get('otp_code')
            remote_ip = client.get('remote_ip')
            devices = self.devices[user_id]

            if not _limiter.validate(remote_ip):
                self.instance_com.send_client_deny(
                    client, 'Too many connect requests')
                return

            org = self.server.get_org(org_id, fields=['_id', 'name'])
            if not org:
                self.instance_com.send_client_deny(
                    client, 'Organization is not valid')
                return

            user = org.get_user(user_id, fields=('_id', 'name', 'email',
                'type', 'auth_type', 'disabled', 'otp_secret',
                'link_server_id'))
            if not user:
                self.instance_com.send_client_deny(client, 'User is not valid')
                return

            if user.disabled:
                logger.LogEntry(message='User failed authentication, ' +
                    'disabled user "%s".' % (user.name))
                self.instance_com.send_client_deny(client, 'User is disabled')
                return

            if not user.auth_check():
                logger.LogEntry(message='User failed authentication, ' +
                    'Google authentication failed "%s".' % (user.name))
                self.instance_com.send_client_deny(
                    client, 'User failed authentication')
                return

            if self.server.otp_auth and  user.type == CERT_CLIENT and \
                not user.verify_otp_code(otp_code, remote_ip):
                logger.LogEntry(message='User failed two-step ' +
                    'authentication "%s".' % user.name)
                self.instance_com.send_client_deny(client, 'Invalid OTP code')
                return

            client_conf = self.generate_client_conf(user)

            if not self.server.multi_device:
                virt_address = self.server.get_ip_addr(org.id, user_id)

                if virt_address and virt_address in self.ips:
                    for cid, device in devices.items():
                        if device['virt_address'] == virt_address:
                            self.instance_com.client_kill(device)
            else:
                virt_address = None
                if devices and device_id:
                    for cid, device in devices.items():
                        if device['device_id'] == device_id:
                            self.instance_com.client_kill(device)

                if not virt_address:
                    virt_address = self.server.get_ip_addr(org.id, user_id)

                if virt_address and virt_address in self.ips:
                    virt_address = None

            if not virt_address:
                while True:
                    try:
                        ip_addr = self.ip_pool.pop()
                    except IndexError:
                        break

                    ip_addr = '%s/%s' % (
                        ip_addr, self.ip_network.prefixlen)

                    if ip_addr not in self.ips:
                        virt_address = ip_addr
                        self.dyn_ips.add(virt_address)
                        break

            if virt_address:
                self.ips[virt_address] = client_id
                devices[client_id] = {
                    'user': user.name,
                    'user_id': user_id,
                    'org': org.name,
                    'org_id': org_id,
                    'client_id': client_id,
                    'device_id': device_id,
                    'device_name': device_name,
                    'type': user.type,
                    'platform': platform,
                    'mac_addr': mac_addr,
                    'virt_address': virt_address,
                    'real_address': remote_ip,
                }
                client_conf += 'ifconfig-push %s %s\n' % utils.parse_network(
                    virt_address)

                if self.server.debug:
                    self.instance_com.push_output('Client conf %s:' % user_id)
                    for conf_line in client_conf.split('\n'):
                        if conf_line:
                            self.instance_com.push_output('  ' + conf_line)

                self.instance_com.send_client_auth(client, client_conf)
            else:
                self.instance_com.send_client_deny(
                    client, 'Unable to assign ip address')
        except:
            logger.exception('Error parsing client connect', 'server',
                server_id=self.server.id,
            )
            self.instance_com.send_client_deny(
                client, 'Error parsing client connect')
예제 #30
0
def settings_put():
    admin = flask.g.administrator

    if 'username' in flask.request.json and flask.request.json['username']:
        admin.username = utils.filter_str(
            flask.request.json['username']).lower()
    if 'password' in flask.request.json and flask.request.json['password']:
        admin.password = flask.request.json['password']
    if 'token' in flask.request.json and flask.request.json['token']:
        admin.generate_token()
    if 'secret' in flask.request.json and flask.request.json['secret']:
        admin.generate_secret()

    settings_commit = False
    if 'email_from' in flask.request.json:
        settings_commit = True
        email_from = flask.request.json['email_from']
        settings.app.email_from = email_from or None

    if 'email_server' in flask.request.json:
        settings_commit = True
        email_server = flask.request.json['email_server']
        settings.app.email_server = email_server or None

    if 'email_username' in flask.request.json:
        settings_commit = True
        email_username = flask.request.json['email_username']
        settings.app.email_username = email_username or None

    if 'email_password' in flask.request.json:
        settings_commit = True
        email_password = flask.request.json['email_password']
        settings.app.email_password = email_password or None

    if 'sso' in flask.request.json:
        settings_commit = True
        sso = flask.request.json['sso']
        settings.app.sso = sso or None

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

        if isinstance(sso_match, list):
            settings_commit = True
            settings.app.sso_match = sso_match or None

    if 'sso_org' in flask.request.json:
        settings_commit = True
        sso_org = flask.request.json['sso_org']
        if sso_org:
            settings.app.sso_org = utils.ObjectId(sso_org)
        else:
            settings.app.sso_org = None

    if 'theme' in flask.request.json:
        settings_commit = True
        theme = 'dark' if flask.request.json['theme'] == 'dark' else 'light'

        if theme != settings.app.theme:
            if theme == 'dark':
                event.Event(type=THEME_DARK)
            else:
                event.Event(type=THEME_LIGHT)

        settings.app.theme = theme

    if 'public_address' in flask.request.json:
        public_address = flask.request.json['public_address']
        settings.local.host.public_address = public_address
        settings.local.host.commit('public_address')

    if 'server_cert' in flask.request.json:
        settings_commit = True
        server_cert = flask.request.json['server_cert']
        if server_cert:
            settings.app.server_cert = server_cert.strip()
        else:
            settings.app.server_cert = None

    if 'server_key' in flask.request.json:
        settings_commit = True
        server_key = flask.request.json['server_key']
        if server_key:
            settings.app.server_key = server_key.strip()
        else:
            settings.app.server_key = None

    if settings_commit:
        settings.commit()

    admin.commit(admin.changed)

    response = flask.g.administrator.dict()
    response.update({
        'theme': settings.app.theme,
        'email_from': settings.app.email_from,
        'email_server': settings.app.email_server,
        'email_username': settings.app.email_username,
        'email_password': bool(settings.app.email_password),
        'sso': bool(settings.app.sso),
        'sso_match': settings.app.sso_match,
        'sso_org': settings.app.sso_org,
        'public_address': settings.local.host.public_addr,
    })
    return utils.jsonify(response)