diff options
| author | mo khan <mo@mokhan.ca> | 2025-04-16 17:01:39 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-04-16 17:01:39 -0600 |
| commit | 0b29a5a4ca71870ab138687e2fc71d6bce2754db (patch) | |
| tree | 0c8897d6efd734b620eab22e8f86e7e9b4d202ea /pkg/oidc | |
| parent | 9e83b4b2e95254ba51c66ed15f400d3bec5712f1 (diff) | |
refactor: verify the id token on every request
Diffstat (limited to 'pkg/oidc')
| -rw-r--r-- | pkg/oidc/id_token.go | 60 | ||||
| -rw-r--r-- | pkg/oidc/oidc.go | 11 | ||||
| -rw-r--r-- | pkg/oidc/oidc_test.go | 33 | ||||
| -rw-r--r-- | pkg/oidc/tokens.go | 4 | ||||
| -rw-r--r-- | pkg/oidc/tokens_test.go | 20 |
5 files changed, 39 insertions, 89 deletions
diff --git a/pkg/oidc/id_token.go b/pkg/oidc/id_token.go index 5fc1e63..ce4ae22 100644 --- a/pkg/oidc/id_token.go +++ b/pkg/oidc/id_token.go @@ -1,39 +1,33 @@ package oidc -import ( - "bytes" - "encoding/base64" - "errors" - "strings" - "time" +import "github.com/coreos/go-oidc/v3/oidc" - "github.com/xlgmokha/x/pkg/serde" -) +type IDToken = oidc.IDToken -type IDToken struct { - Audience string `json:"aud"` - Email string `json:"email"` - EmailVerified bool `json:"email_verified"` - ExpiredAt int64 `json:"exp"` - IssuedAt int64 `json:"iat"` - Issuer string `json:"iss"` - Name string `json:"name"` - Nickname string `json:"nickname"` - Picture string `json:"picture"` - Subject string `json:"sub"` - UpdatedAt time.Time `json:"updated_at"` -} +// type IDToken struct { +// Audience string `json:"aud"` +// Email string `json:"email"` +// EmailVerified bool `json:"email_verified"` +// ExpiredAt int64 `json:"exp"` +// IssuedAt int64 `json:"iat"` +// Issuer string `json:"iss"` +// Name string `json:"name"` +// Nickname string `json:"nickname"` +// Picture string `json:"picture"` +// Subject string `json:"sub"` +// UpdatedAt time.Time `json:"updated_at"` +// } -func NewIDToken(raw string) (*IDToken, error) { - sections := strings.SplitN(raw, ".", 3) - if len(sections) != 3 { - return nil, errors.New("Invalid token") - } - b, err := base64.RawURLEncoding.DecodeString(sections[1]) - if err != nil { - return nil, err - } +// func NewIDToken(raw string) (*IDToken, error) { +// sections := strings.SplitN(raw, ".", 3) +// if len(sections) != 3 { +// return nil, errors.New("Invalid token") +// } +// b, err := base64.RawURLEncoding.DecodeString(sections[1]) +// if err != nil { +// return nil, err +// } - token, err := serde.FromJSON[*IDToken](bytes.NewReader(b)) - return token, err -} +// token, err := serde.FromJSON[*IDToken](bytes.NewReader(b)) +// return token, err +// } diff --git a/pkg/oidc/oidc.go b/pkg/oidc/oidc.go index 0526142..200db69 100644 --- a/pkg/oidc/oidc.go +++ b/pkg/oidc/oidc.go @@ -4,14 +4,18 @@ import ( "context" "github.com/coreos/go-oidc/v3/oidc" + xcontext "github.com/xlgmokha/x/pkg/context" "golang.org/x/oauth2" ) type OpenID struct { - Provider *oidc.Provider - Config *oauth2.Config + Provider *oidc.Provider + Config *oauth2.Config + OIDCConfig *oidc.Config } +var IDTokenKey xcontext.Key[*IDToken] = xcontext.Key[*IDToken]("id_token") + func New(ctx context.Context, issuer string, clientID, clientSecret, callbackURL string) (*OpenID, error) { provider, err := oidc.NewProvider(ctx, issuer) if err != nil { @@ -27,5 +31,8 @@ func New(ctx context.Context, issuer string, clientID, clientSecret, callbackURL Endpoint: provider.Endpoint(), Scopes: []string{oidc.ScopeOpenID, "profile", "email"}, }, + OIDCConfig: &oidc.Config{ + ClientID: clientID, + }, }, nil } diff --git a/pkg/oidc/oidc_test.go b/pkg/oidc/oidc_test.go index ef6a4f6..b7715cf 100644 --- a/pkg/oidc/oidc_test.go +++ b/pkg/oidc/oidc_test.go @@ -2,48 +2,21 @@ package oidc import ( "context" - "net/http" - "net/http/httptest" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/xlgmokha/x/pkg/serde" + "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/test" ) func TestOpenID(t *testing.T) { t.Run("GET /.well-known/openid-configuration", func(t *testing.T) { - srv := httptest.NewServer(nil) - srv.Config = &http.Server{ - Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - require.Equal(t, "/.well-known/openid-configuration", r.URL.Path) - require.NoError(t, serde.ToJSON(w, &Metadata{ - AuthorizationEndpoint: srv.URL + "/authorize", - ClaimsSupported: []string{"aud"}, - CodeChallengeMethodsSupported: []string{"plain"}, - DeviceAuthorizationEndpoint: srv.URL + "/device/authorize", - IDTokenSigningAlgValuesSupported: []string{"RS256"}, - Issuer: srv.URL, - JWKSURI: srv.URL + "/jwks", - MFAChallengeEndpoint: srv.URL + "/mfa", - RegistrationEndpoint: srv.URL + "/users/new", - RequestURIParameterSupported: false, - ResponseModesSupported: []string{"query"}, - ResponseTypeSupported: []string{"code"}, - RevocationEndpoint: srv.URL + "/revoke", - ScopesSupported: []string{"oidc"}, - SubjectTypesSupported: []string{"public"}, - TokenEndpoint: srv.URL + "/token", - TokenEndpointAuthMethodsSupported: []string{"client_secret_post"}, - UserInfoEndpoint: srv.URL + "/users/me", - })) - }), - } + srv := test.OIDCServer() defer srv.Close() openID, err := New(context.Background(), srv.URL, "client_id", "client_secret", "https://example.com/oauth/callback") require.NoError(t, err) - assert.Equal(t, srv.URL+"/authorize", openID.Provider.Endpoint().AuthURL) + assert.Equal(t, srv.URL+"/oauth/authorize", openID.Provider.Endpoint().AuthURL) }) } diff --git a/pkg/oidc/tokens.go b/pkg/oidc/tokens.go index a326ff2..7ff3c07 100644 --- a/pkg/oidc/tokens.go +++ b/pkg/oidc/tokens.go @@ -22,10 +22,6 @@ func (t *Tokens) ToBase64String() (string, error) { return base64.URLEncoding.EncodeToString(data), nil } -func (t *Tokens) ParseIDToken() (*IDToken, error) { - return NewIDToken(t.IDToken) -} - func TokensFromBase64String(encoded string) (*Tokens, error) { decoded, err := base64.URLEncoding.DecodeString(encoded) if err != nil { diff --git a/pkg/oidc/tokens_test.go b/pkg/oidc/tokens_test.go index 3191f97..a7c5e13 100644 --- a/pkg/oidc/tokens_test.go +++ b/pkg/oidc/tokens_test.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "testing" - "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -70,23 +69,4 @@ func TestTokens(t *testing.T) { assert.Equal(t, "eyJ0eXAiOiJKV1QiLCJraWQiOiJ0ZDBTbWRKUTRxUGg1cU5Lek0yNjBDWHgyVWgtd2hHLU1Eam9PS1dmdDhFIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwOi8vZ2RrLnRlc3Q6MzAwMCIsInN1YiI6IjEiLCJhdWQiOiJlMzFlMWRhMGI4ZjZiNmUzNWNhNzBjNzkwYjEzYzA0MDZlNDRhY2E2YjJiZjY3ZjU1ZGU3MzU1YTk3OWEyMjRmIiwiZXhwIjoxNzQ0NzM3NDI3LCJpYXQiOjE3NDQ3MzczMDcsImF1dGhfdGltZSI6MTc0NDczNDY0OSwic3ViX2xlZ2FjeSI6IjI0NzRjZjBiMjIxMTY4OGE1NzI5N2FjZTBlMjYwYTE1OTQ0NzU0ZDE2YjFiZDQyYzlkNjc3OWM5MDAzNjc4MDciLCJuYW1lIjoiQWRtaW5pc3RyYXRvciIsIm5pY2tuYW1lIjoicm9vdCIsInByZWZlcnJlZF91c2VybmFtZSI6InJvb3QiLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsInByb2ZpbGUiOiJodHRwOi8vZ2RrLnRlc3Q6MzAwMC9yb290IiwicGljdHVyZSI6Imh0dHBzOi8vd3d3LmdyYXZhdGFyLmNvbS9hdmF0YXIvMjU4ZDhkYzkxNmRiOGNlYTJjYWZiNmMzY2QwY2IwMjQ2ZWZlMDYxNDIxZGJkODNlYzNhMzUwNDI4Y2FiZGE0Zj9zPTgwJmQ9aWRlbnRpY29uIiwiZ3JvdXBzX2RpcmVjdCI6WyJ0b29sYm94IiwiZ2l0bGFiLW9yZyIsImdudXdnZXQiLCJDb21taXQ0NTEiLCJqYXNoa2VuYXMiLCJmbGlnaHRqcyIsInR3aXR0ZXIiLCJnaXRsYWItZXhhbXBsZXMiLCJnaXRsYWItZXhhbXBsZXMvc2VjdXJpdHkiLCI0MTI3MDgiLCJnaXRsYWItZXhhbXBsZXMvZGVtby1ncm91cCIsImN1c3RvbS1yb2xlcy1yb290LWdyb3VwIiwiNDM0MDQ0LWdyb3VwLTEiLCI0MzQwNDQtZ3JvdXAtMiIsImdpdGxhYi1vcmcxIiwiZ2l0bGFiLW9yZy9zZWN1cmUiLCJnaXRsYWItb3JnL3NlY3VyZS9tYW5hZ2VycyIsImdpdGxhYi1vcmcvc2VjdXJpdHktcHJvZHVjdHMiLCJnaXRsYWItb3JnL3NlY3VyaXR5LXByb2R1Y3RzL2FuYWx5emVycyIsImN1c3RvbS1yb2xlcy1yb290LWdyb3VwL2FhIiwiY3VzdG9tLXJvbGVzLXJvb3QtZ3JvdXAvYWEvYWFhIiwibWFzc19pbnNlcnRfZ3JvdXBfXzBfMTAwIl19.SZu_l7tQ2Kkeogq0z8cRaDWPfv52JTo-RkiExbnud_lrfrXXneS77BIzaGKX_bzq4SM_oO_Q63AzK66B1r6Gp7ACo4DjOUEIWETg7ZBKcDzEZnresB7kmI_MJ5rfIJTmnH75GOfc_pl5l8T896TbaShN6zSpaXXIVEfhyUrflSWb4hhA7Hbwy2b6laXiaDv0qpcn1udPVYMTsll8I5ni_2yzuEPSVRgrcQoQ46OwVDZIi9tlfdT2qNVjH6FxJ3mkBcxtIVjf3_JYAawFEscg2uvQYwFWj9T6LleMknAh3QFJJMrS6mPqlXJGPUE5pTQgsBInfEikfm9PXxezA-IY6g", result.IDToken) }) }) - - t.Run("ParseIDToken", func(t *testing.T) { - tokens := &Tokens{IDToken: "eyJ0eXAiOiJKV1QiLCJraWQiOiJ0ZDBTbWRKUTRxUGg1cU5Lek0yNjBDWHgyVWgtd2hHLU1Eam9PS1dmdDhFIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwOi8vZ2RrLnRlc3Q6MzAwMCIsInN1YiI6IjEiLCJhdWQiOiJlMzFlMWRhMGI4ZjZiNmUzNWNhNzBjNzkwYjEzYzA0MDZlNDRhY2E2YjJiZjY3ZjU1ZGU3MzU1YTk3OWEyMjRmIiwiZXhwIjoxNzQ0NzM3NDI3LCJpYXQiOjE3NDQ3MzczMDcsImF1dGhfdGltZSI6MTc0NDczNDY0OSwic3ViX2xlZ2FjeSI6IjI0NzRjZjBiMjIxMTY4OGE1NzI5N2FjZTBlMjYwYTE1OTQ0NzU0ZDE2YjFiZDQyYzlkNjc3OWM5MDAzNjc4MDciLCJuYW1lIjoiQWRtaW5pc3RyYXRvciIsIm5pY2tuYW1lIjoicm9vdCIsInByZWZlcnJlZF91c2VybmFtZSI6InJvb3QiLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsInByb2ZpbGUiOiJodHRwOi8vZ2RrLnRlc3Q6MzAwMC9yb290IiwicGljdHVyZSI6Imh0dHBzOi8vd3d3LmdyYXZhdGFyLmNvbS9hdmF0YXIvMjU4ZDhkYzkxNmRiOGNlYTJjYWZiNmMzY2QwY2IwMjQ2ZWZlMDYxNDIxZGJkODNlYzNhMzUwNDI4Y2FiZGE0Zj9zPTgwJmQ9aWRlbnRpY29uIiwiZ3JvdXBzX2RpcmVjdCI6WyJ0b29sYm94IiwiZ2l0bGFiLW9yZyIsImdudXdnZXQiLCJDb21taXQ0NTEiLCJqYXNoa2VuYXMiLCJmbGlnaHRqcyIsInR3aXR0ZXIiLCJnaXRsYWItZXhhbXBsZXMiLCJnaXRsYWItZXhhbXBsZXMvc2VjdXJpdHkiLCI0MTI3MDgiLCJnaXRsYWItZXhhbXBsZXMvZGVtby1ncm91cCIsImN1c3RvbS1yb2xlcy1yb290LWdyb3VwIiwiNDM0MDQ0LWdyb3VwLTEiLCI0MzQwNDQtZ3JvdXAtMiIsImdpdGxhYi1vcmcxIiwiZ2l0bGFiLW9yZy9zZWN1cmUiLCJnaXRsYWItb3JnL3NlY3VyZS9tYW5hZ2VycyIsImdpdGxhYi1vcmcvc2VjdXJpdHktcHJvZHVjdHMiLCJnaXRsYWItb3JnL3NlY3VyaXR5LXByb2R1Y3RzL2FuYWx5emVycyIsImN1c3RvbS1yb2xlcy1yb290LWdyb3VwL2FhIiwiY3VzdG9tLXJvbGVzLXJvb3QtZ3JvdXAvYWEvYWFhIiwibWFzc19pbnNlcnRfZ3JvdXBfXzBfMTAwIl19.SZu_l7tQ2Kkeogq0z8cRaDWPfv52JTo-RkiExbnud_lrfrXXneS77BIzaGKX_bzq4SM_oO_Q63AzK66B1r6Gp7ACo4DjOUEIWETg7ZBKcDzEZnresB7kmI_MJ5rfIJTmnH75GOfc_pl5l8T896TbaShN6zSpaXXIVEfhyUrflSWb4hhA7Hbwy2b6laXiaDv0qpcn1udPVYMTsll8I5ni_2yzuEPSVRgrcQoQ46OwVDZIi9tlfdT2qNVjH6FxJ3mkBcxtIVjf3_JYAawFEscg2uvQYwFWj9T6LleMknAh3QFJJMrS6mPqlXJGPUE5pTQgsBInfEikfm9PXxezA-IY6g"} - - idToken, err := tokens.ParseIDToken() - require.NoError(t, err) - - assert.Equal(t, "e31e1da0b8f6b6e35ca70c790b13c0406e44aca6b2bf67f55de7355a979a224f", idToken.Audience) - assert.Equal(t, "admin@example.com", idToken.Email) - assert.Equal(t, true, idToken.EmailVerified) - assert.Equal(t, int64(1744737427), idToken.ExpiredAt) - assert.Equal(t, int64(1744737307), idToken.IssuedAt) - assert.Equal(t, "http://gdk.test:3000", idToken.Issuer) - assert.Equal(t, "Administrator", idToken.Name) - assert.Equal(t, "root", idToken.Nickname) - assert.Equal(t, "https://www.gravatar.com/avatar/258d8dc916db8cea2cafb6c3cd0cb0246efe061421dbd83ec3a350428cabda4f?s=80&d=identicon", idToken.Picture) - assert.Equal(t, "1", idToken.Subject) - assert.Equal(t, time.Time{}, idToken.UpdatedAt) - }) } |
