chore(coderd): add tests for big oidc tokens (#12424)

- Adds two test cases for a 64k+ ID token and a 64k+ userinfo payload.
- Reformats the entire test cases array as instructed by CI
This commit is contained in:
Cian Johnston 2024-03-05 14:46:00 +00:00 committed by GitHub
parent b1f9a6dc31
commit 4343998c37
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 229 additions and 176 deletions

View File

@ -19,6 +19,7 @@ import (
"github.com/stretchr/testify/require"
"golang.org/x/xerrors"
"cdr.dev/slog"
"cdr.dev/slog/sloggers/slogtest"
"github.com/coder/coder/v2/coderd"
"github.com/coder/coder/v2/coderd/audit"
@ -30,6 +31,7 @@ import (
"github.com/coder/coder/v2/coderd/database/dbtestutil"
"github.com/coder/coder/v2/coderd/promoauth"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/cryptorand"
"github.com/coder/coder/v2/testutil"
)
@ -742,202 +744,243 @@ func TestUserOIDC(t *testing.T) {
StatusCode int
IgnoreEmailVerified bool
IgnoreUserInfo bool
}{{
Name: "EmailOnly",
IDTokenClaims: jwt.MapClaims{
"email": "kyle@kwc.io",
}{
{
Name: "EmailOnly",
IDTokenClaims: jwt.MapClaims{
"email": "kyle@kwc.io",
},
AllowSignups: true,
StatusCode: http.StatusOK,
Username: "kyle",
},
AllowSignups: true,
StatusCode: http.StatusOK,
Username: "kyle",
}, {
Name: "EmailNotVerified",
IDTokenClaims: jwt.MapClaims{
"email": "kyle@kwc.io",
"email_verified": false,
{
Name: "EmailNotVerified",
IDTokenClaims: jwt.MapClaims{
"email": "kyle@kwc.io",
"email_verified": false,
},
AllowSignups: true,
StatusCode: http.StatusForbidden,
},
AllowSignups: true,
StatusCode: http.StatusForbidden,
}, {
Name: "EmailNotAString",
IDTokenClaims: jwt.MapClaims{
"email": 3.14159,
"email_verified": false,
{
Name: "EmailNotAString",
IDTokenClaims: jwt.MapClaims{
"email": 3.14159,
"email_verified": false,
},
AllowSignups: true,
StatusCode: http.StatusBadRequest,
},
AllowSignups: true,
StatusCode: http.StatusBadRequest,
}, {
Name: "EmailNotVerifiedIgnored",
IDTokenClaims: jwt.MapClaims{
"email": "kyle@kwc.io",
"email_verified": false,
{
Name: "EmailNotVerifiedIgnored",
IDTokenClaims: jwt.MapClaims{
"email": "kyle@kwc.io",
"email_verified": false,
},
AllowSignups: true,
StatusCode: http.StatusOK,
Username: "kyle",
IgnoreEmailVerified: true,
},
AllowSignups: true,
StatusCode: http.StatusOK,
Username: "kyle",
IgnoreEmailVerified: true,
}, {
Name: "NotInRequiredEmailDomain",
IDTokenClaims: jwt.MapClaims{
"email": "kyle@kwc.io",
"email_verified": true,
{
Name: "NotInRequiredEmailDomain",
IDTokenClaims: jwt.MapClaims{
"email": "kyle@kwc.io",
"email_verified": true,
},
AllowSignups: true,
EmailDomain: []string{
"coder.com",
},
StatusCode: http.StatusForbidden,
},
AllowSignups: true,
EmailDomain: []string{
"coder.com",
{
Name: "EmailDomainCaseInsensitive",
IDTokenClaims: jwt.MapClaims{
"email": "kyle@KWC.io",
"email_verified": true,
},
AllowSignups: true,
EmailDomain: []string{
"kwc.io",
},
StatusCode: http.StatusOK,
},
StatusCode: http.StatusForbidden,
}, {
Name: "EmailDomainCaseInsensitive",
IDTokenClaims: jwt.MapClaims{
"email": "kyle@KWC.io",
"email_verified": true,
{
Name: "EmailDomainSubset",
IDTokenClaims: jwt.MapClaims{
"email": "colin@gmail.com",
"email_verified": true,
},
AllowSignups: true,
EmailDomain: []string{
"mail.com",
},
StatusCode: http.StatusForbidden,
},
AllowSignups: true,
EmailDomain: []string{
"kwc.io",
{
Name: "EmptyClaims",
IDTokenClaims: jwt.MapClaims{},
AllowSignups: true,
StatusCode: http.StatusBadRequest,
},
StatusCode: http.StatusOK,
}, {
Name: "EmailDomainSubset",
IDTokenClaims: jwt.MapClaims{
"email": "colin@gmail.com",
"email_verified": true,
{
Name: "NoSignups",
IDTokenClaims: jwt.MapClaims{
"email": "kyle@kwc.io",
"email_verified": true,
},
StatusCode: http.StatusForbidden,
},
AllowSignups: true,
EmailDomain: []string{
"mail.com",
{
Name: "UsernameFromEmail",
IDTokenClaims: jwt.MapClaims{
"email": "kyle@kwc.io",
"email_verified": true,
},
Username: "kyle",
AllowSignups: true,
StatusCode: http.StatusOK,
},
StatusCode: http.StatusForbidden,
}, {
Name: "EmptyClaims",
IDTokenClaims: jwt.MapClaims{},
AllowSignups: true,
StatusCode: http.StatusBadRequest,
}, {
Name: "NoSignups",
IDTokenClaims: jwt.MapClaims{
"email": "kyle@kwc.io",
"email_verified": true,
{
Name: "UsernameFromClaims",
IDTokenClaims: jwt.MapClaims{
"email": "kyle@kwc.io",
"email_verified": true,
"preferred_username": "hotdog",
},
Username: "hotdog",
AllowSignups: true,
StatusCode: http.StatusOK,
},
StatusCode: http.StatusForbidden,
}, {
Name: "UsernameFromEmail",
IDTokenClaims: jwt.MapClaims{
"email": "kyle@kwc.io",
"email_verified": true,
{
// Services like Okta return the email as the username:
// https://developer.okta.com/docs/reference/api/oidc/#base-claims-always-present
Name: "UsernameAsEmail",
IDTokenClaims: jwt.MapClaims{
"email": "kyle@kwc.io",
"email_verified": true,
"preferred_username": "kyle@kwc.io",
},
Username: "kyle",
AllowSignups: true,
StatusCode: http.StatusOK,
},
Username: "kyle",
AllowSignups: true,
StatusCode: http.StatusOK,
}, {
Name: "UsernameFromClaims",
IDTokenClaims: jwt.MapClaims{
"email": "kyle@kwc.io",
"email_verified": true,
"preferred_username": "hotdog",
{
// See: https://github.com/coder/coder/issues/4472
Name: "UsernameIsEmail",
IDTokenClaims: jwt.MapClaims{
"preferred_username": "kyle@kwc.io",
},
Username: "kyle",
AllowSignups: true,
StatusCode: http.StatusOK,
},
Username: "hotdog",
AllowSignups: true,
StatusCode: http.StatusOK,
}, {
// Services like Okta return the email as the username:
// https://developer.okta.com/docs/reference/api/oidc/#base-claims-always-present
Name: "UsernameAsEmail",
IDTokenClaims: jwt.MapClaims{
"email": "kyle@kwc.io",
"email_verified": true,
"preferred_username": "kyle@kwc.io",
{
Name: "WithPicture",
IDTokenClaims: jwt.MapClaims{
"email": "kyle@kwc.io",
"email_verified": true,
"preferred_username": "kyle",
"picture": "/example.png",
},
Username: "kyle",
AllowSignups: true,
AvatarURL: "/example.png",
StatusCode: http.StatusOK,
},
Username: "kyle",
AllowSignups: true,
StatusCode: http.StatusOK,
}, {
// See: https://github.com/coder/coder/issues/4472
Name: "UsernameIsEmail",
IDTokenClaims: jwt.MapClaims{
"preferred_username": "kyle@kwc.io",
{
Name: "WithUserInfoClaims",
IDTokenClaims: jwt.MapClaims{
"email": "kyle@kwc.io",
"email_verified": true,
},
UserInfoClaims: jwt.MapClaims{
"preferred_username": "potato",
"picture": "/example.png",
},
Username: "potato",
AllowSignups: true,
AvatarURL: "/example.png",
StatusCode: http.StatusOK,
},
Username: "kyle",
AllowSignups: true,
StatusCode: http.StatusOK,
}, {
Name: "WithPicture",
IDTokenClaims: jwt.MapClaims{
"email": "kyle@kwc.io",
"email_verified": true,
"preferred_username": "kyle",
"picture": "/example.png",
{
Name: "GroupsDoesNothing",
IDTokenClaims: jwt.MapClaims{
"email": "coolin@coder.com",
"groups": []string{"pingpong"},
},
AllowSignups: true,
StatusCode: http.StatusOK,
},
Username: "kyle",
AllowSignups: true,
AvatarURL: "/example.png",
StatusCode: http.StatusOK,
}, {
Name: "WithUserInfoClaims",
IDTokenClaims: jwt.MapClaims{
"email": "kyle@kwc.io",
"email_verified": true,
{
Name: "UserInfoOverridesIDTokenClaims",
IDTokenClaims: jwt.MapClaims{
"email": "internaluser@internal.domain",
"email_verified": false,
},
UserInfoClaims: jwt.MapClaims{
"email": "externaluser@external.domain",
"email_verified": true,
"preferred_username": "user",
},
Username: "user",
AllowSignups: true,
IgnoreEmailVerified: false,
StatusCode: http.StatusOK,
},
UserInfoClaims: jwt.MapClaims{
"preferred_username": "potato",
"picture": "/example.png",
{
Name: "InvalidUserInfo",
IDTokenClaims: jwt.MapClaims{
"email": "internaluser@internal.domain",
"email_verified": false,
},
UserInfoClaims: jwt.MapClaims{
"email": 1,
},
AllowSignups: true,
IgnoreEmailVerified: false,
StatusCode: http.StatusInternalServerError,
},
Username: "potato",
AllowSignups: true,
AvatarURL: "/example.png",
StatusCode: http.StatusOK,
}, {
Name: "GroupsDoesNothing",
IDTokenClaims: jwt.MapClaims{
"email": "coolin@coder.com",
"groups": []string{"pingpong"},
{
Name: "IgnoreUserInfo",
IDTokenClaims: jwt.MapClaims{
"email": "user@internal.domain",
"email_verified": true,
"preferred_username": "user",
},
UserInfoClaims: jwt.MapClaims{
"email": "user.mcname@external.domain",
"preferred_username": "Mr. User McName",
},
Username: "user",
IgnoreUserInfo: true,
AllowSignups: true,
StatusCode: http.StatusOK,
},
AllowSignups: true,
StatusCode: http.StatusOK,
}, {
Name: "UserInfoOverridesIDTokenClaims",
IDTokenClaims: jwt.MapClaims{
"email": "internaluser@internal.domain",
"email_verified": false,
{
Name: "HugeIDToken",
IDTokenClaims: inflateClaims(t, jwt.MapClaims{
"email": "user@domain.tld",
"email_verified": true,
}, 65536),
Username: "user",
AllowSignups: true,
StatusCode: http.StatusOK,
},
UserInfoClaims: jwt.MapClaims{
"email": "externaluser@external.domain",
"email_verified": true,
"preferred_username": "user",
{
Name: "HugeClaims",
IDTokenClaims: jwt.MapClaims{
"email": "user@domain.tld",
"email_verified": true,
},
UserInfoClaims: inflateClaims(t, jwt.MapClaims{}, 65536),
Username: "user",
AllowSignups: true,
StatusCode: http.StatusOK,
},
Username: "user",
AllowSignups: true,
IgnoreEmailVerified: false,
StatusCode: http.StatusOK,
}, {
Name: "InvalidUserInfo",
IDTokenClaims: jwt.MapClaims{
"email": "internaluser@internal.domain",
"email_verified": false,
},
UserInfoClaims: jwt.MapClaims{
"email": 1,
},
AllowSignups: true,
IgnoreEmailVerified: false,
StatusCode: http.StatusInternalServerError,
}, {
Name: "IgnoreUserInfo",
IDTokenClaims: jwt.MapClaims{
"email": "user@internal.domain",
"email_verified": true,
"preferred_username": "user",
},
UserInfoClaims: jwt.MapClaims{
"email": "user.mcname@external.domain",
"preferred_username": "Mr. User McName",
},
Username: "user",
IgnoreUserInfo: true,
AllowSignups: true,
StatusCode: http.StatusOK,
}} {
} {
tc := tc
t.Run(tc.Name, func(t *testing.T) {
t.Parallel()
@ -956,7 +999,7 @@ func TestUserOIDC(t *testing.T) {
})
auditor := audit.NewMock()
logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true})
logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true}).Leveled(slog.LevelDebug)
owner := coderdtest.New(t, &coderdtest.Options{
Auditor: auditor,
OIDCConfig: cfg,
@ -1287,3 +1330,13 @@ func authCookieValue(cookies []*http.Cookie) string {
}
return ""
}
// inflateClaims 'inflates' a jwt.MapClaims from a seed by
// adding a ridiculously large key-value pair of length size.
func inflateClaims(t testing.TB, seed jwt.MapClaims, size int) jwt.MapClaims {
t.Helper()
junk, err := cryptorand.String(size)
require.NoError(t, err)
seed["random_data"] = junk
return seed
}