doorkeeper 4.2.5 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE.md +19 -0
  3. data/.github/PULL_REQUEST_TEMPLATE.md +17 -0
  4. data/.gitignore +1 -1
  5. data/.hound.yml +2 -13
  6. data/.rubocop.yml +13 -0
  7. data/.travis.yml +13 -4
  8. data/Appraisals +6 -2
  9. data/CODE_OF_CONDUCT.md +46 -0
  10. data/Gemfile +1 -1
  11. data/NEWS.md +28 -0
  12. data/README.md +40 -10
  13. data/RELEASING.md +5 -12
  14. data/SECURITY.md +13 -0
  15. data/app/controllers/doorkeeper/application_controller.rb +1 -5
  16. data/app/controllers/doorkeeper/applications_controller.rb +14 -1
  17. data/app/controllers/doorkeeper/tokens_controller.rb +13 -1
  18. data/app/helpers/doorkeeper/dashboard_helper.rb +4 -2
  19. data/app/validators/redirect_uri_validator.rb +12 -2
  20. data/app/views/doorkeeper/applications/_form.html.erb +2 -2
  21. data/app/views/doorkeeper/authorizations/new.html.erb +1 -1
  22. data/app/views/doorkeeper/authorized_applications/index.html.erb +0 -1
  23. data/config/locales/en.yml +3 -5
  24. data/doorkeeper.gemspec +4 -4
  25. data/gemfiles/rails_4_2.gemfile +6 -4
  26. data/gemfiles/rails_5_0.gemfile +4 -4
  27. data/gemfiles/rails_5_1.gemfile +6 -7
  28. data/gemfiles/rails_5_2.gemfile +12 -0
  29. data/gemfiles/rails_master.gemfile +14 -0
  30. data/lib/doorkeeper/config.rb +55 -55
  31. data/lib/doorkeeper/engine.rb +3 -3
  32. data/lib/doorkeeper/errors.rb +18 -0
  33. data/lib/doorkeeper/grape/helpers.rb +13 -8
  34. data/lib/doorkeeper/helpers/controller.rb +9 -20
  35. data/lib/doorkeeper/models/access_token_mixin.rb +14 -7
  36. data/lib/doorkeeper/models/application_mixin.rb +11 -6
  37. data/lib/doorkeeper/models/concerns/expirable.rb +7 -5
  38. data/lib/doorkeeper/oauth/authorization/token.rb +22 -18
  39. data/lib/doorkeeper/oauth/authorization_code_request.rb +6 -1
  40. data/lib/doorkeeper/oauth/base_request.rb +5 -5
  41. data/lib/doorkeeper/oauth/client/credentials.rb +2 -2
  42. data/lib/doorkeeper/oauth/client.rb +2 -2
  43. data/lib/doorkeeper/oauth/error.rb +2 -2
  44. data/lib/doorkeeper/oauth/error_response.rb +1 -2
  45. data/lib/doorkeeper/oauth/forbidden_token_response.rb +1 -1
  46. data/lib/doorkeeper/oauth/invalid_token_response.rb +2 -3
  47. data/lib/doorkeeper/oauth/password_access_token_request.rb +1 -0
  48. data/lib/doorkeeper/oauth/refresh_token_request.rb +1 -0
  49. data/lib/doorkeeper/oauth/scopes.rb +18 -8
  50. data/lib/doorkeeper/oauth/token.rb +1 -1
  51. data/lib/doorkeeper/oauth/token_introspection.rb +128 -0
  52. data/lib/doorkeeper/orm/active_record/access_grant.rb +1 -1
  53. data/lib/doorkeeper/orm/active_record/access_token.rb +1 -23
  54. data/lib/doorkeeper/orm/active_record/application.rb +1 -1
  55. data/lib/doorkeeper/orm/active_record/base_record.rb +11 -0
  56. data/lib/doorkeeper/orm/active_record.rb +20 -8
  57. data/lib/doorkeeper/rails/helpers.rb +5 -6
  58. data/lib/doorkeeper/rails/routes.rb +9 -7
  59. data/lib/doorkeeper/request.rb +7 -1
  60. data/lib/doorkeeper/validations.rb +3 -2
  61. data/lib/doorkeeper/version.rb +13 -1
  62. data/lib/doorkeeper.rb +1 -0
  63. data/lib/generators/doorkeeper/application_owner_generator.rb +11 -2
  64. data/lib/generators/doorkeeper/migration_generator.rb +13 -1
  65. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +7 -1
  66. data/lib/generators/doorkeeper/templates/{add_owner_to_application_migration.rb → add_owner_to_application_migration.rb.erb} +1 -1
  67. data/lib/generators/doorkeeper/templates/{add_previous_refresh_token_to_access_tokens.rb → add_previous_refresh_token_to_access_tokens.rb.erb} +1 -1
  68. data/lib/generators/doorkeeper/templates/initializer.rb +19 -3
  69. data/lib/generators/doorkeeper/templates/{migration.rb → migration.rb.erb} +1 -1
  70. data/spec/controllers/applications_controller_spec.rb +15 -4
  71. data/spec/controllers/authorizations_controller_spec.rb +31 -16
  72. data/spec/controllers/protected_resources_controller_spec.rb +28 -19
  73. data/spec/controllers/token_info_controller_spec.rb +17 -13
  74. data/spec/controllers/tokens_controller_spec.rb +138 -4
  75. data/spec/dummy/config/initializers/doorkeeper.rb +1 -1
  76. data/spec/dummy/config/initializers/{active_record_belongs_to_required_by_default.rb → new_framework_defaults.rb} +1 -1
  77. data/spec/dummy/config/initializers/secret_token.rb +0 -1
  78. data/spec/factories.rb +1 -1
  79. data/spec/generators/application_owner_generator_spec.rb +24 -5
  80. data/spec/generators/migration_generator_spec.rb +24 -3
  81. data/spec/generators/previous_refresh_token_generator_spec.rb +57 -0
  82. data/spec/grape/grape_integration_spec.rb +135 -0
  83. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +1 -1
  84. data/spec/lib/config_spec.rb +115 -12
  85. data/spec/lib/models/expirable_spec.rb +0 -1
  86. data/spec/lib/models/revocable_spec.rb +2 -2
  87. data/spec/lib/oauth/authorization_code_request_spec.rb +39 -11
  88. data/spec/lib/oauth/base_request_spec.rb +2 -7
  89. data/spec/lib/oauth/client_credentials/creator_spec.rb +1 -1
  90. data/spec/lib/oauth/client_credentials_integration_spec.rb +1 -1
  91. data/spec/lib/oauth/client_credentials_request_spec.rb +1 -0
  92. data/spec/lib/oauth/code_request_spec.rb +1 -3
  93. data/spec/lib/oauth/helpers/uri_checker_spec.rb +5 -0
  94. data/spec/lib/oauth/invalid_token_response_spec.rb +1 -1
  95. data/spec/lib/oauth/password_access_token_request_spec.rb +9 -3
  96. data/spec/lib/oauth/refresh_token_request_spec.rb +19 -7
  97. data/spec/lib/oauth/scopes_spec.rb +28 -1
  98. data/spec/lib/oauth/token_request_spec.rb +6 -8
  99. data/spec/lib/server_spec.rb +10 -0
  100. data/spec/models/doorkeeper/access_grant_spec.rb +1 -1
  101. data/spec/models/doorkeeper/access_token_spec.rb +72 -48
  102. data/spec/models/doorkeeper/application_spec.rb +51 -18
  103. data/spec/requests/applications/applications_request_spec.rb +5 -5
  104. data/spec/requests/endpoints/token_spec.rb +8 -1
  105. data/spec/requests/flows/authorization_code_errors_spec.rb +11 -1
  106. data/spec/requests/flows/authorization_code_spec.rb +1 -0
  107. data/spec/requests/flows/client_credentials_spec.rb +1 -1
  108. data/spec/requests/flows/implicit_grant_errors_spec.rb +2 -2
  109. data/spec/requests/flows/refresh_token_spec.rb +4 -4
  110. data/spec/requests/flows/revoke_token_spec.rb +15 -15
  111. data/spec/requests/protected_resources/metal_spec.rb +1 -1
  112. data/spec/requests/protected_resources/private_api_spec.rb +1 -1
  113. data/spec/routing/custom_controller_routes_spec.rb +4 -0
  114. data/spec/routing/default_routes_spec.rb +5 -1
  115. data/spec/spec_helper_integration.rb +15 -5
  116. data/spec/support/dependencies/factory_girl.rb +2 -2
  117. data/spec/support/helpers/access_token_request_helper.rb +1 -1
  118. data/spec/support/helpers/model_helper.rb +9 -4
  119. data/spec/support/helpers/request_spec_helper.rb +7 -3
  120. data/spec/support/helpers/url_helper.rb +8 -8
  121. data/spec/support/shared/controllers_shared_context.rb +2 -6
  122. data/spec/support/shared/models_shared_examples.rb +4 -4
  123. data/spec/validators/redirect_uri_validator_spec.rb +51 -6
  124. data/spec/version/version_spec.rb +15 -0
  125. metadata +42 -27
