Skip to content

Commit

Permalink
handler/oauth2: Client IDs in revokation requests must match now
Browse files Browse the repository at this point in the history
  • Loading branch information
arekkas committed Dec 4, 2017
1 parent ff751ee commit 5425584
Show file tree
Hide file tree
Showing 30 changed files with 66 additions and 373 deletions.
45 changes: 23 additions & 22 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,29 @@ import (
)

var (
ErrRequestUnauthorized = errors.New("The request could not be authorized")
ErrRequestForbidden = errors.New("The request is not allowed")
ErrInvalidRequest = errors.New("The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed")
ErrUnauthorizedClient = errors.New("The client is not authorized to request a token using this method")
ErrAccessDenied = errors.New("The resource owner or authorization server denied the request")
ErrUnsupportedResponseType = errors.New("The authorization server does not support obtaining a token using this method")
ErrInvalidScope = errors.New("The requested scope is invalid, unknown, or malformed")
ErrServerError = errors.New("The authorization server encountered an unexpected condition that prevented it from fulfilling the request")
ErrTemporarilyUnavailable = errors.New("The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server")
ErrUnsupportedGrantType = errors.New("The authorization grant type is not supported by the authorization server")
ErrInvalidGrant = errors.New("The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client")
ErrInvalidClient = errors.New("Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method)")
ErrInvalidState = errors.Errorf("The state is missing or has less than %d characters and is therefore considered too weak", MinParameterEntropy)
ErrInsufficientEntropy = errors.Errorf("The request used a security parameter (e.g., anti-replay, anti-csrf) with insufficient entropy (minimum of %d characters)", MinParameterEntropy)
ErrMisconfiguration = errors.New("The request failed because of an internal error that is probably caused by misconfiguration")
ErrNotFound = errors.New("Could not find the requested resource(s)")
ErrInvalidTokenFormat = errors.New("Invalid token format")
ErrTokenSignatureMismatch = errors.New("Token signature mismatch")
ErrTokenExpired = errors.New("Token expired")
ErrScopeNotGranted = errors.New("The token was not granted the requested scope")
ErrTokenClaim = errors.New("The token failed validation due to a claim mismatch")
ErrInactiveToken = errors.New("Token is inactive because it is malformed, expired or otherwise invalid")
ErrRequestUnauthorized = errors.New("The request could not be authorized")
ErrRequestForbidden = errors.New("The request is not allowed")
ErrInvalidRequest = errors.New("The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed")
ErrUnauthorizedClient = errors.New("The client is not authorized to request a token using this method")
ErrAccessDenied = errors.New("The resource owner or authorization server denied the request")
ErrUnsupportedResponseType = errors.New("The authorization server does not support obtaining a token using this method")
ErrInvalidScope = errors.New("The requested scope is invalid, unknown, or malformed")
ErrServerError = errors.New("The authorization server encountered an unexpected condition that prevented it from fulfilling the request")
ErrTemporarilyUnavailable = errors.New("The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server")
ErrUnsupportedGrantType = errors.New("The authorization grant type is not supported by the authorization server")
ErrInvalidGrant = errors.New("The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client")
ErrInvalidClient = errors.New("Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method)")
ErrInvalidState = errors.Errorf("The state is missing or has less than %d characters and is therefore considered too weak", MinParameterEntropy)
ErrInsufficientEntropy = errors.Errorf("The request used a security parameter (e.g., anti-replay, anti-csrf) with insufficient entropy (minimum of %d characters)", MinParameterEntropy)
ErrMisconfiguration = errors.New("The request failed because of an internal error that is probably caused by misconfiguration")
ErrNotFound = errors.New("Could not find the requested resource(s)")
ErrInvalidTokenFormat = errors.New("Invalid token format")
ErrTokenSignatureMismatch = errors.New("Token signature mismatch")
ErrTokenExpired = errors.New("Token expired")
ErrScopeNotGranted = errors.New("The token was not granted the requested scope")
ErrTokenClaim = errors.New("The token failed validation due to a claim mismatch")
ErrInactiveToken = errors.New("Token is inactive because it is malformed, expired or otherwise invalid")
ErrRevokationClientMismatch = errors.New("Token was not issued to the client making the revokation request")
)

