Beispiel #1
0
    def lock(self):
        """Set the entry dn to nsDisabledRole and ensure it exists"""

        current_status = self.status()
        if current_status["state"] == RoleState.DIRECTLY_LOCKED:
            raise ValueError(
                f"Role is already {current_status['state'].describe()}")

        inst = self._instance

        mapping_trees = MappingTrees(inst)
        root_suffix = ""
        root_suffix = mapping_trees.get_root_suffix_by_entry(self.dn)

        if root_suffix:
            managed_roles = ManagedRoles(inst, root_suffix)
            managed_role = managed_roles.ensure_state(
                properties={"cn": "nsManagedDisabledRole"})
            nested_roles = NestedRoles(inst, root_suffix)
            try:
                disabled_role = nested_roles.get("nsDisabledRole")
            except ldap.NO_SUCH_OBJECT:
                # We don't use "ensure_state" because we want to preserve the existing attributes
                disabled_role = nested_roles.create(properties={
                    "cn": "nsDisabledRole",
                    "nsRoleDN": managed_role.dn
                })
            disabled_role.add("nsRoleDN", self.dn)

            inact_containers = nsContainers(inst, basedn=root_suffix)
            inact_container = inact_containers.ensure_state(
                properties={'cn': 'nsAccountInactivationTmp'})

            cos_templates = CosTemplates(inst, inact_container.dn)
            cos_templates.ensure_state(
                properties={
                    'cosPriority': '1',
                    'nsAccountLock': 'true',
                    'cn': f'{disabled_role.dn}'
                })

            cos_classic_defs = CosClassicDefinitions(inst, root_suffix)
            cos_classic_defs.ensure_state(
                properties={
                    'cosAttribute': 'nsAccountLock operational',
                    'cosSpecifier': 'nsRole',
                    'cosTemplateDn': inact_container.dn,
                    'cn': 'nsAccountInactivation_cos'
                })
Beispiel #2
0
    def status(self):
        """Check if role is locked in nsDisabledRole (directly or indirectly)

        :returns: a dict
        """

        inst = self._instance
        disabled_roles = {}
        try:
            mapping_trees = MappingTrees(inst)
            root_suffix = mapping_trees.get_root_suffix_by_entry(self.dn)
            roles = Roles(inst, root_suffix)
            disabled_roles = roles.get_disabled_roles()
            nested_roles = NestedRoles(inst, root_suffix)
            disabled_role = nested_roles.get("nsDisabledRole")
            inact_containers = nsContainers(inst, basedn=root_suffix)
            inact_container = inact_containers.get('nsAccountInactivationTmp')

            cos_templates = CosTemplates(inst, inact_container.dn)
            cos_template = cos_templates.get(f'{disabled_role.dn}')
            cos_template.present('cosPriority', '1')
            cos_template.present('nsAccountLock', 'true')

            cos_classic_defs = CosClassicDefinitions(inst, root_suffix)
            cos_classic_def = cos_classic_defs.get('nsAccountInactivation_cos')
            cos_classic_def.present('cosAttribute',
                                    'nsAccountLock operational')
            cos_classic_def.present('cosTemplateDn', inact_container.dn)
            cos_classic_def.present('cosSpecifier', 'nsRole')
        except ldap.NO_SUCH_OBJECT:
            return self._format_status_message(RoleState.PROBABLY_ACTIVATED)

        for role, parent in disabled_roles.items():
            if str.lower(self.dn) == str.lower(role.dn):
                if parent is None:
                    return self._format_status_message(
                        RoleState.DIRECTLY_LOCKED)
                else:
                    return self._format_status_message(
                        RoleState.INDIRECTLY_LOCKED, parent)

        return self._format_status_message(RoleState.ACTIVATED)
Beispiel #3
0
    def unlock(self):
        """Remove the entry dn from nsDisabledRole if it exists"""

        inst = self._instance
        current_status = self.status()
        if current_status["state"] == RoleState.ACTIVATED:
            raise ValueError("Role is already active")

        mapping_trees = MappingTrees(inst)
        root_suffix = mapping_trees.get_root_suffix_by_entry(self.dn)
        roles = NestedRoles(inst, root_suffix)
        try:
            disabled_role = roles.get("nsDisabledRole")
            # Still we want to ensure that it is not locked directly too
            disabled_role.ensure_removed("nsRoleDN", self.dn)
        except ldap.NO_SUCH_OBJECT:
            pass

        # Notify if it's locked indirectly
        if current_status["state"] == RoleState.INDIRECTLY_LOCKED:
            raise ValueError(
                f"Role is {current_status['state'].describe(current_status['role_dn'])}. Please, deal with it separately"
            )
