def createAddGroupIfNotExists(self, user_dn, user_name, gid_number): if user_dn is None or user_name is None or gid_number is None: return index = PluginRegistry.getInstance("ObjectIndex") res = index.search({ "_type": "PosixGroup", "gidNumber": gid_number }, {"dn": 1}) if len(res) == 0: # create group user = ObjectProxy(user_dn) group = ObjectProxy(user.get_adjusted_parent_dn(), "PosixGroup") group.cn = user_name group.description = N_("Group of user %s" % user_name) group.autoGid = False group.gidNumber = gid_number group.memberUid = [user_name] group.commit() elif len(res) == 1: group = ObjectProxy(res[0]["dn"]) if user_name not in group.memberUid: group.memberUid.append(user_name) group.commit() else: raise GosaException( C.make_error('GROUP_ID_IS_AMBIGUOUS', gid=gid_number))
def applyClientRights(self, device_uuid): # check rights acl = PluginRegistry.getInstance("ACLResolver") if not acl.check( device_uuid, "%s.%s.%s" % (self.env.domain, "command", "preUserSession"), "x"): role_name = "$$ClientDevices" # create AclRole for joining if not exists index = PluginRegistry.getInstance("ObjectIndex") res = index.search({ "_type": "AclRole", "name": role_name }, {"dn": 1}) if len(res) == 0: # create role = ObjectProxy(self.env.base, "AclRole") role.name = role_name # create rule aclentry = { "priority": 0, "scope": "sub", "actions": [{ "topic": "%s\.command\.(joinClient|preUserSession|postUserSession|getMethods)" % self.env.domain, "acl": "x", "options": {} }] } role.AclRoles = [aclentry] role.commit() # check if device has role found = False base = ObjectProxy(self.env.base) if base.is_extended_by("Acl"): for entry in base.AclSets: if entry["rolename"] == role_name and device_uuid in entry[ "members"]: found = True break else: base.extend("Acl") if found is False: acl_entry = { "priority": 0, "members": [device_uuid], "rolename": role_name } base.AclSets.append(acl_entry) base.commit()
def create_container(self): # create incoming ou if not exists index = PluginRegistry.getInstance("ObjectIndex") res = index.search({'_parent_dn': self.type_bases["ForemanHost"], '_type': 'IncomingDeviceContainer'}, {'dn': 1}) if len(res) == 0: ou = ObjectProxy(self.type_bases["ForemanHost"], "IncomingDeviceContainer") ou.commit() res = index.search({'_parent_dn': self.type_bases["ForemanHostGroup"], '_type': 'GroupContainer'}, {'dn': 1}) if len(res) == 0: ou = ObjectProxy(self.type_bases["ForemanHostGroup"], "GroupContainer") ou.commit()
def saveUserPreferences(self, userid, name, value): index = PluginRegistry.getInstance("ObjectIndex") res = index.search({'_type': 'User', 'uid': userid}, {'dn': 1}) if len(res) == 0: raise GOsaException(C.make_error("UNKNOWN_USER", target=userid)) user = ObjectProxy(res[0]['dn']) if user.guiPreferences is None: user.guiPreferences = {} user.guiPreferences[name] = value user.commit() return True
def saveUserPreferences(self, userid, name, value): index = PluginRegistry.getInstance("ObjectIndex") res = index.search({'_type': 'User', 'uid': userid}, {'dn': 1}) if len(res) == 0: raise GOsaException(C.make_error("UNKNOWN_USER", target=userid)) user = ObjectProxy(res[0]['dn']) if user.guiPreferences is None: user.guiPreferences = {} user.guiPreferences[name] = value user.commit() return True
def create_test_data(): """ Insert new data just for testing purposes """ index = PluginRegistry.getInstance("ObjectIndex") res = index.search({"dn": "dc=test,dc=example,dc=net"}, {"dn": 1}) if len(res) > 0: new_domain = ObjectProxy("dc=test,dc=example,dc=net") new_domain.remove(True) new_domain = ObjectProxy("dc=example,dc=net", "DomainComponent") new_domain.dc = "test" new_domain.description = "Domain for testing purposes" new_domain.commit() return "dc=test,dc=example,dc=net"
def __maintain_user_session(self, client_id, user_name): # save login time and system<->user references client = self.__open_device(client_id) client.gotoLastUser = user_name self.systemSetStatus(client, "+B") index = PluginRegistry.getInstance("ObjectIndex") res = index.search({"_type": "User", "uid": user_name}, {"dn": 1}) for u in res: user = ObjectProxy(u["dn"]) if not user.is_extended_by("GosaAccount"): user.extend("GosaAccount") user.gotoLastSystemLogin = datetime.datetime.now() user.gotoLastSystem = client.dn user.commit()
def __maintain_user_session(self, client_id, user_name): # save login time and system<->user references client = self.__open_device(client_id) client.gotoLastUser = user_name self.systemSetStatus(client, "+B") index = PluginRegistry.getInstance("ObjectIndex") res = index.search({"_type": "User", "uid": user_name}, {"dn": 1}) for u in res: user = ObjectProxy(u["dn"]) if not user.is_extended_by("GosaAccount"): user.extend("GosaAccount") user.gotoLastSystemLogin = datetime.datetime.now() user.gotoLastSystem = client.dn user.commit()
def create_test_data(): """ Insert new data just for testing purposes """ index = PluginRegistry.getInstance("ObjectIndex") res = index.search({"dn": "dc=test,dc=example,dc=net"}, {"dn": 1}) if len(res) > 0: new_domain = ObjectProxy("dc=test,dc=example,dc=net") new_domain.remove(True) new_domain.commit() new_domain = ObjectProxy("dc=example,dc=net", "DomainComponent") new_domain.dc = "test" new_domain.description = "Domain for testing purposes" new_domain.commit() return "dc=test,dc=example,dc=net"
def systemSetStatus(self, device_uuid, status): """ TODO """ # Write to backend index = PluginRegistry.getInstance("ObjectIndex") res = index.search({'_type': 'Device', 'deviceUUID': device_uuid}, {'_uuid': 1}) if len(res) != 1: raise ValueError(C.make_error("CLIENT_NOT_FOUND", device_uuid)) device = ObjectProxy(res[0]['_uuid']) r = re.compile(r"([+-].)") for stat in r.findall(status): if stat[1] not in mapping: raise ValueError(C.make_error("CLIENT_STATUS_INVALID", device_uuid, status=stat[1])) setattr(device, mapping[stat[1]], stat.startswith("+")) device.commit()
def test_load_from_object_database(self): # prepare some AclRoles role = ObjectProxy('ou=aclroles,dc=example,dc=net', 'AclRole') role.name = "tester" role.AclRoles = [] aclentry = { "priority": 0, "rolename": "tester" } role.AclRoles.append(aclentry) role.commit() self.__remove_objects.append('name=tester,ou=aclroles,dc=example,dc=net') with mock.patch("gosa.backend.acl.PluginRegistry.getInstance") as m_index: m_index.return_value.search.side_effect = [[ {'dn': 'name=tester,ou=aclroles,dc=example,dc=net'} ], [] # no ACLSets ] self.resolver.load_from_object_database()
def createAddGroupIfNotExists(self, user_dn, user_name, gid_number): if user_dn is None or user_name is None or gid_number is None: return index = PluginRegistry.getInstance("ObjectIndex") res = index.search({"_type": "PosixGroup", "gidNumber": gid_number}, {"dn": 1}) if len(res) == 0: # create group user = ObjectProxy(user_dn) group = ObjectProxy(user.get_adjusted_parent_dn(), "PosixGroup") group.cn = user_name group.description = N_("Group of user %s" % user_name) group.autoGid = False group.gidNumber = gid_number group.memberUid = [user_name] group.commit() elif len(res) == 1: group = ObjectProxy(res[0]["dn"]) if user_name not in group.memberUid: group.memberUid.append(user_name) group.commit() else: raise GosaException(C.make_error('GROUP_ID_IS_AMBIGUOUS', gid=gid_number))
def getDestinationIndicator(self, client_id, uid, cn_query, rotate=True): """ :param client_id: UUID of the client used to find the closest destinationIndicators :param uid: uid of the user :param cn_query: filter for destinationIndicator-cns (e.g. 'lts-% for wildcards) :param rotate: rotate the destinationIndicators (do not use the last one twice in a row) :return: FQDN of the server marked as destinationIndicator """ index = PluginRegistry.getInstance('ObjectIndex') res = index.search({'_type': 'User', 'uid': uid}, {'dn': 1}) if len(res) == 0: raise ValueError(C.make_error("USER_NOT_FOUND", user=uid, status_code=404)) user = ObjectProxy(res[0]['dn']) if rotate is False and user.destinationIndicator is not None: # nothing to rotate, take the stored one return user.destinationIndicator client = self.__open_device(client_id, read_only=True) parent_dn = client.get_adjusted_parent_dn() res = index.search({'_type': 'Device', 'extension': 'GoServer', 'cn': cn_query, '_adjusted_parent_dn': parent_dn}, {'dn': 1}) while len(res) == 0 and len(parent_dn) > len(self.env.base): parent_dn = dn2str(str2dn(parent_dn, flags=ldap.DN_FORMAT_LDAPV3)[1:]) res = index.search({'_type': 'Device', 'cn': cn_query, '_adjusted_parent_dn': parent_dn}, {'dn': 1}) if len(res) > 0: di_pool = sorted([x['dn'] for x in res]) if user.destinationIndicator is None: # nothing to rotate, take the first one user.destinationIndicator = di_pool[0] user.commit() elif rotate is True: if user.destinationIndicator in di_pool: # take the next one from list position = di_pool.index(user.destinationIndicator)+1 if position >= len(di_pool): position = 0 user.destinationIndicator = di_pool[position] user.commit() else: # nothing to rotate, take the first one user.destinationIndicator = di_pool[0] user.commit() return user.destinationIndicator return None
def joinClient(self, user, device_uuid, mac, info=None): """ TODO """ index = PluginRegistry.getInstance("ObjectIndex") uuid_check = re.compile(r"^[0-9a-f]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$", re.IGNORECASE) if not uuid_check.match(device_uuid): raise ValueError(C.make_error("CLIENT_UUID_INVALID", device_uuid)) # Handle info, if present more_info = [] if info: # Check string entries for entry in filter(lambda x: x in info, ["serialNumber", "ou", "o", "l", "description"]): if not re.match(r"^[\w\s]+$", info[entry]): raise ValueError(C.make_error("CLIENT_DATA_INVALID", device_uuid, entry=entry, data=info[entry])) more_info.append((entry, info[entry])) # Check desired device type if set if "deviceType" in info: if re.match(r"^(terminal|workstation|server|sipphone|switch|router|printer|scanner)$", info["deviceType"]): more_info.append(("deviceType", info["deviceType"])) else: raise ValueError(C.make_error("CLIENT_TYPE_INVALID", device_uuid, type=info["deviceType"])) # Check owner for presence if "owner" in info: # Take a look at the directory to see if there's such an owner DN res = index.search({'_dn': info["owner"]}, {'_dn': 1}) if len(res) == 0: raise ValueError(C.make_error("CLIENT_OWNER_NOT_FOUND", device_uuid, owner=info["owner"])) more_info.append(("owner", info["owner"])) # Generate random client key random.seed() key = ''.join(random.Random().sample(string.ascii_letters + string.digits, 32)) salt = os.urandom(4) h = hashlib.sha1(key.encode('ascii')) h.update(salt) # Take a look at the directory to see if there's already a joined client with this uuid res = index.search({'_type': 'Device', 'macAddress': mac}, {'_uuid': 1}) if len(res): raise GOtoException(C.make_error("DEVICE_EXISTS", mac)) # While the client is going to be joined, generate a random uuid and an encoded join key cn = str(uuid4()) device_key = self.__encrypt_key(device_uuid.replace("-", ""), cn + key) # Resolve manager res = index.search({'_type': 'User', 'uid': user}, {'dn': 1}) if len(res) != 1: raise GOtoException(C.make_error("USER_NOT_UNIQUE" if res else "UNKNOWN_USER", target=user)) manager = res[0]['dn'] # Create new machine entry # dn = ",".join([self.env.config.get("goto.machine-rdn", default="ou=systems"), self.env.base]) # container = ObjectProxy(dn, "DeviceContainer") # container.commit() dn = ",".join([self.env.config.get("goto.machine-rdn", default="ou=devices,ou=systems"), self.env.base]) record = ObjectProxy(dn, "Device") record.extend("RegisteredDevice") record.extend("ieee802Device") record.extend("simpleSecurityObject") record.deviceUUID = cn record.deviceKey = Binary(device_key) record.cn = cn record.manager = manager record.status_Offline = True record.macAddress = mac.encode("ascii", "ignore") record.userPassword = "******" + encode(h.digest() + salt).decode() for key, value in more_info: setattr(record, key, value) record.commit() self.log.info("UUID '%s' joined as %s" % (device_uuid, record.dn)) return [key, cn] return None
async def test_provision_host(self, m_get, m_del, m_put, m_post): """ convert a discovered host to a 'real' host """ self._test_dn = GosaTestCase.create_test_data() container = ObjectProxy(self._test_dn, "IncomingDeviceContainer") container.commit() mocked_foreman = MockForeman() m_get.side_effect = mocked_foreman.get m_del.side_effect = mocked_foreman.delete m_put.side_effect = mocked_foreman.put m_post.side_effect = mocked_foreman.post # create the discovered host + foremanHostgroup d_host = ObjectProxy(container.dn, "Device") d_host.cn = "mac00262df16a2c" d_host.extend("ForemanHost") d_host.status = "discovered" d_host.extend("ieee802Device") d_host.macAddress = "00:26:2d:f1:6a:2c" d_host.extend("IpHost") d_host.ipHostNumber = "192.168.0.1" d_host.commit() hostgroup = ObjectProxy("%s" % self._test_dn, "GroupOfNames") hostgroup.extend("ForemanHostGroup") hostgroup.cn = "Test" hostgroup.foremanGroupId = "4" hostgroup.commit() # add host to group logging.getLogger("test.foreman-integration").info("########### START: Add Host to group ############# %s" % AsyncHTTPTestCase.get_url(self, "/hooks/")) d_host = ObjectProxy("cn=mac00262df16a2c,%s" % container.dn) def check(): logging.getLogger("test.foreman-integration").info("check condition: %s, %s" % (d_host.cn, d_host.status)) return d_host.cn == "mac00262df16a2c" and d_host.status == "discovered" def check2(): logging.getLogger("test.foreman-integration").info("check2 condition: %s" % d_host.cn) return d_host.cn == "Testhost" base_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "data") with open(os.path.join(base_dir, "discovered_hosts", "mac00262df16a2c.json")) as f: mocked_foreman.register_conditional_response("http://localhost:8000/api/v2/discovered_hosts/mac00262df16a2c", "get", check, f.read()) with open(os.path.join(base_dir, "conditional", "Testhost.json")) as f: mocked_foreman.register_conditional_response("http://localhost:8000/api/v2/hosts/Testhost", "get", check2, f.read()) def activate(**kwargs): return True mocked_foreman.register_trigger("http://localhost:8000/api/v2/discovered_hosts/mac00262df16a2c", "put", activate, self.execute) with make_session() as session: assert session.query(ObjectInfoIndex.dn)\ .join(ObjectInfoIndex.properties)\ .filter(and_(KeyValueIndex.key == "cn", KeyValueIndex.value == "Testhost"))\ .count() == 0 d_host.cn = "Testhost" d_host.groupMembership = hostgroup.dn d_host.commit() logging.getLogger("test.foreman-integration").info("waiting for 2 seconds") await asyncio.sleep(2) logging.getLogger("test.foreman-integration").info("########### END: Add Host to group #############") # now move the host to the final destination d_host = ObjectProxy("cn=Testhost,ou=incoming,%s" % self._test_dn) assert d_host.status != "discovered" assert d_host.name == "Testhost" assert d_host.hostgroup_id == "4" assert d_host.is_extended_by("RegisteredDevice") is True assert len(d_host.userPassword[0]) > 0 assert d_host.deviceUUID is not None with make_session() as session: assert session.query(ObjectInfoIndex.dn) \ .join(ObjectInfoIndex.properties) \ .filter(and_(KeyValueIndex.key == "cn", KeyValueIndex.value == "Testhost")) \ .count() == 1 logging.getLogger("test.foreman-integration").info("########### START: moving host #############") d_host.move("%s" % self._test_dn) logging.getLogger("test.foreman-integration").info("########### END: moving host #############") # lets check if everything is fine in the database d_host = ObjectProxy("cn=Testhost,ou=devices,%s" % self._test_dn, read_only=True) assert d_host is not None assert d_host.status == "unknown" assert d_host.groupMembership == hostgroup.dn
def remove_test_data(dn): if dn is not None: new_domain = ObjectProxy(dn) new_domain.remove(True) new_domain.commit()
def add_host(self, hostname, base=None): # create dn if base is None: index = PluginRegistry.getInstance("ObjectIndex") # get the IncomingDevice-Container res = index.search({"_type": "IncomingDeviceContainer", "_parent_dn": self.type_bases["ForemanHost"]}, {"dn": 1}) if len(res) > 0: base = res[0]["dn"] else: base = self.type_bases["ForemanHost"] ForemanBackend.modifier = "foreman" device = self.get_object("ForemanHost", hostname, create=False) if device is None: self.log.debug("Realm request: creating new host with hostname: %s" % hostname) device = ObjectProxy(base, "Device") device.extend("ForemanHost") device.cn = hostname # commit now to get a uuid device.commit() # re-open to get a clean object device = ObjectProxy(device.dn) else: self.log.debug("Realm request: use existing host with hostname: %s" % hostname) try: if not device.is_extended_by("ForemanHost"): device.extend("ForemanHost") # Generate random client key h, key, salt = generate_random_key() # While the client is going to be joined, generate a random uuid and an encoded join key if not device.is_extended_by("RegisteredDevice"): device.extend("RegisteredDevice") if not device.is_extended_by("simpleSecurityObject"): device.extend("simpleSecurityObject") if device.deviceUUID is None: cn = str(uuid.uuid4()) device.deviceUUID = cn else: cn = device.deviceUUID device.status = "pending" device.status_InstallationInProgress = True if device.userPassword is None: device.userPassword = [] elif device.otp is not None: device.userPassword.remove(device.otp) device.userPassword.append("{SSHA}" + encode(h.digest() + salt).decode()) # make sure the client has the access rights he needs client_service = PluginRegistry.getInstance("ClientService") client_service.applyClientRights(device.deviceUUID) device.commit() self.mark_for_parameter_setting(hostname, {"status": "added"}) return "%s|%s" % (key, cn) except Exception as e: # remove created device again because something went wrong # self.remove_type("ForemanHost", hostname) self.log.error(str(e)) raise e finally: ForemanBackend.modifier = None
def joinClient(self, user, device_uuid, mac, info=None): """ TODO """ index = PluginRegistry.getInstance("ObjectIndex") uuid_check = re.compile( r"^[0-9a-f]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$", re.IGNORECASE) if not uuid_check.match(device_uuid): raise ValueError(C.make_error("CLIENT_UUID_INVALID", device_uuid)) # Handle info, if present more_info = [] if info: # Check string entries for entry in filter( lambda x: x in info, ["serialNumber", "ou", "o", "l", "description"]): if not re.match(r"^[\w\s]+$", info[entry]): raise ValueError( C.make_error("CLIENT_DATA_INVALID", device_uuid, entry=entry, data=info[entry])) more_info.append((entry, info[entry])) # Check desired device type if set if "deviceType" in info: if re.match( r"^(terminal|workstation|server|sipphone|switch|router|printer|scanner)$", info["deviceType"]): more_info.append(("deviceType", info["deviceType"])) else: raise ValueError( C.make_error("CLIENT_TYPE_INVALID", device_uuid, type=info["deviceType"])) # Check owner for presence if "owner" in info: # Take a look at the directory to see if there's such an owner DN res = index.search({'_dn': info["owner"]}, {'_dn': 1}) if len(res) == 0: raise ValueError( C.make_error("CLIENT_OWNER_NOT_FOUND", device_uuid, owner=info["owner"])) more_info.append(("owner", info["owner"])) # Generate random client key h, key, salt = generate_random_key() # Take a look at the directory to see if there's already a joined client with this uuid res = index.search( { '_type': 'Device', 'macAddress': mac, 'extension': 'RegisteredDevice' }, {'dn': 1}) if len(res) > 0: record = ObjectProxy(res[0]['dn']) for ext in ["simpleSecurityObject", "ieee802Device"]: if not record.is_extended_by(ext): record.extend(ext) if record.is_extended_by("ForemanHost") and record.otp is not None: record.otp = None record.userPassword = [ "{SSHA}" + encode(h.digest() + salt).decode() ] for k, value in more_info: setattr(record, k, value) cn = record.deviceUUID record.status_Online = False record.status_Offline = True record.status_InstallationInProgress = False record.commit() self.log.info("UUID '%s' joined as %s" % (device_uuid, record.dn)) else: # While the client is going to be joined, generate a random uuid and an encoded join key cn = str(uuid4()) device_key = encrypt_key(device_uuid.replace("-", ""), cn + key) # Resolve manager res = index.search({'_type': 'User', 'uid': user}, {'dn': 1}) if len(res) != 1: raise GOtoException( C.make_error("USER_NOT_UNIQUE" if res else "UNKNOWN_USER", target=user)) manager = res[0]['dn'] # Create new machine entry dn = ",".join([ self.env.config.get("goto.machine-rdn", default="ou=systems"), self.env.base ]) record = ObjectProxy(dn, "Device") record.extend("RegisteredDevice") record.extend("ieee802Device") record.extend("simpleSecurityObject") record.deviceUUID = cn record.deviceKey = Binary(device_key) record.cn = "mac%s" % mac.replace(":", "") record.manager = manager record.status_Offline = True record.macAddress = mac.encode("ascii", "ignore") record.userPassword = [ "{SSHA}" + encode(h.digest() + salt).decode() ] for k, value in more_info: setattr(record, k, value) record.commit() self.log.info("UUID '%s' joined as %s" % (device_uuid, record.dn)) # make sure the client has the access rights he needs self.applyClientRights(cn) return [key, cn]
def joinClient(self, user, device_uuid, mac, info=None): """ TODO """ index = PluginRegistry.getInstance("ObjectIndex") uuid_check = re.compile(r"^[0-9a-f]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$", re.IGNORECASE) if not uuid_check.match(device_uuid): raise ValueError(C.make_error("CLIENT_UUID_INVALID", uuid=device_uuid)) # Handle info, if present more_info = [] extensions = ["simpleSecurityObject", "ieee802Device"] if info: # Check string entries for entry in filter(lambda x: x in info, ["serialNumber", "ou", "o", "l", "description"]): if not re.match(r"^[\w\s]+$", info[entry]): raise ValueError(C.make_error("CLIENT_DATA_INVALID", client=device_uuid, entry=entry, data=info[entry])) more_info.append((entry, info[entry])) if "ipHostNumber" in info: if re.match(r"^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}", info["ipHostNumber"]): more_info.append(("ipHostNumber", info["ipHostNumber"])) extensions.append("IpHost") else: raise ValueError(C.make_error("CLIENT_DATA_INVALID", client=device_uuid, entry="ipHostNumber", data=info["ipHostNumber"])) if "hostname" in info: allowed = re.compile("(?!-)[A-Z\d-]{1,63}(?<!-)$", re.IGNORECASE) if all(allowed.match(x) for x in info["hostname"].split(".")): more_info.append(("description", info["hostname"])) # Check desired device type if set if "deviceType" in info: if re.match(r"^(terminal|workstation|server|sipphone|switch|router|printer|scanner)$", info["deviceType"]): more_info.append(("deviceType", info["deviceType"])) else: raise ValueError(C.make_error("CLIENT_TYPE_INVALID", client=device_uuid, type=info["deviceType"])) # Check owner for presence if "owner" in info: # Take a look at the directory to see if there's such an owner DN res = index.search({'_dn': info["owner"]}, {'_dn': 1}) if len(res) == 0: raise ValueError(C.make_error("CLIENT_OWNER_NOT_FOUND", client=device_uuid, owner=info["owner"])) more_info.append(("owner", info["owner"])) # Generate random client key h, key, salt = generate_random_key() # Take a look at the directory to see if there's already a joined client with this uuid res = index.search({'_type': 'Device', 'macAddress': mac, 'extension': 'RegisteredDevice'}, {'dn': 1}) if len(res) > 0: record = ObjectProxy(res[0]['dn']) for ext in extensions: if not record.is_extended_by(ext): record.extend(ext) if record.is_extended_by("ForemanHost") and record.otp is not None: record.otp = None record.userPassword = ["{SSHA}" + encode(h.digest() + salt).decode()] for k, value in more_info: setattr(record, k, value) cn = record.deviceUUID record.status_Online = False record.status_Offline = True record.status_InstallationInProgress = False record.commit() self.log.info("UUID '%s' joined as %s" % (device_uuid, record.dn)) else: # While the client is going to be joined, generate a random uuid and an encoded join key cn = str(uuid4()) device_key = encrypt_key(device_uuid.replace("-", ""), cn + key) # Resolve manager res = index.search({'_type': 'User', 'uid': user}, {'dn': 1}) if len(res) != 1: raise GOtoException(C.make_error("USER_NOT_UNIQUE" if res else "UNKNOWN_USER", user=user)) manager = res[0]['dn'] # Create new machine entry dn = ",".join([self.env.config.get("goto.machine-rdn", default="ou=systems"), self.env.base]) record = ObjectProxy(dn, "Device") record.extend("RegisteredDevice") for ext in extensions: record.extend(ext) record.deviceUUID = cn record.deviceKey = Binary(device_key) record.cn = "mac%s" % mac.replace(":", "") record.manager = manager record.status_Offline = True record.macAddress = mac.encode("ascii", "ignore") record.userPassword = ["{SSHA}" + encode(h.digest() + salt).decode()] for k, value in more_info: setattr(record, k, value) record.commit() self.log.info("UUID '%s' joined as %s" % (device_uuid, record.dn)) # make sure the client has the access rights he needs self.applyClientRights(cn) return [key, cn]
def applyClientRights(self, device_uuid): # check rights acl = PluginRegistry.getInstance("ACLResolver") allowed_commands = [ 'joinClient', 'preUserSession', 'postUserSession', 'getMethods', 'getDestinationIndicator' ] missing = [x for x in allowed_commands if not acl.check(device_uuid, "%s.%s.%s" % (self.env.domain, "command", x), "x")] reload = False role_name = "$$ClientDevices" if len(missing) > 0: # create AclRole for joining if not exists index = PluginRegistry.getInstance("ObjectIndex") res = index.search({"_type": "AclRole", "name": role_name}, {"dn": 1}) if len(res) == 0: # create role = ObjectProxy(self.env.base, "AclRole") role.name = role_name else: role = ObjectProxy(res[0]['dn']) # create rule aclentry = { "priority": 0, "scope": "sub", "actions": [ { "topic": "%s\.command\.(%s)" % (self.env.domain, "|".join(allowed_commands)), "acl": "x", "options": {} } ]} role.AclRoles = [aclentry] role.commit() reload = True # check if device has role found = False base = ObjectProxy(self.env.base) if base.is_extended_by("Acl"): for entry in base.AclSets: if entry["rolename"] == role_name and device_uuid in entry["members"]: found = True break else: base.extend("Acl") if found is False: acl_entry = {"priority": 0, "members": [device_uuid], "rolename": role_name} base.AclSets.append(acl_entry) if self.env.mode != "proxy": self.__acl_change_checks.append({"role": role_name, "member": device_uuid}) base.commit() reload = True if reload is True: # reload acls to make sure that they are applied in the current instance acl.load_acls()
def test_sync_type(self, m_get, m_del, m_put, m_post): mocked_foreman = MockForeman() m_get.side_effect = mocked_foreman.get m_del.side_effect = mocked_foreman.delete m_put.side_effect = mocked_foreman.put m_post.side_effect = mocked_foreman.post # check that there are not Objects yet index = PluginRegistry.getInstance("ObjectIndex") host_query = { '_type': 'Device', 'cn': { 'in_': [ 'smitty.intranet.gonicus.de', 'gosa.test.intranet.gonicus.de' ] }, 'extension': 'ForemanHost' } hostgroup_query = { '_type': 'GroupOfNames', 'extension': 'ForemanHostGroup', 'cn': { 'in_': ['Bereitstellen von smitty.intranet.gonicus.de', 'VM', 'Test'] }, } discovered_host_query = { '_type': 'Device', 'extension': 'ForemanHost', 'status': 'discovered' } res = index.search(host_query, {'dn': 1}) assert len(res) == 0 res = index.search(hostgroup_query, {'dn': 1}) assert len(res) == 0 res = index.search(discovered_host_query, {'dn': 1}) assert len(res) == 0 self.foreman.sync_type("ForemanHostGroup") logging.getLogger("gosa.backend.objects.index").info( "waiting for index update") logging.getLogger("gosa.backend.objects.index").info("checking index") res = index.search(hostgroup_query, {'dn': 1}) self.dns_to_delete.extend([x['dn'] for x in res]) assert len(res) == 3 res = index.search(host_query, {'dn': 1}) assert len(res) == 0 res = index.search(discovered_host_query, {'dn': 1}) assert len(res) == 0 self.foreman.sync_type("ForemanHost") res = index.search(host_query, {'dn': 1}) self.dns_to_delete = [x['dn'] for x in res] assert len(res) == 2 res = index.search(hostgroup_query, {'dn': 1}) self.dns_to_delete.extend([x['dn'] for x in res]) assert len(res) == 3 res = index.search(discovered_host_query, {'dn': 1}) assert len(res) == 0 self.foreman.sync_type("ForemanHost", "discovered_hosts") res = index.search(host_query, {'dn': 1}) assert len(res) == 2 host_dns = [x['dn'] for x in res] self.dns_to_delete = host_dns res = index.search(hostgroup_query, {'dn': 1}) assert len(res) == 3 # delete the groups first self.dns_to_delete = [x['dn'] for x in res] + self.dns_to_delete res = index.search(discovered_host_query, {'dn': 1}) assert len(res) == 1 self.dns_to_delete.extend([x['dn'] for x in res]) # testing relationships: delete host from group group = ObjectProxy("cn=VM,ou=groups,dc=example,dc=net") assert len(group.member) == 2 group.member = host_dns[0:1] group.commit() time.sleep(0.1) # check if the change has been send to foreman assert m_put.called is True args, kwargs = m_put.call_args data = loads(kwargs["data"]) assert "hostgroup_id" in data["host"] assert data["host"]["hostgroup_id"] is None m_put.reset_mock() # add it back group = ObjectProxy("cn=VM,ou=groups,dc=example,dc=net") assert len(group.member) == 1 group.member.append(host_dns[1]) group.commit() # as the mocked foreman backend still sends the original hostgroup_id, there is no change here # and therefore nothing is changed to the backend assert m_put.called is False # args, kwargs = m_put.call_args # data = loads(kwargs["data"]) # assert "hostgroup_id" in data["host"] # assert data["host"]["hostgroup_id"] == "2" # now delete from the host side host = ObjectProxy(host_dns[1]) host.groupMembership = None host.commit() time.sleep(0.1) assert m_put.called is True args, kwargs = m_put.call_args data = loads(kwargs["data"]) assert "hostgroup_id" in data["host"] assert data["host"]["hostgroup_id"] is None