예제 #1
0
    def add_groups_to_group(self, principalids, gid):
        """Method to add user to a group.
           @param principalids: Group ID list.
           @param gid: Group ID.
           @return: Result object with operation status and data. Here data is
           set to None.
        """
        # Filter irregular input objects from principalids
        principalids = filter(is_valid_uuid, principalids)

        if not principalids:
            logging.debug(TSApiWrapper.NO_OPERATION_NEEDED)
            return Result(Constants.OPERATION_SUCCESS)

        success_msg = "Successfully added groups to group."
        failure_msg = "Failed to add groups to the group."

        try:
            response = self.session.post(
                TSApiWrapper.ADD_GROUPS_TO_GROUP.format(
                    hostport=self.hostport
                ),
                data={
                    "principalids": json.dumps(principalids),
                    "groupid": gid,
                },
            )
            if response.status_code == httplib.NO_CONTENT:
                logging.debug(success_msg)
                return Result(Constants.OPERATION_SUCCESS)
            logging.error(failure_msg)
            return Result(Constants.OPERATION_FAILURE, response)
        except Exception as e:
            logging.error(e.message)
            return Result(Constants.OPERATION_FAILURE, e)
예제 #2
0
    def isOfType(self,
                 basedn,
                 ldap_type,
                 user_identifier,
                 email_identifier,
                 member_str,
                 authdomain_identifier):
        """Fetches if the node represented by basedn is of type user or group.

        :param basedn: Distinguished name for the base in LDAP System.
        :return: Result object with operation status and data. Here data is
        EntityType.User for User, EntityType.Group for Group, None for DC
        and others.
        """
        result = self.dn_to_obj(basedn,
                                ldap_type,
                                user_identifier,
                                email_identifier,
                                member_str,
                                authdomain_identifier)
        if result.status == Constants.OPERATION_SUCCESS:
            if result.data is not None:
                return Result(Constants.OPERATION_SUCCESS, result.data.type)
            return Result(Constants.OPERATION_SUCCESS)

        if result.status == Constants.AUTHENTICATION_FAILURE:
            return Result(Constants.AUTHENTICATION_FAILURE)

        return Result(Constants.OPERATION_FAILURE)
예제 #3
0
    def sync_user(
        self,
        name,
        display_name,
        usertype=None,
        password=None,
        properties=None,
        groups=None,
        upsert_user=False
    ):
        """Creates new user and adds it to TS system.
           @param name: Name of the new user.
           @param display_name: Name to be displayed in TS system.
           @param usertype: Type of user to create.
           @param password: Password to be set for the user.
           @param properties: Extra properties related to the user like
           user email etc.
           @param groups: List of group ids the user belongs to.
           @param upsert_user: Upsert the users if true else only create.
           @return: Result object with operation status and data. Here data is
           set to None.
        """
        params = {"name": name, "displayname": display_name}
        if usertype is not None:
            params["usertype"] = usertype
        # If Password is not passed generate a random string as password.
        # Used in cases where authentication is done by an external agent.
        if password is None:
            password = password_gen()
        params["password"] = password
        if properties is not None:
            params["properties"] = json.dumps(properties)
        if groups is not None:
            params["groups"] = json.dumps(groups)

        try:
            if upsert_user:
                response = self.session.post(
                    TSApiWrapper.UPSERT_USER.format(hostport=self.hostport),
                    data=params,
                )
            else:
                response = self.session.post(
                    TSApiWrapper.CREATE_USER.format(hostport=self.hostport),
                    data=params,
                )
            if response.status_code == httplib.OK:
                logging.debug("New user %s added.", name)
                return Result(Constants.OPERATION_SUCCESS)
            if ((upsert_user and response.status_code == httplib.NO_CONTENT) or
                    ((not upsert_user)
                     and response.status_code == httplib.CONFLICT)):
                logging.debug("User %s already exists.", name)
                return Result(Constants.USER_ALREADY_EXISTS)
            logging.error("New user %s not added. Response: %s", name,
                          response.text)
            return Result(Constants.OPERATION_FAILURE, response)
        except Exception as e:
            logging.error(e.message)
            return Result(Constants.OPERATION_FAILURE, e)
