From dbf300e52a6ec2d2a795e4ff1750ff21eec63de0 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 24 Oct 2024 15:32:49 -0400 Subject: [PATCH 1/2] chore: return json for disabled scim Customers reporting html pages returned to SCIM. Likely a disabled SCIM. We should just report a more consumable error by the SCIM provider. --- enterprise/coderd/coderd.go | 12 ++++++++++ enterprise/coderd/coderd_test.go | 40 ++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/enterprise/coderd/coderd.go b/enterprise/coderd/coderd.go index f44c924957e6f..79453d617ed6e 100644 --- a/enterprise/coderd/coderd.go +++ b/enterprise/coderd/coderd.go @@ -465,6 +465,18 @@ func New(ctx context.Context, options *Options) (_ *API, err error) { r.Patch("/{id}", api.scimPatchUser) }) }) + } else { + // Show a helpful 404 error. Because this is not under the /api/v2 routes, + // the frontend is the fallback. A html page is not a helpful error for + // a SCIM provider. This JSON has a call to action that __may__ resolve + // the issue. + // Using Mount to cover all subroute possibilities. + api.AGPL.RootHandler.Mount("/scim/v2", http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + httpapi.Write(r.Context(), w, http.StatusNotFound, codersdk.Response{ + Message: "SCIM is disabled, please contact your administrator if you believe this is an error", + Detail: "SCIM endpoints are disabled if no SCIM is configured. Configure 'CODER_SCIM_AUTH_HEADER' to enable.", + }) + }))) } meshTLSConfig, err := replicasync.CreateDERPMeshTLSConfig(options.AccessURL.Hostname(), options.TLSCertificates) diff --git a/enterprise/coderd/coderd_test.go b/enterprise/coderd/coderd_test.go index fc9c5c1c7de1e..03edd9b6e9bd3 100644 --- a/enterprise/coderd/coderd_test.go +++ b/enterprise/coderd/coderd_test.go @@ -3,6 +3,7 @@ package coderd_test import ( "bytes" "context" + "encoding/json" "fmt" "net/http" "net/http/httptest" @@ -503,6 +504,45 @@ func TestMultiReplica_EmptyRelayAddress_DisabledDERP(t *testing.T) { } } +func TestSCIMDisabled(t *testing.T) { + t.Parallel() + + cli, _ := coderdenttest.New(t, &coderdenttest.Options{}) + + checkPaths := []string{ + "/scim/v2", + "/scim/v2/", + "/scim/v2/users", + "/scim/v2/Users", + "/scim/v2/Users/", + "/scim/v2/random/path/that/is/long", + "/scim/v2/random/path/that/is/long.txt", + } + + for _, p := range checkPaths { + p := p + t.Run(p, func(t *testing.T) { + t.Parallel() + + u, err := cli.URL.Parse(p) + require.NoError(t, err) + + req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, u.String(), nil) + require.NoError(t, err) + + resp, err := http.DefaultClient.Do(req) + require.NoError(t, err) + require.Equal(t, http.StatusNotFound, resp.StatusCode) + + var apiError codersdk.Response + err = json.NewDecoder(resp.Body).Decode(&apiError) + require.NoError(t, err) + + require.Contains(t, apiError.Message, "SCIM is disabled") + }) + } +} + // testDBAuthzRole returns a context with a subject that has a role // with permissions required for test setup. func testDBAuthzRole(ctx context.Context) context.Context { From c4c80f38ff5bdc2aebfa29da51f34d7c2cd3f4a3 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 24 Oct 2024 15:36:39 -0400 Subject: [PATCH 2/2] linting --- enterprise/coderd/coderd_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/enterprise/coderd/coderd_test.go b/enterprise/coderd/coderd_test.go index 03edd9b6e9bd3..d8051d8b502dd 100644 --- a/enterprise/coderd/coderd_test.go +++ b/enterprise/coderd/coderd_test.go @@ -532,6 +532,7 @@ func TestSCIMDisabled(t *testing.T) { resp, err := http.DefaultClient.Do(req) require.NoError(t, err) + defer resp.Body.Close() require.Equal(t, http.StatusNotFound, resp.StatusCode) var apiError codersdk.Response