Skip to content

Allow anonymous binds to be disabled #61

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 4 commits into from
Jan 17, 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
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,12 @@ Do this as follows:
- `realm-management` > `query-groups`
- `realm-management` > `query-users`

## Disabling Apricot groups
## Configuring the Apricot LDAP server

### Anonymous binds

By default, Apricot allows anonymous queries.
If you would prefer to disable these, please use the `--disable-anonymous-binds` command line option.

### Primary groups

Expand Down
3 changes: 3 additions & 0 deletions apricot/apricot_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def __init__(
domain: str,
port: int,
*,
allow_anonymous_binds: bool = True,
background_refresh: bool = False,
debug: bool = False,
enable_mirrored_groups: bool = True,
Expand All @@ -43,6 +44,7 @@ def __init__(
) -> None:
"""Initialise an ApricotServer.

@param allow_anonymous_binds: Whether to allow anonymous LDAP binds
@param backend: An OAuth backend,
@param client_id: An OAuth client ID
@param client_secret: An OAuth client secret
Expand Down Expand Up @@ -125,6 +127,7 @@ def __init__(
factory = OAuthLDAPServerFactory(
oauth_adaptor,
oauth_client,
allow_anonymous_binds=allow_anonymous_binds,
background_refresh=background_refresh,
refresh_interval=refresh_interval,
)
Expand Down
5 changes: 4 additions & 1 deletion apricot/ldap/oauth_ldap_server_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ def __init__(
oauth_adaptor: OAuthDataAdaptor,
oauth_client: OAuthClient,
*,
allow_anonymous_binds: bool,
background_refresh: bool,
refresh_interval: int,
) -> None:
"""Initialise an OAuthLDAPServerFactory.

@param allow_anonymous_binds: Whether to allow anonymous LDAP binds
@param background_refresh: Whether to refresh the LDAP tree in the background rather than on access
@param oauth_adaptor: An OAuth data adaptor used to construct the LDAP tree
@param oauth_client: An OAuth client used to retrieve user and group data
Expand All @@ -34,6 +36,7 @@ def __init__(
background_refresh=background_refresh,
refresh_interval=refresh_interval,
)
self.allow_anonymous_binds = allow_anonymous_binds

def __repr__(self: Self) -> str:
return f"{self.__class__.__name__} using adaptor {self.adaptor}"
Expand All @@ -46,6 +49,6 @@ def buildProtocol(self: Self, addr: IAddress) -> Protocol: # noqa: N802
@param addr: an object implementing L{IAddress}
"""
id(addr) # ignore unused arguments
proto = ReadOnlyLDAPServer()
proto = ReadOnlyLDAPServer(allow_anonymous_binds=self.allow_anonymous_binds)
proto.factory = self.adaptor
return proto
6 changes: 5 additions & 1 deletion apricot/ldap/read_only_ldap_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@
class ReadOnlyLDAPServer(LDAPServer):
"""A read-only LDAP server."""

def __init__(self: Self) -> None:
def __init__(self: Self, *, allow_anonymous_binds: bool = True) -> None:
"""Initialise a ReadOnlyLDAPServer."""
super().__init__()
self.allow_anonymous_binds = allow_anonymous_binds
self.logger = Logger()

def getRootDSE( # noqa: N802
Expand Down Expand Up @@ -71,6 +72,9 @@ def handle_LDAPBindRequest( # noqa: N802
"""Handle an LDAP bind request."""
try:
self.logger.debug("Handling an LDAP bind request.")
if not (self.allow_anonymous_binds or request.dn):
msg = "Anonymous binds are disabled"
raise ValueError(msg) # noqa: TRY301
return super().handle_LDAPBindRequest(request, controls, reply)
except Exception as exc:
msg = f"LDAP bind request failed. {exc!s}"
Expand Down
3 changes: 2 additions & 1 deletion apricot/oauth/oauth_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import requests
from oauthlib.oauth2 import (
BackendApplicationClient,
InvalidClientIdError,
InvalidGrantError,
LegacyApplicationClient,
TokenExpiredError,
Expand Down Expand Up @@ -180,7 +181,7 @@ def verify(self: Self, username: str, password: str) -> bool:
client_id=self.session_interactive._client.client_id,
client_secret=self.client_secret,
)
except InvalidGrantError as exc:
except (InvalidClientIdError, InvalidGrantError) as exc:
self.logger.warn(
"Authentication failed for user '{user}'. {error}",
user=username,
Expand Down
22 changes: 13 additions & 9 deletions docker/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ EXTRA_OPTS=""
# Common server-level options
if [ -z "${PORT}" ]; then
PORT="1389"
echo "$(date +'%Y-%m-%d %H:%M:%S+0000') [-] PORT environment variable is not set: using default of '${PORT}'"
echo "$(date +'%Y-%m-%d %H:%M:%S') [INFO ] PORT environment variable is not set: using default of '${PORT}'"
fi

if [ -n "${DEBUG}" ]; then
Expand All @@ -19,10 +19,14 @@ fi

# LDAP tree arguments
if [ -z "${DOMAIN}" ]; then
echo "$(date +'%Y-%m-%d %H:%M:%S+0000') [-] DOMAIN environment variable is not set"
echo "$(date +'%Y-%m-%d %H:%M:%S') [INFO ] DOMAIN environment variable is not set"
exit 1
fi

if [ -n "${DISABLE_ANONYMOUS_BINDS}" ]; then
EXTRA_OPTS="${EXTRA_OPTS} --disable-anonymous-binds"
fi

if [ -n "${DISABLE_MIRRORED_GROUPS}" ]; then
EXTRA_OPTS="${EXTRA_OPTS} --disable-mirrored-groups"
fi
Expand All @@ -38,17 +42,17 @@ fi

# OAuth client arguments
if [ -z "${BACKEND}" ]; then
echo "$(date +'%Y-%m-%d %H:%M:%S+0000') [-] BACKEND environment variable is not set"
echo "$(date +'%Y-%m-%d %H:%M:%S') [INFO ] BACKEND environment variable is not set"
exit 1
fi

if [ -z "${CLIENT_ID}" ]; then
echo "$(date +'%Y-%m-%d %H:%M:%S+0000') [-] CLIENT_ID environment variable is not set"
echo "$(date +'%Y-%m-%d %H:%M:%S') [INFO ] CLIENT_ID environment variable is not set"
exit 1
fi

if [ -z "${CLIENT_SECRET}" ]; then
echo "$(date +'%Y-%m-%d %H:%M:%S+0000') [-] CLIENT_SECRET environment variable is not set"
echo "$(date +'%Y-%m-%d %H:%M:%S') [INFO ] CLIENT_SECRET environment variable is not set"
exit 1
fi

Expand All @@ -72,7 +76,7 @@ fi
# Backend arguments: Keycloak
if [ -n "${KEYCLOAK_BASE_URL}" ]; then
if [ -z "${KEYCLOAK_REALM}" ]; then
echo "$(date +'%Y-%m-%d %H:%M:%S+0000') [-] KEYCLOAK_REALM environment variable is not set"
echo "$(date +'%Y-%m-%d %H:%M:%S') [INFO ] KEYCLOAK_REALM environment variable is not set"
exit 1
fi
EXTRA_OPTS="${EXTRA_OPTS} --keycloak-base-url $KEYCLOAK_BASE_URL --keycloak-realm $KEYCLOAK_REALM"
Expand All @@ -86,7 +90,7 @@ fi
if [ -n "${REDIS_HOST}" ]; then
if [ -z "${REDIS_PORT}" ]; then
REDIS_PORT="6379"
echo "$(date +'%Y-%m-%d %H:%M:%S+0000') [-] REDIS_PORT environment variable is not set: using default of '${REDIS_PORT}'"
echo "$(date +'%Y-%m-%d %H:%M:%S') [INFO ] REDIS_PORT environment variable is not set: using default of '${REDIS_PORT}'"
fi
EXTRA_OPTS="${EXTRA_OPTS} --redis-host $REDIS_HOST --redis-port $REDIS_PORT"
fi
Expand All @@ -95,11 +99,11 @@ fi
# TLS arguments
if [ -n "${TLS_PORT}" ]; then
if [ -z "${TLS_CERTIFICATE}" ]; then
echo "$(date +'%Y-%m-%d %H:%M:%S+0000') [-] TLS_CERTIFICATE environment variable is not set"
echo "$(date +'%Y-%m-%d %H:%M:%S') [INFO ] TLS_CERTIFICATE environment variable is not set"
exit 1
fi
if [ -z "${TLS_PRIVATE_KEY}" ]; then
echo "$(date +'%Y-%m-%d %H:%M:%S+0000') [-] TLS_PRIVATE_KEY environment variable is not set"
echo "$(date +'%Y-%m-%d %H:%M:%S') [INFO ] TLS_PRIVATE_KEY environment variable is not set"
exit 1
fi
EXTRA_OPTS="${EXTRA_OPTS} --tls-port $TLS_PORT --tls-certificate $TLS_CERTIFICATE --tls-private-key $TLS_PRIVATE_KEY"
Expand Down
7 changes: 7 additions & 0 deletions run.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@
help="Which domain users belong to.",
required=True,
)
ldap_group.add_argument(
"--disable-anonymous-binds",
action="store_false",
default=True,
dest="allow_anonymous_binds",
help="Disable anonymous LDAP binds.",
)
ldap_group.add_argument(
"--disable-mirrored-groups",
action="store_false",
Expand Down
Loading