Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IPA ID Override classes for users and groups #154

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

madhuriupadhye
Copy link
Contributor

@madhuriupadhye madhuriupadhye commented Mar 6, 2025

Add sub classes for IPA ID override for users
and groups.

@madhuriupadhye madhuriupadhye requested a review from danlavu March 6, 2025 16:12
@madhuriupadhye madhuriupadhye marked this pull request as draft March 6, 2025 16:36
@madhuriupadhye madhuriupadhye force-pushed the id_override branch 4 times, most recently from 877b078 to 66b6a26 Compare March 11, 2025 16:12
@madhuriupadhye madhuriupadhye marked this pull request as ready for review March 11, 2025 16:13
@madhuriupadhye madhuriupadhye changed the title Override methods IPA ID Override classes for users and groups Mar 11, 2025
Copy link
Contributor

@justin-stephenson justin-stephenson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack tests with the examples provided are passing for me.


[email protected](KnownTopology.IPA)
+def test_idview_override(client: Client, ipa: IPA):
+    ipa.idview("newview1").add(description="This is a new view")
+    ipa.idview("newview1").apply(hosts=f"{client.host.hostname}")
+    ipa.user("user-1").add().iduseroverride().add_override("newview1", uid=1344567)
+    client.sssd.restart()
+    lookup1 = client.tools.id("user-1")
+    assert lookup1.user.id == 1344567
+
[email protected](KnownTopology.IPA)
+def test_idview_views(ipa: IPA):
+    ipa.idview("newview").add(description="This is a new view")
+    ipa.idview("newview").apply(hosts="client.test")
+    ipa.idview("newview").delete()



tests/test_ipa.py::test_idview_override (ipa) PASSED                                    [ 50%]
tests/test_ipa.py::test_idview_views (ipa) PASSED                                       [100%]

Copy link

@danlavu danlavu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor changes and one question about the clean data, I think we may have a function for it.

