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", 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 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 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]