@@ -12,7 +12,7 @@ module Doorkeeper
12
12
  end
13
13
 
14
14
  def self.find(uid, method = Application.method(:by_uid))
15
- if application = method.call(uid)
15
+ if (application = method.call(uid))
16
16
  new(application)
17
17
  end
18
18
  end
@@ -20,7 +20,7 @@ module Doorkeeper
20
20
  def self.authenticate(credentials, method = Application.method(:by_uid_and_secret))
21
21
  return false if credentials.blank?
22
22
 
23
- if application = method.call(credentials.uid, credentials.secret)
23
+ if (application = method.call(credentials.uid, credentials.secret))
24
24
  new(application)
25
25
  end
26
26
  end
@@ -1,10 +1,10 @@
1
1
  module Doorkeeper
2
2
  module OAuth
3
- class Error < Struct.new(:name, :state)
3
+ Error = Struct.new(:name, :state) do
4
4
  def description
5
5
  I18n.translate(
6
6
  name,
7
- scope: [:doorkeeper, :errors, :messages],
7
+ scope: %i[doorkeeper errors messages],
8
8
  default: :server_error
9
9
  )
10
10
  end
@@ -4,8 +4,7 @@ module Doorkeeper
4
4
  include OAuth::Helpers
5
5
 
6
6
  def self.from_request(request, attributes = {})
