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 __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 get_object(self, object_type, oid, create=True, data=None): backend_attributes = self.factory.getObjectBackendProperties(object_type) foreman_object = None if "Foreman" not in backend_attributes: self.log.warning("no foreman backend attributes found for '%s' object" % object_type) return types = self.factory.getObjectTypes()[object_type] base_type = object_type if types["base"] is True else types["extends"][0] index = PluginRegistry.getInstance("ObjectIndex") # check if the object already exists query = { '_type': base_type, backend_attributes["Foreman"]["_uuidAttribute"]: str(oid) } if types["base"] is False: query["extension"] = object_type res = index.search(query, {'dn': 1}) if len(res) == 0: if create is True: # no object found -> create one self.log.debug(">>> creating new %s" % object_type) base_dn = self.env.base if object_type == "ForemanHost": # get the IncomingDevice-Container res = index.search({"_type": "IncomingDeviceContainer", "_parent_dn": self.type_bases["ForemanHost"]}, {"dn": 1}) if len(res) > 0: base_dn = res[0]["dn"] else: base_dn = self.type_bases["ForemanHost"] elif object_type in self.type_bases: base_dn = self.type_bases[object_type] foreman_object = ObjectProxy(base_dn, base_type) uuid_extension = foreman_object.get_extension_off_attribute(backend_attributes["Foreman"]["_uuidAttribute"]) if base_type != uuid_extension and not foreman_object.is_extended_by(uuid_extension): foreman_object.extend(uuid_extension) setattr(foreman_object, backend_attributes["Foreman"]["_uuidAttribute"], str(oid)) else: # open existing object self.log.debug(">>> open existing %s with DN: %s" % (object_type, res[0]["dn"])) foreman_object = ObjectProxy(res[0]["dn"], data={object_type: {"Foreman": data}} if data is not None else None) return foreman_object
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 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 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
def handle_request(self, request_handler): foreman = PluginRegistry.getInstance("Foreman") data = loads(request_handler.request.body) self.log.debug(data) # TODO disable hook logging to file with open("foreman-log.json", "a") as f: f.write("%s,\n" % dumps(data, indent=4, sort_keys=True)) if data["event"] in ForemanHookReceiver.skip_next_event and data["object"] in ForemanHookReceiver.skip_next_event[data["event"]]: ForemanHookReceiver.skip_next_event[data["event"]].remove(data["object"]) self.log.info("skipped '%s' event for object: '%s'" % (data["event"], data["object"])) return data_keys = list(data['data'].keys()) if len(data_keys) == 1: type = data_keys[0] else: # no type given -> skipping this event as other might come with more information self.log.warning("skipping event '%s' for object '%s' as no type information is given in data: '%s'" % (data["event"], data["object"], data["data"])) return # search for real data if len(data['data'][type].keys()) == 1: # something like {data: 'host': {host: {...}}} # or {data: 'discovered_host': {host: {...}}} payload_data = data['data'][type][list(data['data'][type].keys())[0]] else: payload_data = data['data'][type] if type == "operatingsystem": with make_session() as session: foreman.sync_release_name(payload_data, session, event=data['event']) session.commit() return factory = ObjectFactory.getInstance() foreman_type = type if type == "discovered_host": type = "host" object_types = factory.getObjectNamesWithBackendSetting("Foreman", "type", "%ss" % type) object_type = object_types[0] if len(object_types) else None backend_attributes = factory.getObjectBackendProperties(object_type) if object_type is not None else None self.log.debug("Hookevent: '%s' for '%s' (%s)" % (data['event'], data['object'], object_type)) uuid_attribute = None if "Foreman" in backend_attributes: uuid_attribute = backend_attributes["Foreman"]["_uuidSourceAttribute"] \ if '_uuidSourceAttribute' in backend_attributes["Foreman"] else backend_attributes["Foreman"]["_uuidAttribute"] ForemanBackend.modifier = "foreman" update_data = {} if data['event'] in ["update", "create"] and foreman_type == "host": id = payload_data["id"] if "id" in payload_data else None try: foreman.write_parameters(id if id is not None else data['object']) except: foreman.mark_for_parameter_setting(data['object'], { "status": "created", "use_id": id }) if data['event'] == "after_commit" or data['event'] == "update" or data['event'] == "after_create" or data['event'] == "create": host = None if data['event'] == "update" and foreman_type == "host" and "mac" in payload_data and payload_data["mac"] is not None: # check if we have an discovered host for this mac index = PluginRegistry.getInstance("ObjectIndex") res = index.search({ "_type": "Device", "extension": ["ForemanHost", "ieee802Device"], "macAddress": payload_data["mac"], "status": "discovered" }, {"dn": 1}) if len(res): self.log.debug("update received for existing host with dn: %s" % res[0]["dn"]) host = ObjectProxy(res[0]["dn"]) if foreman_type != "discovered_host" and host.is_extended_by("ForemanHost"): host.status = "unknown" foreman_object = foreman.get_object(object_type, payload_data[uuid_attribute], create=host is None) if foreman_object and host: if foreman_object != host: self.log.debug("using known host instead of creating a new one") # host is the formerly discovered host, which might have been changed in GOsa for provisioning # so we want to use this one, foreman_object is the joined one, so copy the credentials from foreman_object to host if not host.is_extended_by("RegisteredDevice"): host.extend("RegisteredDevice") if not host.is_extended_by("simpleSecurityObject"): host.extend("simpleSecurityObject") host.deviceUUID = foreman_object.deviceUUID host.userPassword = foreman_object.userPassword host.otp = foreman_object.otp host.cn = foreman_object.cn # now delete the formerly joined host foreman_object.remove() foreman_object = host elif foreman_object is None and host is not None: foreman_object = host elif foreman_type == "discovered_host": self.log.debug("setting discovered state for %s" % payload_data[uuid_attribute]) if not foreman_object.is_extended_by("ForemanHost"): foreman_object.extend("ForemanHost") foreman_object.status = "discovered" if foreman_type == "host": old_build_state = foreman_object.build foreman.update_type(object_type, foreman_object, payload_data, uuid_attribute, update_data=update_data) if foreman_type == "host" and old_build_state is True and foreman_object.build is False and \ foreman_object.status == "ready": # send notification e = EventMaker() ev = e.Event(e.Notification( e.Title(N_("Host ready")), e.Body(N_("Host '%s' has been successfully build." % foreman_object.cn)), e.Icon("@Ligature/pc"), e.Timeout("10000") )) event_object = objectify.fromstring(etree.tostring(ev, pretty_print=True).decode('utf-8')) SseHandler.notify(event_object) elif data['event'] == "after_destroy": # print("Payload: %s" % payload_data) foreman.remove_type(object_type, payload_data[uuid_attribute]) # because foreman sends the after_commit event after the after_destroy event # we need to skip this event, otherwise the host would be re-created if "after_commit" not in ForemanHookReceiver.skip_next_event: ForemanHookReceiver.skip_next_event["after_commit"] = [data['object']] else: ForemanHookReceiver.skip_next_event["after_commit"].append(data['object']) # add garbage collection for skip sobj = PluginRegistry.getInstance("SchedulerService") sobj.getScheduler().add_date_job(self.cleanup_event_skipper, datetime.datetime.now() + datetime.timedelta(minutes=1), args=("after_commit", data['object']), tag='_internal', jobstore='ram') else: self.log.info("unhandled hook event '%s' received for '%s'" % (data['event'], type)) ForemanBackend.modifier = None
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]