예제 #4
0
    def login(self, hostport, username, password):
        """Logs the user into LDAP system.

        :param hostport: Complete URL of the LDAP System to connect to
        ldap(s)://<host>:<port>
        :param username: Username for the user.
        :param password: Password for the user.
        :return: Result object with operation status and data. Here data is
        set to None.
        """
        # Store for future use.
        if hostport.startswith("ldap://"):
            self.__protocol = "ldap://"
        else:
            self.__protocol = "ldaps://"
        self.__username = username
        self.__password = password

        try:
            conn = self.bind_to(hostport, self.__username, self.__password)
            logging.debug(LDAPApiWrapper.USER_AUTHENTICATION_SUCCESS)
            self.connection_pool["default"] = conn
            return Result(Constants.OPERATION_SUCCESS)
        except ldap.INVALID_CREDENTIALS as e:
            logging.error("Invalid credentials provided.")
            return Result(Constants.OPERATION_FAILURE, e)
        except ldap.SERVER_DOWN as e:
            logging.error("Server down.")
            return Result(Constants.OPERATION_FAILURE, e)
        except ldap.LDAPError as e:
            logging.error("LDAP connection error.")
            return Result(Constants.OPERATION_FAILURE, e)
        except Exception as e:
            logging.error(e.message)
            return Result(Constants.OPERATION_FAILURE, e)
예제 #5
0
    def list_member_dns(self, basedn, scope=None, filter_str=None):
        """Fetches list of DNs of member entities recursively. This includes
        both users and groups.

        :param basedn: Distinguished name for the base in LDAP System.
        :param filter_str: String to filter the Distinguished Names.
        :return: Result object with operation status and data. Here data is
        a list of member DNs.
        """
        entity_list = []
        attr_list = []

        if scope is None:
            scope = ldap.SCOPE_SUBTREE
        # if filter_str is None:
        #     filter_str = "(cn=*)"
        if filter_str is None:
            filter_str = LDAPApiWrapper.LIST_MEM_FILTER

        logging.debug("Base DN: %s", basedn)
        logging.debug("Filter String: %s", filter_str)
        try:
            item_list = self.get_connection_to(basedn).search_s(
                basedn, int(scope), filter_str, attr_list
            )
        except Exception as e:
            return Result(Constants.OPERATION_FAILURE, e)

        msg = "List of DNs in Base DN for input filter:\n"
        for dn, _ in item_list:
            if dn:
                entity_list.append(dn)
                msg += "==> [{}]\n".format(dn)
        logging.debug(msg)
        return Result(Constants.OPERATION_SUCCESS, entity_list)
예제 #6
0
    def add_user_to_group(self, uid, gid):
        """Method to add user to a group.
           @param uid: User ID.
           @param gid: Group ID.
           @return: Result object with operation status and data. Here data is
           set to None.
        """
        if uid is None:
            logging.debug(TSApiWrapper.NO_OPERATION_NEEDED)
            return Result(Constants.OPERATION_SUCCESS)

        success_msg = "Successfully added the user to group."
        failure_msg = "Failed to add user to the group."

        try:
            response = self.session.post(
                TSApiWrapper.ADD_USER_TO_GROUP.format(hostport=self.hostport),
                data={"userid": uid, "groupid": gid},
            )
            if response.status_code == httplib.NO_CONTENT:
                logging.debug(success_msg)
                return Result(Constants.OPERATION_SUCCESS)
            logging.error(failure_msg)
            return Result(Constants.OPERATION_FAILURE, response)
        except Exception as e:
            logging.error(e.message)
            return Result(Constants.OPERATION_FAILURE, e)