const (
Expand Down
2 changes: 1 addition & 1 deletion handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,5 @@ type TokenEndpointHandler interface {
// token as well.
type RevocationHandler interface {
// RevokeToken handles access and refresh token revocation.
RevokeToken(ctx context.Context, token string, tokenType TokenType) error
RevokeToken(ctx context.Context, token string, tokenType TokenType, client Client) error
}
7 changes: 6 additions & 1 deletion handler/oauth2/revocation.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"context"

"github.com/ory/fosite"
"github.com/pkg/errors"
)

type TokenRevocationHandler struct {
Expand All @@ -28,7 +29,7 @@ type TokenRevocationHandler struct {

// RevokeToken implements https://tools.ietf.org/html/rfc7009#section-2.1
// The token type hint indicates which token type check should be performed first.
func (r *TokenRevocationHandler) RevokeToken(ctx context.Context, token string, tokenType fosite.TokenType) error {
func (r *TokenRevocationHandler) RevokeToken(ctx context.Context, token string, tokenType fosite.TokenType, client fosite.Client) error {
discoveryFuncs := []func() (request fosite.Requester, err error){
func() (request fosite.Requester, err error) {
// Refresh token
Expand Down Expand Up @@ -56,6 +57,10 @@ func (r *TokenRevocationHandler) RevokeToken(ctx context.Context, token string,
return err
}

if ar.GetClient().GetID() != client.GetID() {
return errors.WithStack(fosite.ErrRevokationClientMismatch)
}

requestID := ar.GetID()
r.TokenRevocationStorage.RevokeRefreshToken(ctx, requestID)
r.TokenRevocationStorage.RevokeAccessToken(ctx, requestID)
Expand Down
29 changes: 26 additions & 3 deletions handler/oauth2/revocation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,36 +45,54 @@ func TestRevokeToken(t *testing.T) {
description string
mock func()
expectErr error
client fosite.Client
}{
{
description: "should fail - token was issued to another client",
expectErr: fosite.ErrRevokationClientMismatch,
client: &fosite.DefaultClient{ID: "bar"},
mock: func() {
token = "foo"
tokenType = fosite.RefreshToken
rtStrat.EXPECT().RefreshTokenSignature(token)
store.EXPECT().GetRefreshTokenSession(gomock.Any(), gomock.Any(), gomock.Any()).Return(ar, nil)
ar.EXPECT().GetClient().Return(&fosite.DefaultClient{ID: "foo"})
},
},
{
description: "should pass - refresh token discovery first; refresh token found",
expectErr: nil,
client: &fosite.DefaultClient{ID: "bar"},
mock: func() {
token = "foo"
tokenType = fosite.RefreshToken
rtStrat.EXPECT().RefreshTokenSignature(token)
store.EXPECT().GetRefreshTokenSession(gomock.Any(), gomock.Any(), gomock.Any()).Return(ar, nil)
ar.EXPECT().GetID()
ar.EXPECT().GetClient().Return(&fosite.DefaultClient{ID: "bar"})
store.EXPECT().RevokeRefreshToken(gomock.Any(), gomock.Any())
store.EXPECT().RevokeAccessToken(gomock.Any(), gomock.Any())
},
},
{
description: "should pass - access token discovery first; access token found",
expectErr: nil,
client: &fosite.DefaultClient{ID: "bar"},
mock: func() {
token = "foo"
tokenType = fosite.AccessToken
atStrat.EXPECT().AccessTokenSignature(token)
store.EXPECT().GetAccessTokenSession(gomock.Any(), gomock.Any(), gomock.Any()).Return(ar, nil)
ar.EXPECT().GetID()
ar.EXPECT().GetClient().Return(&fosite.DefaultClient{ID: "bar"})
store.EXPECT().RevokeRefreshToken(gomock.Any(), gomock.Any())
store.EXPECT().RevokeAccessToken(gomock.Any(), gomock.Any())
},
},
{
description: "should pass - refresh token discovery first; refresh token not found",
expectErr: nil,
client: &fosite.DefaultClient{ID: "bar"},
mock: func() {
token = "foo"
tokenType = fosite.AccessToken
Expand All @@ -84,13 +102,15 @@ func TestRevokeToken(t *testing.T) {
rtStrat.EXPECT().RefreshTokenSignature(token)
store.EXPECT().GetRefreshTokenSession(gomock.Any(), gomock.Any(), gomock.Any()).Return(ar, nil)
ar.EXPECT().GetID()
ar.EXPECT().GetClient().Return(&fosite.DefaultClient{ID: "bar"})
store.EXPECT().RevokeRefreshToken(gomock.Any(), gomock.Any())
store.EXPECT().RevokeAccessToken(gomock.Any(), gomock.Any())
},
},
{
description: "should pass - access token discovery first; access token not found",
expectErr: nil,
client: &fosite.DefaultClient{ID: "bar"},
mock: func() {
token = "foo"
tokenType = fosite.RefreshToken
Expand All @@ -100,13 +120,15 @@ func TestRevokeToken(t *testing.T) {
atStrat.EXPECT().AccessTokenSignature(token)
store.EXPECT().GetAccessTokenSession(gomock.Any(), gomock.Any(), gomock.Any()).Return(ar, nil)
ar.EXPECT().GetID()
ar.EXPECT().GetClient().Return(&fosite.DefaultClient{ID: "bar"})
store.EXPECT().RevokeRefreshToken(gomock.Any(), gomock.Any())
store.EXPECT().RevokeAccessToken(gomock.Any(), gomock.Any())
},
},
{
description: "should pass - refresh token discovery first; both tokens not found",
description: "should fail - refresh token discovery first; both tokens not found",
expectErr: fosite.ErrNotFound,
client: &fosite.DefaultClient{ID: "bar"},
mock: func() {
token = "foo"
tokenType = fosite.RefreshToken
Expand All @@ -118,8 +140,9 @@ func TestRevokeToken(t *testing.T) {
},
},
{
description: "should pass - access token discovery first; both tokens not found",
description: "should fail - access token discovery first; both tokens not found",
expectErr: fosite.ErrNotFound,
client: &fosite.DefaultClient{ID: "bar"},
mock: func() {
token = "foo"
tokenType = fosite.AccessToken
Expand All @@ -132,7 +155,7 @@ func TestRevokeToken(t *testing.T) {
},
} {
c.mock()
err := h.RevokeToken(nil, token, tokenType)
err := h.RevokeToken(nil, token, tokenType, c.client)
assert.True(t, errors.Cause(err) == c.expectErr, "(%d) %s\n%s\n%s", k, c.description, err, c.expectErr)
t.Logf("Passed test case %d", k)
}
Expand Down
14 changes: 0 additions & 14 deletions internal/access_request.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,6 @@
// Automatically generated by MockGen. DO NOT EDIT!
// Source: github.com/ory/fosite (interfaces: AccessRequester)

// Copyright © 2017 Aeneas Rekkas <[email protected]>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package internal

import (
Expand Down
14 changes: 0 additions & 14 deletions internal/access_response.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,6 @@
// Automatically generated by MockGen. DO NOT EDIT!
// Source: github.com/ory/fosite (interfaces: AccessResponder)

// Copyright © 2017 Aeneas Rekkas <[email protected]>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package internal

import (
Expand Down
14 changes: 0 additions & 14 deletions internal/access_token_storage.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,6 @@
// Automatically generated by MockGen. DO NOT EDIT!
// Source: github.com/ory/fosite/handler/oauth2 (interfaces: AccessTokenStorage)

// Copyright © 2017 Aeneas Rekkas <[email protected]>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package internal

import (
Expand Down
14 changes: 0 additions & 14 deletions internal/access_token_strategy.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,6 @@
// Automatically generated by MockGen. DO NOT EDIT!
// Source: github.com/ory/fosite/handler/oauth2 (interfaces: AccessTokenStrategy)

// Copyright © 2017 Aeneas Rekkas <[email protected]>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package internal

import (
Expand Down
14 changes: 0 additions & 14 deletions internal/authorize_code_storage.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,6 @@
// Automatically generated by MockGen. DO NOT EDIT!
// Source: github.com/ory/fosite/handler/oauth2 (interfaces: AuthorizeCodeStorage)

// Copyright © 2017 Aeneas Rekkas <[email protected]>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package internal

import (
Expand Down
14 changes: 0 additions & 14 deletions internal/authorize_code_strategy.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,6 @@
// Automatically generated by MockGen. DO NOT EDIT!
// Source: github.com/ory/fosite/handler/oauth2 (interfaces: AuthorizeCodeStrategy)

// Copyright © 2017 Aeneas Rekkas <[email protected]>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package internal

import (
Expand Down
14 changes: 0 additions & 14 deletions internal/authorize_handler.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,6 @@
// Automatically generated by MockGen. DO NOT EDIT!
// Source: github.com/ory/fosite (interfaces: AuthorizeEndpointHandler)

// Copyright © 2017 Aeneas Rekkas <[email protected]>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package internal

import (
Expand Down
14 changes: 0 additions & 14 deletions internal/authorize_request.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,6 @@
// Automatically generated by MockGen. DO NOT EDIT!
// Source: github.com/ory/fosite (interfaces: AuthorizeRequester)

// Copyright © 2017 Aeneas Rekkas <[email protected]>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package internal

import (
Expand Down
14 changes: 0 additions & 14 deletions internal/authorize_response.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,6 @@
// Automatically generated by MockGen. DO NOT EDIT!
// Source: github.com/ory/fosite (interfaces: AuthorizeResponder)

// Copyright © 2017 Aeneas Rekkas <[email protected]>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package internal

import (
Expand Down
Loading

0 comments on commit 5425584

Please sign in to comment.