7
- state = request.state if request.respond_to?(:state)
8
- new(attributes.merge(name: request.error, state: state))
7
+ new(attributes.merge(name: request.error, state: request.try(:state)))
9
8
  end
10
9
 
11
10
  delegate :name, :description, :state, to: :@error
@@ -21,7 +21,7 @@ module Doorkeeper
21
21
  end
22
22
 
23
23
  def description
24
- scope = { scope: [:doorkeeper, :scopes] }
24
+ scope = { scope: %i[doorkeeper scopes] }
25
25
  @description ||= @scopes.map { |r| I18n.translate r, scope }.join('\n')
26
26
  end
27
27
  end
@@ -4,10 +4,9 @@ module Doorkeeper
4
4
  attr_reader :reason
5
5
 
6
6
  def self.from_access_token(access_token, attributes = {})
7
- reason = case
8
- when access_token.try(:revoked?)
7
+ reason = if access_token.try(:revoked?)
9
8
  :revoked
10
- when access_token.try(:expired?)
9
+ elsif access_token.try(:expired?)
11
10
  :expired
12
11
  else
13
12
  :unknown
@@ -22,6 +22,7 @@ module Doorkeeper
22
22
 
23
23
  def before_successful_response
24
24
  find_or_create_access_token(client, resource_owner.id, scopes, server)
25
+ super
25
26
  end
26
27
 
27
28
  def validate_scopes
@@ -35,6 +35,7 @@ module Doorkeeper
35
35
  refresh_token.revoke unless refresh_token_revoked_on_use?
36
36
  create_access_token
37
37
  end
38
+ super
38
39
  end
39
40
 
40
41
  def refresh_token_revoked_on_use?