예제 #7
0
    def _get_batched_entities(self, entity, offset, batchsize):
        """Gets entities in TS system.
           @entity: Entity to fetch User/Group
           @batchsize: Number of entities to fetch
           @offset: Batch offset
           @return: Result object with operation status and data. Here data is
           a list of (user/group)s in the TS system as EntityProperty objects.
        """
        entity_list = []

        success_msg = "Successfully returning {} list.".format(entity)
        failure_msg = "Failed to procure {} list.".format(entity)
        end_point = TSApiWrapper.GET_MEMBERS
        if entity == EntityType.GROUP:
            params = {"type": "USER_GROUP"}
        elif entity == EntityType.USER:
            params = {"type": "USER"}
        else:
            logging.error(TSApiWrapper.UNKNOWN_ENTITY_TYPE)
            return Result(Constants.OPERATION_FAILURE)
        params["batchsize"] = batchsize
        params["offset"] = offset

        try:
            response = self.session.get(
                   end_point.format(hostport=self.hostport), params=params
                   )
            if response.status_code == httplib.OK:
                responseDict = json.loads(response.text)
                for item in responseDict["headers"]:
                    assert "id" in item, "id not in item"
                    assert "name" in item, ("name not present for {}"
                        .format(
                            item["id"]
                        ))
                    assert "type" in item, ("type not present for {} {}"
                        .format(
                            item["id"], item["name"]
                        ))
                    ent_property_obj = EntityProperty(
                        item["id"], item["name"], item["type"]
                    )
                    entity_list.append(ent_property_obj)
                logging.debug(success_msg)
                is_last_batch = responseDict["isLastBatch"]
                return Result(Constants.OPERATION_SUCCESS,
                              (entity_list, is_last_batch))
            logging.error(failure_msg)
            return Result(Constants.OPERATION_FAILURE, response)
        except Exception as e:
            logging.error(e.message)
            return Result(Constants.OPERATION_FAILURE, e)
예제 #8
0
    def sync_group(
        self,
        name,
        display_name,
        grouptype=None,
        description=None,
        privileges=None,
        upsert_group=False
    ):
        """Creates new group and adds it to TS system.
           @param name: Name of the new group.
           @param display_name: Display name of the group.
           @param grouptype: Type of group to create.
           @param description: Description of the new group.
           @param privileges: Privileges provided to the group.
           @param upsert_group: Upsert the groups if true else only create.
           @return: Result object with operation status and data. Here data is
           set to None.
        """
        params = {"name": name, "display_name": display_name}
        if grouptype is not None:
            params["grouptype"] = grouptype
        if description is not None:
            params["description"] = description
        if privileges is not None:
            params["privileges"] = json.dumps(privileges)

        try:
            if upsert_group:
                response = self.session.post(
                    TSApiWrapper.UPSERT_GROUP.format(hostport=self.hostport),
                    data=params,
                )
            else:
                response = self.session.post(
                    TSApiWrapper.CREATE_GROUP.format(hostport=self.hostport),
                    data=params,
                )
            if response.status_code == httplib.OK:
                logging.debug("New group %s added.", name)
                return Result(Constants.OPERATION_SUCCESS)
            if ((upsert_group and response.status_code == httplib.NO_CONTENT) or
                    ((not upsert_group)
                     and response.status_code == httplib.CONFLICT)):
                logging.debug("Group %s already exists.", name)
                return Result(Constants.GROUP_ALREADY_EXISTS)
            logging.error("New group %s not added. Response: %s", name,
                          response.text)
            return Result(Constants.OPERATION_FAILURE, response)
        except Exception as e:
            logging.error(e.message)
            return Result(Constants.OPERATION_FAILURE, e)
예제 #9
0
 def info(self):
     """Gets the session info object.
        @return: Returns map of session info object.
     """
     try:
         response = self.session.get(
             TSApiWrapper.INFO.format(hostport=self.hostport))
         if response.status_code == http.client.OK:
             logging.debug("Info object procured.")
             return Result(Constants.OPERATION_SUCCESS,
                           json.loads(response.text))
         logging.error("Unable to obtain Info object.")
         return Result(Constants.OPERATION_FAILURE)
     except Exception as e:
         logging.error(e.message)
         return Result(Constants.OPERATION_FAILURE, e)
예제 #10
0
    def _list_entities(self, entity, batchsize):
        """Lists (user/group)s in TS system.
           @param entity: Entity to fetch User/Group.
           @param batchsize: Batch size for pagination.
           @return: Result object with operation status and data. Here data is
           a list of (user/group)s in the TS system as EntityProperty objects.
        """
        entity_list = []
        success_msg = "Successfully returning {} list.".format(entity)
        failure_msg = "Failed to procure {} list.".format(entity)
        if batchsize == 0 or batchsize is None:
            batchsize = 200

        is_last_batch = False
        batch_count = 0
        # Paginate the calls to /list
        while not is_last_batch:
            offset = batchsize * batch_count
            result_obj = self._get_batched_entities(entity, offset, batchsize)
            if result_obj.status == Constants.OPERATION_SUCCESS:
                ent_property_obj, is_last_batch = result_obj.data
                entity_list.extend(ent_property_obj)
                batch_count += 1
            else:
                batch_fail_msg = " Failed at batch number: {}".format(
                    batch_count
                    )
                logging.error(failure_msg + batch_fail_msg)
                return result_obj
        logging.debug(success_msg)
        return Result(Constants.OPERATION_SUCCESS, entity_list)
