Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

comment out code that removes trailing slash as per 5823. #11224

Closed
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
1 change: 1 addition & 0 deletions changelog.d/11224.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Remove trialing slashes form homeserver url so other services don't take it literally.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few typos here: trialing -> trailing, form -> from, and I think url -> URL since the latter is an abbreviation.

I also think we can better explain the change from the user's perspective.

Suggested change
Remove trialing slashes form homeserver url so other services don't take it literally.
Ensure the URL served at `/.well-known/matrix/server/` does not end with a trailing slash, to workaround clients which expect this.

20 changes: 0 additions & 20 deletions docs/sample_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -91,28 +91,8 @@ pid_file: DATADIR/homeserver.pid
# Otherwise, it should be the URL to reach Synapse's client HTTP listener (see
# 'listeners' below).
#
# Defaults to 'https://<server_name>/'.
#
#public_baseurl: https://example.com/

# Uncomment the following to tell other servers to send federation traffic on
# port 443.
#
# By default, other servers will try to reach our server on port 8448, which can
# be inconvenient in some environments.
#
# Provided 'https://<server_name>/' on port 443 is routed to Synapse, this
# option configures Synapse to serve a file at
# 'https://<server_name>/.well-known/matrix/server'. This will tell other
# servers to send traffic to port 443 instead.
#
# See https://matrix-org.github.io/synapse/latest/delegate.html for more
# information.
#
# Defaults to 'false'.
#
#serve_server_wellknown: true

Comment on lines -94 to -115
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've commented below where this is generated, but I don't think it's correct to remove this. Don't forget to re-run the script that generates this config once you've made changes.

# Set the soft limit on the number of file descriptors synapse can use
# Zero is used to indicate synapse should set the soft limit to the
# hard limit.
Expand Down
2 changes: 2 additions & 0 deletions synapse/config/cas.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ def read_config(self, config, **kwargs):

# TODO Update this to a _synapse URL.
public_baseurl = self.root.server.public_baseurl
if not public_baseurl.endswith("/"):
public_baseurl = public_baseurl + "/"
self.cas_service_url = public_baseurl + "_matrix/client/r0/login/cas/ticket"
Comment on lines 39 to 42
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as on saml2.py


self.cas_displayname_attribute = cas_config.get("displayname_attribute")
Expand Down
2 changes: 2 additions & 0 deletions synapse/config/oidc.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ def read_config(self, config, **kwargs):
)

public_baseurl = self.root.server.public_baseurl
if not public_baseurl.endswith("/"):
public_baseurl = public_baseurl + "/"
self.oidc_callback_url = public_baseurl + "_synapse/client/oidc/callback"
Comment on lines 61 to 64
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as in saml2 applies


