doorkeeper 4.4.3 → 5.5.2

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 (282) hide show
  1. checksums.yaml +5 -5
  2. data/{NEWS.md → CHANGELOG.md} +393 -19
  3. data/README.md +97 -393
  4. data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
  5. data/app/controllers/doorkeeper/application_controller.rb +8 -5
  6. data/app/controllers/doorkeeper/application_metal_controller.rb +7 -11
  7. data/app/controllers/doorkeeper/applications_controller.rb +62 -27
  8. data/app/controllers/doorkeeper/authorizations_controller.rb +97 -17
  9. data/app/controllers/doorkeeper/authorized_applications_controller.rb +22 -3
  10. data/app/controllers/doorkeeper/token_info_controller.rb +16 -4
  11. data/app/controllers/doorkeeper/tokens_controller.rb +98 -32
  12. data/app/helpers/doorkeeper/dashboard_helper.rb +9 -7
  13. data/app/views/doorkeeper/applications/_delete_form.html.erb +3 -1
  14. data/app/views/doorkeeper/applications/_form.html.erb +27 -26
  15. data/app/views/doorkeeper/applications/edit.html.erb +1 -1
  16. data/app/views/doorkeeper/applications/index.html.erb +17 -7
  17. data/app/views/doorkeeper/applications/new.html.erb +1 -1
  18. data/app/views/doorkeeper/applications/show.html.erb +38 -17
  19. data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
  20. data/app/views/doorkeeper/authorizations/form_post.html.erb +15 -0
  21. data/app/views/doorkeeper/authorizations/new.html.erb +6 -0
  22. data/app/views/layouts/doorkeeper/admin.html.erb +16 -14
  23. data/config/locales/en.yml +23 -3
  24. data/lib/doorkeeper/config/abstract_builder.rb +28 -0
  25. data/lib/doorkeeper/config/option.rb +82 -0
  26. data/lib/doorkeeper/config/validations.rb +53 -0
  27. data/lib/doorkeeper/config.rb +471 -140
  28. data/lib/doorkeeper/engine.rb +8 -2
  29. data/lib/doorkeeper/errors.rb +25 -16
  30. data/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
  31. data/lib/doorkeeper/grant_flow/flow.rb +44 -0
  32. data/lib/doorkeeper/grant_flow/registry.rb +50 -0
  33. data/lib/doorkeeper/grant_flow.rb +45 -0
  34. data/lib/doorkeeper/grape/authorization_decorator.rb +6 -4
  35. data/lib/doorkeeper/grape/helpers.rb +13 -7
  36. data/lib/doorkeeper/helpers/controller.rb +43 -10
  37. data/lib/doorkeeper/models/access_grant_mixin.rb +97 -3
  38. data/lib/doorkeeper/models/access_token_mixin.rb +272 -66
  39. data/lib/doorkeeper/models/application_mixin.rb +50 -5
  40. data/lib/doorkeeper/models/concerns/accessible.rb +2 -0
  41. data/lib/doorkeeper/models/concerns/expirable.rb +7 -3
  42. data/lib/doorkeeper/models/concerns/orderable.rb +2 -0
  43. data/lib/doorkeeper/models/concerns/ownership.rb +4 -7
  44. data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
  45. data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
  46. data/lib/doorkeeper/models/concerns/revocable.rb +3 -27
  47. data/lib/doorkeeper/models/concerns/scopes.rb +12 -2
  48. data/lib/doorkeeper/models/concerns/secret_storable.rb +106 -0
  49. data/lib/doorkeeper/oauth/authorization/code.rb +48 -12
  50. data/lib/doorkeeper/oauth/authorization/context.rb +17 -0
  51. data/lib/doorkeeper/oauth/authorization/token.rb +58 -24
  52. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +7 -5
  53. data/lib/doorkeeper/oauth/authorization_code_request.rb +58 -10
  54. data/lib/doorkeeper/oauth/base_request.rb +35 -24
  55. data/lib/doorkeeper/oauth/base_response.rb +2 -0
  56. data/lib/doorkeeper/oauth/client/credentials.rb +5 -5
  57. data/lib/doorkeeper/oauth/client.rb +10 -11
  58. data/lib/doorkeeper/oauth/client_credentials/creator.rb +47 -4
  59. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +16 -9
  60. data/lib/doorkeeper/oauth/client_credentials/validator.rb +56 -0
  61. data/lib/doorkeeper/oauth/client_credentials_request.rb +10 -11
  62. data/lib/doorkeeper/oauth/code_request.rb +8 -12
  63. data/lib/doorkeeper/oauth/code_response.rb +27 -15
  64. data/lib/doorkeeper/oauth/error.rb +3 -1
  65. data/lib/doorkeeper/oauth/error_response.rb +35 -14
  66. data/lib/doorkeeper/oauth/forbidden_token_response.rb +10 -3
  67. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +23 -18
  68. data/lib/doorkeeper/oauth/helpers/unique_token.rb +20 -3
  69. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +42 -7
  70. data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
  71. data/lib/doorkeeper/oauth/invalid_request_response.rb +43 -0
  72. data/lib/doorkeeper/oauth/invalid_token_response.rb +29 -4
  73. data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
  74. data/lib/doorkeeper/oauth/password_access_token_request.rb +43 -10
  75. data/lib/doorkeeper/oauth/pre_authorization.rb +133 -26
  76. data/lib/doorkeeper/oauth/refresh_token_request.rb +59 -31
  77. data/lib/doorkeeper/oauth/scopes.rb +8 -4
  78. data/lib/doorkeeper/oauth/token.rb +12 -8
  79. data/lib/doorkeeper/oauth/token_introspection.rb +97 -23
  80. data/lib/doorkeeper/oauth/token_request.rb +8 -20
  81. data/lib/doorkeeper/oauth/token_response.rb +14 -10
  82. data/lib/doorkeeper/oauth.rb +13 -0
  83. data/lib/doorkeeper/orm/active_record/access_grant.rb +5 -30
  84. data/lib/doorkeeper/orm/active_record/access_token.rb +5 -43
  85. data/lib/doorkeeper/orm/active_record/application.rb +6 -57
  86. data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +68 -0
  87. data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +59 -0
  88. data/lib/doorkeeper/orm/active_record/mixins/application.rb +198 -0
  89. data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +66 -0
  90. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +33 -0
  91. data/lib/doorkeeper/orm/active_record.rb +27 -9
  92. data/lib/doorkeeper/rails/helpers.rb +10 -8
  93. data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
  94. data/lib/doorkeeper/rails/routes/mapper.rb +4 -2
  95. data/lib/doorkeeper/rails/routes/mapping.rb +9 -7
  96. data/lib/doorkeeper/rails/routes/registry.rb +45 -0
  97. data/lib/doorkeeper/rails/routes.rb +37 -30
  98. data/lib/doorkeeper/rake/db.rake +40 -0
  99. data/lib/doorkeeper/rake/setup.rake +11 -0
  100. data/lib/doorkeeper/rake.rb +14 -0
  101. data/lib/doorkeeper/request/authorization_code.rb +6 -4
  102. data/lib/doorkeeper/request/client_credentials.rb +3 -3
  103. data/lib/doorkeeper/request/code.rb +1 -1
  104. data/lib/doorkeeper/request/password.rb +4 -3
  105. data/lib/doorkeeper/request/refresh_token.rb +6 -5
  106. data/lib/doorkeeper/request/strategy.rb +4 -2
  107. data/lib/doorkeeper/request/token.rb +1 -1
  108. data/lib/doorkeeper/request.rb +61 -34
  109. data/lib/doorkeeper/secret_storing/base.rb +64 -0
  110. data/lib/doorkeeper/secret_storing/bcrypt.rb +60 -0
  111. data/lib/doorkeeper/secret_storing/plain.rb +33 -0
  112. data/lib/doorkeeper/secret_storing/sha256_hash.rb +26 -0
  113. data/lib/doorkeeper/server.rb +9 -11
  114. data/lib/doorkeeper/stale_records_cleaner.rb +24 -0
  115. data/lib/doorkeeper/validations.rb +2 -0
  116. data/lib/doorkeeper/version.rb +7 -29
  117. data/lib/doorkeeper.rb +111 -64
  118. data/lib/generators/doorkeeper/application_owner_generator.rb +24 -18
  119. data/lib/generators/doorkeeper/confidential_applications_generator.rb +33 -0
  120. data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
  121. data/lib/generators/doorkeeper/install_generator.rb +19 -9
  122. data/lib/generators/doorkeeper/migration_generator.rb +23 -18
  123. data/lib/generators/doorkeeper/pkce_generator.rb +33 -0
  124. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +28 -22
  125. data/{spec/dummy/db/migrate/20180210183654_add_confidential_to_application.rb → lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb} +2 -2
  126. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +3 -1
  127. data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +2 -0
  128. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +8 -0
  129. data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
  130. data/lib/generators/doorkeeper/templates/initializer.rb +382 -30
  131. data/lib/generators/doorkeeper/templates/migration.rb.erb +35 -16
  132. data/lib/generators/doorkeeper/views_generator.rb +8 -4
  133. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  134. metadata +95 -309
  135. data/.coveralls.yml +0 -1
  136. data/.github/ISSUE_TEMPLATE.md +0 -25
  137. data/.github/PULL_REQUEST_TEMPLATE.md +0 -17
  138. data/.gitignore +0 -19
  139. data/.hound.yml +0 -2
  140. data/.rspec +0 -1
  141. data/.rubocop.yml +0 -17
  142. data/.travis.yml +0 -38
  143. data/Appraisals +0 -18
  144. data/CODE_OF_CONDUCT.md +0 -46
  145. data/CONTRIBUTING.md +0 -47
  146. data/Gemfile +0 -10
  147. data/RELEASING.md +0 -10
  148. data/Rakefile +0 -20
  149. data/SECURITY.md +0 -15
  150. data/app/validators/redirect_uri_validator.rb +0 -44
  151. data/doorkeeper.gemspec +0 -32
  152. data/gemfiles/rails_4_2.gemfile +0 -13
  153. data/gemfiles/rails_5_0.gemfile +0 -12
  154. data/gemfiles/rails_5_1.gemfile +0 -12
  155. data/gemfiles/rails_5_2.gemfile +0 -12
  156. data/gemfiles/rails_master.gemfile +0 -14
  157. data/lib/doorkeeper/oauth/client_credentials/validation.rb +0 -45
  158. data/lib/generators/doorkeeper/add_client_confidentiality_generator.rb +0 -31
  159. data/lib/generators/doorkeeper/templates/add_confidential_to_application_migration.rb.erb +0 -11
  160. data/spec/controllers/application_metal_controller.rb +0 -10
  161. data/spec/controllers/applications_controller_spec.rb +0 -69
  162. data/spec/controllers/authorizations_controller_spec.rb +0 -250
  163. data/spec/controllers/protected_resources_controller_spec.rb +0 -309
  164. data/spec/controllers/token_info_controller_spec.rb +0 -56
  165. data/spec/controllers/tokens_controller_spec.rb +0 -274
  166. data/spec/dummy/Rakefile +0 -7
  167. data/spec/dummy/app/controllers/application_controller.rb +0 -3
  168. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +0 -7
  169. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +0 -12
  170. data/spec/dummy/app/controllers/home_controller.rb +0 -17
  171. data/spec/dummy/app/controllers/metal_controller.rb +0 -11
  172. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +0 -11
  173. data/spec/dummy/app/helpers/application_helper.rb +0 -5
  174. data/spec/dummy/app/models/user.rb +0 -5
  175. data/spec/dummy/app/views/home/index.html.erb +0 -0
  176. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  177. data/spec/dummy/config/application.rb +0 -23
  178. data/spec/dummy/config/boot.rb +0 -9
  179. data/spec/dummy/config/database.yml +0 -15
  180. data/spec/dummy/config/environment.rb +0 -5
  181. data/spec/dummy/config/environments/development.rb +0 -29
  182. data/spec/dummy/config/environments/production.rb +0 -62
  183. data/spec/dummy/config/environments/test.rb +0 -44
  184. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  185. data/spec/dummy/config/initializers/doorkeeper.rb +0 -112
  186. data/spec/dummy/config/initializers/new_framework_defaults.rb +0 -6
  187. data/spec/dummy/config/initializers/secret_token.rb +0 -8
  188. data/spec/dummy/config/initializers/session_store.rb +0 -8
  189. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
  190. data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
  191. data/spec/dummy/config/routes.rb +0 -52
  192. data/spec/dummy/config.ru +0 -4
  193. data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -11
  194. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -7
  195. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +0 -62
  196. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +0 -9
  197. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +0 -13
  198. data/spec/dummy/db/schema.rb +0 -68
  199. data/spec/dummy/public/404.html +0 -26
  200. data/spec/dummy/public/422.html +0 -26
  201. data/spec/dummy/public/500.html +0 -26
  202. data/spec/dummy/public/favicon.ico +0 -0
  203. data/spec/dummy/script/rails +0 -6
  204. data/spec/factories.rb +0 -28
  205. data/spec/generators/application_owner_generator_spec.rb +0 -41
  206. data/spec/generators/install_generator_spec.rb +0 -31
  207. data/spec/generators/migration_generator_spec.rb +0 -41
  208. data/spec/generators/previous_refresh_token_generator_spec.rb +0 -57
  209. data/spec/generators/templates/routes.rb +0 -3
  210. data/spec/generators/views_generator_spec.rb +0 -27
  211. data/spec/grape/grape_integration_spec.rb +0 -135
  212. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -24
  213. data/spec/lib/config_spec.rb +0 -462
  214. data/spec/lib/doorkeeper_spec.rb +0 -150
  215. data/spec/lib/models/expirable_spec.rb +0 -50
  216. data/spec/lib/models/revocable_spec.rb +0 -59
  217. data/spec/lib/models/scopes_spec.rb +0 -43
  218. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -41
  219. data/spec/lib/oauth/authorization_code_request_spec.rb +0 -123
  220. data/spec/lib/oauth/base_request_spec.rb +0 -155
  221. data/spec/lib/oauth/base_response_spec.rb +0 -45
  222. data/spec/lib/oauth/client/credentials_spec.rb +0 -90
  223. data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -44
  224. data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -86
  225. data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -54
  226. data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -27
  227. data/spec/lib/oauth/client_credentials_request_spec.rb +0 -105
  228. data/spec/lib/oauth/client_spec.rb +0 -39
  229. data/spec/lib/oauth/code_request_spec.rb +0 -43
  230. data/spec/lib/oauth/code_response_spec.rb +0 -34
  231. data/spec/lib/oauth/error_response_spec.rb +0 -61
  232. data/spec/lib/oauth/error_spec.rb +0 -23
  233. data/spec/lib/oauth/forbidden_token_response_spec.rb +0 -23
  234. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -64
  235. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -20
  236. data/spec/lib/oauth/helpers/uri_checker_spec.rb +0 -218
  237. data/spec/lib/oauth/invalid_token_response_spec.rb +0 -56
  238. data/spec/lib/oauth/password_access_token_request_spec.rb +0 -96
  239. data/spec/lib/oauth/pre_authorization_spec.rb +0 -160
  240. data/spec/lib/oauth/refresh_token_request_spec.rb +0 -166
  241. data/spec/lib/oauth/scopes_spec.rb +0 -149
  242. data/spec/lib/oauth/token_request_spec.rb +0 -96
  243. data/spec/lib/oauth/token_response_spec.rb +0 -85
  244. data/spec/lib/oauth/token_spec.rb +0 -116
  245. data/spec/lib/request/strategy_spec.rb +0 -53
  246. data/spec/lib/server_spec.rb +0 -59
  247. data/spec/models/doorkeeper/access_grant_spec.rb +0 -36
  248. data/spec/models/doorkeeper/access_token_spec.rb +0 -418
  249. data/spec/models/doorkeeper/application_spec.rb +0 -303
  250. data/spec/requests/applications/applications_request_spec.rb +0 -94
  251. data/spec/requests/applications/authorized_applications_spec.rb +0 -30
  252. data/spec/requests/endpoints/authorization_spec.rb +0 -71
  253. data/spec/requests/endpoints/token_spec.rb +0 -71
  254. data/spec/requests/flows/authorization_code_errors_spec.rb +0 -76
  255. data/spec/requests/flows/authorization_code_spec.rb +0 -149
  256. data/spec/requests/flows/client_credentials_spec.rb +0 -86
  257. data/spec/requests/flows/implicit_grant_errors_spec.rb +0 -32
  258. data/spec/requests/flows/implicit_grant_spec.rb +0 -61
  259. data/spec/requests/flows/password_spec.rb +0 -197
  260. data/spec/requests/flows/refresh_token_spec.rb +0 -174
  261. data/spec/requests/flows/revoke_token_spec.rb +0 -157
  262. data/spec/requests/flows/skip_authorization_spec.rb +0 -59
  263. data/spec/requests/protected_resources/metal_spec.rb +0 -14
  264. data/spec/requests/protected_resources/private_api_spec.rb +0 -81
  265. data/spec/routing/custom_controller_routes_spec.rb +0 -75
  266. data/spec/routing/default_routes_spec.rb +0 -39
  267. data/spec/routing/scoped_routes_spec.rb +0 -31
  268. data/spec/spec_helper.rb +0 -4
  269. data/spec/spec_helper_integration.rb +0 -74
  270. data/spec/support/dependencies/factory_girl.rb +0 -2
  271. data/spec/support/helpers/access_token_request_helper.rb +0 -11
  272. data/spec/support/helpers/authorization_request_helper.rb +0 -41
  273. data/spec/support/helpers/config_helper.rb +0 -9
  274. data/spec/support/helpers/model_helper.rb +0 -72
  275. data/spec/support/helpers/request_spec_helper.rb +0 -88
  276. data/spec/support/helpers/url_helper.rb +0 -56
  277. data/spec/support/http_method_shim.rb +0 -38
  278. data/spec/support/orm/active_record.rb +0 -3
  279. data/spec/support/shared/controllers_shared_context.rb +0 -65
  280. data/spec/support/shared/models_shared_examples.rb +0 -52
  281. data/spec/validators/redirect_uri_validator_spec.rb +0 -123
  282. data/spec/version/version_spec.rb +0 -15
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class RefreshTokenRequest < BaseRequest
@@ -9,28 +11,28 @@ module Doorkeeper
9
11
  validate :client_match, error: :invalid_grant
10
12
  validate :scope, error: :invalid_scope
11
13
 
12
- attr_accessor :access_token, :client, :credentials, :refresh_token,
13
- :server
14
+ attr_reader :access_token, :client, :credentials, :refresh_token
15
+ attr_reader :missing_param
14
16
 
15
17
  def initialize(server, refresh_token, credentials, parameters = {})
16
- @server = server
17
- @refresh_token = refresh_token
18
- @credentials = credentials
18
+ @server = server
19
+ @refresh_token = refresh_token
20
+ @credentials = credentials
19
21
  @original_scopes = parameters[:scope] || parameters[:scopes]
20
22
  @refresh_token_parameter = parameters[:refresh_token]
21
-
22
- if credentials
23
- @client = Application.by_uid_and_secret credentials.uid,
24
- credentials.secret
25
- end
23
+ @client = load_client(credentials) if credentials
26
24
  end
27
25
 
28
26
  private
29
27
 
28
+ def load_client(credentials)
29
+ server_config.application_model.by_uid_and_secret(credentials.uid, credentials.secret)
30
+ end
31
+
30
32
  def before_successful_response
31
33
  refresh_token.transaction do
32
34
  refresh_token.lock!
33
- raise Errors::InvalidTokenReuse if refresh_token.revoked?
35
+ raise Errors::InvalidGrantReuse if refresh_token.revoked?
34
36
 
35
37
  refresh_token.revoke unless refresh_token_revoked_on_use?
36
38
  create_access_token
@@ -39,7 +41,7 @@ module Doorkeeper
39
41
  end
40
42
 
41
43
  def refresh_token_revoked_on_use?
42
- Doorkeeper::AccessToken.refresh_token_revoked_on_use?
44
+ server_config.access_token_model.refresh_token_revoked_on_use?
43
45
  end
44
46
 
45
47
  def default_scopes
@@ -47,29 +49,46 @@ module Doorkeeper
47
49
  end
48
50
 
49
51
  def create_access_token
50
- @access_token = AccessToken.create!(access_token_attributes)
51
- end
52
+ attributes = {}
52
53
 
53
- def access_token_attributes
54
- {
55
- application_id: refresh_token.application_id,
56
- resource_owner_id: refresh_token.resource_owner_id,
57
- scopes: scopes.to_s,
58
- expires_in: access_token_expires_in,
59
- use_refresh_token: true
60
- }.tap do |attributes|
61
- if refresh_token_revoked_on_use?
62
- attributes[:previous_refresh_token] = refresh_token.refresh_token
54
+ resource_owner =
55
+ if Doorkeeper.config.polymorphic_resource_owner?
56
+ refresh_token.resource_owner
57
+ else
58
+ refresh_token.resource_owner_id
63
59
  end
60
+
61
+ if refresh_token_revoked_on_use?
62
+ attributes[:previous_refresh_token] = refresh_token.refresh_token
64
63
  end
65
- end
66
64
 
67
- def access_token_expires_in
68
- Authorization::Token.access_token_expires_in(server, client)
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
+ #
78
+ @access_token = server_config.access_token_model.create_for(
79
+ application: refresh_token.application,
80
+ resource_owner: resource_owner,
81
+ scopes: scopes,
82
+ expires_in: refresh_token.expires_in,
83
+ use_refresh_token: true,
84
+ **attributes,
85
+ )
69
86
  end
70
87
 
71
88
  def validate_token_presence
72
- refresh_token.present? || @refresh_token_parameter.present?
89
+ @missing_param = :refresh_token if refresh_token.blank? && @refresh_token_parameter.blank?
90
+
91
+ @missing_param.nil?
73
92
  end
74
93
 
75
94
  def validate_token
@@ -77,16 +96,25 @@ module Doorkeeper
77
96
  end
78
97
 
79
98
  def validate_client
80
- !credentials || !!client
99
+ return true if credentials.blank?
100
+
101
+ client.present?
81
102
  end
82
103
 
104
+ # @see https://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-1.5
105
+ #
83
106
  def validate_client_match
84
- !client || refresh_token.application_id == client.id
107
+ return true if refresh_token.application_id.blank?
108
+
109
+ client && refresh_token.application_id == client.id
85
110
  end
86
111
 
87
112
  def validate_scope
88
113
  if @original_scopes.present?
89
- ScopeChecker.valid?(@original_scopes, refresh_token.scopes)
114
+ ScopeChecker.valid?(
115
+ scope_str: @original_scopes,
116
+ server_scopes: refresh_token.scopes,
117
+ )
90
118
  else
91
119
  true
92
120
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class Scopes
@@ -5,7 +7,7 @@ module Doorkeeper
5
7
  include Comparable
6
8
 
7
9
  def self.from_string(string)
8
- string ||= ''
10
+ string ||= ""
9
11
  new.tap do |scope|
10
12
  scope.add(*string.split)
11
13
  end
@@ -37,13 +39,15 @@ module Doorkeeper
37
39
  end
38
40
 
39
41
  def to_s
40
- @scopes.join(' ')
42
+ @scopes.join(" ")
41
43
  end
42
44
 
43
- def has_scopes?(scopes)
44
- scopes.all? { |s| exists?(s) }
45
+ def scopes?(scopes)
46
+ scopes.all? { |scope| exists?(scope) }
45
47
  end
46
48
 
49
+ alias has_scopes? scopes?
50
+
47
51
  def +(other)
48
52
  self.class.from_array(all + to_array(other))
49
53
  end
@@ -1,19 +1,23 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class Token
4
6
  class << self
5
7
  def from_request(request, *methods)
6
- methods.inject(nil) do |credentials, method|
8
+ methods.inject(nil) do |_, method|
7
9
  method = self.method(method) if method.is_a?(Symbol)
8
10
  credentials = method.call(request)
9
- break credentials unless credentials.blank?
11
+ break credentials if credentials.present?
10
12
  end
11
13
  end
12
14
 
13
15
  def authenticate(request, *methods)
14
16
  if (token = from_request(request, *methods))
15
- access_token = AccessToken.by_token(token)
16
- access_token.revoke_previous_refresh_token! if access_token
17
+ access_token = Doorkeeper.config.access_token_model.by_token(token)
18
+ if access_token.present? && Doorkeeper.config.refresh_token_enabled?
19
+ access_token.revoke_previous_refresh_token!
20
+ end
17
21
  access_token
18
22
  end
19
23
  end
@@ -28,13 +32,13 @@ module Doorkeeper
28
32
 
29
33
  def from_bearer_authorization(request)
30
34
  pattern = /^Bearer /i
31
- header = request.authorization
35
+ header = request.authorization
32
36
  token_from_header(header, pattern) if match?(header, pattern)
33
37
  end
34
38
 
35
39
  def from_basic_authorization(request)
36
40
  pattern = /^Basic /i
37
- header = request.authorization
41
+ header = request.authorization
38
42
  token_from_basic_header(header, pattern) if match?(header, pattern)
39
43
  end
40
44
 
@@ -50,11 +54,11 @@ module Doorkeeper
50
54
  end
51
55
 
52
56
  def token_from_header(header, pattern)
53
- header.gsub pattern, ''
57
+ header.gsub(pattern, "")
54
58
  end
55
59
 
56
60
  def match?(header, pattern)
57
- header && header.match(pattern)
61
+ header&.match(pattern)
58
62
  end
59
63
  end
60
64
  end
@@ -1,12 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  # RFC7662 OAuth 2.0 Token Introspection
4
6
  #
5
7
  # @see https://tools.ietf.org/html/rfc7662
6
8
  class TokenIntrospection
7
- attr_reader :server, :token
8
- attr_reader :error
9
-
10
9
  def initialize(server, token)
11
10
  @server = server
12
11
  @token = token
@@ -18,12 +17,27 @@ module Doorkeeper
18
17
  @error.blank?
19
18
  end
20
19
 
21
- def to_json
20
+ def error_response
21
+ return if @error.blank?
22
+
23
+ if @error == :invalid_token
24
+ OAuth::InvalidTokenResponse.from_access_token(authorized_token)
25
+ elsif @error == :invalid_request
26
+ OAuth::InvalidRequestResponse.from_request(self)
27
+ else
28
+ OAuth::ErrorResponse.new(name: @error)
29
+ end
30
+ end
31
+
32
+ def to_json(*)
22
33
  active? ? success_response : failure_response
23
34
  end
24
35
 
25
36
  private
26
37
 
38
+ attr_reader :server, :token
39
+ attr_reader :error, :invalid_request_reason
40
+
27
41
  # If the protected resource uses OAuth 2.0 client credentials to
28
42
  # authenticate to the introspection endpoint and its credentials are
29
43
  # invalid, the authorization server responds with an HTTP 401
@@ -35,37 +49,53 @@ module Doorkeeper
35
49
  #
36
50
  # @see https://www.oauth.com/oauth2-servers/token-introspection-endpoint/
37
51
  #
52
+ # To prevent token scanning attacks, the endpoint MUST also require
53
+ # some form of authorization to access this endpoint, such as client
54
+ # authentication as described in OAuth 2.0 [RFC6749] or a separate
55
+ # OAuth 2.0 access token such as the bearer token described in OAuth
56
+ # 2.0 Bearer Token Usage [RFC6750].
57
+ #
38
58
  def authorize!
39
59
  # Requested client authorization
40
60
  if server.credentials
41
61
  @error = :invalid_client unless authorized_client
42
- else
62
+ elsif authorized_token
43
63
  # Requested bearer token authorization
44
- @error = :invalid_request unless authorized_token
64
+ #
65
+ # If the protected resource uses an OAuth 2.0 bearer token to authorize
66
+ # its call to the introspection endpoint and the token used for
67
+ # authorization does not contain sufficient privileges or is otherwise
68
+ # invalid for this request, the authorization server responds with an
69
+ # HTTP 401 code as described in Section 3 of OAuth 2.0 Bearer Token
70
+ # Usage [RFC6750].
71
+ #
72
+ @error = :invalid_token unless valid_authorized_token?
73
+ else
74
+ @error = :invalid_request
75
+ @invalid_request_reason = :request_not_authorized
45
76
  end
46
77
  end
47
78
 
48
79
  # Client Authentication
49
80
  def authorized_client
50
- @_authorized_client ||= server.credentials && server.client
81
+ @authorized_client ||= server.credentials && server.client
51
82
  end
52
83
 
53
84
  # Bearer Token Authentication
54
85
  def authorized_token
55
- @_authorized_token ||=
56
- OAuth::Token.authenticate(server.context.request, :from_bearer_authorization)
86
+ @authorized_token ||= Doorkeeper.authenticate(server.context.request)
57
87
  end
58
88
 
59
89
  # 2.2. Introspection Response
60
90
  def success_response
61
- {
91
+ customize_response(
62
92
  active: true,
63
93
  scope: @token.scopes_string,
64
94
  client_id: @token.try(:application).try(:uid),
65
95
  token_type: @token.token_type,
66
96
  exp: @token.expires_at.to_i,
67
- iat: @token.created_at.to_i
68
- }
97
+ iat: @token.created_at.to_i,
98
+ )
69
99
  end
70
100
 
71
101
  # If the introspection call is properly authorized but the token is not
@@ -81,7 +111,7 @@ module Doorkeeper
81
111
  #
82
112
  def failure_response
83
113
  {
84
- active: false
114
+ active: false,
85
115
  }
86
116
  end
87
117
 
@@ -101,9 +131,28 @@ module Doorkeeper
101
131
  # * The token expired
102
132
  # * The token was issued to a different client than is making this request
103
133
  #
134
+ # Since resource servers using token introspection rely on the
135
+ # authorization server to determine the state of a token, the
136
+ # authorization server MUST perform all applicable checks against a
137
+ # token's state. For instance, these tests include the following:
138
+ #
139
+ # o If the token can expire, the authorization server MUST determine
140
+ # whether or not the token has expired.
141
+ # o If the token can be issued before it is able to be used, the
142
+ # authorization server MUST determine whether or not a token's valid
143
+ # period has started yet.
144
+ # o If the token can be revoked after it was issued, the authorization
145
+ # server MUST determine whether or not such a revocation has taken
146
+ # place.
147
+ # o If the token has been signed, the authorization server MUST
148
+ # validate the signature.
149
+ # o If the token can be used only at certain resource servers, the
150
+ # authorization server MUST determine whether or not the token can
151
+ # be used at the resource server making the introspection call.
152
+ #
104
153
  def active?
105
154
  if authorized_client
106
- valid_token? && authorized_for_client?
155
+ valid_token? && token_introspection_allowed?(auth_client: authorized_client.application)
107
156
  else
108
157
  valid_token?
109
158
  end
@@ -111,17 +160,42 @@ module Doorkeeper
111
160
 
112
161
  # Token can be valid only if it is not expired or revoked.
113
162
  def valid_token?
114
- @token.present? && @token.accessible?
163
+ @token&.accessible?
115
164
  end
116
165
 
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
166
+ def valid_authorized_token?
167
+ !authorized_token_matches_introspected? &&
168
+ authorized_token.accessible? &&
169
+ token_introspection_allowed?(auth_token: authorized_token)
170
+ end
171
+
172
+ # RFC7662 Section 2.1
173
+ def authorized_token_matches_introspected?
174
+ authorized_token.token == @token&.token
175
+ end
176
+
177
+ # Config constraints for introspection in Doorkeeper.config.allow_token_introspection
178
+ def token_introspection_allowed?(auth_client: nil, auth_token: nil)
179
+ allow_introspection = Doorkeeper.config.allow_token_introspection
180
+ return allow_introspection unless allow_introspection.respond_to?(:call)
181
+
182
+ allow_introspection.call(@token, auth_client, auth_token)
183
+ end
184
+
185
+ # Allows to customize introspection response.
186
+ # Provides context (controller) and token for generating developer-specific
187
+ # response.
188
+ #
189
+ # @see https://tools.ietf.org/html/rfc7662#section-2.2
190
+ #
191
+ def customize_response(response)
192
+ customized_response = Doorkeeper.config.custom_introspection_response.call(
193
+ token,
194
+ server.context,
195
+ )
196
+ return response if customized_response.blank?
197
+
198
+ response.merge(customized_response)
125
199
  end
126
200
  end
127
201
  end
@@ -1,36 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class TokenRequest
4
- attr_accessor :pre_auth, :resource_owner
6
+ attr_reader :pre_auth, :resource_owner
5
7
 
6
8
  def initialize(pre_auth, resource_owner)
7
- @pre_auth = pre_auth
9
+ @pre_auth = pre_auth
8
10
  @resource_owner = resource_owner
9
11
  end
10
12
 
11
13
  def authorize
12
- if pre_auth.authorizable?
13
- auth = Authorization::Token.new(pre_auth, resource_owner)
14
- auth.issue_token
15
- @response = CodeResponse.new pre_auth,
16
- auth,
17
- response_on_fragment: true
18
- else
19
- @response = error_response
20
- end
14
+ auth = Authorization::Token.new(pre_auth, resource_owner)
15
+ auth.issue_token!
16
+ CodeResponse.new(pre_auth, auth, response_on_fragment: true)
21
17
  end
22
18
 
23
19
  def deny
24
20
  pre_auth.error = :access_denied
25
- error_response
26
- end
27
-
28
- private
29
-
30
- def error_response
31
- ErrorResponse.from_request pre_auth,
32
- redirect_uri: pre_auth.redirect_uri,
33
- response_on_fragment: true
21
+ pre_auth.error_response
34
22
  end
35
23
  end
36
24
  end