예제 #11
0
    def _get_entityid_with_name(self, entity, name):
        """Returns user/group id given the unique name of the user/group.
           @param entity: EntityType user/group.
           @param name: Unique name of the user/group.
           @return: Result object with operation status and data. Here data is
           ID if user/group is present in the system else None.
        """
        if entity == EntityType.GROUP:
            entity_list = self.list_groups()
        elif entity == EntityType.USER:
            entity_list = self.list_users()
        else:
            logging.error(TSApiWrapper.UNKNOWN_ENTITY_TYPE)
            return Result(Constants.OPERATION_FAILURE)

        for ent in entity_list.data:
            if ent.name == name:
                return Result(Constants.OPERATION_SUCCESS, ent.id)
        logging.debug("Such an entity doesn't exist.")
        return Result(Constants.OPERATION_FAILURE)
예제 #12
0
    def _list_entities_in_group(self, entity, gid):
        """Method used to list member users/groups of a group.
           @param entity: EntityType user/group.
           @param gid: Group ID.
           @return: Result object with operation status and data. Here data is
           list of EntityProperty objects.
        """
        entity_list = []

        if entity == EntityType.GROUP:
            end_point = TSApiWrapper.LIST_GROUPS_IN_A_GROUP
        elif entity == EntityType.USER:
            end_point = TSApiWrapper.LIST_USERS_IN_A_GROUP
        else:
            logging.error(TSApiWrapper.UNKNOWN_ENTITY_TYPE)
            return Result(Constants.OPERATION_FAILURE)

        success_msg = "Successfully listed the {}s in the group.".format(
            entity
        )
        failure_msg = "Failed to list the {}s the group.".format(entity)

        try:
            response = self.session.get(
                end_point.format(hostport=self.hostport, groupid=gid)
            )
            if response.status_code == httplib.OK:
                for item in json.loads(response.text):
                    ent_property_obj = EntityProperty(
                        item["header"]["id"],
                        item["header"]["name"],
                        item["header"]["type"],
                    )
                    entity_list.append(ent_property_obj)
                logging.debug(success_msg)
                return Result(Constants.OPERATION_SUCCESS, entity_list)
            logging.error(failure_msg)
            return Result(Constants.OPERATION_FAILURE, response)
        except Exception as e:
            logging.error(e.message)
            return Result(Constants.OPERATION_FAILURE, e)
예제 #13
0
 def login(self, hostport, username, password):
     """Logs the user into the system.
        @param hostport: Complete URL of the TS system to connect to
        http(s)://<host>:<port>
        @param username: Username for the user.
        @param password: Password for the user.
        @return: Result object with operation status and data. Here data is
        set to None.
     """
     try:
         self.hostport = hostport
         response = self.session.post(
             TSApiWrapper.LOGIN.format(hostport=self.hostport),
             data={"username": username,
                   "password": password},
         )
         if response.status_code == httplib.OK:
             self.authenticated = True
             logging.debug(TSApiWrapper.USER_AUTHENTICATION_SUCCESS)
             return Result(Constants.OPERATION_SUCCESS)
         logging.error("Login failure.")
         return Result(Constants.OPERATION_FAILURE, response)
     except requests.ConnectionError as e:
         logging.error("Error in network.")
         return Result(Constants.OPERATION_FAILURE, e)
     except requests.HTTPError as e:
         logging.error("Error in HTTP connection.")
         return Result(Constants.OPERATION_FAILURE, e)
     except requests.Timeout as e:
         logging.error("Timeout error.")
         return Result(Constants.OPERATION_FAILURE, e)
     except Exception as e:
         logging.error(e.message)
         return Result(Constants.OPERATION_FAILURE, e)
예제 #14
0
 def wrapper(self, *args, **kwargs):
     """Wrapper to wrap the function in.
        @param self: The self pointer to class instance.
        @param *args: List of arguments being passed to the fucntion which
        is being wrapped.
        @param **kwargs: Dictionary being passed to the fucntion which is
        being wrapped.
        @return: Returns the original function.
     """
     if not self._is_authenticated():
         logging.error(TSApiWrapper.USER_AUTHENTICATION_FAILURE)
         return Result(Constants.AUTHENTICATION_FAILURE)
     return function(self, *args, **kwargs)
