def _create_user(self, username, password, mail, method, uuid): """Create a new user and all initial data""" try: if method == 'Invited': config_role = self.config.group_accept_invited else: config_role = self.config.group_accept_enrolled roles = [] if ',' in config_role: for item in config_role.split(','): roles.append(item.lstrip().rstrip()) else: roles = [config_role] newuser = objectmodels['user']({ 'name': username, 'passhash': std_hash(password, self.salt), 'mail': mail, 'uuid': std_uuid(), 'roles': roles, 'created': std_now() }) if method == 'Invited': newuser.needs_password_change = True newuser.save() except Exception as e: self.log("Problem creating new user: "******"New profile uuid: ", newprofile.uuid, lvl=verbose) newprofile.save() packet = { 'component': 'isomer.enrol.enrolmanager', 'action': 'enrol', 'data': [True, mail] } self.fireEvent(send(uuid, packet)) # TODO: Notify crew-admins except Exception as e: self.log("Problem creating new profile: ", type(e), e, lvl=error)
def test_invalid_user_auth(): """Test if login with invalid credentials fails""" class sock(): """Mock socket""" def getpeername(self): """Mock function to return a fake peer name""" return "localhost" m.start() client_uuid = std_uuid() event = authenticationrequest( username='', password='******', clientuuid=client_uuid, requestedclientuuid=client_uuid, sock=sock(), auto=False ) result = transmit('send', 'isomer-web', event, 'auth', 4) assert result is not None assert isinstance(result, Event)
def test_user_auth(): """Test if login with test credentials succeeds""" class sock(): """Mock socket""" def getpeername(self): """Mock function to return a fake peer name""" return ["localhost"] m.start() client_uuid = std_uuid() event = authenticationrequest( username='******', password='******', clientuuid=client_uuid, requestedclientuuid=client_uuid, sock=sock(), auto=False ) result = transmit('authentication', 'auth', event, 'auth', 1.0) assert isinstance(result, authentication) assert result.username == 'TESTER'
def _invite(self, name, method, email, uuid, event, password=""): """Actually invite a given user""" props = { 'uuid': std_uuid(), 'status': 'Open', 'name': name, 'method': method, 'email': email, 'password': password, 'timestamp': std_now() } enrollment = objectmodels['enrollment'](props) enrollment.save() self.log('Enrollment stored', lvl=debug) self._send_invitation(enrollment, event) packet = { 'component': 'isomer.enrol.enrolmanager', 'action': 'invite', 'data': [True, email] } self.fireEvent(send(uuid, packet))
def test_auth_logout(): client_uuid = std_uuid() user_uuid = std_uuid() cm._clients[client_uuid] = Client(None, '127.0.0.1', client_uuid, user_uuid, 'TESTER') m.start() cm._handle_authentication_events(None, 'logout', client_uuid, None) data = {'component': 'auth', 'action': 'logout', 'data': {}} event = read(None, dumps(data)) result = transmit('clientdisconnect', 'isomer-web', event, 'wsserver') assert result.clientuuid == client_uuid assert isinstance(result, clientdisconnect)
def test_auto_auth_request(): """Tests if automatic authentication requests work""" test_uuid = std_uuid() m.start() # TODO: Rebuild this, to actually connect a fake socket via cm.connect(socket, IP) class sock(): """Mock socket""" @staticmethod def getpeername(): """Mock function to return a fake peer name""" return ["localhost"] def clientuuid(self): return test_uuid socket = sock cm._sockets[socket] = socket client_config_uuid = std_uuid() data = { 'component': 'auth', 'action': 'autologin', 'data': { 'uuid': client_config_uuid } } event = read(socket, dumps(data)) result = transmit('authenticationrequest', 'auth', event, 'wsserver') #pprint(result.__dict__) assert result.auto is True assert result.requestedclientuuid['uuid'] == client_config_uuid
def create(self, event): """An admin user requests to create a new user""" uuid = std_uuid() name = event.data['name'] mail = event.data['mail'] password = event.data['password'] password_verify = event.data['password_verify'] if password != password_verify: self._fail(event, 'Passwords do not match') return if len(password) < minimum_password_length: self._fail(event, msg="Password too short") return if len(name) < minimum_username_length: self._fail(event, msg="Username too short") return passhash = std_hash(password, self.salt) existing = objectmodels['user'].find_one({'name': name}) if existing is not None: self._fail(event, msg='User already exists') return new_user = objectmodels['user']({ 'uuid': uuid, 'name': name, 'passhash': passhash, 'mail': mail }) try: new_user.save() self._acknowledge(event) except ValidationError as e: self.log("Tried to create invalid user:"******"Invalid user data specified")
def test_auth_request(): """Test if clientmanager fires an authentication-request on login""" test_uuid = std_uuid() m.start() # TODO: Rebuild this, to actually connect a fake socket via cm.connect(socket, IP) class sock(): """Mock socket""" @staticmethod def getpeername(): """Mock function to return a fake peer name""" return ["localhost"] def clientuuid(self): return test_uuid socket = sock cm._sockets[socket] = socket data = { 'component': 'auth', 'action': 'login', 'data': { 'username': '******', 'password': '******' } } event = read(socket, dumps(data)) result = transmit('authenticationrequest', 'auth', event, 'wsserver') assert result.username == 'foo' assert result.password == 'bar'
def _get_profile(self, user_account): """Retrieves a user's profile""" try: # TODO: Load active profile, not just any user_profile = objectmodels["profile"].find_one( {"owner": str(user_account.uuid)}) self.log("Profile: ", user_profile, user_account.uuid, lvl=debug) except Exception as e: self.log("No profile due to error: ", e, type(e), lvl=error) user_profile = None if not user_profile: default = { "uuid": std_uuid(), "owner": user_account.uuid, "userdata": { "notes": "Default profile of " + user_account.name }, } user_profile = objectmodels["profile"](default) user_profile.save() return user_profile
def _validate(self, schema_name, model, client_data): """Validates and tries to fix up to 10 errors in client model data..""" # TODO: This should probably move to Formal. # Also i don't like artificially limiting this. # Alas, never giving it up is even worse :) give_up = 10 validated = False while give_up > 0 and validated is False: try: validated = model(client_data) except ValidationError as e: self.log("Validation Error:", e, e.__dict__, pretty=True) give_up -= 1 if e.validator == "type": schema_data = schemastore[schema_name]["schema"] if e.validator_value == "number": definition = nested_map_find(schema_data, list(e.schema_path)[:-1]) if "default" in definition: client_data = nested_map_update( client_data, definition["default"], list(e.path)) else: client_data = nested_map_update( client_data, None, list(e.path)) if (e.validator == "pattern" and "uuid" == e.path[0] and client_data["uuid"] == "create"): client_data["uuid"] = std_uuid() if validated is False: raise ValidationError("Could not validate object") return client_data
from isomer.events.client import authenticationrequest, authentication from isomer.misc.std import std_hash, std_now, std_uuid from isomer.database import objectmodels import isomer.logger as logger from bcrypt import gensalt # from pprint import pprint m = Manager() auth = Authenticator() auth.register(m) new_user = objectmodels['user']({ 'uuid': std_uuid(), 'created': std_now() }) new_user.name = 'TESTER' salt = gensalt().decode("ascii") new_user.passhash = std_hash('PASSWORD', salt) new_user.save() system_config = objectmodels['systemconfig']({ 'uuid': std_uuid(), 'active': True, 'salt': salt
def test_uuid(): uuid = std_uuid() assert isinstance(uuid, str) assert re.match(r'(\w{8}(-\w{4}){3}-\w{12}?)', uuid)
def _install_module(source, url, store_url=DEFAULT_STORE_URL, auth=None, force=False, user=None): """Actually installs a module into an environment""" package_name = package_version = success = output = "" def get_module_info(directory): log("Getting name") success, result = run_process(directory, ["python3", "setup.py", "--name"], sudo=user) if not success: log(format_result(result), pretty=True, lvl=error) return False package_name = str(result.output, encoding="utf8").rstrip("\n") log("Getting version") success, result = run_process(directory, ["python3", "setup.py", "--version"], sudo=user) if not success: log(format_result(result), pretty=True, lvl=error) return False package_version = str(result.output, encoding="utf8").rstrip("\n") log("Package name:", package_name, "version:", package_version) return package_name, package_version if source == "develop": log("Installing module for development") success, output = run_process( url, [ os.path.join(get_path("lib", "venv"), "bin", "python3"), "setup.py", "develop", ], sudo=user, ) if not success: log(output, lvl=verbose) return False else: return get_module_info(url) module_path = get_path("lib", "modules", ensure=True) module_info = False if source not in ("git", "link", "copy", "store"): abort(EXIT_INVALID_SOURCE) uuid = std_uuid() temporary_path = os.path.join(module_path, "%s" % uuid) log("Installing module: %s [%s]" % (url, source)) if source in ("link", "copy") and url.startswith("/"): absolute_path = url else: absolute_path = os.path.abspath(url) if source == "git": log("Cloning repository from", url) success, output = run_process(module_path, ["git", "clone", url, temporary_path], sudo=user) if not success: log("Error:", output, lvl=error) elif source == "link": log("Linking repository from", absolute_path) success, output = run_process( module_path, ["ln", "-s", absolute_path, temporary_path], sudo=user) if not success: log("Error:", output, lvl=error) elif source == "copy": log("Copying repository from", absolute_path) success, output = run_process( module_path, ["cp", "-a", absolute_path, temporary_path], sudo=user) if not success: log("Error:", output, lvl=error) elif source == "store": log("Installing wheel from store", absolute_path) log(store_url, auth) store = get_store(store_url, auth) if url not in store["packages"]: abort(EXIT_STORE_PACKAGE_NOT_FOUND) meta = store["packages"][url] package_name = meta['name'] package_version = meta['version'] venv_path = os.path.join(get_path("lib", "venv"), "bin") success, output = run_process( venv_path, ["pip3", "install", "--extra-index-url", store_url, package_name]) if source != "store": module_info = get_module_info(temporary_path) if module_info is False: log("Could not get name and version information from module.", lvl=error) return False package_name, package_version = module_info final_path = os.path.join(module_path, package_name) if os.path.exists(final_path): log("Module exists.", lvl=warn) if force: log("Removing previous version.") success, result = run_process(module_path, ["rm", "-rf", final_path], sudo=user) if not success: log("Could not remove previous version!", lvl=error) abort(50000) else: log("Not overwriting previous version without --force", lvl=error) abort(50000) log("Renaming to", final_path) os.rename(temporary_path, final_path) log("Installing module") success, output = run_process( final_path, [ os.path.join(get_path("lib", "venv"), "bin", "python3"), "setup.py", "develop", ], sudo=user, ) if not success: log(output, lvl=verbose) return False else: return package_name, package_version