Skip to content

Commit

Permalink
Validate with error classes instead of symbols
Browse files Browse the repository at this point in the history
This way, in :raise mode, we can just raise the associated error in ErrorResponse.
  • Loading branch information
camero2734 committed Nov 23, 2023
1 parent a28b51d commit 0585cc5
Show file tree
Hide file tree
Showing 21 changed files with 97 additions and 78 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ User-visible changes worth mentioning.

## main

- [#ID] Add your PR description here.
- [#1680] Fix handle_auth_errors :raise NotImplementedError

## 5.6.7

Expand Down
14 changes: 14 additions & 0 deletions lib/doorkeeper/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,22 @@ def initialize(response)
TokenGeneratorNotFound = Class.new(DoorkeeperError)
NoOrmCleaner = Class.new(DoorkeeperError)

ServerError = Class.new(BaseResponseError)

InvalidRequest = Class.new(BaseResponseError)
InvalidToken = Class.new(BaseResponseError)
InvalidClient = Class.new(BaseResponseError)
InvalidScope = Class.new(BaseResponseError)
InvalidRedirectUri = Class.new(BaseResponseError)
InvalidCodeChallengeMethod = Class.new(BaseResponseError)
InvalidGrant = Class.new(BaseResponseError)

UnauthorizedClient = Class.new(BaseResponseError)
UnsupportedResponseType = Class.new(BaseResponseError)
UnsupportedResponseMode = Class.new(BaseResponseError)

AccessDenied = Class.new(BaseResponseError)

TokenExpired = Class.new(InvalidToken)
TokenRevoked = Class.new(InvalidToken)
TokenUnknown = Class.new(InvalidToken)
Expand Down
10 changes: 5 additions & 5 deletions lib/doorkeeper/oauth/authorization_code_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
module Doorkeeper
module OAuth
class AuthorizationCodeRequest < BaseRequest
validate :params, error: :invalid_request
validate :client, error: :invalid_client
validate :grant, error: :invalid_grant
validate :params, error: Errors::InvalidRequest
validate :client, error: Errors::InvalidClient
validate :grant, error: Errors::InvalidGrant
# @see https://datatracker.ietf.org/doc/html/rfc6749#section-5.2
validate :redirect_uri, error: :invalid_grant
validate :code_verifier, error: :invalid_grant
validate :redirect_uri, error: Errors::InvalidGrant
validate :code_verifier, error: Errors::InvalidGrant

attr_reader :grant, :client, :redirect_uri, :access_token, :code_verifier,
:invalid_request_reason, :missing_param
Expand Down
2 changes: 1 addition & 1 deletion lib/doorkeeper/oauth/base_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def authorize
@response = TokenResponse.new(access_token)
after_successful_response
@response
elsif error == :invalid_request
elsif error == Errors::InvalidRequest
@response = InvalidRequestResponse.from_request(self)
else
@response = ErrorResponse.from_request(self)
Expand Down
2 changes: 1 addition & 1 deletion lib/doorkeeper/oauth/client_credentials/issuer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def initialize(server, validator)
def create(client, scopes, attributes = {}, creator = Creator.new)
if validator.valid?
@token = create_token(client, scopes, attributes, creator)
@error = :server_error unless @token
@error = Errors::ServerError unless @token
else
@token = false
@error = validator.error
Expand Down
6 changes: 3 additions & 3 deletions lib/doorkeeper/oauth/client_credentials/validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ class Validator
include Validations
include OAuth::Helpers

validate :client, error: :invalid_client
validate :client_supports_grant_flow, error: :unauthorized_client
validate :scopes, error: :invalid_scope
validate :client, error: Errors::InvalidClient
validate :client_supports_grant_flow, error: Errors::UnauthorizedClient
validate :scopes, error: Errors::InvalidScope

def initialize(server, request)
@server = server
Expand Down
2 changes: 1 addition & 1 deletion lib/doorkeeper/oauth/code_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def authorize
end

def deny
pre_auth.error = :access_denied
pre_auth.error = Errors::AccessDenied
pre_auth.error_response
end
end
Expand Down
5 changes: 4 additions & 1 deletion lib/doorkeeper/oauth/error_response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ class ErrorResponse < BaseResponse
def self.from_request(request, attributes = {})
new(
attributes.merge(
name: request.error,
name: request.error.to_s.demodulize.underscore.to_sym,
error_class: request.error <= Errors::BaseResponseError ? request.error : nil,
state: request.try(:state),
redirect_uri: request.try(:redirect_uri),
),
Expand All @@ -21,6 +22,7 @@ def self.from_request(request, attributes = {})

def initialize(attributes = {})
@error = OAuth::Error.new(*attributes.values_at(:name, :state))
@error_class = attributes[:error_class]
@redirect_uri = attributes[:redirect_uri]
@response_on_fragment = attributes[:response_on_fragment]
end
Expand Down Expand Up @@ -72,6 +74,7 @@ def realm
end

def exception_class
return @error_class if @error_class
raise NotImplementedError, "error response must define #exception_class"
end

Expand Down
8 changes: 4 additions & 4 deletions lib/doorkeeper/oauth/password_access_token_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ module OAuth
class PasswordAccessTokenRequest < BaseRequest
include OAuth::Helpers

validate :client, error: :invalid_client
validate :client_supports_grant_flow, error: :unauthorized_client
validate :resource_owner, error: :invalid_grant
validate :scopes, error: :invalid_scope
validate :client, error: Errors::InvalidClient
validate :client_supports_grant_flow, error: Errors::UnauthorizedClient
validate :resource_owner, error: Errors::InvalidGrant
validate :scopes, error: Errors::InvalidScope

attr_reader :client, :credentials, :resource_owner, :parameters, :access_token

Expand Down
22 changes: 11 additions & 11 deletions lib/doorkeeper/oauth/pre_authorization.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ module OAuth
class PreAuthorization
include Validations

validate :client_id, error: :invalid_request
validate :client, error: :invalid_client
validate :client_supports_grant_flow, error: :unauthorized_client
validate :resource_owner_authorize_for_client, error: :invalid_client
validate :redirect_uri, error: :invalid_redirect_uri
validate :params, error: :invalid_request
validate :response_type, error: :unsupported_response_type
validate :response_mode, error: :unsupported_response_mode
validate :scopes, error: :invalid_scope
validate :code_challenge_method, error: :invalid_code_challenge_method
validate :client_id, error: Errors::InvalidRequest
validate :client, error: Errors::InvalidClient
validate :client_supports_grant_flow, error: Errors::UnauthorizedClient
validate :resource_owner_authorize_for_client, error: Errors::InvalidClient
validate :redirect_uri, error: Errors::InvalidRedirectUri
validate :params, error: Errors::InvalidRequest
validate :response_type, error: Errors::UnsupportedResponseType
validate :response_mode, error: Errors::UnsupportedResponseMode
validate :scopes, error: Errors::InvalidScope
validate :code_challenge_method, error: Errors::InvalidCodeChallengeMethod

attr_reader :client, :code_challenge, :code_challenge_method, :missing_param,
:redirect_uri, :resource_owner, :response_type, :state,
Expand Down Expand Up @@ -47,7 +47,7 @@ def scope
end

def error_response
if error == :invalid_request
if error == Errors::InvalidRequest
OAuth::InvalidRequestResponse.from_request(
self,
response_on_fragment: response_on_fragment?,
Expand Down
10 changes: 5 additions & 5 deletions lib/doorkeeper/oauth/refresh_token_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ module OAuth
class RefreshTokenRequest < BaseRequest
include OAuth::Helpers

validate :token_presence, error: :invalid_request
validate :token, error: :invalid_grant
validate :client, error: :invalid_client
validate :client_match, error: :invalid_grant
validate :scope, error: :invalid_scope
validate :token_presence, error: Errors::InvalidRequest
validate :token, error: Errors::InvalidGrant
validate :client, error: Errors::InvalidClient
validate :client_match, error: Errors::InvalidGrant
validate :scope, error: Errors::InvalidScope

attr_reader :access_token, :client, :credentials, :refresh_token
attr_reader :missing_param
Expand Down
16 changes: 9 additions & 7 deletions lib/doorkeeper/oauth/token_introspection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ module OAuth
#
# @see https://datatracker.ietf.org/doc/html/rfc7662
class TokenIntrospection
attr_reader :error

def initialize(server, token)
@server = server
@token = token
Expand All @@ -20,12 +22,12 @@ def authorized?
def error_response
return if @error.blank?

if @error == :invalid_token
if @error == Errors::InvalidToken
OAuth::InvalidTokenResponse.from_access_token(authorized_token)
elsif @error == :invalid_request
elsif @error == Errors::InvalidRequest
OAuth::InvalidRequestResponse.from_request(self)
else
OAuth::ErrorResponse.new(name: @error)
OAuth::ErrorResponse.from_request(self)
end
end

Expand All @@ -36,7 +38,7 @@ def to_json(*)
private

attr_reader :server, :token
attr_reader :error, :invalid_request_reason
attr_reader :invalid_request_reason

# If the protected resource uses OAuth 2.0 client credentials to
# authenticate to the introspection endpoint and its credentials are
Expand All @@ -58,7 +60,7 @@ def to_json(*)
def authorize!
# Requested client authorization
if server.credentials
@error = :invalid_client unless authorized_client
@error = Errors::InvalidClient unless authorized_client
elsif authorized_token
# Requested bearer token authorization
#
Expand All @@ -69,9 +71,9 @@ def authorize!
# HTTP 401 code as described in Section 3 of OAuth 2.0 Bearer Token
# Usage [RFC6750].
#
@error = :invalid_token unless valid_authorized_token?
@error = Errors::InvalidToken unless valid_authorized_token?
else
@error = :invalid_request
@error = Errors::InvalidRequest
@invalid_request_reason = :request_not_authorized
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/doorkeeper/oauth/token_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def authorize
end

def deny
pre_auth.error = :access_denied
pre_auth.error = Errors::AccessDenied
pre_auth.error_response
end
end
Expand Down
6 changes: 3 additions & 3 deletions spec/controllers/authorizations_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1156,7 +1156,7 @@ def query_params
default_scopes_exist :public
end

it "does not redirect" do
it "raises InvalidRequest error" do
expect { get :new, params: { an_invalid: "request" } }.to raise_error(Doorkeeper::Errors::InvalidRequest)
end

Expand All @@ -1171,8 +1171,8 @@ def query_params
default_scopes_exist :public
end

it "does not redirect" do
expect { get :new, params: { client_id: "invalid" } }.to raise_error(Doorkeeper::Errors::InvalidRequest)
it "raises InvalidClient error" do
expect { get :new, params: { client_id: "invalid" } }.to raise_error(Doorkeeper::Errors::InvalidClient)
end
end
end
Expand Down
20 changes: 10 additions & 10 deletions spec/lib/oauth/authorization_code_request_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,39 +50,39 @@
it "requires the grant to be accessible" do
grant.revoke
request.validate
expect(request.error).to eq(:invalid_grant)
expect(request.error).to eq(Doorkeeper::Errors::InvalidGrant)
end

it "requires the grant" do
request = described_class.new(server, nil, client, params)
request.validate
expect(request.error).to eq(:invalid_grant)
expect(request.error).to eq(Doorkeeper::Errors::InvalidGrant)
end

it "requires the client" do
request = described_class.new(server, grant, nil, params)
request.validate
expect(request.error).to eq(:invalid_client)
expect(request.error).to eq(Doorkeeper::Errors::InvalidClient)
end

it "requires the redirect_uri" do
request = described_class.new(server, grant, nil, params.except(:redirect_uri))
request.validate
expect(request.error).to eq(:invalid_request)
expect(request.error).to eq(Doorkeeper::Errors::InvalidRequest)
expect(request.missing_param).to eq(:redirect_uri)
end

it "matches the redirect_uri with grant's one" do
request = described_class.new(server, grant, client, params.merge(redirect_uri: "http://other.com"))
request.validate
expect(request.error).to eq(:invalid_grant)
expect(request.error).to eq(Doorkeeper::Errors::InvalidGrant)
end

it "matches the client with grant's one" do
other_client = FactoryBot.create :application
request = described_class.new(server, grant, other_client, params)
request.validate
expect(request.error).to eq(:invalid_grant)
expect(request.error).to eq(Doorkeeper::Errors::InvalidGrant)
end

it "skips token creation if there is a matching one reusable" do
Expand Down Expand Up @@ -150,7 +150,7 @@

it "responds with invalid_grant" do
request.validate
expect(request.error).to eq(:invalid_grant)
expect(request.error).to eq(Doorkeeper::Errors::InvalidGrant)
end
end

Expand All @@ -159,7 +159,7 @@

it "invalidates when redirect_uri of the grant is not native" do
request.validate
expect(request.error).to eq(:invalid_grant)
expect(request.error).to eq(Doorkeeper::Errors::InvalidGrant)
end

it "validates when redirect_uri of the grant is also native" do
Expand Down Expand Up @@ -195,15 +195,15 @@
it "invalidates when code_verifier is missing" do
request.validate

expect(request.error).to eq(:invalid_request)
expect(request.error).to eq(Doorkeeper::Errors::InvalidRequest)
expect(request.missing_param).to eq(:code_verifier)
end

it "invalidates when code_verifier is the wrong value" do
params[:code_verifier] = "foobar"
request.validate

expect(request.error).to eq(:invalid_grant)
expect(request.error).to eq(Doorkeeper::Errors::InvalidGrant)
end
end

Expand Down
4 changes: 2 additions & 2 deletions spec/lib/oauth/base_request_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
context "with error other than invalid_request" do
before do
allow(request).to receive(:valid?).and_return(false)
allow(request).to receive(:error).and_return(:server_error)
allow(request).to receive(:error).and_return(Doorkeeper::Errors::ServerError)
allow(request).to receive(:state).and_return("hello")
end

Expand All @@ -88,7 +88,7 @@
context "with invalid_request error" do
before do
allow(request).to receive(:valid?).and_return(false)
allow(request).to receive(:error).and_return(:invalid_request)
allow(request).to receive(:error).and_return(Doorkeeper::Errors::InvalidRequest)
allow(request).to receive(:state).and_return("hello")
end

Expand Down
2 changes: 1 addition & 1 deletion spec/lib/oauth/client_credentials/issuer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
expect(creator).to receive(:call).and_return(false)
issuer.create client, scopes, {}, creator

expect(issuer.error).to eq(:server_error)
expect(issuer.error).to eq(Doorkeeper::Errors::ServerError)
end

context "when validator fails" do
Expand Down
Loading

0 comments on commit 0585cc5

Please sign in to comment.