mirror of
https://github.com/element-hq/synapse.git
synced 2026-03-29 15:20:16 +00:00
Fixes: #8088 Previously we would perform OIDC discovery on startup, which involves making HTTP requests to the identity provider(s). If that took a long time, we would block startup. If that failed, we would crash startup. This commit: - makes the loading happen in the background on startup - makes an error in the 'preload' non-fatal (though it logs at CRITICAL for visibility) - adds a templated error page to show on failed redirects (for unavailable providers), as otherwise you get a JSON response in your navigator. - This involves introducing 2 new exception types to mark other exceptions and keep the error handling fine-grained. The machinery was already there to load-on-demand the discovery config, so when the identity provider comes back up, the discovery is reattempted and login can succeed. Signed-off-by: Olivier 'reivilibre <oliverw@matrix.org>
118 lines
4.0 KiB
Go
118 lines
4.0 KiB
Go
// This file is licensed under the Affero General Public License (AGPL) version 3.
|
|
//
|
|
// Copyright (C) 2026 Element Creations Ltd
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// See the GNU Affero General Public License for more details:
|
|
// <https://www.gnu.org/licenses/agpl-3.0.html>.
|
|
|
|
package synapse_tests
|
|
|
|
import (
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
|
|
dockerClient "github.com/docker/docker/client"
|
|
"github.com/element-hq/synapse/tests/internal/dockerutil"
|
|
"github.com/matrix-org/complement"
|
|
"github.com/matrix-org/complement/client"
|
|
"github.com/matrix-org/complement/match"
|
|
"github.com/matrix-org/complement/must"
|
|
)
|
|
|
|
const OIDC_HOMESERVER_CONFIG string = `
|
|
oidc_providers:
|
|
- idp_id: "test_provider"
|
|
idp_name: "Test OIDC Provider"
|
|
issuer: "https://example.invalid"
|
|
client_id: "test_client_id"
|
|
client_secret: "test_secret"
|
|
scopes: ["openid"]
|
|
discover: true
|
|
user_mapping_provider:
|
|
module: "synapse.handlers.oidc.JinjaOidcMappingProvider"
|
|
config:
|
|
display_name_template: "{{ user.given_name }}"
|
|
email_template: "{{ user.email }}"
|
|
`
|
|
|
|
// Test that Synapse still starts up when configured with an OIDC provider that is unavailable.
|
|
//
|
|
// This is a regression test: Synapse previously would fail to start up
|
|
// at all if the OIDC provider was down on startup.
|
|
// https://github.com/element-hq/synapse/issues/8088
|
|
//
|
|
// Now instead of failing to start, Synapse will produce a 503 response on the
|
|
// `/_matrix/client/v3/login/sso/redirect/oidc-test_provider` endpoint.
|
|
func TestOIDCProviderUnavailable(t *testing.T) {
|
|
// Deploy a single homeserver
|
|
deployment := complement.Deploy(t, 1)
|
|
defer deployment.Destroy(t)
|
|
|
|
// Get Docker client to manipulate container
|
|
dc, err := dockerClient.NewClientWithOpts(
|
|
dockerClient.FromEnv,
|
|
dockerClient.WithAPIVersionNegotiation(),
|
|
)
|
|
must.NotError(t, "failed creating docker client", err)
|
|
|
|
// Configure the OIDC Provider by writing a config fragment
|
|
err = dockerutil.WriteFileIntoContainer(
|
|
t,
|
|
dc,
|
|
deployment.ContainerID(t, "hs1"),
|
|
"/conf/homeserver.d/oidc_provider.yaml",
|
|
[]byte(OIDC_HOMESERVER_CONFIG),
|
|
)
|
|
if err != nil {
|
|
t.Fatalf("Failed to write updated config to container: %v", err)
|
|
}
|
|
|
|
// Restart the homeserver to apply the new config
|
|
deployment.StopServer(t, "hs1")
|
|
// Careful: port number changes here
|
|
deployment.StartServer(t, "hs1")
|
|
// Must get after the restart so the port number is correct
|
|
unauthedClient := deployment.UnauthenticatedClient(t, "hs1")
|
|
|
|
// Test that trying to log in with an OIDC provider that is down
|
|
// causes an HTML error page to be shown to the user.
|
|
// (This replaces the redirect that would happen if the provider was
|
|
// up.)
|
|
//
|
|
// More importantly, implicitly tests that Synapse can start up
|
|
// and answer requests even though an OIDC provider is down.
|
|
t.Run("/login/sso/redirect shows HTML error", func(t *testing.T) {
|
|
// Build a request to the /redirect/ endpoint, that would normally be navigated to
|
|
// by the user's browser in order to start the login flow.
|
|
queryParams := url.Values{}
|
|
queryParams.Add("redirectUrl", "http://redirect.invalid/redirect")
|
|
res := unauthedClient.Do(t, "GET", []string{"_matrix", "client", "v3", "login", "sso", "redirect", "oidc-test_provider"},
|
|
client.WithQueries(queryParams),
|
|
)
|
|
|
|
body := must.MatchResponse(t, res, match.HTTPResponse{
|
|
// Should get a 503
|
|
StatusCode: http.StatusServiceUnavailable,
|
|
|
|
Headers: map[string]string{
|
|
// Should get an HTML page explaining the problem to the user
|
|
"Content-Type": "text/html; charset=utf-8",
|
|
},
|
|
})
|
|
|
|
bodyText := string(body)
|
|
|
|
// The HTML page contains phrases from the template we expect
|
|
if !strings.Contains(bodyText, "login provider is unavailable right now") {
|
|
t.Fatalf("Keyword not found in HTML error page, got %s", bodyText)
|
|
}
|
|
})
|
|
}
|