Beispiel #4
0
    def status(self):
        """Check if account is locked by Account Policy plugin or
        nsAccountLock (directly or indirectly)

        :returns: a dict in a format -
                  {"status": status, "params": activity_data, "calc_time": epoch_time}
        """

        inst = self._instance

        # Fetch Account Policy data if its enabled
        plugin = AccountPolicyPlugin(inst)
        state_attr = ""
        alt_state_attr = ""
        limit = ""
        spec_attr = ""
        limit_attr = ""
        process_account_policy = False
        try:
            process_account_policy = plugin.status()
        except IndexError:
            self._log.debug(
                "The bound user doesn't have rights to access Account Policy settings. Not checking."
            )

        if process_account_policy:
            config_dn = plugin.get_attr_val_utf8("nsslapd-pluginarg0")
            config = AccountPolicyConfig(inst, config_dn)
            config_settings = config.get_attrs_vals_utf8([
                "stateattrname", "altstateattrname", "specattrname",
                "limitattrname"
            ])
            state_attr = self._dict_get_with_ignore_indexerror(
                config_settings, "stateattrname")
            alt_state_attr = self._dict_get_with_ignore_indexerror(
                config_settings, "altstateattrname")
            spec_attr = self._dict_get_with_ignore_indexerror(
                config_settings, "specattrname")
            limit_attr = self._dict_get_with_ignore_indexerror(
                config_settings, "limitattrname")

            mapping_trees = MappingTrees(inst)
            root_suffix = mapping_trees.get_root_suffix_by_entry(self.dn)
            cos_entries = CosTemplates(inst, root_suffix)
            accpol_entry_dn = ""
            for cos in cos_entries.list():
                if cos.present(spec_attr):
                    accpol_entry_dn = cos.get_attr_val_utf8_l(spec_attr)
            if accpol_entry_dn:
                accpol_entry = AccountPolicyEntry(inst, accpol_entry_dn)
            else:
                accpol_entry = config
            limit = accpol_entry.get_attr_val_utf8_l(limit_attr)

        # Fetch account data
        account_data = self.get_attrs_vals_utf8([
            "createTimestamp", "modifyTimeStamp", "nsAccountLock", state_attr
        ])

        last_login_time = self._dict_get_with_ignore_indexerror(
            account_data, state_attr)
        if not last_login_time:
            last_login_time = self._dict_get_with_ignore_indexerror(
                account_data, alt_state_attr)

        create_time = self._dict_get_with_ignore_indexerror(
            account_data, "createTimestamp")
        modify_time = self._dict_get_with_ignore_indexerror(
            account_data, "modifyTimeStamp")

        acct_roles = self.get_attr_vals_utf8_l("nsRole")
        mapping_trees = MappingTrees(inst)
        root_suffix = ""
        try:
            root_suffix = mapping_trees.get_root_suffix_by_entry(self.dn)
        except ldap.NO_SUCH_OBJECT:
            self._log.debug(
                "The bound user doesn't have rights to access disabled roles settings. Not checking."
            )
        if root_suffix:
            roles = Roles(inst, root_suffix)
            try:
                disabled_roles = roles.get_disabled_roles()

                # Locked indirectly through a role
                locked_indirectly_role_dn = ""
                for role in acct_roles:
                    if str.lower(role) in [
                            str.lower(role.dn)
                            for role in disabled_roles.keys()
                    ]:
                        locked_indirectly_role_dn = role
                if locked_indirectly_role_dn:
                    return self._format_status_message(
                        AccountState.INDIRECTLY_LOCKED, create_time,
                        modify_time, last_login_time, limit,
                        locked_indirectly_role_dn)
            except ldap.NO_SUCH_OBJECT:
                pass

        # Locked directly
        if self._dict_get_with_ignore_indexerror(account_data,
                                                 "nsAccountLock") == "true":
            return self._format_status_message(AccountState.DIRECTLY_LOCKED,
                                               create_time, modify_time,
                                               last_login_time, limit)

        # Locked indirectly through Account Policy plugin
        if process_account_policy and last_login_time:
            # Now check the Account Policy Plugin inactivity limits
            remaining_time = float(limit) - (time.mktime(
                time.gmtime()) - gentime_to_posix_time(last_login_time))
            if remaining_time <= 0:
                return self._format_status_message(
                    AccountState.INACTIVITY_LIMIT_EXCEEDED, create_time,
                    modify_time, last_login_time, limit)
        # All checks are passed - we are active
        return self._format_status_message(AccountState.ACTIVATED, create_time,
                                           modify_time, last_login_time, limit)