예제 #15
0
    def _delete_entities(self, entity, entity_list):
        """Deletes users/groups given the id list.
           @param entity: EntityType that is being deleted.
           @param entity_list: List of entity IDs to delete.
           @return: Result object with operation status and data. Here data is
           set to None.
        """
        # Filter irregular input objects from entity_list
        entity_list = filter(is_valid_uuid, entity_list)

        if not entity_list:
            logging.debug(TSApiWrapper.NO_OPERATION_NEEDED)
            return Result(Constants.OPERATION_SUCCESS)

        success_msg = "Successfully deleted {}(s).".format(entity)
        failure_msg = "Failed to delete {}(s).".format(entity)
        if entity == EntityType.GROUP:
            end_point = TSApiWrapper.DELETE_GROUPS
        elif entity == EntityType.USER:
            end_point = TSApiWrapper.DELETE_USERS
        else:
            logging.error(TSApiWrapper.UNKNOWN_ENTITY_TYPE)
            return Result(Constants.OPERATION_FAILURE)

        try:
            response = self.session.post(
                end_point.format(hostport=self.hostport),
                data={"ids": json.dumps(entity_list)},
            )
            if response.status_code == httplib.NO_CONTENT:
                logging.debug(success_msg)
                return Result(Constants.OPERATION_SUCCESS)
            logging.error(failure_msg)
            return Result(Constants.OPERATION_FAILURE, response)
        except Exception as e:
            logging.error(e.message)
            return Result(Constants.OPERATION_FAILURE, e)
예제 #16
0
    def dn_to_obj(self,
                  basedn,
                  ldap_type=None,
                  user_identifier=None,
                  email_identifier=None,
                  authdomain_identifier=None,
                  member_str=None,
                  log_entities=True):
        """Fetches if the node represented by basedn is of type user or group.

        :param basedn: Distinguished name for the base in LDAP System.
        :param log_entities: Flag if entity logging should be done.
        :param user_identifier: Identifier key to be used for user name.
        :param authdomain_identifier: Custom domain name to be appended to
        user identifier key for user name.
        :param email_identifier: Identifier key to be used for user email.
        :return: Result object with operation status and data. Here data is
        a LDAP user/group object corresponding to the basedn. None for others.
        """
        components = ldap.dn.explode_dn(basedn)
        # LDAP doesn't provide an information object when queried for just the
        # domain component.
        if (components == [] or components[0].startswith("DC")
                or components[0].startswith("dc")):
            return Result(Constants.OPERATION_SUCCESS)

        filter_str = "({})".format(components[0])

        result = self.list_groups(basedn, ldap_type, user_identifier, 2,
                                  filter_str, log_entities, member_str)
        if result.status == Constants.OPERATION_SUCCESS and result.data:
            return Result(Constants.OPERATION_SUCCESS, result.data[0])
        if result.status == Constants.AUTHENTICATION_FAILURE:
            return Result(Constants.AUTHENTICATION_FAILURE)

        result = self.list_users(basedn, ldap_type, user_identifier,
                                 email_identifier, 2, filter_str, log_entities,
                                 authdomain_identifier, member_str)
        if result.status == Constants.OPERATION_SUCCESS and result.data:
            return Result(Constants.OPERATION_SUCCESS, result.data[0])
        if result.status == Constants.AUTHENTICATION_FAILURE:
            return Result(Constants.AUTHENTICATION_FAILURE)

        return Result(Constants.OPERATION_SUCCESS)
