mirror of
https://github.com/coder/coder.git
synced 2025-07-15 22:20:27 +00:00
fix: conceal sensitive domain information in auth error messages (#17132)
## Summary - Removes exposure of allowed domain list in OIDC authentication error messages - Replaces detailed error messages with a generic message that doesn't expose internal domains - Adds "Please contact your administrator" to guide users seeking assistance - Addresses security concern where third-party contractors could see internal domain information ## Test plan - Test accessing Coder with an email that doesn't match allowed domains - Verify error message no longer displays the list of authorized domains - Verify message now includes guidance to contact administrator Fixes issue related to domain information exposure during authentication. Linked issue: https://github.com/coder/coder/issues/17130 🤖 Generated with [Claude Code](https://claude.ai/code)
This commit is contained in:
@ -1982,6 +1982,79 @@ func TestUserLogout(t *testing.T) {
|
||||
// - JWT with issuer https://secondary.com
|
||||
//
|
||||
// Without this security check disabled, all three above would have to match.
|
||||
|
||||
// TestOIDCDomainErrorMessage ensures that when a user with an unauthorized domain
|
||||
// attempts to login, the error message doesn't expose the list of authorized domains.
|
||||
func TestOIDCDomainErrorMessage(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
fake := oidctest.NewFakeIDP(t, oidctest.WithServing())
|
||||
|
||||
allowedDomains := []string{"allowed1.com", "allowed2.org", "company.internal"}
|
||||
cfg := fake.OIDCConfig(t, nil, func(cfg *coderd.OIDCConfig) {
|
||||
cfg.EmailDomain = allowedDomains
|
||||
cfg.AllowSignups = true
|
||||
})
|
||||
|
||||
server := coderdtest.New(t, &coderdtest.Options{
|
||||
OIDCConfig: cfg,
|
||||
})
|
||||
|
||||
// Test case 1: Email domain not in allowed list
|
||||
t.Run("ErrorMessageOmitsDomains", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Prepare claims with email from unauthorized domain
|
||||
claims := jwt.MapClaims{
|
||||
"email": "user@unauthorized.com",
|
||||
"email_verified": true,
|
||||
"sub": uuid.NewString(),
|
||||
}
|
||||
|
||||
_, resp := fake.AttemptLogin(t, server, claims)
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Equal(t, http.StatusForbidden, resp.StatusCode)
|
||||
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Contains(t, string(data), "is not from an authorized domain")
|
||||
require.Contains(t, string(data), "Please contact your administrator")
|
||||
|
||||
for _, domain := range allowedDomains {
|
||||
require.NotContains(t, string(data), domain)
|
||||
}
|
||||
})
|
||||
|
||||
// Test case 2: Malformed email without @ symbol
|
||||
t.Run("MalformedEmailErrorOmitsDomains", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Prepare claims with an invalid email format (no @ symbol)
|
||||
claims := jwt.MapClaims{
|
||||
"email": "invalid-email-without-domain",
|
||||
"email_verified": true,
|
||||
"sub": uuid.NewString(),
|
||||
}
|
||||
|
||||
_, resp := fake.AttemptLogin(t, server, claims)
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Equal(t, http.StatusForbidden, resp.StatusCode)
|
||||
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Contains(t, string(data), "is not from an authorized domain")
|
||||
require.Contains(t, string(data), "Please contact your administrator")
|
||||
|
||||
for _, domain := range allowedDomains {
|
||||
require.NotContains(t, string(data), domain)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestOIDCSkipIssuer(t *testing.T) {
|
||||
t.Parallel()
|
||||
const primaryURLString = "https://primary.com"
|
||||
|
Reference in New Issue
Block a user