@@ -45,20 +45,30 @@ module Doorkeeper
45
45
  end
46
46
 
47
47
  def +(other)
48
- if other.is_a? Scopes
49
- self.class.from_array(all + other.all)
50
- else
51
- super(other)
52
- end
48
+ self.class.from_array(all + to_array(other))
53
49
  end
54
50
 
55
51
  def <=>(other)
56
- map(&:to_s).sort <=> other.map(&:to_s).sort
52
+ if other.respond_to?(:map)
53
+ map(&:to_s).sort <=> other.map(&:to_s).sort
54
+ else
55
+ super
56
+ end
57
57
  end
58
58
 
59
59
  def &(other)
60
- other_array = other.present? ? other.all : []
61
- self.class.from_array(all & other_array)
60
+ self.class.from_array(all & to_array(other))
61
+ end
62
+
63
+ private
64
+
65
+ def to_array(other)
66
+ case other
67
+ when Scopes
68
+ other.all
69
+ else
70
+ other.to_a
71
+ end
62
72
  end
63
73
  end
64
74
  end
@@ -11,7 +11,7 @@ module Doorkeeper
11
11
  end
12
12
 
13
13
  def authenticate(request, *methods)
14
- if token = from_request(request, *methods)
14
+ if (token = from_request(request, *methods))
15
15
  access_token = AccessToken.by_token(token)
16
16
  access_token.revoke_previous_refresh_token! if access_token
17
17
  access_token
@@ -0,0 +1,128 @@
1
+ module Doorkeeper
2
+ module OAuth
3
+ # RFC7662 OAuth 2.0 Token Introspection
4
+ #
5
+ # @see https://tools.ietf.org/html/rfc7662
6
+ class TokenIntrospection
7
+ attr_reader :server, :token
8
+ attr_reader :error
9
+
10
+ def initialize(server, token)
11
+ @server = server
12
+ @token = token
13
+
14
+ authorize!
15
+ end
16
+
17
+ def authorized?
18
+ @error.blank?
19
+ end
20
+
21
+ def to_json
22
+ active? ? success_response : failure_response
23
+ end
24
+
25
+ private
26
+
27
+ # If the protected resource uses OAuth 2.0 client credentials to
28
+ # authenticate to the introspection endpoint and its credentials are
29
+ # invalid, the authorization server responds with an HTTP 401
30
+ # (Unauthorized) as described in Section 5.2 of OAuth 2.0 [RFC6749].
31
+ #
32
+ # Endpoint must first validate the authentication.
33
+ # If the authentication is invalid, the endpoint should respond with
34
+ # an HTTP 401 status code and an invalid_client response.
35
+ #
36
+ # @see https://www.oauth.com/oauth2-servers/token-introspection-endpoint/
37
+ #
38
+ def authorize!
39
+ # Requested client authorization
40
+ if server.credentials
41
+ @error = :invalid_client unless authorized_client
42
+ else
43
+ # Requested bearer token authorization
44
+ @error = :invalid_request unless authorized_token
45
+ end
46
+ end
47
+
48
+ # Client Authentication
49
+ def authorized_client
50
+ @_authorized_client ||= server.credentials && server.client
51
+ end
52
+
53
+ # Bearer Token Authentication
54
+ def authorized_token
55
+ @_authorized_token ||=
56
+ OAuth::Token.authenticate(server.context.request, :from_bearer_authorization)
57
+ end
58
+
59
+ # 2.2. Introspection Response
60
+ def success_response
61
+ {
62
+ active: true,
63
+ scope: @token.scopes_string,
64
+ client_id: @token.try(:application).try(:uid),
65
+ token_type: @token.token_type,
66
+ exp: @token.expires_at.to_i,
67
+ iat: @token.created_at.to_i
68
+ }
69
+ end
70
+
71
+ # If the introspection call is properly authorized but the token is not
72
+ # active, does not exist on this server, or the protected resource is
73
+ # not allowed to introspect this particular token, then the
74
+ # authorization server MUST return an introspection response with the
75
+ # "active" field set to "false". Note that to avoid disclosing too
76
+ # much of the authorization server's state to a third party, the
77
+ # authorization server SHOULD NOT include any additional information
78
+ # about an inactive token, including why the token is inactive.
79
+ #
80
+ # @see https://tools.ietf.org/html/rfc7662 2.2. Introspection Response
81
+ #
82
+ def failure_response
83
+ {
84
+ active: false
85
+ }
86
+ end
87
+
88
+ # Boolean indicator of whether or not the presented token
89
+ # is currently active. The specifics of a token's "active" state
90
+ # will vary depending on the implementation of the authorization
91
+ # server and the information it keeps about its tokens, but a "true"
92
+ # value return for the "active" property will generally indicate
93
+ # that a given token has been issued by this authorization server,
94
+ # has not been revoked by the resource owner, and is within its
95
+ # given time window of validity (e.g., after its issuance time and
96
+ # before its expiration time).
97
+ #
98
+ # Any other error is considered an "inactive" token.
99
+ #
100
+ # * The token requested does not exist or is invalid
101
+ # * The token expired
102
+ # * The token was issued to a different client than is making this request
103
+ #
104
+ def active?
105
+ if authorized_client
106
+ valid_token? && authorized_for_client?
107
+ else
108
+ valid_token?
109
+ end
110
+ end
111
+
112
+ # Token can be valid only if it is not expired or revoked.
113
+ def valid_token?
114
+ @token.present? && @token.accessible?
115
+ end
116
+
117
+ # If token doesn't belong to some client, then it is public.
118
+ # Otherwise in it required for token to be connected to the same client.
119
+ def authorized_for_client?
120
+ if @token.application.present?
121
+ @token.application == authorized_client.application
122
+ else
123
+ true
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
@@ -1,5 +1,5 @@
1
1
  module Doorkeeper
