Verified Commit 3b82b970 authored by Jakob Moser's avatar Jakob Moser
Browse files

Support User Principal Names (= Faux DNs)

parent e3e8e030
Loading
Loading
Loading
Loading
+17 −2
Original line number Diff line number Diff line
@@ -28,8 +28,14 @@ class Directory:
        """
        Creates the LdapDatabase instance. Does not establish any connections whatsoever.

        `base_dn` is not correctly named (for reasons of backwards compatibility). It can take an
        actual distinguished name (DN), but it can also accept a domain name starting with @.
        The user name with which to bind to the ldap server is then created by simply concatenating
        the provided common name with the domain name to form a User Principal Name, a standard understood
        only be Microsoft Active Directory.

        :param url: A ldap server url (must use either ldaps:// or ldap:// scheme)
        :param base_dn: The distinguished name below which to look for users (e.g. "ou=employees,dc=example,dc=com")
        :param base_dn: The distinguished name below which to look for users (e.g. "ou=employees,dc=example,dc=com"), or a domain starting with @ (e.g. "@example.com")
        :param ca_certs_file_path: Path to a file containing a root CA, if e.g., a self-created one should be used
        """
        if not is_valid_server_url(url):
@@ -102,4 +108,13 @@ class Directory:
        # Or can we? The documentation (https://ldap3.readthedocs.io/en/latest/connection.html) recommends using
        # escape_rdn() for the username, so we do this, better safe than sorry.

        if self.base_dn.startswith("@"):
            # Special case: If self.base_dn starts with an @, we assume it is not actually a DN, but instead
            # a domain, which is used to construct an Active Directory-style User Principal Name.
            #
            # The common name is not escaped here, because I don't really know how, and because one could argue
            # that again, the untrusted input is processed in an untrusted context.
            return f"{common_name}{self.base_dn}"
        else:
            # Standard case: Actually construct a proper DN and return it.
            return f"cn={escape_rdn(common_name)},{self.base_dn}"