From f767408c2c92354ec51c3aa8fe387e7eed4379b8 Mon Sep 17 00:00:00 2001 From: Max Erenberg <> Date: Sat, 23 Oct 2021 20:33:13 -0400 Subject: [PATCH] add one-time script --- .drone/data.ldif | 18 +++++++-- one_time_scripts/inetorgperson.py | 67 +++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 one_time_scripts/inetorgperson.py diff --git a/.drone/data.ldif b/.drone/data.ldif index 2863b81..59f6931 100644 --- a/.drone/data.ldif +++ b/.drone/data.ldif @@ -80,6 +80,8 @@ uniqueMember: uid=ctdalek,ou=People,dc=csclub,dc=internal dn: uid=ctdalek,ou=People,dc=csclub,dc=internal cn: Calum Dalek +givenName: Calum +sn: Dalek userPassword: {SASL}ctdalek@CSCLUB.INTERNAL loginShell: /bin/bash homeDirectory: /users/ctdalek @@ -87,7 +89,9 @@ uid: ctdalek uidNumber: 20001 gidNumber: 20001 objectClass: top -objectClass: account +objectClass: person +objectClass: organizationalPerson +objectClass: inetOrgPerson objectClass: posixAccount objectClass: shadowAccount objectClass: member @@ -103,6 +107,8 @@ gidNumber: 20001 dn: uid=regular1,ou=People,dc=csclub,dc=internal cn: Regular One +givenName: Regular +sn: One userPassword: {SASL}regular1@CSCLUB.INTERNAL loginShell: /bin/bash homeDirectory: /users/regular1 @@ -110,7 +116,9 @@ uid: regular1 uidNumber: 20002 gidNumber: 20002 objectClass: top -objectClass: account +objectClass: person +objectClass: organizationalPerson +objectClass: inetOrgPerson objectClass: posixAccount objectClass: shadowAccount objectClass: member @@ -126,6 +134,8 @@ gidNumber: 20002 dn: uid=exec1,ou=People,dc=csclub,dc=internal cn: Exec One +givenName: Exec +sn: One userPassword: {SASL}exec1@CSCLUB.INTERNAL loginShell: /bin/bash homeDirectory: /users/exec1 @@ -133,7 +143,9 @@ uid: exec1 uidNumber: 20003 gidNumber: 20003 objectClass: top -objectClass: account +objectClass: person +objectClass: organizationalPerson +objectClass: inetOrgPerson objectClass: posixAccount objectClass: shadowAccount objectClass: member diff --git a/one_time_scripts/inetorgperson.py b/one_time_scripts/inetorgperson.py new file mode 100644 index 0000000..59301eb --- /dev/null +++ b/one_time_scripts/inetorgperson.py @@ -0,0 +1,67 @@ +#!/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. + +GSSAPI is used for LDAP authentication, so make sure to run `kinit` first. +Also, make sure to run this script from the top-level of the git directory +(see the sys.path hack below). +""" +import sys +import traceback + +import ldap3 + +# modify as necessary +LDAP_URI = "ldap://auth1.csclub.internal" +LDAP_MEMBERS_BASE = "ou=People,dc=csclub,dc=internal" +UWLDAP_URI = "ldap://auth1.csclub.internal" +UWLDAP_MEMBERS_BASE = "ou=UWLDAP,dc=csclub,dc=internal" + +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) +total_records_updated = 0 +for csc_entry in csc_conn.entries: + uid = csc_entry.uid.value + cn = csc_entry.cn.value + sn = None + given_name = None + try: + uw_conn.search( + f'uid={uid},{UWLDAP_MEMBERS_BASE}', '(objectClass=*)', + attributes=ldap3.ALL_ATTRIBUTES, search_scope=ldap3.BASE) + uw_entry = uw_conn.entries[0] + sn = uw_entry.sn.value + given_name = uw_entry.givenName.value + except ldap3.core.exceptions.LDAPNoSuchObjectResult: + pass + if given_name is None or sn is None: + 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}') + total_records_updated += 1 +print(f'Total records updated: {total_records_updated}')