doorkeeper 1.3.1 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of doorkeeper might be problematic. Click here for more details.

Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/.hound.yml +4 -1
  3. data/CHANGELOG.md +18 -0
  4. data/README.md +2 -1
  5. data/app/controllers/doorkeeper/application_metal_controller.rb +16 -0
  6. data/app/controllers/doorkeeper/applications_controller.rb +0 -6
  7. data/app/controllers/doorkeeper/authorizations_controller.rb +14 -15
  8. data/app/controllers/doorkeeper/authorized_applications_controller.rb +10 -8
  9. data/app/controllers/doorkeeper/token_info_controller.rb +1 -1
  10. data/app/controllers/doorkeeper/tokens_controller.rb +3 -11
  11. data/app/validators/redirect_uri_validator.rb +0 -1
  12. data/config/locales/en.yml +0 -3
  13. data/doorkeeper.gemspec +1 -0
  14. data/lib/doorkeeper.rb +1 -0
  15. data/lib/doorkeeper/config.rb +5 -5
  16. data/lib/doorkeeper/doorkeeper_for.rb +7 -17
  17. data/lib/doorkeeper/helpers/controller.rb +11 -8
  18. data/lib/doorkeeper/helpers/filter.rb +35 -13
  19. data/lib/doorkeeper/models/access_grant.rb +5 -5
  20. data/lib/doorkeeper/models/access_token.rb +9 -5
  21. data/lib/doorkeeper/models/active_record/access_grant.rb +1 -1
  22. data/lib/doorkeeper/models/active_record/access_token.rb +1 -1
  23. data/lib/doorkeeper/models/active_record/application.rb +3 -3
  24. data/lib/doorkeeper/models/application.rb +1 -1
  25. data/lib/doorkeeper/models/mongo_mapper/access_grant.rb +0 -3
  26. data/lib/doorkeeper/models/mongo_mapper/access_token.rb +0 -3
  27. data/lib/doorkeeper/models/mongoid2/access_grant.rb +1 -3
  28. data/lib/doorkeeper/models/mongoid2/access_token.rb +1 -3
  29. data/lib/doorkeeper/models/mongoid3_4/access_grant.rb +2 -4
  30. data/lib/doorkeeper/models/mongoid3_4/access_token.rb +2 -4
  31. data/lib/doorkeeper/models/revocable.rb +1 -1
  32. data/lib/doorkeeper/models/scopes.rb +6 -2
  33. data/lib/doorkeeper/oauth/authorization/code.rb +4 -0
  34. data/lib/doorkeeper/oauth/authorization/token.rb +8 -0
  35. data/lib/doorkeeper/oauth/authorization_code_request.rb +2 -2
  36. data/lib/doorkeeper/oauth/client.rb +2 -2
  37. data/lib/doorkeeper/oauth/client_credentials/creator.rb +1 -1
  38. data/lib/doorkeeper/oauth/client_credentials/validation.rb +2 -2
  39. data/lib/doorkeeper/oauth/client_credentials_request.rb +3 -12
  40. data/lib/doorkeeper/oauth/code_response.rb +3 -4
  41. data/lib/doorkeeper/oauth/error_response.rb +3 -3
  42. data/lib/doorkeeper/oauth/forbidden_token_response.rb +29 -0
  43. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +1 -1
  44. data/lib/doorkeeper/oauth/password_access_token_request.rb +5 -5
  45. data/lib/doorkeeper/oauth/pre_authorization.rb +2 -2
  46. data/lib/doorkeeper/oauth/refresh_token_request.rb +6 -6
  47. data/lib/doorkeeper/oauth/request_concern.rb +2 -2
  48. data/lib/doorkeeper/oauth/token.rb +1 -1
  49. data/lib/doorkeeper/server.rb +2 -2
  50. data/lib/doorkeeper/version.rb +1 -1
  51. data/spec/controllers/authorizations_controller_spec.rb +46 -0
  52. data/spec/controllers/protected_resources_controller_spec.rb +13 -6
  53. data/spec/lib/models/revocable_spec.rb +1 -1
  54. data/spec/lib/models/scopes_spec.rb +11 -0
  55. data/spec/lib/oauth/authorization/uri_builder_spec.rb +5 -0
  56. data/spec/lib/oauth/forbidden_token_response_spec.rb +23 -0
  57. data/spec/models/doorkeeper/access_token_spec.rb +30 -0
  58. data/spec/requests/flows/refresh_token_spec.rb +2 -2
  59. data/spec/requests/protected_resources/private_api_spec.rb +5 -5
  60. data/spec/support/shared/controllers_shared_context.rb +2 -2
  61. data/spec/validators/redirect_uri_validator_spec.rb +1 -2
  62. metadata +19 -4
  63. data/lib/doorkeeper/models/mongo_mapper/revocable.rb +0 -15
  64. data/lib/doorkeeper/models/mongoid/revocable.rb +0 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1cf5353e6f59ed9314bed48b00fee6eef151e62e
4
- data.tar.gz: e9fbdfa650708ab9e9fdea68e96ab2c712910308
3
+ metadata.gz: 2effc07ab96a92f6ce4bf22833e99079c1309b01
4
+ data.tar.gz: b2d4793140041f6a71b3eddc5ce74c61bca8de8e
5
5
  SHA512:
6
- metadata.gz: 5492059f736ca023683d8b9227dbe61648501742ae4d3d1aa6b8ec302906d57764760814647e06105f1b20e2eb902c3c934ef7d216c5600dc470fa356e1572ca
7
- data.tar.gz: 871bc1c1cd6a7adc602e1d929f4f546cf95a89ef454a767719ad2a559d156c9e34121268aa11fde46c02d080be5d08992f2c57a130cd0a87691cb9aee9d1e5aa
6
+ metadata.gz: 55e4089805323ebc56efff0306872bfea4b19b814131632c62885975aebe452338612ced9f3137e20500b9dfa298bec2f8b3de7b385d3e1be16df804a0c8ccb7
7
+ data.tar.gz: 50b4631d1e4f14557aba937edb12d225e2a704d80142b3e3e487d8f36a5c097a89bfdd871bda1012e690324c3833605ca51c23820aa47a5b7baba242bf782287
data/.hound.yml CHANGED
@@ -1,3 +1,6 @@
1
1
  LineLength:
2
2
  Exclude:
3
- - app/spec/**/*
3
+ - spec/**/*
4
+
5
+ StringLiterals:
6
+ Enabled: false
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## master
4
+
5
+ ## 1.4.0
6
+
7
+ - internals
8
+ - [#427] Adds specs expectations.
9
+ - [#428] Error response refactor.
10
+ - [#417] Moves token validation into Access Token class.
11
+ - [#439] Removes redundant module includes.
12
+ - [#443] TokensController and TokenInfoController inherit from ActionController::Metal
13
+ - bug
14
+ - [#418] fixes #243, requests with insufficient scope now respond 403 instead
15
+ of 401. (API change)
16
+ - [#438] fixes #398, native redirect for implicit token grant bug.
17
+ - [#440] namespace fixes
18
+ - enhancements
19
+ - [#432] Keeps query parameters
20
+
3
21
  ## 1.3.1
4
22
 
5
23
  - enhancements
data/README.md CHANGED
@@ -20,7 +20,8 @@ Doorkeeper is a gem that makes it easy to introduce OAuth 2 provider functionali
20
20
  - [Routes](#routes)
21
21
  - [Authenticating](#authenticating)
22
22
  - [Protecting resources with OAuth (a.k.a your API endpoint)](#protecting-resources-with-oauth-aka-your-api-endpoint)
23
- - [ActionController::Metal integration and other integrations](#actioncontrollermetal-integration-and-other-integrations)
23
+ - [ActionController::Metal integration](#actioncontrollermetal-integration)
24
+ - [Route Constraints and other integrations](#route-constraints-and-other-integrations)
24
25
  - [Access Token Scopes](#access-token-scopes)
25
26
  - [Authenticated resource owner](#authenticated-resource-owner)
26
27
  - [Applications list](#applications-list)
@@ -0,0 +1,16 @@
1
+ module Doorkeeper
2
+ class ApplicationMetalController < ActionController::Metal
3
+ MODULES = [
4
+ ActionController::RackDelegation,
5
+ ActionController::Instrumentation,
6
+ AbstractController::Rendering,
7
+ ActionController::Rendering,
8
+ ActionController::Renderers::All,
9
+ Helpers::Controller
10
+ ]
11
+
12
+ MODULES.each do |mod|
13
+ include mod
14
+ end
15
+ end
16
+ end
@@ -24,12 +24,6 @@ module Doorkeeper
24
24
  end
25
25
  end
26
26
 
27
- def show
28
- end
29
-
30
- def edit
31
- end
32
-
33
27
  def update
34
28
  if @application.update_attributes(application_params)
35
29
  flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :update])
@@ -1,10 +1,10 @@
1
1
  module Doorkeeper
2
- class AuthorizationsController < ::Doorkeeper::ApplicationController
2
+ class AuthorizationsController < Doorkeeper::ApplicationController
3
3
  before_filter :authenticate_resource_owner!
4
4
 
5
5
  def new
6
6
  if pre_auth.authorizable?
7
- if Doorkeeper::AccessToken.matching_token_for(pre_auth.client, current_resource_owner.id, pre_auth.scopes) || skip_authorization?
7
+ if matching_token? || skip_authorization?
8
8
  auth = authorization.authorize
9
9
  redirect_to auth.redirect_uri
10
10
  else
@@ -15,23 +15,24 @@ module Doorkeeper
15
15
  end
16
16
  end
17
17
 
18
- def show
19
- end
20
-
21
18
  # TODO: Handle raise invalid authorization
22
19
  def create
23
- auth = authorization.authorize
24
-
25
- if auth.redirectable?
26
- redirect_to auth.redirect_uri
27
- else
28
- render json: auth.body, status: auth.status
29
- end
20
+ redirect_or_render authorization.authorize
30
21
  end
31
22
 
32
23
  def destroy
33
- auth = authorization.deny
24
+ redirect_or_render authorization.deny
25
+ end
26
+
27
+ private
34
28
 
29
+ def matching_token?
30
+ AccessToken.matching_token_for pre_auth.client,
31
+ current_resource_owner.id,
32
+ pre_auth.scopes
33
+ end
34
+
35
+ def redirect_or_render(auth)
35
36
  if auth.redirectable?
36
37
  redirect_to auth.redirect_uri
37
38
  else
@@ -39,8 +40,6 @@ module Doorkeeper
39
40
  end
40
41
  end
41
42
 
42
- private
43
-
44
43
  def pre_auth
45
44
  @pre_auth ||= OAuth::PreAuthorization.new(Doorkeeper.configuration, server.client_via_uid, params)
46
45
  end
@@ -1,12 +1,14 @@
1
- class Doorkeeper::AuthorizedApplicationsController < Doorkeeper::ApplicationController
2
- before_filter :authenticate_resource_owner!
1
+ module Doorkeeper
2
+ class AuthorizedApplicationsController < Doorkeeper::ApplicationController
3
+ before_filter :authenticate_resource_owner!
3
4
 
4
- def index
5
- @applications = Doorkeeper::Application.authorized_for(current_resource_owner)
6
- end
5
+ def index
6
+ @applications = Application.authorized_for(current_resource_owner)
7
+ end
7
8
 
8
- def destroy
9
- Doorkeeper::AccessToken.revoke_all_for params[:id], current_resource_owner
10
- redirect_to oauth_authorized_applications_url, notice: I18n.t(:notice, scope: [:doorkeeper, :flash, :authorized_applications, :destroy])
9
+ def destroy
10
+ AccessToken.revoke_all_for params[:id], current_resource_owner
11
+ redirect_to oauth_authorized_applications_url, notice: I18n.t(:notice, scope: [:doorkeeper, :flash, :authorized_applications, :destroy])
12
+ end
11
13
  end
12
14
  end
@@ -1,5 +1,5 @@
1
1
  module Doorkeeper
2
- class TokenInfoController < ::Doorkeeper::ApplicationController
2
+ class TokenInfoController < Doorkeeper::ApplicationMetalController
3
3
  def show
4
4
  if doorkeeper_token && doorkeeper_token.accessible?
5
5
  render json: doorkeeper_token, status: :ok
@@ -1,9 +1,5 @@
1
1
  module Doorkeeper
2
- class TokensController < ::Doorkeeper::ApplicationController
3
- include Helpers::Controller
4
- include ActionController::RackDelegation
5
- include ActionController::Instrumentation
6
-
2
+ class TokensController < Doorkeeper::ApplicationMetalController
7
3
  def create
8
4
  response = strategy.authorize
9
5
  self.headers.merge! response.headers
@@ -13,11 +9,7 @@ module Doorkeeper
13
9
  handle_token_exception e
14
10
  end
15
11
 
16
- #############################################
17
- # RFC 7009 - OAuth 2.0 Token Revocation #
18
- # #
19
- # http://tools.ietf.org/html/rfc7009 #
20
- #############################################
12
+ # OAuth 2.0 Token Revocation - http://tools.ietf.org/html/rfc7009
21
13
  def revoke
22
14
  # The authorization server first validates the client credentials
23
15
  if doorkeeper_token && doorkeeper_token.accessible?
@@ -33,7 +25,7 @@ module Doorkeeper
33
25
  private
34
26
 
35
27
  def revoke_token(token)
36
- token = Doorkeeper::AccessToken.authenticate(token) || Doorkeeper::AccessToken.by_refresh_token(token)
28
+ token = AccessToken.authenticate(token) || AccessToken.by_refresh_token(token)
37
29
  if token && doorkeeper_token.same_credential?(token)
38
30
  token.revoke
39
31
  true
@@ -14,7 +14,6 @@ class RedirectUriValidator < ActiveModel::EachValidator
14
14
  return if native_redirect_uri?(uri)
15
15
  record.errors.add(attribute, :fragment_present) unless uri.fragment.nil?
16
16
  record.errors.add(attribute, :relative_uri) if uri.scheme.nil? || uri.host.nil?
17
- record.errors.add(attribute, :has_query_parameter) unless uri.query.nil?
18
17
  end
19
18
  end
20
19
  rescue URI::InvalidURIError
@@ -6,7 +6,6 @@ en:
6
6
  attributes:
7
7
  redirect_uri:
8
8
  fragment_present: 'cannot contain a fragment.'
9
- has_query_parameter: 'cannot contain a query parameter.'
10
9
  invalid_uri: 'must be a valid URI.'
11
10
  relative_uri: 'must be an absolute URI.'
12
11
  mongoid:
@@ -16,7 +15,6 @@ en:
16
15
  attributes:
17
16
  redirect_uri:
18
17
  fragment_present: 'cannot contain a fragment.'
19
- has_query_parameter: 'cannot contain a query parameter.'
20
18
  invalid_uri: 'must be a valid URI.'
21
19
  relative_uri: 'must be an absolute URI.'
22
20
  mongo_mapper:
@@ -26,7 +24,6 @@ en:
26
24
  attributes:
27
25
  redirect_uri:
28
26
  fragment_present: 'cannot contain a fragment.'
29
- has_query_parameter: 'cannot contain a query parameter.'
30
27
  invalid_uri: 'must be a valid URI.'
31
28
  relative_uri: 'must be an absolute URI.'
32
29
  doorkeeper:
@@ -27,4 +27,5 @@ Gem::Specification.new do |s|
27
27
  s.add_development_dependency "database_cleaner", "~> 1.3.0"
28
28
  s.add_development_dependency "rspec-activemodel-mocks", "~> 1.0.0"
29
29
  s.add_development_dependency "bcrypt-ruby", "~> 3.0.1"
30
+ s.add_development_dependency "pry", "~> 0.10.0"
30
31
  end
@@ -31,6 +31,7 @@ require 'doorkeeper/oauth/token_request'
31
31
  require 'doorkeeper/oauth/client'
32
32
  require 'doorkeeper/oauth/token'
33
33
  require 'doorkeeper/oauth/invalid_token_response'
34
+ require 'doorkeeper/oauth/forbidden_token_response'
34
35
 
35
36
  require 'doorkeeper/models/scopes'
36
37
  require 'doorkeeper/models/expirable'
@@ -35,7 +35,7 @@ module Doorkeeper
35
35
 
36
36
  def self.setup_application_owner
37
37
  require File.join(File.dirname(__FILE__), 'models', 'ownership')
38
- Doorkeeper::Application.send :include, Doorkeeper::Models::Ownership
38
+ Application.send :include, Models::Ownership
39
39
  end
40
40
 
41
41
  class Config
@@ -59,11 +59,11 @@ module Doorkeeper
59
59
  end
60
60
 
61
61
  def default_scopes(*scopes)
62
- @config.instance_variable_set('@default_scopes', Doorkeeper::OAuth::Scopes.from_array(scopes))
62
+ @config.instance_variable_set('@default_scopes', OAuth::Scopes.from_array(scopes))
63
63
  end
64
64
 
65
65
  def optional_scopes(*scopes)
66
- @config.instance_variable_set('@optional_scopes', Doorkeeper::OAuth::Scopes.from_array(scopes))
66
+ @config.instance_variable_set('@optional_scopes', OAuth::Scopes.from_array(scopes))
67
67
  end
68
68
 
69
69
  def client_credentials(*methods)
@@ -198,11 +198,11 @@ module Doorkeeper
198
198
  end
199
199
 
200
200
  def default_scopes
201
- @default_scopes ||= Doorkeeper::OAuth::Scopes.new
201
+ @default_scopes ||= OAuth::Scopes.new
202
202
  end
203
203
 
204
204
  def optional_scopes
205
- @optional_scopes ||= Doorkeeper::OAuth::Scopes.new
205
+ @optional_scopes ||= OAuth::Scopes.new
206
206
  end
207
207
 
208
208
  def scopes
@@ -1,51 +1,41 @@
1
1
  module Doorkeeper
2
2
  class InvalidSyntax < StandardError; end
3
3
  class DoorkeeperFor
4
+ attr_reader :scopes
5
+
4
6
  def initialize(options)
5
7
  options ||= {}
6
8
  fail InvalidSyntax unless options.is_a? Hash
7
9
  @filter_options = {}
8
10
 
9
11
  options.each do |k, v|
10
- self.send(k, v)
12
+ send("#{k}=", v)
11
13
  end
12
14
  end
13
15
 
14
- # TODO: move this to Token class
15
- def validate_token(token)
16
- return false unless token
17
- token.accessible? && validate_token_scopes(token)
18
- end
19
-
20
16
  def filter_options
21
17
  @filter_options
22
18
  end
23
19
 
24
20
  private
25
21
 
26
- def scopes(scopes)
22
+ def scopes=(scopes)
27
23
  @scopes = scopes.map(&:to_s)
28
24
  end
29
25
 
30
- def if(if_block)
26
+ def if=(if_block)
31
27
  @filter_options[:if] = if_block
32
28
  end
33
29
 
34
- def unless(unless_block)
30
+ def unless=(unless_block)
35
31
  @filter_options[:unless] = unless_block
36
32
  end
37
-
38
- # TODO: move this to Token class
39
- def validate_token_scopes(token)
40
- return true if @scopes.blank?
41
- token.scopes.any? { |scope| @scopes.include? scope }
42
- end
43
33
  end
44
34
 
45
35
  class AllDoorkeeperFor < DoorkeeperFor
46
36
  private
47
37
 
48
- def except(actions)
38
+ def except=(actions)
49
39
  @filter_options[:except] = actions
50
40
  end
51
41
  end
@@ -1,14 +1,9 @@
1
1
  module Doorkeeper
2
2
  module Helpers
3
3
  module Controller
4
- def self.included(base)
5
- base.send :private,
6
- :authenticate_resource_owner!,
7
- :authenticate_admin!,
8
- :current_resource_owner,
9
- :resource_owner_from_credentials,
10
- :skip_authorization?
11
- end
4
+ extend ActiveSupport::Concern
5
+
6
+ private
12
7
 
13
8
  def authenticate_resource_owner!
14
9
  current_resource_owner
@@ -30,6 +25,14 @@ module Doorkeeper
30
25
  @server ||= Server.new(self)
31
26
  end
32
27
 
28
+ def doorkeeper_token
29
+ @token ||= OAuth::Token.authenticate request, *config_methods
30
+ end
31
+
32
+ def config_methods
33
+ @methods ||= Doorkeeper.configuration.access_token_methods
34
+ end
35
+
33
36
  def get_error_response_from_exception(exception)
34
37
  error_name = case exception
35
38
  when Errors::InvalidTokenStrategy
@@ -6,18 +6,18 @@ module Doorkeeper
6
6
  doorkeeper_for = DoorkeeperForBuilder.create_doorkeeper_for(*args)
7
7
 
8
8
  before_filter doorkeeper_for.filter_options do
9
- unless doorkeeper_for.validate_token(doorkeeper_token)
10
- @error = OAuth::InvalidTokenResponse.from_access_token(doorkeeper_token)
11
- headers.merge!(@error.headers.reject { |k, v| ['Content-Type'].include? k })
12
- render_options = doorkeeper_unauthorized_render_options
13
-
14
- if render_options.nil? || render_options.empty?
15
- head :unauthorized
9
+ unless valid_token?(doorkeeper_for.scopes)
10
+ if !doorkeeper_token || !doorkeeper_token.accessible?
11
+ @error = OAuth::InvalidTokenResponse.from_access_token(doorkeeper_token)
12
+ error_status = :unauthorized
13
+ options = doorkeeper_unauthorized_render_options
16
14
  else
17
- render_options[:status] = :unauthorized
18
- render_options[:layout] = false if render_options[:layout].nil?
19
- render render_options
15
+ @error = OAuth::ForbiddenTokenResponse.from_scopes(doorkeeper_for.scopes)
16
+ error_status = :forbidden
17
+ options = doorkeeper_forbidden_render_options
20
18
  end
19
+ headers.merge!(@error.headers.reject { |k, v| ['Content-Type'].include? k })
20
+ render_error(error_status, options)
21
21
  end
22
22
  end
23
23
  end
@@ -29,14 +29,36 @@ module Doorkeeper
29
29
  end
30
30
 
31
31
  def doorkeeper_token
32
- return @token if instance_variable_defined?(:@token)
33
- methods = Doorkeeper.configuration.access_token_methods
34
- @token = OAuth::Token.authenticate request, *methods
32
+ @token ||= OAuth::Token.authenticate request, *config_methods
33
+ end
34
+
35
+ def config_methods
36
+ @methods ||= Doorkeeper.configuration.access_token_methods
35
37
  end
36
38
 
37
39
  def doorkeeper_unauthorized_render_options
38
40
  nil
39
41
  end
42
+
43
+ def doorkeeper_forbidden_render_options
44
+ nil
45
+ end
46
+
47
+ private
48
+
49
+ def valid_token?(scopes)
50
+ doorkeeper_token && doorkeeper_token.acceptable?(scopes)
51
+ end
52
+
53
+ def render_error(error, options)
54
+ if options.blank?
55
+ head error
56
+ else
57
+ options[:status] = error
58
+ options[:layout] = false if options[:layout].nil?
59
+ render options
60
+ end
61
+ end
40
62
  end
41
63
  end
42
64
  end