예제 #17
0
    def list_users(
        self,
        basedn,
        ldap_type,
        user_identifier,
        email_identifier,
        scope=None,
        filter_str=None,
        log_entities=True,
        authdomain_identifier=None,
        member_str=None
    ):
        """Fetches users present in LDAP System.

        :param basedn: Distinguished name for the base in LDAP System.
        :param scope: Scope to limit the search to (0:base, 1:one, 2:tree).
        :param filter_str: Filter string to apply to search.
        :param log_entities: Flag if entity logging should be done.
        :param user_identifier: Identifier key to be used for user name.
        :param authdomain_identifier: Custom domain name to be appended to
        user identifier key for user name.
        :param email_identifier: Identifier key to be used for user email.
        :return: Result object with operation status and data. Here data is
        a list of User objects present in LDAP System.
        """
        if LDAPApiWrapper.OPEN_LDAP == ldap_type:
            if user_identifier is None:
                attr_uid = LDAPApiWrapper.OPEN_LDAP_ATTR_UID
            else:
                attr_uid = user_identifier
            user_filter = LDAPApiWrapper.USER_FILTER_OPEN_LDAP
        else:
            attr_uid = LDAPApiWrapper.AD_ATTR_UID
            user_filter = LDAPApiWrapper.USER_FILTER_AD

            attr_list = [
                attr_uid,
                LDAPApiWrapper.ATTR_UPN,
                LDAPApiWrapper.ATTR_NAME,
                LDAPApiWrapper.ATTR_DISPLAY_NAME,
                LDAPApiWrapper.ATTR_CN,
                LDAPApiWrapper.ATTR_EMAIL,
            ]
            entity_list = []

        # Add user_identifier to attr_list if not already in retrieval list.
        if user_identifier is not None and user_identifier not in attr_list:
            attr_list.append(user_identifier)
        # Add email_identifier to attr_list if not already in retrieval list.
        if email_identifier is not None and email_identifier not in attr_list:
            attr_list.append(email_identifier)

        if scope is None:
            scope = ldap.SCOPE_SUBTREE

        # If filter string is not specified we use default user filters.
        # If a filter is being provided we need to stitch together the
        # user given filter with default filters to fetch specific users.
        if filter_str is None:
            filter_str = user_filter
        else:
            filter_str = LDAPApiWrapper.FILTER_ADD.format(
                user_filter, filter_str
            )

        filter_str = self._sanitize_filters(filter_str)

        if log_entities:
            logging.debug("Base DN: %s", basedn)
            logging.debug("Filter String: %s", filter_str)

        try:
            item_list = self.get_connection_to(basedn).search_s(
                basedn, int(scope), filter_str, attr_list
            )
        except Exception as e:
            return Result(Constants.OPERATION_FAILURE, e)

        msg = "List of DNs retrieved from LDAP server:\n"
        for dn, entry in item_list:
            # Skip entities which are None
            #
            # NOTE: This becomes necessary because when we get the list of
            # entities back we also have a reference entity describing where
            # it was fetched from which has a None value for dn.
            #
            # This filtering helps us skip these metadata information.
            if dn is None:
                continue
            msg += "==> [{},{}]\n".format(dn, entry)

            name = None

            # Entity specific attributes and handling of unique name attribute
            # if defaults are not present.
            # Default attributes to be used as unique names.
            if user_identifier in entry:
                name = (
                    entry[user_identifier][0].decode('utf-8')
                    + self._get_domain_name(
                        dn,
                        user_identifier,
                        authdomain_identifier
                    )
                )
                msg += (
                    "Using `" + user_identifier + "` for"
                    + " constructing unique name.\n"
                )

            elif LDAPApiWrapper.AD_ATTR_UID in entry:
                # If userPrincipalName not present then use sAMAccountName to
                # construct user name.
                # For sAMAccountName, also append domain name in user name.
                name = (
                    entry[LDAPApiWrapper.AD_ATTR_UID][0]
                    + self._get_domain_name(
                        dn,
                        LDAPApiWrapper.AD_ATTR_UID,
                        authdomain_identifier
                    )
                )
                msg += (
                    "Using `sAMAccountName` for"
                    + " constructing unique name.\n"
                )

            if entry.has_key(LDAPApiWrapper.ATTR_DISPLAY_NAME):
                display_name = entry[LDAPApiWrapper.ATTR_DISPLAY_NAME][0]
            elif entry.has_key(LDAPApiWrapper.ATTR_NAME):
                display_name = entry[LDAPApiWrapper.ATTR_NAME][0]
            elif entry.has_key(LDAPApiWrapper.ATTR_CN):
                display_name = entry[LDAPApiWrapper.ATTR_CN][0]
            else:
                display_name = name

            email = None
            if email_identifier in entry:
                email = entry[email_identifier][0]

            # Unique name is required to login. Hence any user without
            # a userPrincipalName/sAMAccountName would not be created
            # as such a user cannot log into the system.
            # NOTE: Should not be combined with previous if/elif as that
            # would miss the case where one of them is present but is None.
            if name is None:
                msg += "No unique name found for entry\n"
                continue

            entity_list.append(
                LDAPApiWrapper.User(dn, name, display_name, email)
            )

        if log_entities:
            logging.debug(msg)

        return Result(Constants.OPERATION_SUCCESS, entity_list)
