Skip to content

Commit

Permalink
Merge e4fc24b into 4c94445
Browse files Browse the repository at this point in the history
  • Loading branch information
nbulaj committed Sep 7, 2018
2 parents 4c94445 + e4fc24b commit 4bcca28
Show file tree
Hide file tree
Showing 10 changed files with 180 additions and 3 deletions.
5 changes: 5 additions & 0 deletions lib/doorkeeper/config.rb
Expand Up @@ -239,6 +239,7 @@ def option(name, options = {})
option :native_redirect_uri, default: 'urn:ietf:wg:oauth:2.0:oob'
option :active_record_options, default: {}
option :grant_flows, default: %w[authorization_code client_credentials]
option :handle_auth_errors, default: :render

# Allows to forbid specific Application redirect URI's by custom rules.
# Doesn't forbid any URI by default.
Expand Down Expand Up @@ -317,6 +318,10 @@ def confirm_application_owner?
!!(defined?(@confirm_application_owner) && @confirm_application_owner)
end

def raise_on_errors?
handle_auth_errors == :raise
end

def default_scopes
@default_scopes ||= OAuth::Scopes.new
end
Expand Down
14 changes: 14 additions & 0 deletions lib/doorkeeper/errors.rb
Expand Up @@ -36,7 +36,21 @@ def type
end
end

class BaseResponseError < DoorkeeperError
attr_reader :response

def initialize(response)
@response = response
end
end

UnableToGenerateToken = Class.new(DoorkeeperError)
TokenGeneratorNotFound = Class.new(DoorkeeperError)

InvalidToken = Class.new BaseResponseError
TokenExpired = Class.new InvalidToken
TokenRevoked = Class.new InvalidToken
TokenUnknown = Class.new InvalidToken
TokenForbidden = Class.new InvalidToken
end
end
8 changes: 8 additions & 0 deletions lib/doorkeeper/oauth/error_response.rb
Expand Up @@ -55,6 +55,10 @@ def headers
}
end

def raise_exception!
raise exception_class.new(self), description
end

protected

delegate :realm, to: :configuration
Expand All @@ -63,6 +67,10 @@ def configuration
Doorkeeper.configuration
end

def exception_class
raise NotImplementedError, "error response must define #exception_class"
end

private

def authenticate_info
Expand Down
9 changes: 7 additions & 2 deletions lib/doorkeeper/oauth/forbidden_token_response.rb
Expand Up @@ -21,8 +21,13 @@ def headers
end

def description
scope = { scope: %i[doorkeeper scopes] }
@description ||= @scopes.map { |r| I18n.translate r, scope }.join('\n')
@description ||= @scopes.map { |s| I18n.t(s, scope: %i[doorkeeper scopes]) }.join("\n")
end

protected

def exception_class
Doorkeeper::Errors::TokenForbidden
end
end
end
Expand Down
16 changes: 16 additions & 0 deletions lib/doorkeeper/oauth/invalid_token_response.rb
Expand Up @@ -24,6 +24,22 @@ def description
scope = { scope: %i[doorkeeper errors messages invalid_token] }
@description ||= I18n.translate @reason, scope
end

protected

def exception_class
errors_mapping.fetch(reason)
end

private

def errors_mapping
{
expired: Doorkeeper::Errors::TokenExpired,
revoked: Doorkeeper::Errors::TokenRevoked,
unknown: Doorkeeper::Errors::TokenUnknown
}
end
end
end
end
2 changes: 2 additions & 0 deletions lib/doorkeeper/rails/helpers.rb
Expand Up @@ -19,6 +19,8 @@ def valid_doorkeeper_token?

def doorkeeper_render_error
error = doorkeeper_error
error.raise_exception! if Doorkeeper.configuration.raise_on_errors?

headers.merge!(error.headers.reject { |k| k == "Content-Type" })
doorkeeper_render_error_with(error)
end
Expand Down
16 changes: 15 additions & 1 deletion lib/generators/doorkeeper/templates/initializer.rb
Expand Up @@ -121,7 +121,8 @@
# access_token_methods :from_bearer_authorization, :from_access_token_param, :from_bearer_param

# Change the native redirect uri for client apps
# When clients register with the following redirect uri, they won't be redirected to any server and the authorization code will be displayed within the provider
# When clients register with the following redirect uri, they won't be redirected to any server and
# the authorizationcode will be displayed within the provider
# The value can be any string. Use nil to disable this feature. When disabled, clients must provide a valid URL
# (Similar behaviour: https://developers.google.com/accounts/docs/OAuth2InstalledApp#choosingredirecturi)
#
Expand All @@ -147,6 +148,19 @@
#
# forbid_redirect_uri { |uri| uri.scheme.to_s.downcase == 'javascript' }

