def _generate_conf(self, server, include_user_cert=True): if not self.sync_token or not self.sync_secret: self.sync_token = utils.generate_secret() self.sync_secret = utils.generate_secret() self.commit(('sync_token', 'sync_secret')) file_name = '%s_%s_%s.ovpn' % ( self.org.name, self.name, server.name) if not server.ca_certificate: server.generate_ca_cert() key_remotes = server.get_key_remotes() ca_certificate = server.ca_certificate certificate = utils.get_cert_block(self.certificate) private_key = self.private_key.strip() conf_hash = hashlib.md5() conf_hash.update(self.name.encode('utf-8')) conf_hash.update(self.org.name.encode('utf-8')) conf_hash.update(server.name.encode('utf-8')) conf_hash.update(server.protocol) for key_remote in sorted(key_remotes): conf_hash.update(key_remote) conf_hash.update(CIPHERS[server.cipher]) conf_hash.update(str(server.lzo_compression)) conf_hash.update(str(server.otp_auth)) conf_hash.update(JUMBO_FRAMES[server.jumbo_frames]) conf_hash.update(ca_certificate) conf_hash = conf_hash.hexdigest() client_conf = OVPN_INLINE_CLIENT_CONF % ( self._get_key_info_str(server, conf_hash), uuid.uuid4().hex, utils.random_name(), server.protocol, server.get_key_remotes(), CIPHERS[server.cipher], server.ping_interval, server.ping_timeout, ) if server.lzo_compression != ADAPTIVE: client_conf += 'comp-lzo no\n' if server.otp_auth: client_conf += 'auth-user-pass\n' if server.tls_auth: client_conf += 'key-direction 1\n' client_conf += JUMBO_FRAMES[server.jumbo_frames] client_conf += '<ca>\n%s\n</ca>\n' % ca_certificate if include_user_cert: if server.tls_auth: client_conf += '<tls-auth>\n%s\n</tls-auth>\n' % ( server.tls_auth_key) client_conf += '<cert>\n%s\n</cert>\n' % certificate client_conf += '<key>\n%s\n</key>\n' % private_key return file_name, client_conf, conf_hash
def _upgrade_auth(): username = None password = None administrators_db = get_collection('administrators') db_path = settings.conf.db_path if db_path and os.path.exists(db_path): with open(db_path, 'r') as db_file: db_data = json.loads(db_file.read()) for key, _, _, value in db_data['data']: if key == 'auth': username = value.get('username') password = value.get('password') else: logger.warning( 'No db file found in upgraded', 'upgrade', path=db_path, ) if username and password: update_doc = { 'username': username, 'password': password, 'token': utils.generate_secret(), 'secret': utils.generate_secret(), 'default': False, 'sessions': [], } doc = administrators_db.find_one() if doc: spec = { '_id': doc['_id'], } else: spec = { 'username': username, } administrators_db.update(spec, update_doc, upsert=True) else: logger.warning( 'Username and password not upgraded', 'upgrade', path=db_path, )
def _upgrade_auth(): username = None password = None administrators_db = get_collection('administrators') db_path = settings.conf.db_path if db_path and os.path.exists(db_path): with open(db_path, 'r') as db_file: db_data = json.loads(db_file.read()) for key, _, _, value in db_data['data']: if key == 'auth': username = value.get('username') password = value.get('password') else: logger.warning('No db file found in upgraded', 'upgrade', path=db_path, ) if username and password: update_doc = { 'username': username, 'password': password, 'token': utils.generate_secret(), 'secret': utils.generate_secret(), 'default': False, 'sessions': [], } doc = administrators_db.find_one() if doc: spec = { '_id': doc['_id'], } else: spec = { 'username': username, } administrators_db.update(spec, update_doc, upsert=True) else: logger.warning('Username and password not upgraded', 'upgrade', path=db_path, )
def get_token(): coll = mongo.get_collection('auth_csrf_tokens') token = utils.generate_secret() coll.insert({ '_id': token, 'timestamp': utils.now(), }) return token
def setup_vault(): if SE_MODE: try: os.remove(settings.conf.se_init_path) except OSError: pass try: os.remove(settings.conf.se_secret_path) except OSError: pass settings.local.se_authorize_key = utils.generate_secret() settings.local.se_encryption_key = None settings.local.se_client_key, settings.local.se_client_pub_key = \ vault.generate_client_key() if os.path.isfile(settings.conf.se_host_key_path): with open(settings.conf.se_host_key_path, 'r') as key_file: settings.local.se_host_key = key_file.read().strip() else: logger.info('Generating se host key', 'setup') settings.local.se_host_key = vault.generate_host_key() with open(settings.conf.se_host_key_path, 'w') as key_file: key_file.write(settings.local.se_host_key) threading.Thread(target=_vault_thread).start() time.sleep(4) vault.init() vault.init_host_key() init_data = vault.init_server_key() with open(settings.conf.se_init_path, 'w') as key_file: key_file.write(json.dumps(init_data)) subprocess.check_call(['/home/cloud/go/bin/pritunl-key']) logger.info('Waiting for se secret', 'setup') while True: time.sleep(0.5) if os.path.isfile(settings.conf.se_secret_path): with open(settings.conf.se_secret_path, 'r') as secret_file: data = json.loads(secret_file.read().strip()) break logger.info('Loading se secret', 'setup') vault.init_master_key(data)
def generate_token(self): logger.info('Generating auth token', 'auth') self.token = utils.generate_secret()
def sso_callback_get(): sso_mode = settings.app.sso if sso_mode not in (AZURE_AUTH, AZURE_DUO_AUTH, AZURE_YUBICO_AUTH, 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] org_names = [] if params.get('org'): org_names_param = params.get('org')[0] if ';' in org_names_param: org_names = org_names_param.split(';') else: org_names = org_names_param.split(',') org_names = [x for x in org_names if x] org_names = sorted(org_names) groups = [] if params.get('groups'): groups_param = params.get('groups')[0] if ';' in groups_param: groups = groups_param.split(';') else: groups = groups_param.split(',') groups = [x for x in groups if x] groups = set(groups) if not username: return flask.abort(406) org_id = settings.app.sso_org if org_names: not_found = False for org_name in org_names: org = organization.get_by_name( utils.filter_unicode(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=doc.get('type'), user_name=username, user_email=email, org_names=org_names, ) 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_names, ) 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 = sorted(org_names.split(',')) if user_team != settings.app.sso_match[0]: return flask.abort(401) not_found = False org_id = settings.app.sso_org for org_name in org_names: org = organization.get_by_name( utils.filter_unicode(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=doc.get('type'), user_name=username, user_email=email, org_names=org_names, ) 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 []) elif doc.get('type') == GOOGLE_AUTH: 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: not_found = False google_groups = sorted(google_groups) for org_name in google_groups: org = organization.get_by_name( utils.filter_unicode(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=doc.get('type'), user_name=username, user_email=email, org_names=google_groups, ) elif doc.get('type') == AZURE_AUTH: username = params.get('username')[0] email = None tenant, username = username.split('/', 2) if tenant != settings.app.sso_azure_directory_id: logger.error( 'Azure directory ID mismatch', 'sso', username=username, ) return flask.abort(401) valid, azure_groups = sso.verify_azure(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='azure', 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( 'Azure plugin authentication not valid', 'sso', username=username, ) return flask.abort(401) groups = set(groups or []) if settings.app.sso_azure_mode == 'groups': groups = groups | set(azure_groups) else: not_found = False azure_groups = sorted(azure_groups) for org_name in azure_groups: org = organization.get_by_name( utils.filter_unicode(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=doc.get('type'), user_name=username, user_email=email, org_names=azure_groups, ) else: logger.error( 'Unknown sso type', 'sso', sso_type=doc.get('type'), ) return flask.abort(401) 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() return _validate_user(username, email, sso_mode, org_id, groups, http_redirect=True)
def sso_callback_get(): sso_mode = settings.app.sso if sso_mode not in (GOOGLE_AUTH, GOOGLE_DUO_AUTH, GOOGLE_YUBICO_AUTH, SLACK_AUTH, SLACK_DUO_AUTH, SLACK_YUBICO_AUTH, SAML_AUTH, SAML_DUO_AUTH, SAML_YUBICO_AUTH, SAML_OKTA_AUTH, SAML_OKTA_DUO_AUTH, SAML_OKTA_YUBICO_AUTH, SAML_ONELOGIN_AUTH, SAML_ONELOGIN_DUO_AUTH, SAML_ONELOGIN_YUBICO_AUTH): return flask.abort(405) state = flask.request.args.get('state') sig = flask.request.args.get('sig') tokens_collection = mongo.get_collection('sso_tokens') doc = tokens_collection.find_and_modify(query={ '_id': state, }, remove=True) if not doc: return flask.abort(404) query = flask.request.query_string.split('&sig=')[0] test_sig = base64.urlsafe_b64encode( hmac.new(str(doc['secret']), query, hashlib.sha512).digest()) if sig != test_sig: return flask.abort(401) params = urlparse.parse_qs(query) if doc.get('type') == SAML_AUTH: username = params.get('username')[0] email = params.get('email', [None])[0] org_name = params.get('org', [None])[0] if not username: return flask.abort(406) valid, org_name = sso.verify_saml(username, email, org_name) if not valid: return flask.abort(401) org_id = settings.app.sso_org if org_name: org = organization.get_by_name(org_name, fields=('_id')) if org: org_id = org.id valid, org_id_new, groups = sso.plugin_sso_authenticate( sso_type='saml', user_name=username, user_email=email, remote_ip=utils.get_remote_addr(), sso_org_names=[org_name], ) if valid: org_id = org_id_new or org_id else: logger.error( 'Saml plugin authentication not valid', 'sso', username=username, ) return flask.abort(401) elif doc.get('type') == SLACK_AUTH: username = params.get('username')[0] email = None user_team = params.get('team')[0] org_names = params.get('orgs', [''])[0] org_names = org_names.split(',') valid, org_name = sso.verify_slack(username, user_team, org_names) if not valid: return flask.abort(401) if org_name: org_names = [org_name] org_id = settings.app.sso_org for org_name in org_names: org = organization.get_by_name(org_name, fields=('_id')) if org: org_id = org.id break valid, org_id_new, groups = sso.plugin_sso_authenticate( sso_type='slack', user_name=username, user_email=email, remote_ip=utils.get_remote_addr(), sso_org_names=org_names, ) if valid: org_id = org_id_new or org_id else: logger.error( 'Slack plugin authentication not valid', 'sso', username=username, ) return flask.abort(401) else: username = params.get('username')[0] email = username valid, org_name = sso.verify_google(username) if not valid: return flask.abort(401) org_id = settings.app.sso_org if org_name: org = organization.get_by_name(org_name, fields=('_id')) if org: org_id = org.id valid, org_id_new, groups = sso.plugin_sso_authenticate( sso_type='google', user_name=username, user_email=email, remote_ip=utils.get_remote_addr(), ) if valid: org_id = org_id_new or org_id else: logger.error( 'Google plugin authentication not valid', 'sso', username=username, ) return flask.abort(401) if DUO_AUTH in sso_mode: if settings.app.sso_duo_mode == 'passcode': token = utils.generate_secret() tokens_collection = mongo.get_collection('sso_tokens') tokens_collection.insert({ '_id': token, 'type': DUO_AUTH, 'username': username, 'email': email, 'org_id': org_id, 'groups': groups, 'timestamp': utils.now(), }) duo_page = static.StaticFile(settings.conf.www_path, 'duo.html', cache=False, gzip=False) if settings.app.theme == 'dark': duo_page.data = duo_page.data.replace('<body>', '<body class="dark">') duo_page.data = duo_page.data.replace('<%= token %>', token) return duo_page.get_response() else: duo_auth = sso.Duo( username=username, factor=settings.app.sso_duo_mode, remote_ip=utils.get_remote_addr(), auth_type='Key', ) valid = duo_auth.authenticate() if valid: valid, org_id_new, groups2 = sso.plugin_sso_authenticate( sso_type='duo', user_name=username, user_email=email, remote_ip=utils.get_remote_addr(), ) if valid: org_id = org_id_new or org_id else: logger.error( 'Duo plugin authentication not valid', 'sso', username=username, ) return flask.abort(401) groups = ((groups or set()) | (groups2 or set())) or None else: logger.error( 'Duo authentication not valid', 'sso', username=username, ) return flask.abort(401) if YUBICO_AUTH in sso_mode: token = utils.generate_secret() tokens_collection = mongo.get_collection('sso_tokens') tokens_collection.insert({ '_id': token, 'type': YUBICO_AUTH, 'username': username, 'email': email, 'org_id': org_id, 'groups': groups, 'timestamp': utils.now(), }) yubico_page = static.StaticFile(settings.conf.www_path, 'yubico.html', cache=False, gzip=False) if settings.app.theme == 'dark': yubico_page.data = yubico_page.data.replace( '<body>', '<body class="dark">') yubico_page.data = yubico_page.data.replace('<%= token %>', token) return yubico_page.get_response() org = organization.get_by_id(org_id) if not org: return flask.abort(405) usr = org.find_user(name=username) if not usr: usr = org.new_user(name=username, email=email, type=CERT_CLIENT, auth_type=sso_mode, groups=list(groups) if groups else None) usr.audit_event('user_created', 'User created with single sign-on', remote_addr=utils.get_remote_addr()) event.Event(type=ORGS_UPDATED) event.Event(type=USERS_UPDATED, resource_id=org.id) event.Event(type=SERVERS_UPDATED) else: if usr.disabled: return flask.abort(403) if groups and groups - set(usr.groups or []): usr.groups = list(set(usr.groups or []) | groups) usr.commit('groups') if usr.auth_type != sso_mode: usr.auth_type = sso_mode usr.commit('auth_type') key_link = org.create_user_key_link(usr.id, one_time=True) usr.audit_event( 'user_profile', 'User profile viewed from single sign-on', remote_addr=utils.get_remote_addr(), ) return utils.redirect(utils.get_url_root() + key_link['view_url'])
def generate_secret(self): logger.info('Generating auth secret', 'auth') self.secret = utils.generate_secret()
def generate_auth_secret(self): self.auth_secret = utils.generate_secret()
def sso_callback_get(): sso_mode = settings.app.sso if sso_mode not in (AZURE_AUTH, AZURE_DUO_AUTH, AZURE_YUBICO_AUTH, GOOGLE_AUTH, GOOGLE_DUO_AUTH, GOOGLE_YUBICO_AUTH, AUTHZERO_AUTH, AUTHZERO_DUO_AUTH, AUTHZERO_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) remote_addr = utils.get_remote_addr() 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): journal.entry( journal.SSO_AUTH_FAILURE, state=state, remote_address=remote_addr, reason=journal.SSO_AUTH_REASON_INVALID_CALLBACK, reason_long='Signature mismatch', ) 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_names = [] if params.get('org'): org_names_param = params.get('org')[0] if ';' in org_names_param: org_names = org_names_param.split(';') else: org_names = org_names_param.split(',') org_names = [x for x in org_names if x] org_names = sorted(org_names) groups = [] if params.get('groups'): groups_param = params.get('groups')[0] if ';' in groups_param: groups = groups_param.split(';') else: groups = groups_param.split(',') groups = [x for x in groups if x] groups = set(groups) if not username: return flask.abort(406) org_id = settings.app.sso_org if org_names: not_found = False for org_name in org_names: org = organization.get_by_name( utils.filter_unicode(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=doc.get('type'), user_name=username, user_email=email, org_names=org_names, ) valid, org_id_new, groups2 = sso.plugin_sso_authenticate( sso_type='saml', user_name=username, user_email=email, remote_ip=remote_addr, sso_org_names=org_names, ) if valid: org_id = org_id_new or org_id else: logger.error('Saml plugin authentication not valid', 'sso', username=username, ) journal.entry( journal.SSO_AUTH_FAILURE, user_name=username, remote_address=remote_addr, reason=journal.SSO_AUTH_REASON_PLUGIN_FAILED, reason_long='Saml plugin authentication failed', ) 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 = sorted(org_names.split(',')) if user_team != settings.app.sso_match[0]: return flask.abort(401) not_found = False org_id = settings.app.sso_org for org_name in org_names: org = organization.get_by_name( utils.filter_unicode(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=doc.get('type'), user_name=username, user_email=email, org_names=org_names, ) valid, org_id_new, groups = sso.plugin_sso_authenticate( sso_type='slack', user_name=username, user_email=email, remote_ip=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, ) journal.entry( journal.SSO_AUTH_FAILURE, user_name=username, remote_address=remote_addr, reason=journal.SSO_AUTH_REASON_PLUGIN_FAILED, reason_long='Slack plugin authentication failed', ) return flask.abort(401) groups = set(groups or []) elif doc.get('type') == GOOGLE_AUTH: username = params.get('username')[0] email = username valid, google_groups = sso.verify_google(username) if not valid: journal.entry( journal.SSO_AUTH_FAILURE, user_name=username, remote_address=remote_addr, reason=journal.SSO_AUTH_REASON_GOOGLE_FAILED, reason_long='Google authentication failed', ) 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=remote_addr, ) if valid: org_id = org_id_new or org_id else: logger.error('Google plugin authentication not valid', 'sso', username=username, ) journal.entry( journal.SSO_AUTH_FAILURE, user_name=username, remote_address=remote_addr, reason=journal.SSO_AUTH_REASON_PLUGIN_FAILED, reason_long='Google plugin authentication failed', ) return flask.abort(401) groups = set(groups or []) if settings.app.sso_google_mode == 'groups': groups = groups | set(google_groups) else: not_found = False google_groups = sorted(google_groups) for org_name in google_groups: org = organization.get_by_name( utils.filter_unicode(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=doc.get('type'), user_name=username, user_email=email, org_names=google_groups, ) elif doc.get('type') == AZURE_AUTH: username = params.get('username')[0] email = None tenant, username = username.split('/', 2) if tenant != settings.app.sso_azure_directory_id: logger.error('Azure directory ID mismatch', 'sso', username=username, ) journal.entry( journal.SSO_AUTH_FAILURE, user_name=username, azure_tenant=tenant, remote_address=remote_addr, reason=journal.SSO_AUTH_REASON_AZURE_FAILED, reason_long='Azure directory ID mismatch', ) return flask.abort(401) valid, azure_groups = sso.verify_azure(username) if not valid: journal.entry( journal.SSO_AUTH_FAILURE, user_name=username, remote_address=remote_addr, reason=journal.SSO_AUTH_REASON_AZURE_FAILED, reason_long='Azure authentication failed', ) return flask.abort(401) org_id = settings.app.sso_org valid, org_id_new, groups = sso.plugin_sso_authenticate( sso_type='azure', user_name=username, user_email=email, remote_ip=remote_addr, ) if valid: org_id = org_id_new or org_id else: logger.error('Azure plugin authentication not valid', 'sso', username=username, ) journal.entry( journal.SSO_AUTH_FAILURE, user_name=username, remote_address=remote_addr, reason=journal.SSO_AUTH_REASON_PLUGIN_FAILED, reason_long='Azure plugin authentication failed', ) return flask.abort(401) groups = set(groups or []) if settings.app.sso_azure_mode == 'groups': groups = groups | set(azure_groups) else: not_found = False azure_groups = sorted(azure_groups) for org_name in azure_groups: org = organization.get_by_name( utils.filter_unicode(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=doc.get('type'), user_name=username, user_email=email, org_names=azure_groups, ) elif doc.get('type') == AUTHZERO_AUTH: username = params.get('username')[0] email = None valid, authzero_groups = sso.verify_authzero(username) if not valid: journal.entry( journal.SSO_AUTH_FAILURE, user_name=username, remote_address=remote_addr, reason=journal.SSO_AUTH_REASON_AUTHZERO_FAILED, reason_long='Auth0 authentication failed', ) return flask.abort(401) org_id = settings.app.sso_org valid, org_id_new, groups = sso.plugin_sso_authenticate( sso_type='authzero', user_name=username, user_email=email, remote_ip=remote_addr, ) if valid: org_id = org_id_new or org_id else: logger.error('Auth0 plugin authentication not valid', 'sso', username=username, ) journal.entry( journal.SSO_AUTH_FAILURE, user_name=username, remote_address=remote_addr, reason=journal.SSO_AUTH_REASON_PLUGIN_FAILED, reason_long='Auth0 plugin authentication failed', ) return flask.abort(401) groups = set(groups or []) if settings.app.sso_authzero_mode == 'groups': groups = groups | set(authzero_groups) else: not_found = False authzero_groups = sorted(authzero_groups) for org_name in authzero_groups: org = organization.get_by_name( utils.filter_unicode(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=doc.get('type'), user_name=username, user_email=email, org_names=authzero_groups, ) else: logger.error('Unknown sso type', 'sso', sso_type=doc.get('type'), ) return flask.abort(401) 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() return _validate_user(username, email, sso_mode, org_id, groups, remote_addr, http_redirect=True)
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] 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, 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 = sso.verify_slack(username, user_team) if not valid: 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) else: username = params.get('username')[0] email = username valid = 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) 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': groups, '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': groups, 'timestamp': utils.now(), }) yubico_page = static.StaticFile(settings.conf.www_path, 'yubico.html', cache=False, gzip=False) if settings.app.theme == 'dark': yubico_page.data = yubico_page.data.replace( '<body>', '<body class="dark">') yubico_page.data = yubico_page.data.replace('<%= token %>', token) return yubico_page.get_response() org = organization.get_by_id(org_id) if not org: return flask.abort(405) usr = org.find_user(name=username) if not usr: usr = org.new_user(name=username, email=email, type=CERT_CLIENT, auth_type=sso_mode, groups=list(groups) if groups else None) usr.audit_event('user_created', 'User created with single sign-on', remote_addr=utils.get_remote_addr()) event.Event(type=ORGS_UPDATED) event.Event(type=USERS_UPDATED, resource_id=org.id) event.Event(type=SERVERS_UPDATED) else: if usr.disabled: return flask.abort(403) if groups and groups - set(usr.groups or []): usr.groups = list(set(usr.groups or []) | groups) usr.commit('groups') if usr.auth_type != sso_mode: usr.auth_type = sso_mode usr.commit('auth_type') key_link = org.create_user_key_link(usr.id, one_time=True) usr.audit_event('user_profile', 'User profile viewed from single sign-on', remote_addr=utils.get_remote_addr(), ) return utils.redirect(utils.get_url_root() + key_link['view_url'])
def generate_auth_token(self): self.auth_token = utils.generate_secret()
def _generate_conf(self, svr, include_user_cert=True): if not self.sync_token or not self.sync_secret: self.sync_token = utils.generate_secret() self.sync_secret = utils.generate_secret() self.commit(('sync_token', 'sync_secret')) file_name = '%s_%s_%s.ovpn' % ( self.org.name, self.name, svr.name) if not svr.ca_certificate: svr.generate_ca_cert() key_remotes = svr.get_key_remotes() ca_certificate = svr.ca_certificate certificate = utils.get_cert_block(self.certificate) private_key = self.private_key.strip() conf_hash = hashlib.md5() conf_hash.update(self.name.encode('utf-8')) conf_hash.update(self.org.name.encode('utf-8')) conf_hash.update(svr.name.encode('utf-8')) conf_hash.update(svr.protocol) for key_remote in sorted(key_remotes): conf_hash.update(key_remote) conf_hash.update(CIPHERS[svr.cipher]) conf_hash.update(str(svr.lzo_compression)) conf_hash.update(str(svr.block_outside_dns)) conf_hash.update(str(svr.otp_auth)) conf_hash.update(JUMBO_FRAMES[svr.jumbo_frames]) conf_hash.update(ca_certificate) conf_hash.update(self._get_key_info_str(svr, None, False)) plugin_config = '' if settings.local.sub_plan and \ 'enterprise' in settings.local.sub_plan: returns = plugins.caller( 'user_config', host_id=settings.local.host_id, host_name=settings.local.host.name, org_id=self.org_id, user_id=self.id, user_name=self.name, server_id=svr.id, server_name=svr.name, server_port=svr.port, server_protocol=svr.protocol, server_ipv6=svr.ipv6, server_ipv6_firewall=svr.ipv6_firewall, server_network=svr.network, server_network6=svr.network6, server_network_mode=svr.network_mode, server_network_start=svr.network_start, server_network_stop=svr.network_end, server_restrict_routes=svr.restrict_routes, server_bind_address=svr.bind_address, server_onc_hostname=None, server_dh_param_bits=svr.dh_param_bits, server_multi_device=svr.multi_device, server_dns_servers=svr.dns_servers, server_search_domain=svr.search_domain, server_otp_auth=svr.otp_auth, server_cipher=svr.cipher, server_hash=svr.hash, server_inter_client=svr.inter_client, server_ping_interval=svr.ping_interval, server_ping_timeout=svr.ping_timeout, server_link_ping_interval=svr.link_ping_interval, server_link_ping_timeout=svr.link_ping_timeout, server_allowed_devices=svr.allowed_devices, server_max_clients=svr.max_clients, server_replica_count=svr.replica_count, server_dns_mapping=svr.dns_mapping, server_debug=svr.debug, ) if returns: for return_val in returns: if not return_val: continue val = return_val.strip() conf_hash.update(val) plugin_config += val + '\n' conf_hash = conf_hash.hexdigest() client_conf = OVPN_INLINE_CLIENT_CONF % ( self._get_key_info_str(svr, conf_hash, include_user_cert), uuid.uuid4().hex, utils.random_name(), svr.adapter_type, svr.adapter_type, svr.get_key_remotes(), CIPHERS[svr.cipher], HASHES[svr.hash], svr.ping_interval, svr.ping_timeout, ) if svr.lzo_compression != ADAPTIVE: client_conf += 'comp-lzo no\n' if svr.block_outside_dns: client_conf += 'ignore-unknown-option block-outside-dns\n' client_conf += 'block-outside-dns\n' if self.has_password(svr): client_conf += 'auth-user-pass\n' if svr.tls_auth: client_conf += 'key-direction 1\n' client_conf += JUMBO_FRAMES[svr.jumbo_frames] client_conf += plugin_config client_conf += '<ca>\n%s\n</ca>\n' % ca_certificate if include_user_cert: if svr.tls_auth: client_conf += '<tls-auth>\n%s\n</tls-auth>\n' % ( svr.tls_auth_key) client_conf += '<cert>\n%s\n</cert>\n' % certificate client_conf += '<key>\n%s\n</key>\n' % private_key return file_name, client_conf, conf_hash
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: if settings.app.sso_duo_mode == "passcode": token = utils.generate_secret() tokens_collection = mongo.get_collection("sso_tokens") tokens_collection.insert( { "_id": token, "type": DUO_AUTH, "username": username, "email": email, "org_id": org_id, "groups": groups, "timestamp": utils.now(), } ) duo_page = static.StaticFile(settings.conf.www_path, "duo.html", cache=False, gzip=False) if settings.app.theme == "dark": duo_page.data = duo_page.data.replace("<body>", '<body class="dark">') duo_page.data = duo_page.data.replace("<%= token %>", token) return duo_page.get_response() else: duo_auth = sso.Duo( username=username, factor=settings.app.sso_duo_mode, remote_ip=utils.get_remote_addr(), auth_type="Key" ) valid = duo_auth.authenticate() if valid: valid, org_id_new, groups2 = sso.plugin_sso_authenticate( sso_type="duo", user_name=username, user_email=email, remote_ip=utils.get_remote_addr() ) if valid: org_id = org_id_new or org_id else: logger.error("Duo plugin authentication not valid", "sso", username=username) return flask.abort(401) groups = ((groups or set()) | (groups2 or set())) or None else: logger.error("Duo authentication not valid", "sso", username=username) return flask.abort(401) 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"])
def _generate_conf(self, svr, include_user_cert=True): if not self.sync_token or not self.sync_secret: self.sync_token = utils.generate_secret() self.sync_secret = utils.generate_secret() self.commit(('sync_token', 'sync_secret')) file_name = '%s_%s_%s.ovpn' % (self.org.name, self.name, svr.name) if not svr.ca_certificate: svr.generate_ca_cert() key_remotes = svr.get_key_remotes() ca_certificate = svr.ca_certificate certificate = utils.get_cert_block(self.certificate) private_key = self.private_key.strip() conf_hash = hashlib.md5() conf_hash.update(self.name.encode('utf-8')) conf_hash.update(self.org.name.encode('utf-8')) conf_hash.update(svr.name.encode('utf-8')) conf_hash.update(svr.protocol) for key_remote in sorted(key_remotes): conf_hash.update(key_remote) conf_hash.update(CIPHERS[svr.cipher]) conf_hash.update(str(svr.lzo_compression)) conf_hash.update(str(svr.block_outside_dns)) conf_hash.update(str(svr.otp_auth)) conf_hash.update(JUMBO_FRAMES[svr.jumbo_frames]) conf_hash.update(ca_certificate) conf_hash.update(self._get_key_info_str(svr, None, False)) plugin_config = '' if settings.local.sub_plan and \ 'enterprise' in settings.local.sub_plan: returns = plugins.caller( 'user_config', host_id=settings.local.host_id, host_name=settings.local.host.name, org_id=self.org_id, user_id=self.id, user_name=self.name, server_id=svr.id, server_name=svr.name, server_port=svr.port, server_protocol=svr.protocol, server_ipv6=svr.ipv6, server_ipv6_firewall=svr.ipv6_firewall, server_network=svr.network, server_network6=svr.network6, server_network_mode=svr.network_mode, server_network_start=svr.network_start, server_network_stop=svr.network_end, server_restrict_routes=svr.restrict_routes, server_bind_address=svr.bind_address, server_onc_hostname=None, server_dh_param_bits=svr.dh_param_bits, server_multi_device=svr.multi_device, server_dns_servers=svr.dns_servers, server_search_domain=svr.search_domain, server_otp_auth=svr.otp_auth, server_cipher=svr.cipher, server_hash=svr.hash, server_inter_client=svr.inter_client, server_ping_interval=svr.ping_interval, server_ping_timeout=svr.ping_timeout, server_link_ping_interval=svr.link_ping_interval, server_link_ping_timeout=svr.link_ping_timeout, server_allowed_devices=svr.allowed_devices, server_max_clients=svr.max_clients, server_replica_count=svr.replica_count, server_dns_mapping=svr.dns_mapping, server_debug=svr.debug, ) if returns: for return_val in returns: if not return_val: continue val = return_val.strip() conf_hash.update(val) plugin_config += val + '\n' conf_hash = conf_hash.hexdigest() client_conf = OVPN_INLINE_CLIENT_CONF % ( self._get_key_info_str(svr, conf_hash, include_user_cert), uuid.uuid4().hex, utils.random_name(), svr.adapter_type, svr.adapter_type, svr.get_key_remotes(), CIPHERS[svr.cipher], HASHES[svr.hash], svr.ping_interval, svr.ping_timeout, ) if svr.lzo_compression != ADAPTIVE: client_conf += 'comp-lzo no\n' if svr.block_outside_dns: client_conf += 'ignore-unknown-option block-outside-dns\n' client_conf += 'block-outside-dns\n' if self.has_password(svr): client_conf += 'auth-user-pass\n' if svr.tls_auth: client_conf += 'key-direction 1\n' client_conf += JUMBO_FRAMES[svr.jumbo_frames] client_conf += plugin_config client_conf += '<ca>\n%s\n</ca>\n' % ca_certificate if include_user_cert: if svr.tls_auth: client_conf += '<tls-auth>\n%s\n</tls-auth>\n' % ( svr.tls_auth_key) client_conf += '<cert>\n%s\n</cert>\n' % certificate client_conf += '<key>\n%s\n</key>\n' % private_key return file_name, client_conf, conf_hash