From 3c8dd1bc2d91dc7983b37d969c1ba30001ace7a6 Mon Sep 17 00:00:00 2001 From: James Elliott Date: Mon, 21 Nov 2022 15:18:08 +1100 Subject: [PATCH] test: add integration test --- integration/helper_endpoints_test.go | 24 ++++--- integration/refresh_token_grant_test.go | 89 +++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 9 deletions(-) diff --git a/integration/helper_endpoints_test.go b/integration/helper_endpoints_test.go index 76e4b5201..dfb491fae 100644 --- a/integration/helper_endpoints_test.go +++ b/integration/helper_endpoints_test.go @@ -77,16 +77,22 @@ func authEndpointHandler(t *testing.T, oauth2 fosite.OAuth2Provider, session fos return } - if ar.GetRequestedScopes().Has("fosite") { - ar.GrantScope("fosite") - } + if ar.GetClient().GetID() == "grant-all-requested-scopes-client" { + for _, scope := range ar.GetRequestedScopes() { + ar.GrantScope(scope) + } + } else { + if ar.GetRequestedScopes().Has("fosite") { + ar.GrantScope("fosite") + } - if ar.GetRequestedScopes().Has("offline") { - ar.GrantScope("offline") - } + if ar.GetRequestedScopes().Has("offline") { + ar.GrantScope("offline") + } - if ar.GetRequestedScopes().Has("openid") { - ar.GrantScope("openid") + if ar.GetRequestedScopes().Has("openid") { + ar.GrantScope("openid") + } } for _, a := range ar.GetRequestedAudience() { @@ -134,7 +140,7 @@ func tokenEndpointHandler(t *testing.T, provider fosite.OAuth2Provider) func(rw accessRequest, err := provider.NewAccessRequest(ctx, req, &oauth2.JWTSession{}) if err != nil { - t.Logf("Access request failed because: %+v", err) + t.Logf("Access request failed because: %+v", fosite.ErrorToRFC6749Error(err).WithExposeDebug(true).GetDescription()) t.Logf("Request: %+v", accessRequest) provider.WriteAccessError(req.Context(), rw, accessRequest, err) return diff --git a/integration/refresh_token_grant_test.go b/integration/refresh_token_grant_test.go index 89f73db39..7e3693f39 100644 --- a/integration/refresh_token_grant_test.go +++ b/integration/refresh_token_grant_test.go @@ -265,3 +265,92 @@ func TestRefreshTokenFlow(t *testing.T) { }) } } + +func TestRefreshTokenFlowScopeNarrowing(t *testing.T) { + session := &defaultSession{ + DefaultSession: &openid.DefaultSession{ + Claims: &jwt.IDTokenClaims{ + Subject: "peter", + }, + Headers: &jwt.Headers{}, + Subject: "peter", + Username: "peteru", + }, + } + fc := new(fosite.Config) + fc.RefreshTokenLifespan = -1 + fc.GlobalSecret = []byte("some-secret-thats-random-some-secret-thats-random-") + f := compose.ComposeAllEnabled(fc, fositeStore, gen.MustRSAKey()) + ts := mockServer(t, f, session) + defer ts.Close() + + fc.ScopeStrategy = fosite.ExactScopeStrategy + + oauthClient := newOAuth2Client(ts) + oauthClient.Scopes = []string{"openid", "offline", "offline_access", "foo", "bar"} + oauthClient.ClientID = "grant-all-requested-scopes-client" + + state := "1234567890" + + testRefreshingClient := &fosite.DefaultClient{ + ID: "grant-all-requested-scopes-client", + Secret: []byte(`$2a$10$IxMdI6d.LIRZPpSfEwNoeu4rY3FhDREsxFJXikcgdRRAStxUlsuEO`), // = "foobar" + RedirectURIs: []string{ts.URL + "/callback"}, + ResponseTypes: []string{"code"}, + GrantTypes: []string{"implicit", "refresh_token", "authorization_code", "password", "client_credentials"}, + Scopes: []string{"openid", "offline_access", "offline", "foo", "bar", "baz"}, + Audience: []string{"https://www.ory.sh/api"}, + } + + fositeStore.Clients["grant-all-requested-scopes-client"] = testRefreshingClient + + resp, err := http.Get(oauthClient.AuthCodeURL(state)) + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) + + token, err := oauthClient.Exchange(oauth2.NoContext, resp.Request.URL.Query().Get("code"), oauth2.SetAuthURLParam("client_id", oauthClient.ClientID)) + require.NoError(t, err) + require.NotEmpty(t, token.AccessToken) + require.NotEmpty(t, token.RefreshToken) + + assert.Equal(t, "openid offline offline_access foo bar", token.Extra("scope")) + + token1Refresh, err := doRefresh(oauthClient, token, nil) + require.NoError(t, err) + require.NotEmpty(t, token1Refresh.AccessToken) + require.NotEmpty(t, token1Refresh.RefreshToken) + + assert.Equal(t, "openid offline offline_access foo bar", token1Refresh.Extra("scope")) + + token2Refresh, err := doRefresh(oauthClient, token1Refresh, []string{"openid", "offline_access", "foo"}) + require.NoError(t, err) + require.NotEmpty(t, token2Refresh.AccessToken) + require.NotEmpty(t, token2Refresh.RefreshToken) + + assert.Equal(t, "openid offline_access foo", token2Refresh.Extra("scope")) + + token3Refresh, err := doRefresh(oauthClient, token2Refresh, []string{"openid", "offline", "offline_access", "foo", "bar"}) + require.NoError(t, err) + require.NotEmpty(t, token3Refresh.AccessToken) + require.NotEmpty(t, token3Refresh.RefreshToken) + + assert.Equal(t, "openid offline offline_access foo bar", token3Refresh.Extra("scope")) + + token4Refresh, err := doRefresh(oauthClient, token3Refresh, []string{"openid", "offline", "offline_access", "foo", "bar", "baz"}) + require.Error(t, err) + require.Nil(t, token4Refresh) + require.Contains(t, err.Error(), "The requested scope is invalid, unknown, or malformed. The requested scope 'baz' was not originally granted by the resource owner.") +} + +func doRefresh(client *oauth2.Config, t *oauth2.Token, scopes []string) (token *oauth2.Token, err error) { + opts := []oauth2.AuthCodeOption{ + oauth2.SetAuthURLParam("refresh_token", t.RefreshToken), + oauth2.SetAuthURLParam("grant_type", "refresh_token"), + } + + if len(scopes) != 0 { + opts = append(opts, oauth2.SetAuthURLParam("scope", strings.Join(scopes, " ")), oauth2.SetAuthURLParam("client_id", client.ClientID)) + } + + return client.Exchange(oauth2.NoContext, "", opts...) +}