:rtype: list[str]
"""
find_result = self.role.host.conn.exec(["ipa", "idoverridegroup-find", idview_name, "--anchor", self.name])
cleaned_data = [line for line in find_result.stdout.splitlines() if "-" not in line]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

def to_list(value: Any | list[Any] | None) -> list[Any]:

Is it possible that one of these functions cleans the data? If it doesn't, will it make sense that we had a function here?

Copy link
Contributor Author

@madhuriupadhye madhuriupadhye Mar 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can add as most of all ipa *-show or ipa *-find command give us output in following format where ----- are unnecessary in result.

[root@client ~]# ipa idoverrideuser-find newview1 user-2
--------------------------
1 User ID override matched
--------------------------
  Anchor to override: user-2
  User login: newuser
  UID: 1234567
  GECOS: This is the ID user override
  GID: 7654321
  Home directory: /home/newhomedir
  Login shell: /bin/newloginshell
----------------------------
Number of entries returned 1
----------------------------

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can add as most of all ipa *-show or ipa *-find command give us output in following format where ----- are unnecessary in result.

So Pavel converts the output into a dict of lists. I'd like to see the same method used, so instead of a list, a dict[str, list[str]]

The output in the same for all of the ipa commands it seems, can we make this consistent?

[root@master /]# ipa user-find admin --raw
--------------
1 user matched
--------------
  dn: uid=admin,cn=users,cn=accounts,dc=ipa,dc=test
  uid: admin
  sn: Administrator
  cn: Administrator
  homedirectory: /home/admin
  gecos: Administrator
  loginshell: /bin/bash
  krbprincipalname: [email protected]
  krbprincipalname: [email protected]
  uidnumber: 1636200000
  gidnumber: 1636200000
  nsaccountlock: FALSE
  ipaNTSecurityIdentifier: S-1-5-21-1061865485-3290583131-1435945682-500
  ipaUniqueID: 98064296-fc8b-11ef-9e81-ae6dd4cde335
  krbExtraData: AAKs+cxnYWRtaW5ASVBBLlRFU1QA
  krbLastAdminUnlock: 20250309021404Z
  krbLastPwdChange: 20250309021508Z
  krbPwdPolicyReference: cn=pw-never-expires,cn=IPA.TEST,cn=kerberos,dc=ipa,dc=test
  memberOf: cn=admins,cn=groups,cn=accounts,dc=ipa,dc=test
  memberOf: cn=Replication Administrators,cn=privileges,cn=pbac,dc=ipa,dc=test
  memberOf: cn=Add Replication Agreements,cn=permissions,cn=pbac,dc=ipa,dc=test
  memberOf: cn=Modify Replication Agreements,cn=permissions,cn=pbac,dc=ipa,dc=test
  memberOf: cn=Read Replication Agreements,cn=permissions,cn=pbac,dc=ipa,dc=test
  memberOf: cn=Remove Replication Agreements,cn=permissions,cn=pbac,dc=ipa,dc=test
  memberOf: cn=Modify DNA Range,cn=permissions,cn=pbac,dc=ipa,dc=test
  memberOf: cn=Read PassSync Managers Configuration,cn=permissions,cn=pbac,dc=ipa,dc=test
  memberOf: cn=Read Replication Changelog Configuration,cn=permissions,cn=pbac,dc=ipa,dc=test
  memberOf: cn=Write Replication Changelog Configuration,cn=permissions,cn=pbac,dc=ipa,dc=test
  memberOf: cn=Modify PassSync Managers Configuration,cn=permissions,cn=pbac,dc=ipa,dc=test
  memberOf: cn=Read LDBM Database Configuration,cn=permissions,cn=pbac,dc=ipa,dc=test
  memberOf: cn=Add Configuration Sub-Entries,cn=permissions,cn=pbac,dc=ipa,dc=test
  memberOf: cn=Read DNA Range,cn=permissions,cn=pbac,dc=ipa,dc=test
  memberOf: cn=Read domain level,cn=permissions,cn=pbac,dc=ipa,dc=test
  memberOf: cn=System: Add Topology Segments,cn=permissions,cn=pbac,dc=ipa,dc=test
  memberOf: cn=System: Modify Topology Segments,cn=permissions,cn=pbac,dc=ipa,dc=test
  memberOf: cn=System: Read Topology Segments,cn=permissions,cn=pbac,dc=ipa,dc=test
  memberOf: cn=System: Remove Topology Segments,cn=permissions,cn=pbac,dc=ipa,dc=test
  memberOf: cn=Host Enrollment,cn=privileges,cn=pbac,dc=ipa,dc=test
  memberOf: cn=System: Add krbPrincipalName to a Host,cn=permissions,cn=pbac,dc=ipa,dc=test
  memberOf: cn=System: Enroll a Host,cn=permissions,cn=pbac,dc=ipa,dc=test
  memberOf: cn=System: Manage Host Certificates,cn=permissions,cn=pbac,dc=ipa,dc=test
  memberOf: cn=System: Manage Host Enrollment Password,cn=permissions,cn=pbac,dc=ipa,dc=test
  memberOf: cn=System: Manage Host Keytab,cn=permissions,cn=pbac,dc=ipa,dc=test
  memberOf: cn=System: Manage Host Principals,cn=permissions,cn=pbac,dc=ipa,dc=test
  memberOf: cn=trust admins,cn=groups,cn=accounts,dc=ipa,dc=test
  memberOf: cn=pw-never-expires,cn=groups,cn=accounts,dc=ipa,dc=test
  objectClass: top
  objectClass: person
  objectClass: posixaccount
  objectClass: krbprincipalaux
  objectClass: krbticketpolicyaux
  objectClass: inetuser
  objectClass: ipaobject
  objectClass: ipasshuser
  objectClass: ipaSshGroupOfPubKeys
  objectClass: ipaNTUserAttrs
----------------------------
Number of entries returned 1
----------------------------
    def get(self, attrs: list[str] | None = None) -> dict[str, list[str]] | None:
        """
        Get IPA object attributes.

        :param attrs: If set, only requested attributes are returned, defaults to None
        :type attrs: list[str] | None, optional
        :return: Dictionary with attribute name as a key or None if no such attribute is found.
        :rtype: dict[str, list[str]] | None
        """
        cmd = self._exec("show", ["--all", "--raw"], raise_on_error=False)

        # ipa output starts with space
        lines = dedent(cmd.stdout).splitlines()

        if lines is None or len(lines) == 0:
            return None

        # Remove first line that contains the object name and not attribute
        return attrs_parse(lines[1:], attrs)
def attrs_parse(lines: list[str], attrs: list[str] | None = None) -> dict[str, list[str]]:
    """
    Parse LDAP attributes from output.

    :param lines: Output.
    :type lines: list[str]
    :param attrs: If set, only requested attributes are returned, defaults to None
    :type attrs: list[str] | None, optional
    :return: Dictionary with attribute name as a key.
    :rtype: dict[str, list[str]]
    """

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got an idea, updating

Add sub classes for IPA ID override for users
and groups.

Signed-off-by: Madhuri Upadhye <[email protected]>
@alexey-tikhonov
Copy link
Member

Ack tests with the examples provided are passing for me.


[email protected](KnownTopology.IPA)
+def test_idview_override(client: Client, ipa: IPA):
+    ipa.idview("newview1").add(description="This is a new view")

Where is idview() method added?

I pinned this branch and added this test (SSSD/sssd@4914992) and it failed for me with:

E       AttributeError: 'IPA' object has no attribute 'idview'

What did I miss?

@danlavu
Copy link

danlavu commented Mar 15, 2025

What did I miss?

this PR needs #146

@alexey-tikhonov
Copy link
Member

What did I miss?

this PR needs #146

Hm... what sense does it make to split over 2 PRs?

@danlavu
Copy link

danlavu commented Mar 15, 2025

Hm... what sense does it make to split over 2 PRs?

It doesn't, learning experience, I mentioned that it should be in one PR, two commits next time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants