diff --git a/apricot/apricot_server.py b/apricot/apricot_server.py index 20bc696..28a2638 100644 --- a/apricot/apricot_server.py +++ b/apricot/apricot_server.py @@ -30,6 +30,7 @@ def __init__( background_refresh: bool = False, debug: bool = False, enable_mirrored_groups: bool = True, + enable_primary_groups: bool = True, enable_user_domain_verification: bool = True, redis_host: str | None = None, redis_port: int | None = None, @@ -49,6 +50,7 @@ def __init__( @param background_refresh: Whether to refresh the LDAP tree in the background @param debug: Enable debug output @param enable_mirrored_groups: Whether to create a mirrored LDAP group-of-groups for each group-of-users + @param enable_primary_groups: Whether to create an LDAP primary group for each user @param enable_user_domain_verification: Whether to verify users belong to the correct domain @param redis_host: Host for a Redis cache (if used) @param redis_port: Port for a Redis cache (if used) @@ -93,10 +95,13 @@ def __init__( raise ValueError(msg) from exc # Initialise the OAuth data adaptor + if self.debug: + log.msg("Creating an OAuthDataAdaptor.") oauth_adaptor = OAuthDataAdaptor( domain, oauth_client, enable_mirrored_groups=enable_mirrored_groups, + enable_primary_groups=enable_primary_groups, enable_user_domain_verification=enable_user_domain_verification, ) diff --git a/apricot/ldap/oauth_ldap_tree.py b/apricot/ldap/oauth_ldap_tree.py index e46cf1c..2b7f93f 100644 --- a/apricot/ldap/oauth_ldap_tree.py +++ b/apricot/ldap/oauth_ldap_tree.py @@ -69,8 +69,6 @@ def lookup(self: Self, dn: DistinguishedName | str) -> defer.Deferred[ILDAPEntry """Lookup the referred to by dn. @return: A Deferred returning an ILDAPEntry. - - @raises: LDAPNoSuchObject. """ if not isinstance(dn, DistinguishedName): dn = DistinguishedName(stringValue=dn) diff --git a/apricot/ldap/read_only_ldap_server.py b/apricot/ldap/read_only_ldap_server.py index 48b965c..c9f08f4 100644 --- a/apricot/ldap/read_only_ldap_server.py +++ b/apricot/ldap/read_only_ldap_server.py @@ -50,6 +50,8 @@ def getRootDSE( # noqa: N802 return super().getRootDSE(request, reply) except Exception as exc: msg = f"LDAP Root DSE request failed. {exc}" + if self.debug: + log.msg(msg) raise LDAPProtocolError(msg) from exc def handle_LDAPAddRequest( # noqa: N802 @@ -59,10 +61,12 @@ def handle_LDAPAddRequest( # noqa: N802 reply: Callable[..., None] | None, ) -> defer.Deferred[ILDAPEntry]: """Refuse to handle an LDAP add request.""" + id((request, controls, reply)) # ignore unused arguments if self.debug: log.msg("Handling an LDAP add request.") - id((request, controls, reply)) # ignore unused arguments msg = "ReadOnlyLDAPServer will not handle LDAP add requests" + if self.debug: + log.msg(msg) raise LDAPProtocolError(msg) def handle_LDAPBindRequest( # noqa: N802 @@ -78,6 +82,8 @@ def handle_LDAPBindRequest( # noqa: N802 return super().handle_LDAPBindRequest(request, controls, reply) except Exception as exc: msg = f"LDAP bind request failed. {exc}" + if self.debug: + log.msg(msg) raise LDAPProtocolError(msg) from exc def handle_LDAPCompareRequest( # noqa: N802 @@ -93,6 +99,8 @@ def handle_LDAPCompareRequest( # noqa: N802 return super().handle_LDAPCompareRequest(request, controls, reply) except Exception as exc: msg = f"LDAP compare request failed. {exc}" + if self.debug: + log.msg(msg) raise LDAPProtocolError(msg) from exc def handle_LDAPDelRequest( # noqa: N802 @@ -102,10 +110,12 @@ def handle_LDAPDelRequest( # noqa: N802 reply: Callable[..., None] | None, ) -> defer.Deferred[ILDAPEntry]: """Refuse to handle an LDAP delete request.""" + id((request, controls, reply)) # ignore unused arguments if self.debug: log.msg("Handling an LDAP delete request.") - id((request, controls, reply)) # ignore unused arguments msg = "ReadOnlyLDAPServer will not handle LDAP delete requests" + if self.debug: + log.msg(msg) raise LDAPProtocolError(msg) def handle_LDAPExtendedRequest( # noqa: N802 @@ -121,6 +131,8 @@ def handle_LDAPExtendedRequest( # noqa: N802 return super().handle_LDAPExtendedRequest(request, controls, reply) except Exception as exc: msg = f"LDAP extended request failed. {exc}" + if self.debug: + log.msg(msg) raise LDAPProtocolError(msg) from exc def handle_LDAPModifyDNRequest( # noqa: N802 @@ -134,6 +146,8 @@ def handle_LDAPModifyDNRequest( # noqa: N802 log.msg("Handling an LDAP modify DN request.") id((request, controls, reply)) # ignore unused arguments msg = "ReadOnlyLDAPServer will not handle LDAP modify DN requests" + if self.debug: + log.msg(msg) raise LDAPProtocolError(msg) def handle_LDAPModifyRequest( # noqa: N802 @@ -162,6 +176,8 @@ def handle_LDAPSearchRequest( # noqa: N802 return super().handle_LDAPSearchRequest(request, controls, reply) except Exception as exc: msg = f"LDAP search request failed. {exc}" + if self.debug: + log.msg(msg) raise LDAPProtocolError(msg) from exc def handle_LDAPUnbindRequest( # noqa: N802 @@ -177,4 +193,6 @@ def handle_LDAPUnbindRequest( # noqa: N802 super().handle_LDAPUnbindRequest(request, controls, reply) except Exception as exc: msg = f"LDAP unbind request failed. {exc}" + if self.debug: + log.msg(msg) raise LDAPProtocolError(msg) from exc diff --git a/apricot/oauth/oauth_data_adaptor.py b/apricot/oauth/oauth_data_adaptor.py index 23d549d..81722ea 100644 --- a/apricot/oauth/oauth_data_adaptor.py +++ b/apricot/oauth/oauth_data_adaptor.py @@ -32,12 +32,14 @@ def __init__( oauth_client: OAuthClient, *, enable_mirrored_groups: bool, + enable_primary_groups: bool, enable_user_domain_verification: bool, ) -> None: """Initialise an OAuthDataAdaptor. @param domain: The root domain of the LDAP tree @param enable_mirrored_groups: Whether to create a mirrored LDAP group-of-groups for each group-of-users + @param enable_primary_groups: Whether to create an LDAP primary group for each user @param enable_user_domain_verification: Whether to verify users belong to the correct domain @param oauth_client: An OAuth client used to construct the LDAP tree """ @@ -46,6 +48,7 @@ def __init__( self.oauth_client = oauth_client self.root_dn = "DC=" + domain.replace(".", ",DC=") self.enable_mirrored_groups = enable_mirrored_groups + self.enable_primary_groups = enable_primary_groups self.enable_user_domain_verification = enable_user_domain_verification def _dn_from_group_cn(self: Self, group_cn: str) -> str: @@ -75,21 +78,22 @@ def _retrieve_entries( self._dn_from_user_cn(user_cn) for user_cn in group_dict["memberUid"] ] - # Add one self-titled group for each user + # Add one self-titled primary group for each user # Group name is taken from 'cn' which should match the username user_primary_groups = [] - for user in oauth_users: - group_dict = {} - for attr in ("cn", "description", "gidNumber"): - group_dict[attr] = user[attr] - group_dict["member"] = [self._dn_from_user_cn(user["cn"])] - group_dict["memberUid"] = [user["cn"]] - user_primary_groups.append(group_dict) + if self.enable_primary_groups: + for user in oauth_users: + group_dict = {} + for attr in ("cn", "description", "gidNumber"): + group_dict[attr] = user[attr] + group_dict["member"] = [self._dn_from_user_cn(user["cn"])] + group_dict["memberUid"] = [user["cn"]] + user_primary_groups.append(group_dict) # Add one group of groups for each existing group. # Its members are the primary user groups for each original group member. groups_of_groups = [] - if self.enable_mirrored_groups: + if self.enable_primary_groups and self.enable_mirrored_groups: for group in oauth_groups: group_dict = {} group_dict["cn"] = f"Primary user groups for {group['cn']}" diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 3729b0c..a4fbe37 100644 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -27,6 +27,10 @@ if [ -n "${DISABLE_MIRRORED_GROUPS}" ]; then EXTRA_OPTS="${EXTRA_OPTS} --disable-mirrored-groups" fi +if [ -n "${DISABLE_PRIMARY_GROUPS}" ]; then + EXTRA_OPTS="${EXTRA_OPTS} --disable-primary-groups" +fi + if [ -n "${DISABLE_USER_DOMAIN_VERIFICATION}" ]; then EXTRA_OPTS="${EXTRA_OPTS} --disable-user-domain-verification" fi diff --git a/run.py b/run.py index 000620e..7a655a6 100644 --- a/run.py +++ b/run.py @@ -40,6 +40,13 @@ dest="enable_mirrored_groups", help="Disable creation of mirrored groups.", ) + ldap_group.add_argument( + "--disable-primary-groups", + action="store_false", + default=True, + dest="enable_primary_groups", + help="Disable creation of POSIX primary groups for each user.", + ) ldap_group.add_argument( "--disable-user-domain-verification", action="store_false",