예제 #18
0
    def _update_group_membership(self, entity, entity_list, gid,
                                 keep_local_membership):
        """Method used to update a group with member users/groups. Update is
           designed to be of the form delete all and create. So when member
           groups are being updated current member group list is deleted and
           udpated with the new memeber group list being provided. Similar
           steps are taken for member user list update too.
           @param entity: EntityType user/group.
           @param entity_list: Entity ID list to be updated as members of
           the group.
           @param gid: Group ID.
           @return: Result object with operation status and data. Here data is
           set to None.
        """
        # Append local object IDs to keep local memberships
        if keep_local_membership:
            if entity == EntityType.GROUP:
                result = self.list_groups_in_group(gid)
                if result.status != Constants.OPERATION_SUCCESS:
                    return Result(result.status)
                current_groups = result.data
                for group in current_groups:
                    if group.type == "LOCAL_GROUP":
                        entity_list.append(group.id)
            else:
                result = self.list_users_in_group(gid)
                if result.status != Constants.OPERATION_SUCCESS:
                    return Result(result.status)
                current_users = result.data
                for user in current_users:
                    if user.type == "LOCAL_USER":
                        entity_list.append(user.id)
        # Filter irregular input objects from entity_list
        entity_list = filter(is_valid_uuid, entity_list)

        if entity == EntityType.GROUP:
            id_list_key = "principalids"
            end_point = TSApiWrapper.UPDATE_GROUPS_IN_GROUPS
        elif entity == EntityType.USER:
            id_list_key = "userids"
            end_point = TSApiWrapper.UPDATE_USERS_IN_GROUPS
        else:
            logging.error(TSApiWrapper.UNKNOWN_ENTITY_TYPE)
            return Result(Constants.OPERATION_FAILURE)

        success_msg = "Successfully updated the group with {}s.".format(entity)
        failure_msg = "Failed to update {}s the group.".format(entity)

        try:
            response = self.session.post(
                end_point.format(hostport=self.hostport),
                data={id_list_key: json.dumps(entity_list), "groupid": gid},
            )
            if response.status_code == httplib.NO_CONTENT:
                logging.debug(success_msg)
                return Result(Constants.OPERATION_SUCCESS)
            logging.error(failure_msg)
            return Result(Constants.OPERATION_FAILURE, response)
        except Exception as e:
            logging.error(e.message)
            return Result(Constants.OPERATION_FAILURE, e)