2
- class AccessGrant < ActiveRecord::Base
2
+ class AccessGrant < BaseRecord
3
3
  self.table_name = "#{table_name_prefix}oauth_access_grants#{table_name_suffix}".to_sym
4
4
 
5
5
  include AccessGrantMixin
@@ -1,21 +1,9 @@
1
1
  module Doorkeeper
2
- class AccessToken < ActiveRecord::Base
2
+ class AccessToken < BaseRecord
3
3
  self.table_name = "#{table_name_prefix}oauth_access_tokens#{table_name_suffix}".to_sym
4
4
 
5
5
  include AccessTokenMixin
6
6
 
7
- # Deletes all the Access Tokens created for the specific
8
- # Application and Resource Owner.
9
- #
10
- # @param application_id [Integer] Application ID
11
- # @param resource_owner [ActiveRecord::Base] Resource Owner model instance
12
- #
13
- def self.delete_all_for(application_id, resource_owner)
14
- where(application_id: application_id,
15
- resource_owner_id: resource_owner.id).delete_all
16
- end
17
- private_class_method :delete_all_for
18
-
19
7
  # Searches for not revoked Access Tokens associated with the
20
8
  # specific Resource Owner.
21
9
  #
@@ -29,18 +17,8 @@ module Doorkeeper
29
17
  where(resource_owner_id: resource_owner.id, revoked_at: nil)
30
18
  end
31
19
 
32
- # ORM-specific order method.
33
- def self.order_method
34
- :order
35
- end
36
-
37
20
  def self.refresh_token_revoked_on_use?
38
21
  column_names.include?('previous_refresh_token')
39
22
  end
40
-
41
- # ORM-specific DESC order for `:created_at` column.
42
- def self.created_at_desc
43
- 'created_at desc'
44
- end
45
23
  end
46
24
  end
@@ -1,5 +1,5 @@
1
1
  module Doorkeeper
2
- class Application < ActiveRecord::Base
2
+ class Application < BaseRecord
3
3
  self.table_name = "#{table_name_prefix}oauth_applications#{table_name_suffix}".to_sym
4
4
 
5
5
  include ApplicationMixin
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ class BaseRecord < ActiveRecord::Base
5
+ self.abstract_class = true
6
+
7
+ def self.ordered_by(attribute, direction = :asc)
8
+ order(attribute => direction)
9
+ end
10
+ end
11
+ end
@@ -1,22 +1,34 @@
1
+ require 'active_support/lazy_load_hooks'
2
+
1
3
  module Doorkeeper
