From 9419b7392dd7fa20f0ab9f02f111de48ff8a69d7 Mon Sep 17 00:00:00 2001 From: Margo Crawford Date: Wed, 2 Dec 2020 16:26:47 -0500 Subject: [PATCH] WIP: start to validate ID token returned from token endpoint This won't compile, but we are passing this between two teammates. Signed-off-by: Andrew Keesler --- internal/oidc/token/token_handler_test.go | 31 ++++++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/internal/oidc/token/token_handler_test.go b/internal/oidc/token/token_handler_test.go index 9009d7d5..e6a594db 100644 --- a/internal/oidc/token/token_handler_test.go +++ b/internal/oidc/token/token_handler_test.go @@ -21,6 +21,7 @@ import ( "testing" "time" + coreosoidc "github.com/coreos/go-oidc" "github.com/ory/fosite" "github.com/ory/fosite/handler/openid" "github.com/ory/fosite/storage" @@ -360,7 +361,7 @@ func TestTokenEndpoint(t *testing.T) { } oauthStore := storage.NewMemoryStore() - oauthHelper, authCode := makeHappyOauthHelper(t, authRequest, oauthStore) + oauthHelper, authCode, jwtSigningKey := makeHappyOauthHelper(t, authRequest, oauthStore) if test.storage != nil { test.storage(t, oauthStore, authCode) } @@ -390,6 +391,10 @@ func TestTokenEndpoint(t *testing.T) { requireValidAccessTokenStorage(t, m, oauthStore, wantOpenidScope) requireInvalidPKCEStorage(t, code, oauthStore) requireValidOIDCStorage(t, m, code, oauthStore, wantOpenidScope) + + if wantOpenidScope { + requireValidIDToken(t, m, jwtSigningKey) + } } else { require.JSONEq(t, test.wantExactBody, rsp.Body.String()) } @@ -399,7 +404,7 @@ func TestTokenEndpoint(t *testing.T) { t.Run("auth code is used twice", func(t *testing.T) { authRequest := deepCopyRequestForm(happyAuthRequest) oauthStore := storage.NewMemoryStore() - oauthHelper, authCode := makeHappyOauthHelper(t, authRequest, oauthStore) + oauthHelper, authCode, jwtSigningKey := makeHappyOauthHelper(t, authRequest, oauthStore) subject := NewHandler(oauthHelper) req := httptest.NewRequest("POST", "/path/shouldn't/matter", happyBody(authCode).ReadCloser()) @@ -425,6 +430,7 @@ func TestTokenEndpoint(t *testing.T) { requireValidAccessTokenStorage(t, m, oauthStore, wantOpenidScope) requireInvalidPKCEStorage(t, code, oauthStore) requireValidOIDCStorage(t, m, code, oauthStore, wantOpenidScope) + requireValidIDToken(t, m, jwtSigningKey) // Second call - should be unsuccessful since auth code was already used. // @@ -503,7 +509,7 @@ func makeHappyOauthHelper( t *testing.T, authRequest *http.Request, store *storage.MemoryStore, -) (fosite.OAuth2Provider, string) { +) (fosite.OAuth2Provider, string, *ecdsa.PrivateKey) { t.Helper() jwtSigningKey := generateJWTSigningKey(t) @@ -533,7 +539,7 @@ func makeHappyOauthHelper( authResponder, err := oauthHelper.NewAuthorizeResponse(ctx, authRequester, session) require.NoError(t, err) - return oauthHelper, authResponder.GetCode() + return oauthHelper, authResponder.GetCode(), jwtSigningKey } func generateJWTSigningKey(t *testing.T) *ecdsa.PrivateKey { @@ -765,6 +771,23 @@ func requireValidAuthRequest( require.Equal(t, goodSubject, session.Subject) } +func requireValidIDToken(t *testing.T, body map[string]interface{}, jwtSigningKey *ecdsa.PrivateKey) { + idToken, ok := body["id_token"] + require.Truef(t, ok, "body did not contain 'id_token': %s", body) + idTokenString, ok := idToken.(string) + require.Truef(t, ok, "wanted id_token to be a string, but got %T", idToken) + + // The go-oidc library will validate the signature and the client claim in the ID token. + keySet := newStaticKeySet(jwtSigningKey) // TODO: implement this static key set + verifyConfig := coreosoidc.Config{ClientID: goodClient, SupportedSigningAlgs: []string{coreosoidc.ES256}} + verifier := coreosoidc.NewVerifier(goodIssuer, keySet, &verifyConfig) + token, err := verifier.Verify(context.Background(), idTokenString) + require.NoError(t, err) + + // TODO: we will need to validate all of the other claims! + _ = token +} + // TODO: de-dup me. func requireEqualContentType(t *testing.T, actual string, expected string) { t.Helper()