예제 #19
0
    def list_groups(
        self,
        basedn,
        ldap_type,
        user_identifier,
        scope=None,
        filter_str=None,
        log_entities=True,
        member_str=None
    ):
        """Fetches groups present in LDAP System.

        :param basedn: Distinguished name for the base in LDAP System.
        :param scope: Scope to limit the search to (0:base, 1:one, 2:tree).
        :param filter_str: Filter string to apply to search.
        :param log_entities: Flag if entity logging should be done.
        :return: Result object with operation status and data. Here data is
        a list of Group objects present in LDAP System.
        """
        if LDAPApiWrapper.OPEN_LDAP == ldap_type:
            if user_identifier is None:
                attr_uid = LDAPApiWrapper.OPEN_LDAP_ATTR_UID
            else:
                attr_uid = user_identifier
            common_attrs = [
                attr_uid,
                LDAPApiWrapper.ATTR_UPN,
                LDAPApiWrapper.ATTR_NAME,
                LDAPApiWrapper.ATTR_DISPLAY_NAME,
                LDAPApiWrapper.ATTR_CN,
                LDAPApiWrapper.ATTR_MEMBER,
            ]
            group_filter = LDAPApiWrapper.GROUP_FILTER_OPEN_LDAP
            member_str = LDAPApiWrapper.ATTR_MEMBER
        else:
            common_attrs = [
                LDAPApiWrapper.AD_ATTR_UID,
                LDAPApiWrapper.ATTR_UPN,
                LDAPApiWrapper.ATTR_NAME,
                LDAPApiWrapper.ATTR_DISPLAY_NAME,
                LDAPApiWrapper.ATTR_CN,
                LDAPApiWrapper.ATTR_MEMBER,
            ]
            group_filter = LDAPApiWrapper.GROUP_FILTER_AD
            member_str = LDAPApiWrapper.ATTR_MEMBER
        entity_list = []

        if scope is None:
            scope = ldap.SCOPE_SUBTREE
        if member_str is None:
            member_str = LDAPApiWrapper.ATTR_MEMBER

        # If filter string is not specified we use default group filters.
        # If a filter is being provided we need to stitch together the
        # user given filter with default filters to fetch specific groups.
        if filter_str is None:
            filter_str = group_filter
        else:
            filter_str = LDAPApiWrapper.FILTER_ADD.format(
                group_filter, filter_str
            )

        filter_str = self._sanitize_filters(filter_str)

        if log_entities:
            logging.debug("Base DN: %s", basedn)
            logging.debug("Filter String: %s", filter_str)

        item_list = []
        window = 999
        total_lim = 10000
        for ind in range(0, total_lim, window + 1):
            st, en = ind, ind + window
            memberrange = "member;range={}-{}".format(st, en)
            attr_list = common_attrs + [memberrange]
            if log_entities:
                logging.debug(
                    "Basedn %s with member range %s filter_str %s.",
                    basedn,
                    memberrange,
                    filter_str,
                )
            try:
                i_list = self.get_connection_to(basedn).search_s(
                    basedn, int(scope), filter_str, attr_list
                )
                if not i_list:
                    if log_entities:
                        logging.debug(
                            "Empty return for "
                            + "basedn %s with member range %s filter_str %s.",
                            basedn,
                            memberrange,
                            filter_str,
                        )
                    break
                item_list.extend(i_list)
            except Exception as e:
                if log_entities:
                    logging.debug(
                        "Threw exception for "
                        + "basedn %s with member range %s filter_str %s.",
                        basedn,
                        memberrange,
                        filter_str,
                    )
                    logging.error(e)
                break

        valid_dn_cnt = 0
        none_dn_cnt = 0
        msg = "List of DNs retrieved from LDAP server:\n"
        for dn, entry in item_list:
            # Skip entities which are None
            #
            # NOTE: This becomes necessary because when we get the list of
            # entities back we also have a reference entity describing where
            # it was fetched from which has a None value for dn.
            #
            # This filtering helps us skip these metadata information.
            if dn is None:
                none_dn_cnt += 1
                continue
            msg += "==> [{},{}]\n".format(dn, entry)
            valid_dn_cnt += 1

            # Entity specific attributes and handling of unique name attribute
            # if defaults are not present.
            name = ".".join(
                self._fetch_components_from_dn(dn)[0]
            ) + self.fetch_domain_name_from_dn(dn)
            # If name follows a consistant rule then we can use patterns
            # to create good looking display names.
            if entry.has_key(LDAPApiWrapper.ATTR_DISPLAY_NAME):
                display_name = entry[LDAPApiWrapper.ATTR_DISPLAY_NAME][0]
            elif entry.has_key(LDAPApiWrapper.ATTR_NAME):
                display_name = entry[LDAPApiWrapper.ATTR_NAME][0]
            elif entry.has_key(LDAPApiWrapper.ATTR_CN):
                display_name = entry[LDAPApiWrapper.ATTR_CN][0]
            else:
                display_name = dn

            # Populate member information.
            member = []
            for member_key in entry:
                if member_key.startswith(member_str):
                    member.extend(entry[member_key])
            if not member:
                logging.debug("Group DN(%s) has no key `member`.", dn)

            entity_list.append(
                LDAPApiWrapper.Group(dn, name, display_name, member)
            )

        if log_entities:
            logging.debug(
                "valid_dn_cnt %d none_dn_cnt %d procured",
                valid_dn_cnt,
                none_dn_cnt)
            logging.debug(msg)

        # Ensure we send back unique entities with all members and not
        # duplicate entities with members in parts.
        entity_map = {}
        for entity in entity_list:
            if entity.dn in entity_map:
                entity_map[entity.dn].members.extend(entity.members)
            else:
                entity_map[entity.dn] = entity

        return Result(Constants.OPERATION_SUCCESS, entity_map.values())