# Specify how authorization errors should be handled.
# By default, doorkeeper renders json errors when access token
# is invalid, expired, revoked or has invalid scopes.
#
# If you want to render error response yourself (i.e. rescue exceptions),
# set handle_auth_errors to `:raise` and rescue Doorkeeper::Errors::InvalidToken
# or following specific errors:
#
# Doorkeeper::Errors::TokenForbidden, Doorkeeper::Errors::TokenExpired,
# Doorkeeper::Errors::TokenRevoked, Doorkeeper::Errors::TokenUnknown
#
# handle_auth_errors = :raise

# Specify what grant flows are enabled in array of Strings. The valid
# strings and the flows they enable are:
#
Expand Down
43 changes: 43 additions & 0 deletions spec/controllers/protected_resources_controller_spec.rb
Expand Up @@ -306,4 +306,47 @@ def doorkeeper_forbidden_render_options(*)
end
end
end

context 'when handle_auth_errors option is set to :raise' do
subject { get :index, params: { access_token: token_string } }

before do
config_is_set(:handle_auth_errors, :raise)
end

controller do
before_action :doorkeeper_authorize!
include ControllerActions
end

context 'when token is unknown' do
it 'raises Doorkeeper::Errors::TokenUnknown exception', token: :invalid do
expect { subject }.to raise_error(Doorkeeper::Errors::TokenUnknown)
end
end

context 'when token is expired' do
it 'raises Doorkeeper::Errors::TokenExpired exception', token: :expired do
expect { subject }.to raise_error(Doorkeeper::Errors::TokenExpired)
end
end

context 'when token is revoked' do
it 'raises Doorkeeper::Errors::TokenRevoked exception', token: :revoked do
expect { subject }.to raise_error(Doorkeeper::Errors::TokenRevoked)
end
end

context 'when token is forbidden' do
it 'raises Doorkeeper::Errors::TokenForbidden exception', token: :forbidden do
expect { subject }.to raise_error(Doorkeeper::Errors::TokenForbidden)
end
end

context 'when token is valid' do
it 'allows into index action', token: :valid do
expect(response).to be_successful
end
end
end
end
13 changes: 13 additions & 0 deletions spec/lib/config_spec.rb
Expand Up @@ -508,4 +508,17 @@
expect(subject.enforce_content_type).to eq(true)
end
end

describe 'handle_auth_errors' do
it 'is set to render by default' do
expect(Doorkeeper.configuration.handle_auth_errors).to eq(:render)
end
it 'can change the value' do
Doorkeeper.configure {
orm DOORKEEPER_ORM
handle_auth_errors :raise
}
expect(subject.handle_auth_errors).to eq(:raise)
end
end
end
57 changes: 57 additions & 0 deletions spec/support/shared/controllers_shared_context.rb
Expand Up @@ -63,3 +63,60 @@
allow(controller).to receive(:authorization) { authorization }
end
end

shared_context 'expired token', token: :expired do
let :token_string do
'1A2B3C4DEXP'
end

let :token do
double(Doorkeeper::AccessToken,
accessible?: false, revoked?: false, expired?: true,
includes_scope?: false, acceptable?: false,
previous_refresh_token: "", revoke_previous_refresh_token!: true)
end

before :each do
allow(
Doorkeeper::AccessToken
).to receive(:by_token).with(token_string).and_return(token)
end
end

shared_context 'revoked token', token: :revoked do
let :token_string do
'1A2B3C4DREV'
end

let :token do
double(Doorkeeper::AccessToken,
accessible?: false, revoked?: true, expired?: false,
includes_scope?: false, acceptable?: false,
previous_refresh_token: "", revoke_previous_refresh_token!: true)
end

before :each do
allow(
Doorkeeper::AccessToken
).to receive(:by_token).with(token_string).and_return(token)
end
end

shared_context 'forbidden token', token: :forbidden do
let :token_string do
'1A2B3C4DFORB'
end

let :token do
double(Doorkeeper::AccessToken,
accessible?: true, includes_scope?: true, acceptable?: false,
previous_refresh_token: "", revoke_previous_refresh_token!: true)
end

before :each do
allow(
Doorkeeper::AccessToken
).to receive(:by_token).with(token_string).and_return(token)
end
end

0 comments on commit 4bcca28

Please sign in to comment.