2
4
  module Orm
3
5
  module ActiveRecord
4
6
  def self.initialize_models!
5
- require 'doorkeeper/orm/active_record/access_grant'
6
- require 'doorkeeper/orm/active_record/access_token'
7
- require 'doorkeeper/orm/active_record/application'
7
+ lazy_load do
8
+ require 'doorkeeper/orm/active_record/base_record'
9
+ require 'doorkeeper/orm/active_record/access_grant'
10
+ require 'doorkeeper/orm/active_record/access_token'
11
+ require 'doorkeeper/orm/active_record/application'
8
12
 
9
- if Doorkeeper.configuration.active_record_options[:establish_connection]
10
- [Doorkeeper::AccessGrant, Doorkeeper::AccessToken, Doorkeeper::Application].each do |c|
11
- c.send :establish_connection, Doorkeeper.configuration.active_record_options[:establish_connection]
13
+ if Doorkeeper.configuration.active_record_options[:establish_connection]
14
+ [Doorkeeper::AccessGrant, Doorkeeper::AccessToken, Doorkeeper::Application].each do |model|
15
+ options = Doorkeeper.configuration.active_record_options[:establish_connection]
16
+ model.establish_connection(options)
17
+ end
12
18
  end
13
19
  end
14
20
  end
15
21
 
16
22
  def self.initialize_application_owner!
17
- require 'doorkeeper/models/concerns/ownership'
23
+ lazy_load do
24
+ require 'doorkeeper/models/concerns/ownership'
25
+
26
+ Doorkeeper::Application.send :include, Doorkeeper::Models::Ownership
27
+ end
28
+ end
18
29
 
19
- Doorkeeper::Application.send :include, Doorkeeper::Models::Ownership
30
+ def self.lazy_load(&block)
31
+ ActiveSupport.on_load(:active_record, {}, &block)
20
32
  end
21
33
  end
22
34
  end
@@ -9,11 +9,9 @@ module Doorkeeper
9
9
  end
10
10
  end
11
11
 
12
- def doorkeeper_unauthorized_render_options(error: nil)
13
- end
12
+ def doorkeeper_unauthorized_render_options(**); end
14
13
 
15
- def doorkeeper_forbidden_render_options(error: nil)
16
- end
14
+ def doorkeeper_forbidden_render_options(**); end
17
15
 
18
16
  def valid_doorkeeper_token?
19
17
  doorkeeper_token && doorkeeper_token.acceptable?(@_doorkeeper_scopes)
@@ -23,14 +21,15 @@ module Doorkeeper
23
21
 
24
22
  def doorkeeper_render_error
25
23
  error = doorkeeper_error
26
- headers.merge! error.headers.reject { |k| "Content-Type" == k }
24
+ headers.merge!(error.headers.reject { |k| k == "Content-Type" })
27
25
  doorkeeper_render_error_with(error)
28
26
  end
29
27
 
30
28
  def doorkeeper_render_error_with(error)
31
29
  options = doorkeeper_render_options(error) || {}
32
30
  status = doorkeeper_status_for_error(
33
- error, options.delete(:respond_not_found_when_forbidden))
31
+ error, options.delete(:respond_not_found_when_forbidden)
32
+ )
34
33
  if options.blank?
35
34
  head status
36
35
  else
@@ -5,7 +5,6 @@ module Doorkeeper
5
5
  module Rails
6
6
  class Routes # :nodoc:
7
7
  module Helper
8
- # TODO: options hash is not being used
9
8
  def use_doorkeeper(options = {}, &block)
10
9
  Doorkeeper::Rails::Routes.new(self, &block).generate_routes!(options)
11
10
  end
@@ -27,6 +26,7 @@ module Doorkeeper
27
26
  map_route(:authorizations, :authorization_routes)
28
27
  map_route(:tokens, :token_routes)
29
28
  map_route(:tokens, :revoke_routes)
29
+ map_route(:tokens, :introspect_routes)
30
30
  map_route(:applications, :application_routes)
31
31
  map_route(:authorized_applications, :authorized_applications_routes)
32
32
  map_route(:token_info, :token_info_routes)
@@ -36,20 +36,18 @@ module Doorkeeper
36
36
  private
37
37
 
38
38
  def map_route(name, method)
39
- unless @mapping.skipped?(name)
40
- send method, @mapping[name]
41
- end
39
+ send(method, @mapping[name]) unless @mapping.skipped?(name)
42
40
  end
43
41
 
44
42
  def authorization_routes(mapping)
45
43
  routes.resource(
46
44
  :authorization,
47
45
  path: 'authorize',
48
- only: [:create, :destroy],
46
+ only: %i[create destroy],
49
47
  as: mapping[:as],
50
48
  controller: mapping[:controllers]
51
49
  ) do
52
- routes.get '/:code', action: :show, on: :member
50
+ routes.get '/native', action: :show, on: :member
53
51
  routes.get '/', action: :new, on: :member
54
52
  end
55
53
  end
@@ -67,6 +65,10 @@ module Doorkeeper
67
65
  routes.post 'revoke', controller: mapping[:controllers], action: :revoke
68
66
  end
69
67
 
68
+ def introspect_routes(mapping)
69
+ routes.post 'introspect', controller: mapping[:controllers], action: :introspect
70
+ end
71
+
70
72
  def token_info_routes(mapping)
71
73
  routes.resource(
72
74
  :token_info,
@@ -81,7 +83,7 @@ module Doorkeeper
81
83
  end
82
84
 
83
85
  def authorized_applications_routes(mapping)
84
- routes.resources :authorized_applications, only: [:index, :destroy], controller: mapping[:controllers]
86
+ routes.resources :authorized_applications, only: %i[index destroy], controller: mapping[:controllers]
85
87
  end
86
88
  end
87
89
  end
@@ -24,7 +24,7 @@ module Doorkeeper
24
24
  def get_strategy(grant_or_request_type, available)
25
25
  fail Errors::MissingRequestStrategy unless grant_or_request_type.present?
26
26
  fail NameError unless available.include?(grant_or_request_type.to_s)
27
- "Doorkeeper::Request::#{grant_or_request_type.to_s.camelize}".constantize
27
+ strategy_class(grant_or_request_type)
28
28
  end
29
29
 
30
30
  def authorization_response_types
@@ -36,5 +36,11 @@ module Doorkeeper
36
36
  Doorkeeper.configuration.token_grant_types
37
37
  end
38
38
  private_class_method :token_grant_types
39
+
40
+ def strategy_class(grant_or_request_type)
41
+ strategy_class_name = grant_or_request_type.to_s.tr(' ', '_').camelize
42
+ "Doorkeeper::Request::#{strategy_class_name}".constantize
43
+ end
44
+ private_class_method :strategy_class
39
45
  end
40
46
  end
@@ -6,9 +6,10 @@ module Doorkeeper
6
6
 
7
7
  def validate
8
8
  @error = nil
9
+
9
10
  self.class.validations.each do |validation|
11
+ @error = validation[:options][:error] unless send("validate_#{validation[:attribute]}")
10
12
  break if @error
11
- @error = validation.last unless send("validate_#{validation.first}")
12
13
  end
13
14
  end
14
15
 
@@ -19,7 +20,7 @@ module Doorkeeper
19
20
 
20
21
  module ClassMethods
21
22
  def validate(attribute, options = {})
22
- validations << [attribute, options[:error]]
23
+ validations << { attribute: attribute, options: options }
23
24
  end
24
25
 
25
26
  def validations
@@ -1,3 +1,15 @@
1
1
  module Doorkeeper
2
- VERSION = "4.2.5".freeze
2
+ def self.gem_version
3
+ Gem::Version.new VERSION::STRING
4
+ end
5
+
6
+ module VERSION
7
+ # Semantic versioning
8
+ MAJOR = 4
9
+ MINOR = 3
10
+ TINY = 0
11
+
12
+ # Full version number
13
+ STRING = [MAJOR, MINOR, TINY].compact.join('.')
14
+ end
3
15
  end
data/lib/doorkeeper.rb CHANGED
@@ -30,6 +30,7 @@ require 'doorkeeper/oauth/code_request'
30
30
  require 'doorkeeper/oauth/token_request'
31
31
  require 'doorkeeper/oauth/client'
32
32
  require 'doorkeeper/oauth/token'
33
+ require 'doorkeeper/oauth/token_introspection'
33
34
  require 'doorkeeper/oauth/invalid_token_response'
34
35
  require 'doorkeeper/oauth/forbidden_token_response'
35
36
 
@@ -7,12 +7,21 @@ class Doorkeeper::ApplicationOwnerGenerator < Rails::Generators::Base
7
7
 
8
8
  def application_owner
9
9
  migration_template(
10
- 'add_owner_to_application_migration.rb',
11
- 'db/migrate/add_owner_to_application.rb'
10
+ 'add_owner_to_application_migration.rb.erb',
11
+ 'db/migrate/add_owner_to_application.rb',
12
+ migration_version: migration_version
12
13
  )
13
14
  end
14
15
 
15
16
  def self.next_migration_number(dirname)
16
17
  ActiveRecord::Generators::Base.next_migration_number(dirname)
17
18
  end
19
+
20
+ private
21
+
22
+ def migration_version
23
+ if ActiveRecord::VERSION::MAJOR >= 5
24
+ "[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
25
+ end
26
+ end
18
27
  end
@@ -6,10 +6,22 @@ class Doorkeeper::MigrationGenerator < ::Rails::Generators::Base
6
6
  desc 'Installs Doorkeeper migration file.'
7
7
 
8
8
  def install
9
- migration_template 'migration.rb', 'db/migrate/create_doorkeeper_tables.rb'
9
+ migration_template(
10
+ 'migration.rb.erb',
11
+ 'db/migrate/create_doorkeeper_tables.rb',
12
+ migration_version: migration_version
13
+ )
10
14
  end
11
15
 
12
16
  def self.next_migration_number(dirname)
13
17
  ActiveRecord::Generators::Base.next_migration_number(dirname)
14
18
  end
19
+
20
+ private
21
+
22
+ def migration_version
23
+ if ActiveRecord::VERSION::MAJOR >= 5
24
+ "[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
25
+ end
26
+ end
15
27
  end
@@ -12,7 +12,7 @@ class Doorkeeper::PreviousRefreshTokenGenerator < Rails::Generators::Base
12
12
  def previous_refresh_token
13
13
  if no_previous_refresh_token_column?
14
14
  migration_template(
15
- 'add_previous_refresh_token_to_access_tokens.rb',
15
+ 'add_previous_refresh_token_to_access_tokens.rb.erb',
16
16
  'db/migrate/add_previous_refresh_token_to_access_tokens.rb'
17
17
  )
18
18
  end
@@ -20,6 +20,12 @@ class Doorkeeper::PreviousRefreshTokenGenerator < Rails::Generators::Base
20
20
 
21
21
  private
22
22
 
23
+ def migration_version
24
+ if ActiveRecord::VERSION::MAJOR >= 5
25
+ "[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
26
+ end
27
+ end
28
+
23
29
  def no_previous_refresh_token_column?
24
30
  !ActiveRecord::Base.connection.column_exists?(
25
31
  :oauth_access_tokens,
@@ -1,4 +1,4 @@
1
- class AddOwnerToApplication < ActiveRecord::Migration
1
+ class AddOwnerToApplication < ActiveRecord::Migration<%= migration_version %>
2
2
  def change
3
3
  add_column :oauth_applications, :owner_id, :integer, null: true
4
4
  add_column :oauth_applications, :owner_type, :string, null: true
@@ -1,4 +1,4 @@
1
- class AddPreviousRefreshTokenToAccessTokens < ActiveRecord::Migration
1
+ class AddPreviousRefreshTokenToAccessTokens < ActiveRecord::Migration<%= migration_version %>
2
2
  def change
3
3
  add_column(
4
4
  :oauth_access_tokens,