Skip to content

Commit

Permalink
fix: fix the refresh token issue (#14)
Browse files Browse the repository at this point in the history
* fix: fix the refresh token issue

* fix: fix the OIDC token missing issue
  • Loading branch information
wood-push-melon authored and nsklikas committed Sep 12, 2024
1 parent ebd0f54 commit 55bed76
Show file tree
Hide file tree
Showing 8 changed files with 411 additions and 216 deletions.
274 changes: 198 additions & 76 deletions handler/oauth2/flow_authorize_code_token_test.go

Large diffs are not rendered by default.

11 changes: 7 additions & 4 deletions handler/oauth2/flow_generic_code_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func (c *GenericCodeTokenEndpointHandler) PopulateTokenEndpointResponse(ctx cont
return errorsx.WithStack(err)
}

for _, scope := range ar.GetRequestedScopes() {
for _, scope := range ar.GetGrantedScopes() {
requester.GrantScope(scope)
}

Expand All @@ -105,7 +105,7 @@ func (c *GenericCodeTokenEndpointHandler) PopulateTokenEndpointResponse(ctx cont
}

var refreshToken, refreshTokenSignature string
if c.canIssueRefreshToken(ctx, ar) {
if c.canIssueRefreshToken(ctx, requester) {
refreshToken, refreshTokenSignature, err = c.RefreshTokenStrategy.GenerateRefreshToken(ctx, requester)
if err != nil {
return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error()))
Expand Down Expand Up @@ -229,11 +229,14 @@ func (c *GenericCodeTokenEndpointHandler) CanHandleTokenEndpointRequest(ctx cont
}

func (c *GenericCodeTokenEndpointHandler) canIssueRefreshToken(ctx context.Context, requester fosite.Requester) bool {
scope := c.Config.GetRefreshTokenScopes(ctx)
if len(scope) > 0 && !requester.GetGrantedScopes().HasOneOf(scope...) {
scopes := c.Config.GetRefreshTokenScopes(ctx)

// Require one of the refresh token scopes, if set.
if len(scopes) > 0 && !requester.GetGrantedScopes().HasOneOf(scopes...) {
return false
}

// Do not issue a refresh token to clients that cannot use the refresh token grant type.
if !requester.GetClient().GetGrantTypes().Has("refresh_token") {
return false
}
Expand Down
4 changes: 2 additions & 2 deletions handler/openid/flow_device_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ type OpenIDConnectDeviceHandler struct {
}

func (c *OpenIDConnectDeviceHandler) HandleDeviceEndpointRequest(ctx context.Context, dar fosite.DeviceRequester, resp fosite.DeviceResponder) error {
if !(dar.GetGrantedScopes().Has("openid")) {
if !(dar.GetRequestedScopes().Has("openid")) {
return nil
}

if !dar.GetClient().GetGrantTypes().Has(string(fosite.GrantTypeDeviceCode)) {
return nil
}

if len(resp.GetDeviceCode()) == 0 {
if resp.GetDeviceCode() == "" {
return errorsx.WithStack(fosite.ErrMisconfiguration.WithDebug("The device code has not been issued yet, indicating a broken code configuration."))
}

Expand Down
24 changes: 12 additions & 12 deletions handler/openid/flow_device_auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func TestDeviceAuth_HandleDeviceEndpointRequest(t *testing.T) {

client := &fosite.DefaultClient{
ID: "foo",
GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)},
GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"},
}

testCases := []struct {
Expand All @@ -78,17 +78,17 @@ func TestDeviceAuth_HandleDeviceEndpointRequest(t *testing.T) {
description: "should ignore because scope openid is not set",
authreq: &fosite.DeviceRequest{
Request: fosite.Request{
GrantedScope: fosite.Arguments{"email"},
RequestedScope: fosite.Arguments{"email"},
},
},
},
{
description: "should ignore because client grant type is invalid",
authreq: &fosite.DeviceRequest{
Request: fosite.Request{
GrantedScope: fosite.Arguments{"openid", "email"},
RequestedScope: fosite.Arguments{"openid", "email"},
Client: &fosite.DefaultClient{
GrantTypes: []string{string(fosite.GrantTypeAuthorizationCode)},
GrantTypes: []string{"authorization_code"},
},
},
},
Expand All @@ -97,8 +97,8 @@ func TestDeviceAuth_HandleDeviceEndpointRequest(t *testing.T) {
description: "should fail because device code is not issued",
authreq: &fosite.DeviceRequest{
Request: fosite.Request{
GrantedScope: fosite.Arguments{"openid", "email"},
Client: client,
RequestedScope: fosite.Arguments{"openid", "email"},
Client: client,
},
},
authresp: &fosite.DeviceResponse{},
Expand All @@ -108,9 +108,9 @@ func TestDeviceAuth_HandleDeviceEndpointRequest(t *testing.T) {
description: "should fail because cannot create session",
authreq: &fosite.DeviceRequest{
Request: fosite.Request{
GrantedScope: fosite.Arguments{"openid", "email"},
Client: client,
Session: session,
RequestedScope: fosite.Arguments{"openid", "email"},
Client: client,
Session: session,
},
},
authresp: &fosite.DeviceResponse{
Expand All @@ -128,9 +128,9 @@ func TestDeviceAuth_HandleDeviceEndpointRequest(t *testing.T) {
description: "should pass",
authreq: &fosite.DeviceRequest{
Request: fosite.Request{
GrantedScope: fosite.Arguments{"openid", "email"},
Client: client,
Session: session,
RequestedScope: fosite.Arguments{"openid", "email"},
Client: client,
Session: session,
},
},
authresp: &fosite.DeviceResponse{
Expand Down
8 changes: 4 additions & 4 deletions handler/openid/flow_device_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ func (c *OpenIDConnectDeviceHandler) PopulateTokenEndpointResponse(ctx context.C
return errorsx.WithStack(fosite.ErrUnknownRequest)
}

if !requester.GetClient().GetGrantTypes().Has(string(fosite.GrantTypeDeviceCode)) {
return errorsx.WithStack(fosite.ErrUnauthorizedClient.WithHint("The OAuth 2.0 Client is not allowed to use the authorization grant \"urn:ietf:params:oauth:grant-type:device_code\"."))
}

deviceCode := requester.GetRequestForm().Get("device_code")
signature, err := c.DeviceCodeStrategy.DeviceCodeSignature(ctx, deviceCode)
ar, err := c.OpenIDConnectRequestStorage.GetOpenIDConnectSession(ctx, signature, requester)
Expand All @@ -35,10 +39,6 @@ func (c *OpenIDConnectDeviceHandler) PopulateTokenEndpointResponse(ctx context.C
return errorsx.WithStack(fosite.ErrMisconfiguration.WithDebug("An OpenID Connect session was found but the openid scope is missing, probably due to a broken code configuration."))
}

if !requester.GetClient().GetGrantTypes().Has(string(fosite.GrantTypeDeviceCode)) {
return errorsx.WithStack(fosite.ErrUnauthorizedClient.WithHint("The OAuth 2.0 Client is not allowed to use the authorization grant \"urn:ietf:params:oauth:grant-type:device_code\"."))
}

session, ok := ar.GetSession().(Session)
if !ok {
return errorsx.WithStack(fosite.ErrServerError.WithDebug("Failed to generate id token because session must be of type fosite/handler/openid.Session."))
Expand Down
46 changes: 15 additions & 31 deletions handler/openid/flow_device_token_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ func TestDeviceToken_PopulateTokenEndpointResponse(t *testing.T) {

client := &fosite.DefaultClient{
ID: "foo",
GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)},
GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"},
}

testCases := []struct {
Expand All @@ -95,8 +95,9 @@ func TestDeviceToken_PopulateTokenEndpointResponse(t *testing.T) {
{
description: "should fail because the grant type is invalid",
areq: &fosite.AccessRequest{
GrantTypes: fosite.Arguments{string(fosite.GrantTypeAuthorizationCode)},
GrantTypes: fosite.Arguments{"authorization_code"},
Request: fosite.Request{
Client: client,
Form: url.Values{"device_code": []string{"device_code"}},
Session: session,
},
Expand All @@ -107,8 +108,9 @@ func TestDeviceToken_PopulateTokenEndpointResponse(t *testing.T) {
{
description: "should fail because session not found",
areq: &fosite.AccessRequest{
GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)},
GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"},
Request: fosite.Request{
Client: client,
Form: url.Values{"device_code": []string{"device_code"}},
Session: session,
},
Expand All @@ -122,8 +124,9 @@ func TestDeviceToken_PopulateTokenEndpointResponse(t *testing.T) {
{
description: "should fail because session lookup fails",
areq: &fosite.AccessRequest{
GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)},
GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"},
Request: fosite.Request{
Client: client,
Form: url.Values{"device_code": []string{"device_code"}},
Session: session,
},
Expand All @@ -136,15 +139,17 @@ func TestDeviceToken_PopulateTokenEndpointResponse(t *testing.T) {
{
description: "should fail because auth request grant scope is invalid",
areq: &fosite.AccessRequest{
GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)},
GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"},
Request: fosite.Request{
Client: client,
Form: url.Values{"device_code": []string{"device_code"}},
Session: session,
},
},
setup: func(areq *fosite.AccessRequest) {
authreq := &fosite.DeviceRequest{
Request: fosite.Request{
Client: client,
GrantedScope: fosite.Arguments{"email"},
Session: session,
},
Expand All @@ -153,33 +158,10 @@ func TestDeviceToken_PopulateTokenEndpointResponse(t *testing.T) {
},
expectErr: fosite.ErrMisconfiguration,
},
{
description: "should fail because auth request's client grant type is invalid",
areq: &fosite.AccessRequest{
GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)},
Request: fosite.Request{
Client: &fosite.DefaultClient{
GrantTypes: fosite.Arguments{string(fosite.GrantTypeAuthorizationCode)},
},
Form: url.Values{"device_code": []string{"device_code"}},
Session: session,
},
},
setup: func(areq *fosite.AccessRequest) {
authreq := &fosite.DeviceRequest{
Request: fosite.Request{
GrantedScope: fosite.Arguments{"openid", "email"},
Session: session,
},
}
store.EXPECT().GetOpenIDConnectSession(gomock.Any(), gomock.Any(), areq).Return(authreq, nil)
},
expectErr: fosite.ErrUnauthorizedClient,
},
{
description: "should fail because auth request is missing session",
areq: &fosite.AccessRequest{
GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)},
GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"},
Request: fosite.Request{
Client: client,
Form: url.Values{"device_code": []string{"device_code"}},
Expand All @@ -189,6 +171,7 @@ func TestDeviceToken_PopulateTokenEndpointResponse(t *testing.T) {
setup: func(areq *fosite.AccessRequest) {
authreq := &fosite.DeviceRequest{
Request: fosite.Request{
Client: client,
GrantedScope: fosite.Arguments{"openid", "email"},
},
}
Expand All @@ -199,7 +182,7 @@ func TestDeviceToken_PopulateTokenEndpointResponse(t *testing.T) {
{
description: "should fail because auth request session is missing subject claims",
areq: &fosite.AccessRequest{
GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)},
GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"},
Request: fosite.Request{
Client: client,
Form: url.Values{"device_code": []string{"device_code"}},
Expand All @@ -209,6 +192,7 @@ func TestDeviceToken_PopulateTokenEndpointResponse(t *testing.T) {
setup: func(areq *fosite.AccessRequest) {
authreq := &fosite.DeviceRequest{
Request: fosite.Request{
Client: client,
GrantedScope: fosite.Arguments{"openid", "email"},
Session: NewDefaultSession(),
},
Expand All @@ -220,7 +204,7 @@ func TestDeviceToken_PopulateTokenEndpointResponse(t *testing.T) {
{
description: "should pass",
areq: &fosite.AccessRequest{
GrantTypes: fosite.Arguments{string(fosite.GrantTypeDeviceCode)},
GrantTypes: fosite.Arguments{"urn:ietf:params:oauth:grant-type:device_code"},
Request: fosite.Request{
Client: client,
Form: url.Values{"device_code": []string{"device_code"}},
Expand Down
Loading

0 comments on commit 55bed76

Please sign in to comment.