diff --git a/docker/rucio_client/scripts/user_to_site_mapping.py b/docker/rucio_client/scripts/user_to_site_mapping.py index 0f3f4b2..1216ebe 100755 --- a/docker/rucio_client/scripts/user_to_site_mapping.py +++ b/docker/rucio_client/scripts/user_to_site_mapping.py @@ -15,6 +15,7 @@ sys.path.insert(1, './tests') from policy_test import TestPolicy from cric_user import CricUser +from utils import rfc2253dn PROXY = os.getenv('X509_USER_PROXY') @@ -163,21 +164,6 @@ def usage(): print("\t-d, --dry_run=\tt|f") -def rfc2253dn(legacy_dn): - """ - Convert a slash separated DN to a comma separated format - :param legacy_dn: - :return: - """ - if not legacy_dn.startswith('/'): # No op for things which aren't DNs - return legacy_dn - legacy_dn = legacy_dn.replace(',', r'\,') - parts = legacy_dn.split('/')[1:] # Get rid of leading slash - new_dn = ','.join(parts) - - return new_dn - - def main(): option = 'set-new-only' dry_run = False diff --git a/docker/rucio_client/scripts/utils.py b/docker/rucio_client/scripts/utils.py new file mode 100644 index 0000000..84d65f7 --- /dev/null +++ b/docker/rucio_client/scripts/utils.py @@ -0,0 +1,53 @@ +""" +Common utility functions between scripts +""" + +RFC_ATTRIBUTE_ORDER = ["CN", "L", "ST", "O", "OU", "C", "STREET", "DC", "UID"] + +def get_attribute(attribute: str) -> str: + """Extracts attribute key""" + try: + return attribute[:attribute.index("=")] + except ValueError: + # print(f"element lacks attribute, {attribute}, {dn}") + return "" + + +def rfc2253dn(legacy_dn: str, verbose: bool = False) -> str: + """Converts legacy slash DB to comma separated DN""" + if not legacy_dn.startswith('/'): + if verbose: + print(f'DN does not start with /: {legacy_dn}') + return legacy_dn + + # replace commas with an escape character + legacy_dn = legacy_dn.replace(',', r'\,') + parts = legacy_dn.split('/')[1:] + + # parts are reversed. See https://datatracker.ietf.org/doc/html/rfc2253#section-2.3 + elements = parts[::-1] + attributes = [get_attribute(e) for e in elements] + + # skip any DNs who have an element without an attribute + if "" in attributes: + return "" + + if verbose: + print(f"Attributes: {attributes}") + print(f"Expected order: {RFC_ATTRIBUTE_ORDER}") + + indexes = [] + for attr in attributes: + try: + indexes.append(RFC_ATTRIBUTE_ORDER.index(attr)) + except ValueError: + # skips any DNs that don't have a attribute in the RFC_ATTRIBUTE_ORDER + pass + + # sort existing attributes based on expected attribute order + result = [a[0] for a in sorted(zip(elements, attributes, indexes), key=lambda x: x[2])] + + if verbose: + print(f"original: {legacy_dn}\nindexes: {indexes}\nconverted: {','.join(result)}") + + return ','.join(result)