Skip to content

Add flag to disable primary groups #59

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions apricot/apricot_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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)
Expand Down Expand Up @@ -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,
)

Expand Down
2 changes: 0 additions & 2 deletions apricot/ldap/oauth_ldap_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
22 changes: 20 additions & 2 deletions apricot/ldap/read_only_ldap_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
22 changes: 13 additions & 9 deletions apricot/oauth/oauth_data_adaptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
"""
Expand All @@ -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:
Expand Down Expand Up @@ -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']}"
Expand Down
4 changes: 4 additions & 0 deletions docker/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions run.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Loading