Skip to content

Commit

Permalink
roles: Add attributes to IPA|AD|LDAP User methods
Browse files Browse the repository at this point in the history
* first/last name attributes for IPA/AD/LDAP User modify methods.
* password_expiration to IPA User modify method
* external IdP attributes to IPA User modify method
* Do not fail if users OU already exists in LDAP
* add ability to override the rdn user attribute from cn
* add givenName attribute for LDAP users
  • Loading branch information
spoore1 committed Sep 25, 2024
1 parent f349b28 commit dade9e1
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 6 deletions.
8 changes: 8 additions & 0 deletions sssd_test_framework/hosts/ldap.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ def __init__(self, *args, **kwargs) -> None:
self.client.setdefault("id_provider", "ldap")
self.client.setdefault("ldap_uri", f"ldap://{self.hostname}")

# Use different default for domain
if "domain" not in self.config and "dns_discovery_domain" in self.client:
self.domain = self.client["dns_discovery_domain"]

# Use different default for realm
if "realm" not in self.config:
self.realm = self.domain.upper()

@property
def features(self) -> dict[str, bool]:
"""
Expand Down
13 changes: 12 additions & 1 deletion sssd_test_framework/roles/ad.py
Original file line number Diff line number Diff line change
Expand Up @@ -781,6 +781,8 @@ def modify(
gecos: str | DeleteAttribute | None = None,
shell: str | DeleteAttribute | None = None,
email: str | DeleteAttribute | None = None,
givenname: str | DeleteAttribute | None = None,
surname: str | DeleteAttribute | None = None,
) -> ADUser:
"""
Modify existing AD user.
Expand All @@ -800,6 +802,10 @@ def modify(
:type shell: str | DeleteAttribute | None, optional
:param email: Email address, defaults to None
:type email: str | DeleteAttribute | None, optional
:param givenname: Given name of user, defaults to None
:type givenname: str | DeleteAttribute | None, optional
:param surname: Sur name of user, defaults to None
:type surname: str | DeleteAttribute | None, optional
:return: Self.
:rtype: ADUser
"""
Expand All @@ -811,7 +817,11 @@ def modify(
"loginShell": shell,
}

ad_attrs = {"emailAddress": email}
ad_attrs = {
"emailAddress": email,
"GivenName": givenname,
"SurName": surname,
}
all_attrs = {**unix_attrs, **ad_attrs}

clear = [key for key, value in all_attrs.items() if isinstance(value, DeleteAttribute)]
Expand All @@ -828,6 +838,7 @@ def modify(
}

self._modify(attrs)

return self

def passkey_add(self, passkey_mapping: str) -> ADUser:
Expand Down
20 changes: 20 additions & 0 deletions sssd_test_framework/roles/ipa.py
Original file line number Diff line number Diff line change
Expand Up @@ -455,19 +455,28 @@ def add(
def modify(
self,
*,
first: str | None = None,
last: str | None = None,
uid: int | None = None,
gid: int | None = None,
password: str | None = None,
home: str | None = None,
gecos: str | None = None,
shell: str | None = None,
user_auth_type: str | list[str] | None = None,
idp: str | None = None,
idp_user_id: str | None = None,
password_expiration: str | None = None,
) -> IPAUser:
"""
Modify existing IPA user.
Parameters that are not set are ignored.
:param first: First name of user
:type first: str | None, optional
:param last: Last name of user
:type last: str | None, optional
:param uid: User id, defaults to None
:type uid: int | None, optional
:param gid: Primary group id, defaults to None
Expand All @@ -482,17 +491,28 @@ def modify(
:type shell: str | None, optional
:param user_auth_type: Types of supported user authentication, defaults to None
:type user_auth_type: str | list[str] | None, optional
:param idp: Name of external IdP configured in IPA for user
:type idp: str | None, optional
:param idp_user_id: User ID used to map IPA user to external IdP user
:type idp_user_id: str | None, optional
:param password_expiration: Date and time stamp for password expiration
:type password_expiration: str | None, optional
:return: Self.
:rtype: IPAUser
"""
attrs = {
"first": (self.cli.option.VALUE, first),
"last": (self.cli.option.VALUE, last),
"uid": (self.cli.option.VALUE, uid),
"gidnumber": (self.cli.option.VALUE, gid),
"homedir": (self.cli.option.VALUE, home),
"gecos": (self.cli.option.VALUE, gecos),
"shell": (self.cli.option.VALUE, shell),
"password": (self.cli.option.SWITCH, True) if password is not None else None,
"user-auth-type": (self.cli.option.VALUE, user_auth_type),
"idp": (self.cli.option.VALUE, idp),
"idp-user-id": (self.cli.option.VALUE, idp_user_id),
"password-expiration": (self.cli.option.VALUE, password_expiration),
}

self._modify(attrs, input=password)
Expand Down
31 changes: 26 additions & 5 deletions sssd_test_framework/roles/ldap.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ def test_example(client: Client, ldap: LDAP):
"""
return LDAPOrganizationalUnit[LDAPHost, LDAP](self, name, basedn)

def user(self, name: str, basedn: LDAPObject | str | None = "ou=users") -> LDAPUser:
def user(self, name: str, basedn: LDAPObject | str | None = "ou=users", rdn_attr: str | None = "cn") -> LDAPUser:
"""
Get user object.
Expand All @@ -210,10 +210,12 @@ def test_example(client: Client, ldap: LDAP):
:type name: str
:param basedn: Base dn, defaults to ``ou=users``
:type basedn: LDAPObject | str | None, optional
:param rdn_attr: RDN Attribute (uid, cn, etc)
:type rdn_attr: str, defaults to 'cn'
:return: New user object.
:rtype: LDAPUser
"""
return LDAPUser(self, name, basedn)
return LDAPUser(self, name, basedn, rdn_attr)

def group(
self, name: str, basedn: LDAPObject | str | None = "ou=groups", *, rfc2307bis: bool = False
Expand Down Expand Up @@ -401,7 +403,12 @@ def __create_default_ou(self, basedn: LDAPObject | str | None, default_ou: str |
if basedn.lower() != f"ou={default_ou}" or default_ou in self.role.auto_ou:
return

self.role.ou(default_ou).add()
try:
self.role.ou(default_ou).add()
except ldap.ALREADY_EXISTS:
pass
except Exception as err:
raise err
self.role.auto_ou[default_ou] = True

def _dn(self, rdn: str, basedn: LDAPObject | str | None = None) -> str:
Expand Down Expand Up @@ -623,16 +630,18 @@ class LDAPUser(LDAPObject[LDAPHost, LDAP]):
LDAP user management.
"""

def __init__(self, role: LDAP, name: str, basedn: LDAPObject | str | None = "ou=users") -> None:
def __init__(self, role: LDAP, name: str, basedn: LDAPObject | str | None = "ou=users", rdn_attr: str | None = "cn") -> None:
"""
:param role: LDAP role object.
:type role: LDAP
:param name: User name.
:type name: str
:param basedn: Base dn, defaults to ``ou=users``
:type basedn: LDAPObject | str | None, optional
:param rdn_attr: RDN Attribute (uid, cn, etc)
:type rdn_attr: str, defaults to 'cn'
"""
super().__init__(role, name, f"cn={name}", basedn, default_ou="users")
super().__init__(role, name, f"{rdn_attr}={name}", basedn, default_ou="users")

self.first_passkey_add = False
"""Whether the 'passkeyUser' objectClass has already been added."""
Expand All @@ -651,6 +660,7 @@ def add(
shadowWarning: int | None = None,
shadowLastChange: int | None = None,
sn: str | None = None,
givenName: str | None = None,
mail: str | None = None,
) -> LDAPUser:
"""
Expand Down Expand Up @@ -681,6 +691,8 @@ def add(
:type shadowLastChange: int | None, optional
:param sn: surname LDAP attribute, defaults to None
:type sn: str | None, optional
:param givenName: givenName LDAP attribute, defaults to None
:type givenName: str | None, optional
:param mail: mail LDAP attribute, defaults to None
:type mail: str | None, optional
:return: Self.
Expand Down Expand Up @@ -709,6 +721,7 @@ def add(
"shadowWarning": shadowWarning,
"shadowLastChange": shadowLastChange,
"sn": sn,
"givenName": givenName,
"mail": mail,
}

Expand All @@ -735,7 +748,9 @@ def modify(
shadowMax: int | DeleteAttribute | None = None,
shadowWarning: int | DeleteAttribute | None = None,
shadowLastChange: int | DeleteAttribute | None = None,
cn: str | DeleteAttribute | None = None,
sn: str | DeleteAttribute | None = None,
givenName: str | DeleteAttribute | None = None,
mail: str | DeleteAttribute | None = None,
) -> LDAPUser:
"""
Expand All @@ -762,8 +777,12 @@ def modify(
:type shadowWarning: int | DeleteAttribute | None, optional
:param shadowLastChange: shadowlastchage LDAP attribute, defaults to None
:type shadowLastChange: int | DeleteAttribute | None, optional
:param cn: common name LDAP attribute, defaults to None
:type cn: str | DeleteAttribute | None, optional
:param sn: surname LDAP attribute, defaults to None
:type sn: str | DeleteAttribute | None, optional
:param givenName: givenName LDAP attribute, defaults to None
:type givenName: str | DeleteAttribute | None, optional
:param mail: mail LDAP attribute, defaults to None
:type mail: str | DeleteAttribute | None, optional
:return: Self.
Expand All @@ -780,7 +799,9 @@ def modify(
"shadowMax": shadowMax,
"shadowWarning": shadowWarning,
"shadowLastChange": shadowLastChange,
"cn": cn,
"sn": sn,
"givenName": givenName,
"mail": mail,
}

Expand Down

0 comments on commit dade9e1

Please sign in to comment.