diff --git a/CHANGELOG.md b/CHANGELOG.md index c3f3cb51..8ef6be2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ * Fix: broken start when UID does not exist (potential container startup case) * Improve: user/group retrievement for running service and directories * Extend/Improve: [auth] ldap: group membership lookup -* Add: option [auth] dovecot_rip_x_remote_addr +* Add: [auth] remote_ip_source: set the remote IP source for auth algorithms ## 3.5.5 * Improve: [auth] ldap: do not read server info by bind to avoid needless network traffic diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md index 4f6b7ed0..0d0ab6cd 100644 --- a/DOCUMENTATION.md +++ b/DOCUMENTATION.md @@ -1187,17 +1187,25 @@ Port of via network exposed dovecot socket Default: `12345` -##### dovecot_rip_x_remote_addr +##### remote_ip_source _(>= 3.5.6)_ -Use the `X-Remote-Addr` value for the remote IP (rip) parameter in the -dovecot authentication protocol. +For authentication mechanisms that are made aware of the remote IP +(such as dovecot via the `rip=` auth protocol parameter), determine +the source to use. Currently, valid values are -If set, Radicale must be running behind a proxy that you control and -that sets/overwrites the `X-Remote-Addr` header (doesn't pass it) so -that the value passed to dovecot is reliable. For example, for nginx, -add +`REMOTE_ADDR` (default) +: Use the REMOTE_ADDR environment variable that captures the remote + address of the socket connection. + +`X-Remote-Addr` +: Use the `X-Remote-Addr` HTTP header value. + +In the case of `X-Remote-Addr`, Radicale must be running be running +behind a proxy that you control and that sets/overwrites the +`X-Remote-Addr` header (doesn't pass it) so that the value passed +to dovecot is reliable. For example, for nginx, add ``` proxy_set_header X-Remote-Addr $remote_addr; @@ -1205,7 +1213,7 @@ add to the configuration sample. -Default: `False` +Default: `REMOTE_ADDR` ##### imap_host diff --git a/config b/config index 37040eff..79bb275a 100644 --- a/config +++ b/config @@ -136,8 +136,9 @@ # Port of via network exposed dovecot socket #dovecot_port = 12345 -# Use X-Remote-Addr for remote IP (rip) in dovecot authentication -#dovecot_rip_x_remote_addr = False +# Remote address source for authentication mechanisms (such as dovecot) +# that are passed this information. +#remote_ip_source = REMOTE_ADDR # IMAP server hostname # Syntax: address | address:port | [address]:port | imap.server.tld diff --git a/radicale/auth/__init__.py b/radicale/auth/__init__.py index d6371383..c32a8306 100644 --- a/radicale/auth/__init__.py +++ b/radicale/auth/__init__.py @@ -64,6 +64,8 @@ INSECURE_IF_NO_LOOPBACK_TYPES: Sequence[str] = ( AUTH_SOCKET_FAMILY: Sequence[str] = ("AF_UNIX", "AF_INET", "AF_INET6") +REMOTE_ADDR_SOURCE: Sequence[str] = ("REMOTE_ADDR", "X-Remote-Addr") + def load(configuration: "config.Configuration") -> "BaseAuth": """Load the authentication module chosen in configuration.""" diff --git a/radicale/auth/dovecot.py b/radicale/auth/dovecot.py index b4d28c32..479f4111 100644 --- a/radicale/auth/dovecot.py +++ b/radicale/auth/dovecot.py @@ -33,7 +33,8 @@ class Auth(auth.BaseAuth): self.timeout = 5 self.request_id_gen = itertools.count(1) - self.use_x_remote_addr = configuration.get("auth", "dovecot_rip_x_remote_addr") + remote_ip_source = configuration.get("auth", "remote_ip_source") + self.use_x_remote_addr = remote_ip_source == 'X-Remote-Addr' config_family = configuration.get("auth", "dovecot_connection_type") if config_family == "AF_UNIX": diff --git a/radicale/config.py b/radicale/config.py index a228ed97..7693e9e6 100644 --- a/radicale/config.py +++ b/radicale/config.py @@ -253,10 +253,11 @@ DEFAULT_CONFIG_SCHEMA: types.CONFIG_SCHEMA = OrderedDict([ "value": "12345", "help": "dovecot auth port", "type": int}), - ("dovecot_rip_x_remote_addr", { - "value": "False", - "help": "use X-Remote-Addr for dovecot auth remote IP (rip) parameter", - "type": bool}), + ("remote_ip_source", { + "value": "REMOTE_ADDR", + "help": "remote address source for passing it to auth method", + "type": str, + "internal": auth.REMOTE_ADDR_SOURCE}), ("realm", { "value": "Radicale - Password Required", "help": "message displayed when a password is needed", diff --git a/radicale/tests/test_auth.py b/radicale/tests/test_auth.py index e34256ed..5ffc540d 100644 --- a/radicale/tests/test_auth.py +++ b/radicale/tests/test_auth.py @@ -428,7 +428,7 @@ class TestBaseAuthRequests(BaseTest): 'HTTP_X_REMOTE_ADDR': '172.17.16.15', }, extra_config={ - 'auth': {"dovecot_rip_x_remote_addr": "True"}, + 'auth': {"remote_ip_source": "X-Remote-Addr"}, }) @pytest.mark.skipif(sys.platform == 'win32', reason="Not supported on Windows") @@ -439,7 +439,7 @@ class TestBaseAuthRequests(BaseTest): 'HTTP_X_REMOTE_ADDR': '172.17.16.15\trip=127.0.0.1', }, extra_config={ - 'auth': {"dovecot_rip_x_remote_addr": "True"}, + 'auth': {"remote_ip_source": "X-Remote-Addr"}, }) def test_custom(self) -> None: