doorkeeper 5.4.0.rc1 → 5.5.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 (219) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +108 -9
  3. data/README.md +4 -4
  4. data/app/controllers/doorkeeper/applications_controller.rb +3 -3
  5. data/app/controllers/doorkeeper/authorizations_controller.rb +16 -5
  6. data/app/controllers/doorkeeper/authorized_applications_controller.rb +1 -1
  7. data/app/controllers/doorkeeper/token_info_controller.rb +12 -2
  8. data/app/controllers/doorkeeper/tokens_controller.rb +34 -26
  9. data/app/views/doorkeeper/applications/_form.html.erb +1 -1
  10. data/app/views/doorkeeper/applications/show.html.erb +16 -12
  11. data/app/views/doorkeeper/authorizations/form_post.html.erb +11 -0
  12. data/config/locales/en.yml +3 -1
  13. data/lib/doorkeeper.rb +6 -1
  14. data/lib/doorkeeper/config.rb +109 -78
  15. data/lib/doorkeeper/config/abstract_builder.rb +1 -1
  16. data/lib/doorkeeper/config/option.rb +1 -3
  17. data/lib/doorkeeper/config/validations.rb +53 -0
  18. data/lib/doorkeeper/engine.rb +1 -1
  19. data/lib/doorkeeper/grant_flow.rb +45 -0
  20. data/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
  21. data/lib/doorkeeper/grant_flow/flow.rb +44 -0
  22. data/lib/doorkeeper/grant_flow/registry.rb +50 -0
  23. data/lib/doorkeeper/helpers/controller.rb +8 -4
  24. data/lib/doorkeeper/models/access_grant_mixin.rb +12 -7
  25. data/lib/doorkeeper/models/access_token_mixin.rb +12 -8
  26. data/lib/doorkeeper/models/application_mixin.rb +5 -4
  27. data/lib/doorkeeper/models/concerns/revocable.rb +1 -1
  28. data/lib/doorkeeper/oauth/authorization/code.rb +5 -1
  29. data/lib/doorkeeper/oauth/authorization/context.rb +5 -5
  30. data/lib/doorkeeper/oauth/authorization/token.rb +11 -5
  31. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +1 -1
  32. data/lib/doorkeeper/oauth/authorization_code_request.rb +10 -17
  33. data/lib/doorkeeper/oauth/base_request.rb +1 -1
  34. data/lib/doorkeeper/oauth/client_credentials/creator.rb +3 -2
  35. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +1 -0
  36. data/lib/doorkeeper/oauth/client_credentials/validator.rb +3 -1
  37. data/lib/doorkeeper/oauth/code_request.rb +2 -2
  38. data/lib/doorkeeper/oauth/code_response.rb +17 -11
  39. data/lib/doorkeeper/oauth/error_response.rb +4 -3
  40. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +1 -3
  41. data/lib/doorkeeper/oauth/password_access_token_request.rb +21 -2
  42. data/lib/doorkeeper/oauth/pre_authorization.rb +37 -11
  43. data/lib/doorkeeper/oauth/refresh_token_request.rb +13 -0
  44. data/lib/doorkeeper/oauth/token.rb +4 -5
  45. data/lib/doorkeeper/oauth/token_introspection.rb +1 -5
  46. data/lib/doorkeeper/oauth/token_request.rb +1 -1
  47. data/lib/doorkeeper/orm/active_record.rb +5 -6
  48. data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +12 -2
  49. data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +10 -2
  50. data/lib/doorkeeper/orm/active_record/mixins/application.rb +76 -10
  51. data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +5 -0
  52. data/lib/doorkeeper/rails/routes.rb +1 -3
  53. data/lib/doorkeeper/rake/db.rake +3 -3
  54. data/lib/doorkeeper/rake/setup.rake +5 -0
  55. data/lib/doorkeeper/request.rb +49 -12
  56. data/lib/doorkeeper/request/refresh_token.rb +2 -1
  57. data/lib/doorkeeper/server.rb +1 -1
  58. data/lib/doorkeeper/stale_records_cleaner.rb +4 -4
  59. data/lib/doorkeeper/version.rb +2 -6
  60. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +1 -1
  61. data/lib/generators/doorkeeper/templates/initializer.rb +9 -7
  62. data/lib/generators/doorkeeper/templates/migration.rb.erb +12 -5
  63. metadata +25 -306
  64. data/Appraisals +0 -26
  65. data/CODE_OF_CONDUCT.md +0 -46
  66. data/CONTRIBUTING.md +0 -49
  67. data/Dangerfile +0 -67
  68. data/Dockerfile +0 -29
  69. data/Gemfile +0 -25
  70. data/NEWS.md +0 -1
  71. data/RELEASING.md +0 -11
  72. data/Rakefile +0 -28
  73. data/SECURITY.md +0 -15
  74. data/UPGRADE.md +0 -2
  75. data/bin/console +0 -30
  76. data/doorkeeper.gemspec +0 -42
  77. data/gemfiles/rails_5_0.gemfile +0 -19
  78. data/gemfiles/rails_5_1.gemfile +0 -19
  79. data/gemfiles/rails_5_2.gemfile +0 -19
  80. data/gemfiles/rails_6_0.gemfile +0 -19
  81. data/gemfiles/rails_master.gemfile +0 -19
  82. data/spec/controllers/application_metal_controller_spec.rb +0 -64
  83. data/spec/controllers/applications_controller_spec.rb +0 -274
  84. data/spec/controllers/authorizations_controller_spec.rb +0 -743
  85. data/spec/controllers/protected_resources_controller_spec.rb +0 -361
  86. data/spec/controllers/token_info_controller_spec.rb +0 -50
  87. data/spec/controllers/tokens_controller_spec.rb +0 -499
  88. data/spec/dummy/Rakefile +0 -9
  89. data/spec/dummy/app/assets/config/manifest.js +0 -2
  90. data/spec/dummy/app/controllers/application_controller.rb +0 -5
  91. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +0 -9
  92. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +0 -14
  93. data/spec/dummy/app/controllers/home_controller.rb +0 -18
  94. data/spec/dummy/app/controllers/metal_controller.rb +0 -13
  95. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +0 -13
  96. data/spec/dummy/app/helpers/application_helper.rb +0 -7
  97. data/spec/dummy/app/models/user.rb +0 -11
  98. data/spec/dummy/app/views/home/index.html.erb +0 -0
  99. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  100. data/spec/dummy/config.ru +0 -6
  101. data/spec/dummy/config/application.rb +0 -51
  102. data/spec/dummy/config/boot.rb +0 -7
  103. data/spec/dummy/config/database.yml +0 -15
  104. data/spec/dummy/config/environment.rb +0 -5
  105. data/spec/dummy/config/environments/development.rb +0 -31
  106. data/spec/dummy/config/environments/production.rb +0 -64
  107. data/spec/dummy/config/environments/test.rb +0 -45
  108. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -9
  109. data/spec/dummy/config/initializers/doorkeeper.rb +0 -166
  110. data/spec/dummy/config/initializers/secret_token.rb +0 -10
  111. data/spec/dummy/config/initializers/session_store.rb +0 -10
  112. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -16
  113. data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
  114. data/spec/dummy/config/routes.rb +0 -13
  115. data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -11
  116. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -7
  117. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +0 -69
  118. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +0 -9
  119. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +0 -13
  120. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +0 -8
  121. data/spec/dummy/db/migrate/20180210183654_add_confidential_to_applications.rb +0 -13
  122. data/spec/dummy/db/schema.rb +0 -70
  123. data/spec/dummy/public/404.html +0 -26
  124. data/spec/dummy/public/422.html +0 -26
  125. data/spec/dummy/public/500.html +0 -26
  126. data/spec/dummy/public/favicon.ico +0 -0
  127. data/spec/dummy/script/rails +0 -9
  128. data/spec/factories.rb +0 -30
  129. data/spec/generators/application_owner_generator_spec.rb +0 -28
  130. data/spec/generators/confidential_applications_generator_spec.rb +0 -29
  131. data/spec/generators/enable_polymorphic_resource_owner_generator_spec.rb +0 -47
  132. data/spec/generators/install_generator_spec.rb +0 -36
  133. data/spec/generators/migration_generator_spec.rb +0 -28
  134. data/spec/generators/pkce_generator_spec.rb +0 -28
  135. data/spec/generators/previous_refresh_token_generator_spec.rb +0 -44
  136. data/spec/generators/templates/routes.rb +0 -4
  137. data/spec/generators/views_generator_spec.rb +0 -29
  138. data/spec/grape/grape_integration_spec.rb +0 -137
  139. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -26
  140. data/spec/lib/config_spec.rb +0 -813
  141. data/spec/lib/doorkeeper_spec.rb +0 -27
  142. data/spec/lib/models/expirable_spec.rb +0 -61
  143. data/spec/lib/models/reusable_spec.rb +0 -40
  144. data/spec/lib/models/revocable_spec.rb +0 -58
  145. data/spec/lib/models/scopes_spec.rb +0 -61
  146. data/spec/lib/models/secret_storable_spec.rb +0 -135
  147. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -39
  148. data/spec/lib/oauth/authorization_code_request_spec.rb +0 -180
  149. data/spec/lib/oauth/base_request_spec.rb +0 -210
  150. data/spec/lib/oauth/base_response_spec.rb +0 -45
  151. data/spec/lib/oauth/client/credentials_spec.rb +0 -90
  152. data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -135
  153. data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -110
  154. data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -57
  155. data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -27
  156. data/spec/lib/oauth/client_credentials_request_spec.rb +0 -108
  157. data/spec/lib/oauth/client_spec.rb +0 -38
  158. data/spec/lib/oauth/code_request_spec.rb +0 -46
  159. data/spec/lib/oauth/code_response_spec.rb +0 -36
  160. data/spec/lib/oauth/error_response_spec.rb +0 -64
  161. data/spec/lib/oauth/error_spec.rb +0 -21
  162. data/spec/lib/oauth/forbidden_token_response_spec.rb +0 -20
  163. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -110
  164. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -21
  165. data/spec/lib/oauth/helpers/uri_checker_spec.rb +0 -262
  166. data/spec/lib/oauth/invalid_request_response_spec.rb +0 -73
  167. data/spec/lib/oauth/invalid_token_response_spec.rb +0 -53
  168. data/spec/lib/oauth/password_access_token_request_spec.rb +0 -201
  169. data/spec/lib/oauth/pre_authorization_spec.rb +0 -218
  170. data/spec/lib/oauth/refresh_token_request_spec.rb +0 -166
  171. data/spec/lib/oauth/scopes_spec.rb +0 -146
  172. data/spec/lib/oauth/token_request_spec.rb +0 -164
  173. data/spec/lib/oauth/token_response_spec.rb +0 -84
  174. data/spec/lib/oauth/token_spec.rb +0 -156
  175. data/spec/lib/option_spec.rb +0 -51
  176. data/spec/lib/request/strategy_spec.rb +0 -54
  177. data/spec/lib/secret_storing/base_spec.rb +0 -60
  178. data/spec/lib/secret_storing/bcrypt_spec.rb +0 -49
  179. data/spec/lib/secret_storing/plain_spec.rb +0 -44
  180. data/spec/lib/secret_storing/sha256_hash_spec.rb +0 -48
  181. data/spec/lib/server_spec.rb +0 -49
  182. data/spec/lib/stale_records_cleaner_spec.rb +0 -102
  183. data/spec/models/doorkeeper/access_grant_spec.rb +0 -175
  184. data/spec/models/doorkeeper/access_token_spec.rb +0 -650
  185. data/spec/models/doorkeeper/application_spec.rb +0 -442
  186. data/spec/requests/applications/applications_request_spec.rb +0 -259
  187. data/spec/requests/applications/authorized_applications_spec.rb +0 -32
  188. data/spec/requests/endpoints/authorization_spec.rb +0 -91
  189. data/spec/requests/endpoints/token_spec.rb +0 -79
  190. data/spec/requests/flows/authorization_code_errors_spec.rb +0 -82
  191. data/spec/requests/flows/authorization_code_spec.rb +0 -530
  192. data/spec/requests/flows/client_credentials_spec.rb +0 -207
  193. data/spec/requests/flows/implicit_grant_errors_spec.rb +0 -46
  194. data/spec/requests/flows/implicit_grant_spec.rb +0 -91
  195. data/spec/requests/flows/password_spec.rb +0 -316
  196. data/spec/requests/flows/refresh_token_spec.rb +0 -241
  197. data/spec/requests/flows/revoke_token_spec.rb +0 -196
  198. data/spec/requests/flows/skip_authorization_spec.rb +0 -66
  199. data/spec/requests/protected_resources/metal_spec.rb +0 -16
  200. data/spec/requests/protected_resources/private_api_spec.rb +0 -83
  201. data/spec/routing/custom_controller_routes_spec.rb +0 -133
  202. data/spec/routing/default_routes_spec.rb +0 -41
  203. data/spec/routing/scoped_routes_spec.rb +0 -47
  204. data/spec/spec_helper.rb +0 -54
  205. data/spec/spec_helper_integration.rb +0 -4
  206. data/spec/support/dependencies/factory_bot.rb +0 -4
  207. data/spec/support/doorkeeper_rspec.rb +0 -22
  208. data/spec/support/helpers/access_token_request_helper.rb +0 -14
  209. data/spec/support/helpers/authorization_request_helper.rb +0 -43
  210. data/spec/support/helpers/config_helper.rb +0 -11
  211. data/spec/support/helpers/model_helper.rb +0 -78
  212. data/spec/support/helpers/request_spec_helper.rb +0 -110
  213. data/spec/support/helpers/url_helper.rb +0 -62
  214. data/spec/support/orm/active_record.rb +0 -5
  215. data/spec/support/shared/controllers_shared_context.rb +0 -133
  216. data/spec/support/shared/hashing_shared_context.rb +0 -36
  217. data/spec/support/shared/models_shared_examples.rb +0 -56
  218. data/spec/validators/redirect_uri_validator_spec.rb +0 -183
  219. data/spec/version/version_spec.rb +0 -17
@@ -21,23 +21,29 @@ module Doorkeeper
21
21
  auth.token
22
22
  end
23
23
 
24
- def redirect_uri
25
- if URIChecker.oob_uri?(pre_auth.redirect_uri)
26
- auth.oob_redirect
27
- elsif response_on_fragment
28
- Authorization::URIBuilder.uri_with_fragment(
29
- pre_auth.redirect_uri,
24
+ def body
25
+ if auth.try(:access_token?)
26
+ {
30
27
  access_token: auth.token.plaintext_token,
31
28
  token_type: auth.token.token_type,
32
29
  expires_in: auth.token.expires_in_seconds,
33
30
  state: pre_auth.state,
34
- )
35
- else
36
- Authorization::URIBuilder.uri_with_query(
37
- pre_auth.redirect_uri,
31
+ }
32
+ elsif auth.try(:access_grant?)
33
+ {
38
34
  code: auth.token.plaintext_token,
39
35
  state: pre_auth.state,
40
- )
36
+ }
37
+ end
38
+ end
39
+
40
+ def redirect_uri
41
+ if URIChecker.oob_uri?(pre_auth.redirect_uri)
42
+ auth.oob_redirect
43
+ elsif response_on_fragment
44
+ Authorization::URIBuilder.uri_with_fragment(pre_auth.redirect_uri, body)
45
+ else
46
+ Authorization::URIBuilder.uri_with_query(pre_auth.redirect_uri, body)
41
47
  end
