From 2493bb1a6bcb39750911c53c9688e4286d4b6ee6 Mon Sep 17 00:00:00 2001 From: Max Erenberg <> Date: Thu, 28 Oct 2021 21:33:32 -0400 Subject: [PATCH] modify CSC schema instead of using inetOrgPerson --- .drone/csc.schema | 3 +- .drone/data.ldif | 12 ++---- .gitignore | 1 + ceod/model/LDAPService.py | 10 ++--- ...etorgperson.py => first_and_last_names.py} | 38 +++++++------------ 5 files changed, 22 insertions(+), 42 deletions(-) rename one_time_scripts/{inetorgperson.py => first_and_last_names.py} (53%) diff --git a/.drone/csc.schema b/.drone/csc.schema index 9c00a43..af6c5e4 100644 --- a/.drone/csc.schema +++ b/.drone/csc.schema @@ -27,7 +27,8 @@ attributetype ( 1.3.6.1.4.1.27934.1.1.6 NAME 'isClubRep' objectclass ( 1.3.6.1.4.1.27934.1.2.1 NAME 'member' SUP top AUXILIARY MUST ( cn $ uid ) - MAY ( studentid $ program $ term $ nonMemberTerm $ description $ position $ isClubRep ) ) + MAY ( studentid $ program $ term $ nonMemberTerm $ description $ position $ + isClubRep $ sn $ givenName ) ) objectclass ( 1.3.6.1.4.1.27934.1.2.2 NAME 'club' SUP top AUXILIARY diff --git a/.drone/data.ldif b/.drone/data.ldif index 59f6931..383e051 100644 --- a/.drone/data.ldif +++ b/.drone/data.ldif @@ -89,9 +89,7 @@ uid: ctdalek uidNumber: 20001 gidNumber: 20001 objectClass: top -objectClass: person -objectClass: organizationalPerson -objectClass: inetOrgPerson +objectClass: account objectClass: posixAccount objectClass: shadowAccount objectClass: member @@ -116,9 +114,7 @@ uid: regular1 uidNumber: 20002 gidNumber: 20002 objectClass: top -objectClass: person -objectClass: organizationalPerson -objectClass: inetOrgPerson +objectClass: account objectClass: posixAccount objectClass: shadowAccount objectClass: member @@ -143,9 +139,7 @@ uid: exec1 uidNumber: 20003 gidNumber: 20003 objectClass: top -objectClass: person -objectClass: organizationalPerson -objectClass: inetOrgPerson +objectClass: account objectClass: posixAccount objectClass: shadowAccount objectClass: member diff --git a/.gitignore b/.gitignore index 24c32f2..4b5b571 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ __pycache__/ /docs/*.5 /debian/ceo/ /debian/ceod/ +/debian/ceo-common/ /debian/tmp/ /debian/ceo.substvars /debian/files diff --git a/ceod/model/LDAPService.py b/ceod/model/LDAPService.py index 5708ce1..22f14f6 100644 --- a/ceod/model/LDAPService.py +++ b/ceod/model/LDAPService.py @@ -164,19 +164,15 @@ class LDAPService: conn.delete(dn) def add_user(self, user: IUser): + object_classes = ['top', 'account', 'posixAccount', 'shadowAccount'] if user.is_club(): min_id, max_id = self.club_min_id, self.club_max_id - object_classes = [ - 'top', 'account', 'posixAccount', 'shadowAccount', 'club', - ] + object_classes.append('club') else: assert user.given_name and user.sn, \ 'First name and last name must be specified for new members' min_id, max_id = self.member_min_id, self.member_max_id - object_classes = [ - 'top', 'person', 'organizationalPerson', 'inetOrgPerson', - 'posixAccount', 'shadowAccount', 'member', - ] + object_classes.append('member') if user.mail_local_addresses: object_classes.append('inetLocalMailRecipient') conn = self._get_ldap_conn() diff --git a/one_time_scripts/inetorgperson.py b/one_time_scripts/first_and_last_names.py similarity index 53% rename from one_time_scripts/inetorgperson.py rename to one_time_scripts/first_and_last_names.py index 96a34c8..8a4701c 100644 --- a/one_time_scripts/inetorgperson.py +++ b/one_time_scripts/first_and_last_names.py @@ -1,8 +1,7 @@ #!/usr/bin/env python3 """ -This is a script which converts each user record in CSC LDAP from the -'account' to the 'inetOrgPerson' objectClass. It pulls first/last name -information from UWLDAP. +This is a script which adds 'sn' and 'givenName' attributes to each user record. +It pulls first/last name information from UWLDAP. GSSAPI is used for LDAP authentication, so make sure to run `kinit` first. """ @@ -21,8 +20,10 @@ csc_conn = ldap3.Connection( LDAP_URI, authentication=ldap3.SASL, sasl_mechanism=ldap3.KERBEROS, auto_bind=True, raise_exceptions=True) uw_conn = ldap3.Connection(UWLDAP_URI, auto_bind=True, raise_exceptions=True) -csc_conn.search(LDAP_MEMBERS_BASE, '(&(objectClass=member)(objectClass=account))', - attributes=ldap3.ALL_ATTRIBUTES) +csc_conn.search( + LDAP_MEMBERS_BASE, + '(&(objectClass=member)(!(|(sn=*)(givenName=*))))', + attributes=['uid', 'cn']) total_records_updated = 0 for csc_entry in csc_conn.entries: uid = csc_entry.uid.value @@ -32,7 +33,7 @@ for csc_entry in csc_conn.entries: try: uw_conn.search( f'uid={uid},{UWLDAP_MEMBERS_BASE}', '(objectClass=*)', - attributes=ldap3.ALL_ATTRIBUTES, search_scope=ldap3.BASE) + attributes=['sn', 'givenName'], search_scope=ldap3.BASE) uw_entry = uw_conn.entries[0] sn = uw_entry.sn.value given_name = uw_entry.givenName.value @@ -42,24 +43,11 @@ for csc_entry in csc_conn.entries: print(f'WARNING: could not retrieve first and last names for {uid}; inferring from whitespace instead') words = cn.split() given_name, sn = words[0], words[-1] - old_object_classes = csc_entry.objectClass.values.copy() - old_object_classes.remove('account') - new_object_classes = old_object_classes + [ - 'person', 'organizationalPerson', 'inetOrgPerson', - ] - attrs = csc_entry.entry_attributes_as_dict.copy() - attrs['objectClass'] = new_object_classes - attrs['givenName'] = [given_name] - attrs['sn'] = [sn] - csc_conn.delete(csc_entry.entry_dn) - try: - csc_conn.add(csc_entry.entry_dn, attributes=attrs) - except Exception: - print(traceback.format_exc()) - print(f"!!! ERROR !!! We weren't able to create a new record for {uid}.") - print('You need to add the old record back in. Here it is:') - print(csc_entry) - sys.exit(1) - print(f'Created new record for {uid}') + changes = { + 'givenName': [(ldap3.MODIFY_ADD, [given_name])], + 'sn': [(ldap3.MODIFY_ADD, [sn])], + } + csc_conn.modify(csc_entry.entry_dn, changes) + print(f'Updated record for {uid}') total_records_updated += 1 print(f'Total records updated: {total_records_updated}')