@property
Expand Down
2 changes: 2 additions & 0 deletions synapse/config/saml2.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@ def _default_saml_config_dict(
optional_attributes -= required_attributes

public_baseurl = self.root.server.public_baseurl
if not public_baseurl.endswith("/"):
public_baseurl = public_baseurl + "/"
metadata_url = public_baseurl + "_synapse/client/saml2/metadata.xml"
response_url = public_baseurl + "_synapse/client/saml2/authn_response"
return {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it'd be clearer if things called public_baseurl consistently did not end in a slash, and we changed path building to explicitly add in the slash. After all, the slash is part of a URL's path.

Also, I think the if is redundant because the public_baseurl is never going to end in a / with the proposed changes?

Expand Down
66 changes: 7 additions & 59 deletions synapse/config/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import logging
import os.path
import re
import urllib.parse
from textwrap import indent
from typing import Any, Dict, Iterable, List, Optional, Set, Tuple, Union

Expand Down Expand Up @@ -265,44 +264,13 @@ def read_config(self, config, **kwargs):
self.use_frozen_dicts = config.get("use_frozen_dicts", False)
self.serve_server_wellknown = config.get("serve_server_wellknown", False)

# Whether we should serve a "client well-known":
# (a) at .well-known/matrix/client on our client HTTP listener
# (b) in the response to /login
#
# ... which together help ensure that clients use our public_baseurl instead of
# whatever they were told by the user.
#
# For the sake of backwards compatibility with existing installations, this is
# True if public_baseurl is specified explicitly, and otherwise False. (The
# reasoning here is that we have no way of knowing that the default
# public_baseurl is actually correct for existing installations - many things
# will not work correctly, but that's (probably?) better than sending clients
# to a completely broken URL.
self.serve_client_wellknown = False
Comment on lines -268 to -281
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this removed? This removes functionality that we're not adjusting here (serving a json document at /.well-known/matrix/client)


public_baseurl = config.get("public_baseurl")
if public_baseurl is None:
public_baseurl = f"https://{self.server_name}/"
logger.info("Using default public_baseurl %s", public_baseurl)
else:
self.serve_client_wellknown = True
if public_baseurl[-1] != "/":
public_baseurl += "/"
self.public_baseurl = public_baseurl

# check that public_baseurl is valid
try:
splits = urllib.parse.urlsplit(self.public_baseurl)
except Exception as e:
raise ConfigError(f"Unable to parse URL: {e}", ("public_baseurl",))
if splits.scheme not in ("https", "http"):
raise ConfigError(
f"Invalid scheme '{splits.scheme}': only https and http are supported"
)
if splits.query or splits.fragment:
raise ConfigError(
"public_baseurl cannot contain query parameters or a #-fragment"
)
self.public_baseurl = config.get("public_baseurl") or "/"
if not self.public_baseurl.endswith("/"):
self.public_baseurl = self.public_baseurl + "/"
# Commented out due to https://github.com/matrix-org/synapse/issues/8308
# if self.public_baseurl is not None:
# if self.public_baseurl[-1] != "/":
# self.public_baseurl += "/"
richvdh marked this conversation as resolved.
Show resolved Hide resolved

# Whether to enable user presence.
presence_config = config.get("presence") or {}
Expand Down Expand Up @@ -808,28 +776,8 @@ def generate_config_section(
# Otherwise, it should be the URL to reach Synapse's client HTTP listener (see
# 'listeners' below).
#
# Defaults to 'https://<server_name>/'.
#
Comment on lines -811 to -812
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this removed? At the very least, we should still describe the behaviour that happens if this config option is omitted (or else note and enforce that it is mandatory)

#public_baseurl: https://example.com/

# Uncomment the following to tell other servers to send federation traffic on
# port 443.
#
# By default, other servers will try to reach our server on port 8448, which can
# be inconvenient in some environments.
#
# Provided 'https://<server_name>/' on port 443 is routed to Synapse, this
# option configures Synapse to serve a file at
# 'https://<server_name>/.well-known/matrix/server'. This will tell other
# servers to send traffic to port 443 instead.
#
# See https://matrix-org.github.io/synapse/latest/delegate.html for more
# information.
#
# Defaults to 'false'.
#
#serve_server_wellknown: true

Comment on lines -815 to -832
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this removed? We are trying to tweak the behaviour when serve_server_wellknown is true.

# Set the soft limit on the number of file descriptors synapse can use
# Zero is used to indicate synapse should set the soft limit to the
# hard limit.
Expand Down
8 changes: 5 additions & 3 deletions synapse/config/sso.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,11 @@ def read_config(self, config, **kwargs):
# gracefully to the client). This would make it pointless to ask the user for
# confirmation, since the URL the confirmation page would be showing wouldn't be
# the client's.
login_fallback_url = (
self.root.server.public_baseurl + "_matrix/static/client/login"
)

_b_url = self.root.server.public_baseurl or "/"
# if _b_url.endswith("/"):
# _b_url = _b_url[:-1]
login_fallback_url = _b_url + "_matrix/static/client/login"
Comment on lines +105 to +108
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's going on here? self.root.server.public_baseurl doesn't end in /, so why are we falling back to "/"?

I would have expected to see _matrix replaced with /_matrix here --- it seems that the previous code assumped this ended with a slash.

self.sso_client_whitelist.append(login_fallback_url)

def generate_config_section(self, **kwargs):
Expand Down
7 changes: 4 additions & 3 deletions synapse/handlers/oidc.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,9 +282,10 @@ def __init__(
# Calculate the prefix for OIDC callback paths based on the public_baseurl.
# We'll insert this into the Path= parameter of any session cookies we set.
public_baseurl_path = urlparse(hs.config.server.public_baseurl).path
self._callback_path_prefix = (
public_baseurl_path.encode("utf-8") + b"_synapse/client/oidc"
)
_b_url = public_baseurl_path
if _b_url.endswith("/"):
_b_url = _b_url[:-1]
self._callback_path_prefix = _b_url.encode("utf-8") + b"_synapse/client/oidc"
Comment on lines +285 to +288
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As below, isn't the public_baseurl never going to end in a "/" and so I think line +287 will never run?
I think it might make more sense to change b"_synapse/client/oidc" to b"/_synapse/client/oidc"


self._oidc_attribute_requirements = provider.attribute_requirements
self._scopes = provider.scopes
Expand Down
5 changes: 4 additions & 1 deletion synapse/module_api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,10 @@ def public_baseurl(self) -> str:

Added in Synapse v1.39.0.
"""
return self._hs.config.server.public_baseurl
_b_url = self._hs.config.server.public_baseurl
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As below, isn't the public_baseurl never going to end in a "/" and so I think line +358 will never run?

if _b_url.endswith("/"):
_b_url = _b_url[:-1]
return _b_url

@property
def email_app_name(self) -> str:
Expand Down
5 changes: 4 additions & 1 deletion synapse/rest/client/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,14 @@ async def on_GET(self, request: SynapseRequest, stagetype: str) -> None:
sitekey=self.hs.config.captcha.recaptcha_public_key,
)
elif stagetype == LoginType.TERMS:
_b_url = self.hs.config.server.public_baseurl
if _b_url.endswith("/"):
_b_url = _b_url[:-1]
html = self.terms_template.render(
session=session,
terms_url="%s_matrix/consent?v=%s"
% (
self.hs.config.server.public_baseurl,
_b_url,
Comment on lines 68 to +77
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't look right to me.

  • the PR changes public_baseurl to never end in a forward slash, so we're never going to hit line +72
  • the left hand side seems to assume that the baseurl ends in a slash, so that the terms_url contains a / before _matrix. But as written tht slash will never be present.

self.hs.config.consent.user_consent_version,
),
myurl="%s/r0/auth/%s/fallback/web"
Expand Down
6 changes: 6 additions & 0 deletions synapse/rest/client/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,8 @@ def __init__(self, hs: "HomeServer"):
_load_sso_handlers(hs)
self._sso_handler = hs.get_sso_handler()
self._public_baseurl = hs.config.server.public_baseurl
if not self._public_baseurl.endswith("/"):
self._public_baseurl = self._public_baseurl + "/"
Comment on lines 494 to +496
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't hs.config.server.public_baseurl never going to end with a / after this PR? So the branch condition is always true?


async def on_GET(
self, request: SynapseRequest, idp_id: Optional[str] = None
Expand Down Expand Up @@ -543,6 +545,10 @@ def __init__(self, hs: "HomeServer"):

async def on_GET(self, request: SynapseRequest) -> None:
client_redirect_url = parse_string(request, "redirectUrl")

if client_redirect_url and not (client_redirect_url.endswith("/")):
client_redirect_url = client_redirect_url + "/"

ticket = parse_string(request, "ticket", required=True)

# Maybe get a session ID (if this ticket is from user interactive
Expand Down
12 changes: 10 additions & 2 deletions synapse/rest/well_known.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,18 @@ def __init__(self, hs: "HomeServer"):
self._config = hs.config

def get_well_known(self) -> Optional[JsonDict]:
if not self._config.server.serve_client_wellknown:
if not self._config.server.serve_server_wellknown:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is incorrect. result below looks like it is matching the client wellknown response, see https://spec.matrix.org/v1.1/client-server-api/#getwell-knownmatrixclient

return None

result = {"m.homeserver": {"base_url": self._config.server.public_baseurl}}
_b_url = self._config.server.public_baseurl
if _b_url.endswith("/"):
Comment on lines +40 to +41
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the point of your change to ensure that self._config.server.public_baseurl doesn't end with "/"? So isn't this branch redundant?

_b_url = _b_url[:-1]

result = {
"m.homeserver": {
"base_url": _b_url,
}
}

if self._config.registration.default_identity_server:
result["m.identity_server"] = {
Expand Down
2 changes: 1 addition & 1 deletion tests/handlers/test_oidc.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ def test_redirect_request(self):
# The cookie name and path don't really matter, just that it has to be coherent
# between the callback & redirect handlers.
parts = [p.strip() for p in cookie_header.split(b";")]
self.assertIn(b"Path=/_synapse/client/oidc", parts)
self.assertIn(b"Path=_synapse/client/oidc", parts)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks highly suspicious to me. What's your thinking here? My concerns:

  1. Does this cause problems for clients who already have an existing cookie with the old path? Not familiar enough with OIDC to say either way.
  2. As I understand it, the goal for this PR is that the only externally visible changes are to the .well-known/matrix/server response.

name, cookie = parts[0].split(b"=")
self.assertEqual(name, b"oidc_session")

Expand Down
2 changes: 1 addition & 1 deletion tests/rest/client/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ def default_config(self):
# public_baseurl uses an http:// scheme because FakeChannel.isSecure() returns
# False, so synapse will see the requested uri as http://..., so using http in
# the public_baseurl stops Synapse trying to redirect to https.
config["public_baseurl"] = "http://synapse.test"
config["public_baseurl"] = "http://synapse.test/"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't follow this.

  1. default_config gets called here and passed to setup_test_homeserver.
    config = self.default_config()
    config["enable_registration_captcha"] = True
    config["recaptcha_public_key"] = "brokencake"
    config["registrations_require_3pid"] = []
    hs = self.setup_test_homeserver(config=config)
  2. this then gets parsed just as if it was a config file on disk:

    synapse/tests/unittest.py

    Lines 486 to 493 in 0dda1a7

    if "config" not in kwargs:
    config = self.default_config()
    else:
    config = kwargs["config"]
    # Parse the config from a config dict into a HomeServerConfig
    config_obj = HomeServerConfig()
    config_obj.parse_config_dict(config, "", "")

This PR means the config parsing should ignore the final trailing slash. So I don't see what this change achieves?


if HAS_OIDC:
# we enable OIDC as a way of testing SSO flows
Expand Down
4 changes: 3 additions & 1 deletion tests/rest/test_well_known.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,20 @@ def create_test_resource(self):
{
"public_baseurl": "https://tesths",
"default_identity_server": "https://testis",
"serve_server_wellknown": True,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are testing the client wellknown here---this doesn't look right.

}
)
def test_client_well_known(self):
channel = self.make_request(
"GET", "/.well-known/matrix/client", shorthand=False
)

# import ipdb; ipdb.set_trace()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this needs removing.

self.assertEqual(channel.code, 200)
self.assertEqual(
channel.json_body,
{
"m.homeserver": {"base_url": "https://tesths/"},
"m.homeserver": {"base_url": "https://tesths"},
"m.identity_server": {"base_url": "https://testis"},
},
)
Expand Down
2 changes: 1 addition & 1 deletion tests/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ def make_request(
):
if path.startswith(b"/"):
path = path[1:]
path = b"/_matrix/client/r0/" + path
path = b"_matrix/client/r0/" + path

if not path.startswith(b"/"):
path = b"/" + path
Expand Down