42
48
  end
43
49
  end
@@ -5,6 +5,8 @@ module Doorkeeper
5
5
  class ErrorResponse < BaseResponse
6
6
  include OAuth::Helpers
7
7
 
8
+ NON_REDIRECTABLE_STATES = %i[invalid_redirect_uri invalid_client unauthorized_client].freeze
9
+
8
10
  def self.from_request(request, attributes = {})
9
11
  new(
10
12
  attributes.merge(
@@ -32,7 +34,7 @@ module Doorkeeper
32
34
  end
33
35
 
34
36
  def status
35
- if name == :invalid_client
37
+ if name == :invalid_client || name == :unauthorized_client
36
38
  :unauthorized
37
39
  else
38
40
  :bad_request
@@ -40,8 +42,7 @@ module Doorkeeper
40
42
  end
41
43
 
42
44
  def redirectable?
43
- name != :invalid_redirect_uri && name != :invalid_client &&
44
- !URIChecker.oob_uri?(@redirect_uri)
45
+ !NON_REDIRECTABLE_STATES.include?(name) && !URIChecker.oob_uri?(@redirect_uri)
45
46
  end
46
47
 
47
48
  def redirect_uri
@@ -12,9 +12,7 @@ module Doorkeeper
12
12
  @scope_str = scope_str
13
13
  @valid_scopes = valid_scopes(server_scopes, app_scopes)
14
14
 
15
- if grant_type
16
- @scopes_by_grant_type = Doorkeeper.config.scopes_by_grant_type[grant_type.to_sym]
17
- end
15
+ @scopes_by_grant_type = Doorkeeper.config.scopes_by_grant_type[grant_type.to_sym] if grant_type
18
16
  end
19
17
 
20
18
  def valid?
@@ -43,12 +43,31 @@ module Doorkeeper
43
43
  resource_owner.present?
44
44
  end
45
45
 
46
+ # Section 4.3.2. Access Token Request for Resource Owner Password Credentials Grant:
47
+ #
48
+ # If the client type is confidential or the client was issued client credentials (or assigned
49
+ # other authentication requirements), the client MUST authenticate with the authorization
50
+ # server as described in Section 3.2.1.
51
+ #
52
+ # The authorization server MUST:
53
+ #
54
+ # o require client authentication for confidential clients or for any client that was
55
+ # issued client credentials (or with other authentication requirements)
56
+ #
57
+ # o authenticate the client if client authentication is included,
58
+ #
59
+ # @see https://tools.ietf.org/html/rfc6749#section-4.3
60
+ #
46
61
  def validate_client
47
- !parameters[:client_id] || client.present?
62
+ if Doorkeeper.config.skip_client_authentication_for_password_grant
63
+ !parameters[:client_id] || client.present?
64
+ else
65
+ client.present?
66
+ end
48
67
  end
49
68
 
50
69
  def validate_client_supports_grant_flow
51
- server_config.allow_grant_flow_for_client?(grant_type, client)
70
+ server_config.allow_grant_flow_for_client?(grant_type, client&.application)
52
71
  end
53
72
  end
54
73
  end
@@ -7,21 +7,24 @@ module Doorkeeper
7
7
 
8
8
  validate :client_id, error: :invalid_request
9
9
  validate :client, error: :invalid_client
10
+ validate :client_supports_grant_flow, error: :unauthorized_client
10
11
  validate :resource_owner_authorize_for_client, error: :invalid_client
11
12
  validate :redirect_uri, error: :invalid_redirect_uri
12
13
  validate :params, error: :invalid_request
13
14
  validate :response_type, error: :unsupported_response_type
15
+ validate :response_mode, error: :unsupported_response_mode
14
16
  validate :scopes, error: :invalid_scope
15
17
  validate :code_challenge_method, error: :invalid_code_challenge_method
16
- validate :client_supports_grant_flow, error: :unauthorized_client
17
18
 
18
- attr_reader :server, :client_id, :client, :redirect_uri, :response_type, :state,
19
- :code_challenge, :code_challenge_method, :missing_param, :resource_owner
19
+ attr_reader :client, :code_challenge, :code_challenge_method, :missing_param,
20
+ :redirect_uri, :resource_owner, :response_type, :state,
21
+ :authorization_response_flow, :response_mode
20
22
 
21
23
  def initialize(server, parameters = {}, resource_owner = nil)
22
24
  @server = server
23
25
  @client_id = parameters[:client_id]
24
26
  @response_type = parameters[:response_type]
27
+ @response_mode = parameters[:response_mode]
25
28
  @redirect_uri = parameters[:redirect_uri]
26
29
  @scope = parameters[:scope]
27
30
  @state = parameters[:state]
@@ -57,8 +60,14 @@ module Doorkeeper
57
60
  pre_auth_hash
58
61
  end
59
62
 
63
+ def form_post_response?
64
+ response_mode == "form_post"
65
+ end
66
+
60
67
  private
61
68
 
69
+ attr_reader :client_id, :server
70
+
62
71
  def build_scopes
63
72
  client_scopes = client.scopes
64
73
  if client_scopes.blank?
@@ -70,7 +79,6 @@ module Doorkeeper
70
79
 
71
80
  def validate_client_id
72
81
  @missing_param = :client_id if client_id.blank?
73
-
74
82
  @missing_param.nil?
75
83
  end
76
84
 
@@ -83,6 +91,11 @@ module Doorkeeper
83
91
  Doorkeeper.config.allow_grant_flow_for_client?(grant_type, client.application)
84
92
  end
85
93
 
94
+ def validate_resource_owner_authorize_for_client
95
+ # The `authorize_resource_owner_for_client` config option is used for this validation
96
+ client.application.authorized_for_resource_owner?(@resource_owner)
97
+ end
98
+
86
99
  def validate_redirect_uri
87
100
  return false if redirect_uri.blank?
88
101
 
@@ -103,7 +116,21 @@ module Doorkeeper
103
116
  end
104
117
 
105
118
  def validate_response_type
106
- server.authorization_response_types.include?(response_type)
119
+ server.authorization_response_flows.any? do |flow|
120
+ if flow.matches_response_type?(response_type)
121
+ @authorization_response_flow = flow
122
+ true
123
+ end
124
+ end
125
+ end
126
+
127
+ def validate_response_mode
128
+ if response_mode.blank?
129
+ @response_mode = authorization_response_flow.default_response_mode
130
+ return true
131
+ end
132
+
133
+ authorization_response_flow.matches_response_mode?(response_mode)
107
134
  end
108
135
 
109
136
  def validate_scopes
@@ -116,17 +143,16 @@ module Doorkeeper
116
143
  end
117
144
 
118
145
  def validate_code_challenge_method
146
+ return true unless Doorkeeper.config.access_grant_model.pkce_supported?
147
+
119
148
  code_challenge.blank? ||
120
149
  (code_challenge_method.present? && code_challenge_method =~ /^plain$|^S256$/)
121
150
  end
122
151
 
123
- def validate_resource_owner_authorize_for_client
124
- # The `authorize_resource_owner_for_client` config option is used for this validation
125
- client.application.authorized_for_resource_owner?(@resource_owner)
126
- end
127
-
128
152
  def response_on_fragment?
129
- response_type == "token"
153
+ return response_type == "token" if response_mode.nil?
154
+
155
+ response_mode == "fragment"
130
156
  end
131
157
 
132
158
  def grant_type
@@ -62,6 +62,19 @@ module Doorkeeper
62
62
  attributes[:previous_refresh_token] = refresh_token.refresh_token
63
63
  end
64
64
 
65
+ # RFC6749
66
+ # 1.5. Refresh Token
67
+ #
68
+ # Refresh tokens are issued to the client by the authorization server and are
69
+ # used to obtain a new access token when the current access token
70
+ # becomes invalid or expires, or to obtain additional access tokens
71
+ # with identical or narrower scope (access tokens may have a shorter
72
+ # lifetime and fewer permissions than authorized by the resource
73
+ # owner).
74
+ #
75
+ # Here we assume that TTL of the token received after refreshing should be
76
+ # the same as that of the original token.
77
+ #
65
78
  @access_token = server_config.access_token_model.create_for(
66
79
  application: refresh_token.application,
67
80
  resource_owner: resource_owner,
@@ -15,8 +15,7 @@ module Doorkeeper
15
15
  def authenticate(request, *methods)
16
16
  if (token = from_request(request, *methods))
17
17
  access_token = Doorkeeper.config.access_token_model.by_token(token)
18
- refresh_token_enabled = Doorkeeper.config.refresh_token_enabled?
19
- if access_token.present? && refresh_token_enabled
18
+ if access_token.present? && Doorkeeper.config.refresh_token_enabled?
20
19
  access_token.revoke_previous_refresh_token!
21
20
  end
22
21
  access_token
@@ -33,13 +32,13 @@ module Doorkeeper
33
32
 
34
33
  def from_bearer_authorization(request)
35
34
  pattern = /^Bearer /i
36
- header = request.authorization
35
+ header = request.authorization
37
36
  token_from_header(header, pattern) if match?(header, pattern)
38
37
  end
39
38
 
40
39
  def from_basic_authorization(request)
41
40
  pattern = /^Basic /i
42
- header = request.authorization
41
+ header = request.authorization
43
42
  token_from_basic_header(header, pattern) if match?(header, pattern)
44
43
  end
45
44
 
@@ -55,7 +54,7 @@ module Doorkeeper
55
54
  end
56
55
 
57
56
  def token_from_header(header, pattern)
58
- header.gsub pattern, ""
57
+ header.gsub(pattern, "")
59
58
  end
60
59
 
61
60
  def match?(header, pattern)
@@ -179,11 +179,7 @@ module Doorkeeper
179
179
  allow_introspection = Doorkeeper.config.allow_token_introspection
180
180
  return allow_introspection unless allow_introspection.respond_to?(:call)
181
181
 
182
- allow_introspection.call(
183
- @token,
184
- auth_client,
185
- auth_token,
186
- )
182
+ allow_introspection.call(@token, auth_client, auth_token)
187
183
  end
188
184
 
189
185
  # Allows to customize introspection response.
@@ -12,7 +12,7 @@ module Doorkeeper
12
12
 
13
13
  def authorize
14
14
  auth = Authorization::Token.new(pre_auth, resource_owner)
15
- auth.issue_token
15
+ auth.issue_token!
16
16
  CodeResponse.new(pre_auth, auth, response_on_fragment: true)
17
17
  end
18
18
 
@@ -20,9 +20,8 @@ module Doorkeeper
20
20
  require "doorkeeper/orm/active_record/access_token"
21
21
  require "doorkeeper/orm/active_record/application"
22
22
 
23
- if Doorkeeper.config.active_record_options[:establish_connection]
23
+ if (options = Doorkeeper.config.active_record_options[:establish_connection])
24
24
  Doorkeeper::Orm::ActiveRecord.models.each do |model|
25
- options = Doorkeeper.config.active_record_options[:establish_connection]
26
25
  model.establish_connection(options)
27
26
  end
28
27
  end
@@ -33,7 +32,7 @@ module Doorkeeper
33
32
  lazy_load do
34
33
  require "doorkeeper/models/concerns/ownership"
35
34
 
36
- Doorkeeper.config.application_model.send :include, Doorkeeper::Models::Ownership
35
+ Doorkeeper.config.application_model.include(Doorkeeper::Models::Ownership)
37
36
  end
38
37
  end
39
38
 
@@ -43,9 +42,9 @@ module Doorkeeper
43
42
 
44
43
  def self.models
45
44
  [
46
- Doorkeeper::AccessGrant,
47
- Doorkeeper::AccessToken,
48
- Doorkeeper::Application,
45
+ Doorkeeper.config.access_grant_model,
46
+ Doorkeeper.config.access_token_model,
47
+ Doorkeeper.config.application_model,
49
48
  ]
50
49
  end
51
50
  end
@@ -5,11 +5,11 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- self.table_name = "#{table_name_prefix}oauth_access_grants#{table_name_suffix}"
8
+ self.table_name = compute_doorkeeper_table_name
9
9
 
10
10
  include ::Doorkeeper::AccessGrantMixin
11
11
 
12
- belongs_to :application, class_name: Doorkeeper.config.application_class,
12
+ belongs_to :application, class_name: Doorkeeper.config.application_class.to_s,
13
13
  optional: true,
14
14
  inverse_of: :access_grants
15
15
 
@@ -54,5 +54,15 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
54
54
  secret_strategy.store_secret(self, :token, @raw_token)
55
55
  end
56
56
  end
57
+
58
+ module ClassMethods
59
+ private
60
+
61
+ def compute_doorkeeper_table_name
62
+ table_name = "oauth_access_grant"
63
+ table_name = table_name.pluralize if pluralize_table_names
64
+ "#{table_name_prefix}#{table_name}#{table_name_suffix}"
65
+ end
66
+ end
57
67
  end
58
68
  end
@@ -5,11 +5,11 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- self.table_name = "#{table_name_prefix}oauth_access_tokens#{table_name_suffix}"
8
+ self.table_name = compute_doorkeeper_table_name
9
9
 
10
10
  include ::Doorkeeper::AccessTokenMixin
11
11
 
12
- belongs_to :application, class_name: Doorkeeper.config.application_class,
12
+ belongs_to :application, class_name: Doorkeeper.config.application_class.to_s,
13
13
  inverse_of: :access_tokens,
14
14
  optional: true
15
15
 
@@ -46,6 +46,14 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
46
46
  def refresh_token_revoked_on_use?
47
47
  column_names.include?("previous_refresh_token")
48
48
  end
49
+
50
+ private
51
+
52
+ def compute_doorkeeper_table_name
53
+ table_name = "oauth_access_token"
54
+ table_name = table_name.pluralize if pluralize_table_names
55
+ "#{table_name_prefix}#{table_name}#{table_name_suffix}"
56
+ end
49
57
  end
50
58
  end
51
59
  end
@@ -5,19 +5,19 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- self.table_name = "#{table_name_prefix}oauth_applications#{table_name_suffix}"
8
+ self.table_name = compute_doorkeeper_table_name
9
9
 
10
10
  include ::Doorkeeper::ApplicationMixin
11
11
 
12
12
  has_many :access_grants,
13
13
  foreign_key: :application_id,
14
14
  dependent: :delete_all,
15
- class_name: Doorkeeper.config.access_grant_class
15
+ class_name: Doorkeeper.config.access_grant_class.to_s
16
16
 
17
17
  has_many :access_tokens,
18
18
  foreign_key: :application_id,
19
19
  dependent: :delete_all,
20
- class_name: Doorkeeper.config.access_token_class
20
+ class_name: Doorkeeper.config.access_token_class.to_s
21
21
 
22
22
  validates :name, :secret, :uid, presence: true
23
23
  validates :uid, uniqueness: { case_sensitive: true }
@@ -31,7 +31,7 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
31
31
  has_many :authorized_tokens,
32
32
  -> { where(revoked_at: nil) },
33
33
  foreign_key: :application_id,
34
- class_name: Doorkeeper.config.access_token_class
34
+ class_name: Doorkeeper.config.access_token_class.to_s
35
35
 
36
36
  has_many :authorized_applications,
37
37
  through: :authorized_tokens,
@@ -61,21 +61,44 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
61
61
  end
62
62
  end
63
63
 
64
- # This is the right way how we want to override ActiveRecord #to_json
64
+ # Represents client as set of it's attributes in JSON format.
65
+ # This is the right way how we want to override ActiveRecord #to_json.
65
66
  #
66
- # @return [String] entity attributes as JSON
67
+ # Respects privacy settings and serializes minimum set of attributes
68
+ # for public/private clients and full set for authorized owners.
69
+ #
70
+ # @return [Hash] entity attributes for JSON
67
71
  #
68
72
  def as_json(options = {})
69
- hash = super
70
-
71
- hash["secret"] = plaintext_secret if hash.key?("secret")
72
- hash
73
+ # if application belongs to some owner we need to check if it's the same as
74
+ # the one passed in the options or check if we render the client as an owner
75
+ if (respond_to?(:owner) && owner && owner == options[:current_resource_owner]) ||
76
+ options[:as_owner]
77
+ # Owners can see all the client attributes, fallback to ActiveModel serialization
78
+ super
79
+ else
80
+ # if application has no owner or it's owner doesn't match one from the options
81
+ # we render only minimum set of attributes that could be exposed to a public
82
+ only = extract_serializable_attributes(options)
83
+ super(options.merge(only: only))
84
+ end
73
85
  end
74
86
 
75
87
  def authorized_for_resource_owner?(resource_owner)
76
88
  Doorkeeper.configuration.authorize_resource_owner_for_client.call(self, resource_owner)
77
89
  end
78
90
 
91
+ # We need to hook into this method to allow serializing plan-text secrets
92
+ # when secrets hashing enabled.
93
+ #
94
+ # @param key [String] attribute name
95
+ #
96
+ def read_attribute_for_serialization(key)
97
+ return super unless key.to_s == "secret"
98
+
99
+ plaintext_secret || secret
100
+ end
101
+
79
102
  private
80
103
 
81
104
  def generate_uid
@@ -100,6 +123,41 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
100
123
  def enforce_scopes?
101
124
  Doorkeeper.config.enforce_configured_scopes?
102
125
  end
126
+
127
+ # Helper method to extract collection of serializable attribute names
128
+ # considering serialization options (like `only`, `except` and so on).
129
+ #
130
+ # @param options [Hash] serialization options
131
+ #
132
+ # @return [Array<String>]
133
+ # collection of attributes to be serialized using #as_json
134
+ #
135
+ def extract_serializable_attributes(options = {})
136
+ opts = options.try(:dup) || {}
137
+ only = Array.wrap(opts[:only]).map(&:to_s)
138
+
139
+ only = if only.blank?
140
+ client_serializable_attributes
141
+ else
142
+ only & client_serializable_attributes
143
+ end
144
+
145
+ only -= Array.wrap(opts[:except]).map(&:to_s) if opts.key?(:except)
146
+ only.uniq
147
+ end
148
+
149
+ # Collection of attributes that could be serialized for public.
150
+ # Override this method if you need additional attributes to be serialized.
151
+ #
152
+ # @return [Array<String>] collection of serializable attributes
153
+ #
154
+ # NOTE: `serializable_attributes` method already taken by Rails >= 6
155
+ #
156
+ def client_serializable_attributes
157
+ attributes = %w[id name created_at]
158
+ attributes << "uid" unless confidential?
159
+ attributes
160
+ end
103
161
  end
104
162
 
105
163
  module ClassMethods
@@ -127,6 +185,14 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
127
185
  Doorkeeper.config.access_token_model.revoke_all_for(id, resource_owner)
128
186
  Doorkeeper.config.access_grant_model.revoke_all_for(id, resource_owner)
129
187
  end
188
+
189
+ private
190
+
191
+ def compute_doorkeeper_table_name
192
+ table_name = "oauth_application"
193
+ table_name = table_name.pluralize if pluralize_table_names
194
+ "#{table_name_prefix}#{table_name}#{table_name_suffix}"
195
+ end
130
196
  end
131
197
  end
132
198
  end