Ejemplo n.º 1
0
 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))
Ejemplo n.º 2
0
    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()
Ejemplo n.º 3
0
Archivo: main.py Proyecto: GOsa3/gosa
    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()
Ejemplo n.º 4
0
    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
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
    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"
Ejemplo n.º 7
0
    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()
Ejemplo n.º 8
0
    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()
Ejemplo n.º 9
0
    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"
Ejemplo n.º 10
0
    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()
Ejemplo n.º 11
0
    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()
Ejemplo n.º 12
0
Archivo: main.py Proyecto: gonicus/gosa
 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))
Ejemplo n.º 13
0
    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
Ejemplo n.º 14
0
    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
Ejemplo n.º 15
0
    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
Ejemplo n.º 16
0
 def remove_test_data(dn):
     if dn is not None:
         new_domain = ObjectProxy(dn)
         new_domain.remove(True)
         new_domain.commit()
Ejemplo n.º 17
0
Archivo: main.py Proyecto: GOsa3/gosa
    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
Ejemplo n.º 18
0
    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]
Ejemplo n.º 19
0
    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]
Ejemplo n.º 20
0
    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()
Ejemplo n.º 21
0
    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