From dd2463a1a262600096f040867dcabe2a28e1a56c Mon Sep 17 00:00:00 2001 From: arekkas Date: Sun, 9 Jul 2017 17:49:29 +0200 Subject: [PATCH] handler/openid: only refresh id token with id_token response type Closes #199 --- handler/openid/flow_refresh_token.go | 17 ++- handler/openid/flow_refresh_token_test.go | 166 ++++++++++++++++++++++ 2 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 handler/openid/flow_refresh_token_test.go diff --git a/handler/openid/flow_refresh_token.go b/handler/openid/flow_refresh_token.go index 1c8d61fe6..f7020d309 100644 --- a/handler/openid/flow_refresh_token.go +++ b/handler/openid/flow_refresh_token.go @@ -2,7 +2,6 @@ package openid import ( "context" - "time" "github.com/ory/fosite" @@ -22,6 +21,14 @@ func (c *OpenIDConnectRefreshHandler) HandleTokenEndpointRequest(ctx context.Con return errors.WithStack(fosite.ErrUnknownRequest) } + if !request.GetClient().GetGrantTypes().Has("refresh_token") { + return errors.Wrap(fosite.ErrInvalidGrant, "The client is not allowed to use the authorization_code grant type") + } + + if !request.GetClient().GetResponseTypes().Has("id_token") { + return errors.Wrap(fosite.ErrUnknownRequest, "The client is not allowed to use response type id_token") + } + sess, ok := request.GetSession().(Session) if !ok { return errors.New("Failed to generate id token because session must be of type fosite/handler/openid.Session") @@ -41,5 +48,13 @@ func (c *OpenIDConnectRefreshHandler) PopulateTokenEndpointResponse(ctx context. return errors.WithStack(fosite.ErrUnknownRequest) } + if !requester.GetClient().GetGrantTypes().Has("refresh_token") { + return errors.Wrap(fosite.ErrInvalidGrant, "The client is not allowed to use the authorization_code grant type") + } + + if !requester.GetClient().GetResponseTypes().Has("id_token") { + return errors.Wrap(errors.WithStack(fosite.ErrUnknownRequest), "The client is not allowed to use response type id_token") + } + return c.IssueExplicitIDToken(ctx, requester, responder) } diff --git a/handler/openid/flow_refresh_token_test.go b/handler/openid/flow_refresh_token_test.go new file mode 100644 index 000000000..e8a00b0ef --- /dev/null +++ b/handler/openid/flow_refresh_token_test.go @@ -0,0 +1,166 @@ +package openid + +import ( + "testing" + + "github.com/ory/fosite" + "github.com/ory/fosite/token/jwt" + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestOpenIDConnectRefreshHandler_HandleTokenEndpointRequest(t *testing.T) { + h := &OpenIDConnectRefreshHandler{} + for _, c := range []struct { + areq *fosite.AccessRequest + expectedErr error + description string + }{ + { + description: "should not pass because grant_type is wrong", + areq: &fosite.AccessRequest{ + GrantTypes: []string{"foo"}, + }, + expectedErr: fosite.ErrUnknownRequest, + }, + { + description: "should not pass because grant_type is right but scope is missing", + areq: &fosite.AccessRequest{ + GrantTypes: []string{"refresh_token"}, + Request: fosite.Request{ + GrantedScopes: []string{"something"}, + }, + }, + expectedErr: fosite.ErrUnknownRequest, + }, + { + description: "should not pass because client may not execute this grant type", + areq: &fosite.AccessRequest{ + GrantTypes: []string{"refresh_token"}, + Request: fosite.Request{ + GrantedScopes: []string{"openid"}, + Client: &fosite.DefaultClient{}, + }, + }, + expectedErr: fosite.ErrInvalidGrant, + }, + { + description: "should not pass because client may not ask for id_token", + areq: &fosite.AccessRequest{ + GrantTypes: []string{"refresh_token"}, + Request: fosite.Request{ + GrantedScopes: []string{"openid"}, + Client: &fosite.DefaultClient{ + GrantTypes: []string{"refresh_token"}, + }, + }, + }, + expectedErr: fosite.ErrUnknownRequest, + }, + { + description: "should pass", + areq: &fosite.AccessRequest{ + GrantTypes: []string{"refresh_token"}, + Request: fosite.Request{ + GrantedScopes: []string{"openid"}, + Client: &fosite.DefaultClient{ + GrantTypes: []string{"refresh_token"}, + ResponseTypes: []string{"id_token"}, + }, + Session: &DefaultSession{}, + }, + }, + }, + } { + t.Run("case="+c.description, func(t *testing.T) { + err := h.HandleTokenEndpointRequest(nil, c.areq) + if c.expectedErr != nil { + require.EqualError(t, errors.Cause(err), c.expectedErr.Error(), "%v", err) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestOpenIDConnectRefreshHandler_PopulateTokenEndpointResponse(t *testing.T) { + h := &OpenIDConnectRefreshHandler{ + IDTokenHandleHelper: &IDTokenHandleHelper{ + IDTokenStrategy: j, + }, + } + for _, c := range []struct { + areq *fosite.AccessRequest + expectedErr error + check func(t *testing.T, aresp *fosite.AccessResponse) + description string + }{ + { + description: "should not pass because grant_type is wrong", + areq: &fosite.AccessRequest{ + GrantTypes: []string{"foo"}, + }, + expectedErr: fosite.ErrUnknownRequest, + }, + { + description: "should not pass because grant_type is right but scope is missing", + areq: &fosite.AccessRequest{ + GrantTypes: []string{"refresh_token"}, + Request: fosite.Request{ + GrantedScopes: []string{"something"}, + }, + }, + expectedErr: fosite.ErrUnknownRequest, + }, + { + description: "should not pass because client may not ask for id_token", + areq: &fosite.AccessRequest{ + GrantTypes: []string{"refresh_token"}, + Request: fosite.Request{ + GrantedScopes: []string{"openid"}, + Client: &fosite.DefaultClient{ + GrantTypes: []string{"refresh_token"}, + }, + }, + }, + expectedErr: fosite.ErrUnknownRequest, + }, + { + description: "should pass", + areq: &fosite.AccessRequest{ + GrantTypes: []string{"refresh_token"}, + Request: fosite.Request{ + GrantedScopes: []string{"openid"}, + Client: &fosite.DefaultClient{ + GrantTypes: []string{"refresh_token"}, + ResponseTypes: []string{"id_token"}, + }, + Session: &DefaultSession{ + Subject: "foo", + Claims: &jwt.IDTokenClaims{ + Subject: "foo", + }, + }, + }, + }, + check: func(t *testing.T, aresp *fosite.AccessResponse) { + assert.NotEmpty(t, aresp.GetExtra("id_token")) + }, + }, + } { + t.Run("case="+c.description, func(t *testing.T) { + aresp := fosite.NewAccessResponse() + err := h.PopulateTokenEndpointResponse(nil, c.areq, aresp) + if c.expectedErr != nil { + require.EqualError(t, errors.Cause(err), c.expectedErr.Error(), "%v", err) + } else { + require.NoError(t, err) + } + + if c.check != nil { + c.check(t, aresp) + } + }) + } +}