doorkeeper 4.2.6 → 5.5.4

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 (274) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1049 -0
  3. data/README.md +110 -353
  4. data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
  5. data/app/controllers/doorkeeper/application_controller.rb +6 -7
  6. data/app/controllers/doorkeeper/application_metal_controller.rb +7 -11
  7. data/app/controllers/doorkeeper/applications_controller.rb +65 -16
  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 +115 -38
  12. data/app/helpers/doorkeeper/dashboard_helper.rb +10 -6
  13. data/app/views/doorkeeper/applications/_delete_form.html.erb +3 -1
  14. data/app/views/doorkeeper/applications/_form.html.erb +33 -21
  15. data/app/views/doorkeeper/applications/edit.html.erb +1 -1
  16. data/app/views/doorkeeper/applications/index.html.erb +18 -6
  17. data/app/views/doorkeeper/applications/new.html.erb +1 -1
  18. data/app/views/doorkeeper/applications/show.html.erb +40 -16
  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/doorkeeper/authorized_applications/index.html.erb +0 -1
  23. data/app/views/layouts/doorkeeper/admin.html.erb +16 -14
  24. data/config/locales/en.yml +34 -7
  25. data/lib/doorkeeper/config/abstract_builder.rb +28 -0
  26. data/lib/doorkeeper/config/option.rb +82 -0
  27. data/lib/doorkeeper/config/validations.rb +53 -0
  28. data/lib/doorkeeper/config.rb +514 -167
  29. data/lib/doorkeeper/engine.rb +11 -5
  30. data/lib/doorkeeper/errors.rb +25 -16
  31. data/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
  32. data/lib/doorkeeper/grant_flow/flow.rb +44 -0
  33. data/lib/doorkeeper/grant_flow/registry.rb +50 -0
  34. data/lib/doorkeeper/grant_flow.rb +45 -0
  35. data/lib/doorkeeper/grape/authorization_decorator.rb +6 -4
  36. data/lib/doorkeeper/grape/helpers.rb +23 -12
  37. data/lib/doorkeeper/helpers/controller.rb +51 -14
  38. data/lib/doorkeeper/models/access_grant_mixin.rb +94 -27
  39. data/lib/doorkeeper/models/access_token_mixin.rb +284 -96
  40. data/lib/doorkeeper/models/application_mixin.rb +58 -27
  41. data/lib/doorkeeper/models/concerns/accessible.rb +2 -0
  42. data/lib/doorkeeper/models/concerns/expirable.rb +12 -6
  43. data/lib/doorkeeper/models/concerns/orderable.rb +15 -0
  44. data/lib/doorkeeper/models/concerns/ownership.rb +4 -7
  45. data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
  46. data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
  47. data/lib/doorkeeper/models/concerns/revocable.rb +3 -27
  48. data/lib/doorkeeper/models/concerns/scopes.rb +12 -2
  49. data/lib/doorkeeper/models/concerns/secret_storable.rb +106 -0
  50. data/lib/doorkeeper/oauth/authorization/code.rb +48 -12
  51. data/lib/doorkeeper/oauth/authorization/context.rb +17 -0
  52. data/lib/doorkeeper/oauth/authorization/token.rb +66 -28
  53. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +7 -5
  54. data/lib/doorkeeper/oauth/authorization_code_request.rb +63 -10
  55. data/lib/doorkeeper/oauth/base_request.rb +35 -19
  56. data/lib/doorkeeper/oauth/base_response.rb +2 -0
  57. data/lib/doorkeeper/oauth/client/credentials.rb +9 -7
  58. data/lib/doorkeeper/oauth/client.rb +10 -11
  59. data/lib/doorkeeper/oauth/client_credentials/creator.rb +47 -4
  60. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +16 -9
  61. data/lib/doorkeeper/oauth/client_credentials/validator.rb +56 -0
  62. data/lib/doorkeeper/oauth/client_credentials_request.rb +10 -11
  63. data/lib/doorkeeper/oauth/code_request.rb +8 -12
  64. data/lib/doorkeeper/oauth/code_response.rb +27 -15
  65. data/lib/doorkeeper/oauth/error.rb +5 -3
  66. data/lib/doorkeeper/oauth/error_response.rb +35 -15
  67. data/lib/doorkeeper/oauth/forbidden_token_response.rb +11 -3
  68. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +23 -18
  69. data/lib/doorkeeper/oauth/helpers/unique_token.rb +20 -3
  70. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +53 -3
  71. data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
  72. data/lib/doorkeeper/oauth/invalid_request_response.rb +43 -0
  73. data/lib/doorkeeper/oauth/invalid_token_response.rb +29 -5
  74. data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
  75. data/lib/doorkeeper/oauth/password_access_token_request.rb +44 -10
  76. data/lib/doorkeeper/oauth/pre_authorization.rb +135 -26
  77. data/lib/doorkeeper/oauth/refresh_token_request.rb +60 -31
  78. data/lib/doorkeeper/oauth/scopes.rb +26 -12
  79. data/lib/doorkeeper/oauth/token.rb +13 -9
  80. data/lib/doorkeeper/oauth/token_introspection.rb +202 -0
  81. data/lib/doorkeeper/oauth/token_request.rb +8 -20
  82. data/lib/doorkeeper/oauth/token_response.rb +14 -10
  83. data/lib/doorkeeper/oauth.rb +13 -0
  84. data/lib/doorkeeper/orm/active_record/access_grant.rb +6 -4
  85. data/lib/doorkeeper/orm/active_record/access_token.rb +5 -42
  86. data/lib/doorkeeper/orm/active_record/application.rb +6 -20
  87. data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +69 -0
  88. data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +60 -0
  89. data/lib/doorkeeper/orm/active_record/mixins/application.rb +199 -0
  90. data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +66 -0
  91. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +33 -0
  92. data/lib/doorkeeper/orm/active_record.rb +37 -8
  93. data/lib/doorkeeper/rails/helpers.rb +14 -13
  94. data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
  95. data/lib/doorkeeper/rails/routes/mapper.rb +4 -2
  96. data/lib/doorkeeper/rails/routes/mapping.rb +9 -7
  97. data/lib/doorkeeper/rails/routes/registry.rb +45 -0
  98. data/lib/doorkeeper/rails/routes.rb +41 -28
  99. data/lib/doorkeeper/rake/db.rake +40 -0
  100. data/lib/doorkeeper/rake/setup.rake +11 -0
  101. data/lib/doorkeeper/rake.rb +14 -0
  102. data/lib/doorkeeper/request/authorization_code.rb +6 -4
  103. data/lib/doorkeeper/request/client_credentials.rb +3 -3
  104. data/lib/doorkeeper/request/code.rb +1 -1
  105. data/lib/doorkeeper/request/password.rb +5 -14
  106. data/lib/doorkeeper/request/refresh_token.rb +6 -5
  107. data/lib/doorkeeper/request/strategy.rb +4 -2
  108. data/lib/doorkeeper/request/token.rb +1 -1
  109. data/lib/doorkeeper/request.rb +62 -29
  110. data/lib/doorkeeper/secret_storing/base.rb +64 -0
  111. data/lib/doorkeeper/secret_storing/bcrypt.rb +60 -0
  112. data/lib/doorkeeper/secret_storing/plain.rb +33 -0
  113. data/lib/doorkeeper/secret_storing/sha256_hash.rb +26 -0
  114. data/lib/doorkeeper/server.rb +9 -11
  115. data/lib/doorkeeper/stale_records_cleaner.rb +24 -0
  116. data/lib/doorkeeper/validations.rb +5 -2
  117. data/lib/doorkeeper/version.rb +12 -1
  118. data/lib/doorkeeper.rb +111 -62
  119. data/lib/generators/doorkeeper/application_owner_generator.rb +28 -13
  120. data/lib/generators/doorkeeper/confidential_applications_generator.rb +33 -0
  121. data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
  122. data/lib/generators/doorkeeper/install_generator.rb +19 -9
  123. data/lib/generators/doorkeeper/migration_generator.rb +27 -10
  124. data/lib/generators/doorkeeper/pkce_generator.rb +33 -0
  125. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +31 -19
  126. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  127. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +9 -0
  128. data/{spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb → lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb} +3 -1
  129. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +8 -0
  130. data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
  131. data/lib/generators/doorkeeper/templates/initializer.rb +412 -33
  132. data/lib/generators/doorkeeper/templates/migration.rb.erb +88 -0
  133. data/lib/generators/doorkeeper/views_generator.rb +8 -4
  134. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  135. metadata +114 -276
  136. data/.coveralls.yml +0 -1
  137. data/.gitignore +0 -19
  138. data/.hound.yml +0 -13
  139. data/.rspec +0 -1
  140. data/.travis.yml +0 -26
  141. data/Appraisals +0 -14
  142. data/CONTRIBUTING.md +0 -47
  143. data/Gemfile +0 -10
  144. data/NEWS.md +0 -606
  145. data/RELEASING.md +0 -10
  146. data/Rakefile +0 -20
  147. data/app/validators/redirect_uri_validator.rb +0 -34
  148. data/doorkeeper.gemspec +0 -29
  149. data/gemfiles/rails_4_2.gemfile +0 -11
  150. data/gemfiles/rails_5_0.gemfile +0 -12
  151. data/gemfiles/rails_5_1.gemfile +0 -13
  152. data/lib/doorkeeper/oauth/client_credentials/validation.rb +0 -45
  153. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb +0 -7
  154. data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb +0 -11
  155. data/lib/generators/doorkeeper/templates/migration.rb +0 -68
  156. data/spec/controllers/application_metal_controller.rb +0 -10
  157. data/spec/controllers/applications_controller_spec.rb +0 -58
  158. data/spec/controllers/authorizations_controller_spec.rb +0 -218
  159. data/spec/controllers/protected_resources_controller_spec.rb +0 -300
  160. data/spec/controllers/token_info_controller_spec.rb +0 -52
  161. data/spec/controllers/tokens_controller_spec.rb +0 -88
  162. data/spec/dummy/Rakefile +0 -7
  163. data/spec/dummy/app/controllers/application_controller.rb +0 -3
  164. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +0 -7
  165. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +0 -12
  166. data/spec/dummy/app/controllers/home_controller.rb +0 -17
  167. data/spec/dummy/app/controllers/metal_controller.rb +0 -11
  168. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +0 -11
  169. data/spec/dummy/app/helpers/application_helper.rb +0 -5
  170. data/spec/dummy/app/models/user.rb +0 -5
  171. data/spec/dummy/app/views/home/index.html.erb +0 -0
  172. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  173. data/spec/dummy/config/application.rb +0 -23
  174. data/spec/dummy/config/boot.rb +0 -9
  175. data/spec/dummy/config/database.yml +0 -15
  176. data/spec/dummy/config/environment.rb +0 -5
  177. data/spec/dummy/config/environments/development.rb +0 -29
  178. data/spec/dummy/config/environments/production.rb +0 -62
  179. data/spec/dummy/config/environments/test.rb +0 -44
  180. data/spec/dummy/config/initializers/active_record_belongs_to_required_by_default.rb +0 -6
  181. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  182. data/spec/dummy/config/initializers/doorkeeper.rb +0 -96
  183. data/spec/dummy/config/initializers/secret_token.rb +0 -9
  184. data/spec/dummy/config/initializers/session_store.rb +0 -8
  185. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
  186. data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
  187. data/spec/dummy/config/routes.rb +0 -52
  188. data/spec/dummy/config.ru +0 -4
  189. data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -9
  190. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -5
  191. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +0 -60
  192. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +0 -7
  193. data/spec/dummy/db/schema.rb +0 -67
  194. data/spec/dummy/public/404.html +0 -26
  195. data/spec/dummy/public/422.html +0 -26
  196. data/spec/dummy/public/500.html +0 -26
  197. data/spec/dummy/public/favicon.ico +0 -0
  198. data/spec/dummy/script/rails +0 -6
  199. data/spec/factories.rb +0 -28
  200. data/spec/generators/application_owner_generator_spec.rb +0 -22
  201. data/spec/generators/install_generator_spec.rb +0 -31
  202. data/spec/generators/migration_generator_spec.rb +0 -20
  203. data/spec/generators/templates/routes.rb +0 -3
  204. data/spec/generators/views_generator_spec.rb +0 -27
  205. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -24
  206. data/spec/lib/config_spec.rb +0 -334
  207. data/spec/lib/doorkeeper_spec.rb +0 -150
  208. data/spec/lib/models/expirable_spec.rb +0 -50
  209. data/spec/lib/models/revocable_spec.rb +0 -59
  210. data/spec/lib/models/scopes_spec.rb +0 -43
  211. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -41
  212. data/spec/lib/oauth/authorization_code_request_spec.rb +0 -80
  213. data/spec/lib/oauth/base_request_spec.rb +0 -160
  214. data/spec/lib/oauth/base_response_spec.rb +0 -45
  215. data/spec/lib/oauth/client/credentials_spec.rb +0 -88
  216. data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -44
  217. data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -86
  218. data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -54
  219. data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -27
  220. data/spec/lib/oauth/client_credentials_request_spec.rb +0 -104
  221. data/spec/lib/oauth/client_spec.rb +0 -39
  222. data/spec/lib/oauth/code_request_spec.rb +0 -45
  223. data/spec/lib/oauth/code_response_spec.rb +0 -34
  224. data/spec/lib/oauth/error_response_spec.rb +0 -61
  225. data/spec/lib/oauth/error_spec.rb +0 -23
  226. data/spec/lib/oauth/forbidden_token_response_spec.rb +0 -23
  227. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -64
  228. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -20
  229. data/spec/lib/oauth/helpers/uri_checker_spec.rb +0 -104
  230. data/spec/lib/oauth/invalid_token_response_spec.rb +0 -56
  231. data/spec/lib/oauth/password_access_token_request_spec.rb +0 -90
  232. data/spec/lib/oauth/pre_authorization_spec.rb +0 -155
  233. data/spec/lib/oauth/refresh_token_request_spec.rb +0 -154
  234. data/spec/lib/oauth/scopes_spec.rb +0 -122
  235. data/spec/lib/oauth/token_request_spec.rb +0 -98
  236. data/spec/lib/oauth/token_response_spec.rb +0 -85
  237. data/spec/lib/oauth/token_spec.rb +0 -116
  238. data/spec/lib/request/strategy_spec.rb +0 -53
  239. data/spec/lib/server_spec.rb +0 -49
  240. data/spec/models/doorkeeper/access_grant_spec.rb +0 -36
  241. data/spec/models/doorkeeper/access_token_spec.rb +0 -394
  242. data/spec/models/doorkeeper/application_spec.rb +0 -179
  243. data/spec/requests/applications/applications_request_spec.rb +0 -94
  244. data/spec/requests/applications/authorized_applications_spec.rb +0 -30
  245. data/spec/requests/endpoints/authorization_spec.rb +0 -71
  246. data/spec/requests/endpoints/token_spec.rb +0 -64
  247. data/spec/requests/flows/authorization_code_errors_spec.rb +0 -76
  248. data/spec/requests/flows/authorization_code_spec.rb +0 -148
  249. data/spec/requests/flows/client_credentials_spec.rb +0 -58
  250. data/spec/requests/flows/implicit_grant_errors_spec.rb +0 -32
  251. data/spec/requests/flows/implicit_grant_spec.rb +0 -61
  252. data/spec/requests/flows/password_spec.rb +0 -115
  253. data/spec/requests/flows/refresh_token_spec.rb +0 -174
  254. data/spec/requests/flows/revoke_token_spec.rb +0 -157
  255. data/spec/requests/flows/skip_authorization_spec.rb +0 -59
  256. data/spec/requests/protected_resources/metal_spec.rb +0 -14
  257. data/spec/requests/protected_resources/private_api_spec.rb +0 -81
  258. data/spec/routing/custom_controller_routes_spec.rb +0 -71
  259. data/spec/routing/default_routes_spec.rb +0 -35
  260. data/spec/routing/scoped_routes_spec.rb +0 -31
  261. data/spec/spec_helper.rb +0 -4
  262. data/spec/spec_helper_integration.rb +0 -63
  263. data/spec/support/dependencies/factory_girl.rb +0 -2
  264. data/spec/support/helpers/access_token_request_helper.rb +0 -11
  265. data/spec/support/helpers/authorization_request_helper.rb +0 -41
  266. data/spec/support/helpers/config_helper.rb +0 -9
  267. data/spec/support/helpers/model_helper.rb +0 -67
  268. data/spec/support/helpers/request_spec_helper.rb +0 -84
  269. data/spec/support/helpers/url_helper.rb +0 -55
  270. data/spec/support/http_method_shim.rb +0 -38
  271. data/spec/support/orm/active_record.rb +0 -3
  272. data/spec/support/shared/controllers_shared_context.rb +0 -69
  273. data/spec/support/shared/models_shared_examples.rb +0 -52
  274. data/spec/validators/redirect_uri_validator_spec.rb +0 -78
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class RefreshTokenRequest < BaseRequest
@@ -9,36 +11,37 @@ 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
37
39
  end
40
+ super
38
41
  end
39
42
 
40
43
  def refresh_token_revoked_on_use?
41
- Doorkeeper::AccessToken.refresh_token_revoked_on_use?
44
+ server_config.access_token_model.refresh_token_revoked_on_use?
42
45
  end
43
46
 
44
47
  def default_scopes
@@ -46,29 +49,46 @@ module Doorkeeper
46
49
  end
47
50
 
48
51
  def create_access_token
49
- @access_token = AccessToken.create!(access_token_attributes)
50
- end
52
+ attributes = {}
51
53
 
52
- def access_token_attributes
53
- {
54
- application_id: refresh_token.application_id,
55
- resource_owner_id: refresh_token.resource_owner_id,
56
- scopes: scopes.to_s,
57
- expires_in: access_token_expires_in,
58
- use_refresh_token: true
59
- }.tap do |attributes|
60
- if refresh_token_revoked_on_use?
61
- 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
62
59
  end
60
+
61
+ if refresh_token_revoked_on_use?
62
+ attributes[:previous_refresh_token] = refresh_token.refresh_token
63
63
  end
64
- end
65
64
 
66
- def access_token_expires_in
67
- 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
+ )
68
86
  end
69
87
 
70
88
  def validate_token_presence
71
- 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?
72
92
  end
73
93
 
74
94
  def validate_token
@@ -76,16 +96,25 @@ module Doorkeeper
76
96
  end
77
97
 
78
98
  def validate_client
79
- !credentials || !!client
99
+ return true if credentials.blank?
100
+
101
+ client.present?
80
102
  end
81
103
 
104
+ # @see https://datatracker.ietf.org/doc/html/rfc6749#section-1.5
105
+ #
82
106
  def validate_client_match
83
- !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
84
110
  end
85
111
 
86
112
  def validate_scope
87
113
  if @original_scopes.present?
88
- ScopeChecker.valid?(@original_scopes, refresh_token.scopes)
114
+ ScopeChecker.valid?(
115
+ scope_str: @original_scopes,
116
+ server_scopes: refresh_token.scopes,
117
+ )
89
118
  else
90
119
  true
91
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,28 +39,40 @@ 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
- if other.is_a? Scopes
49
- self.class.from_array(all + other.all)
50
- else
51
- super(other)
52
- end
52
+ self.class.from_array(all + to_array(other))
53
53
  end
54
54
 
55
55
  def <=>(other)
56
- map(&:to_s).sort <=> other.map(&:to_s).sort
56
+ if other.respond_to?(:map)
57
+ map(&:to_s).sort <=> other.map(&:to_s).sort
58
+ else
59
+ super
60
+ end
57
61
  end
58
62
 
59
63
  def &(other)
60
- other_array = other.present? ? other.all : []
61
- self.class.from_array(all & other_array)
64
+ self.class.from_array(all & to_array(other))
65
+ end
66
+
67
+ private
68
+
69
+ def to_array(other)
70
+ case other
71
+ when Scopes
72
+ other.all
73
+ else
74
+ other.to_a
75
+ end
62
76
  end
63
77
  end
64
78
  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
- if token = from_request(request, *methods)
15
- access_token = AccessToken.by_token(token)
16
- access_token.revoke_previous_refresh_token! if access_token
16
+ if (token = from_request(request, *methods))
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
@@ -0,0 +1,202 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module OAuth
5
+ # RFC7662 OAuth 2.0 Token Introspection
6
+ #
7
+ # @see https://datatracker.ietf.org/doc/html/rfc7662
8
+ class TokenIntrospection
9
+ def initialize(server, token)
10
+ @server = server
11
+ @token = token
12
+
13
+ authorize!
14
+ end
15
+
16
+ def authorized?
17
+ @error.blank?
18
+ end
19
+
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(*)
33
+ active? ? success_response : failure_response
34
+ end
35
+
36
+ private
37
+
38
+ attr_reader :server, :token
39
+ attr_reader :error, :invalid_request_reason
40
+
41
+ # If the protected resource uses OAuth 2.0 client credentials to
42
+ # authenticate to the introspection endpoint and its credentials are
43
+ # invalid, the authorization server responds with an HTTP 401
44
+ # (Unauthorized) as described in Section 5.2 of OAuth 2.0 [RFC6749].
45
+ #
46
+ # Endpoint must first validate the authentication.
47
+ # If the authentication is invalid, the endpoint should respond with
48
+ # an HTTP 401 status code and an invalid_client response.
49
+ #
50
+ # @see https://www.oauth.com/oauth2-servers/token-introspection-endpoint/
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
+ #
58
+ def authorize!
59
+ # Requested client authorization
60
+ if server.credentials
61
+ @error = :invalid_client unless authorized_client
62
+ elsif authorized_token
63
+ # Requested bearer token authorization
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
76
+ end
77
+ end
78
+
79
+ # Client Authentication
80
+ def authorized_client
81
+ @authorized_client ||= server.credentials && server.client
82
+ end
83
+
84
+ # Bearer Token Authentication
85
+ def authorized_token
86
+ @authorized_token ||= Doorkeeper.authenticate(server.context.request)
87
+ end
88
+
89
+ # 2.2. Introspection Response
90
+ def success_response
91
+ customize_response(
92
+ active: true,
93
+ scope: @token.scopes_string,
94
+ client_id: @token.try(:application).try(:uid),
95
+ token_type: @token.token_type,
96
+ exp: @token.expires_at.to_i,
97
+ iat: @token.created_at.to_i,
98
+ )
99
+ end
100
+
101
+ # If the introspection call is properly authorized but the token is not
102
+ # active, does not exist on this server, or the protected resource is
103
+ # not allowed to introspect this particular token, then the
104
+ # authorization server MUST return an introspection response with the
105
+ # "active" field set to "false". Note that to avoid disclosing too
106
+ # much of the authorization server's state to a third party, the
107
+ # authorization server SHOULD NOT include any additional information
108
+ # about an inactive token, including why the token is inactive.
109
+ #
110
+ # @see https://datatracker.ietf.org/doc/html/rfc7662 2.2. Introspection Response
111
+ #
112
+ def failure_response
113
+ {
114
+ active: false,
115
+ }
116
+ end
117
+
118
+ # Boolean indicator of whether or not the presented token
119
+ # is currently active. The specifics of a token's "active" state
120
+ # will vary depending on the implementation of the authorization
121
+ # server and the information it keeps about its tokens, but a "true"
122
+ # value return for the "active" property will generally indicate
123
+ # that a given token has been issued by this authorization server,
124
+ # has not been revoked by the resource owner, and is within its
125
+ # given time window of validity (e.g., after its issuance time and
126
+ # before its expiration time).
127
+ #
128
+ # Any other error is considered an "inactive" token.
129
+ #
130
+ # * The token requested does not exist or is invalid
131
+ # * The token expired
132
+ # * The token was issued to a different client than is making this request
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
+ #
153
+ def active?
154
+ if authorized_client
155
+ valid_token? && token_introspection_allowed?(auth_client: authorized_client.application)
156
+ else
157
+ valid_token?
158
+ end
159
+ end
160
+
161
+ # Token can be valid only if it is not expired or revoked.
162
+ def valid_token?
163
+ @token&.accessible?
164
+ end
165
+
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://datatracker.ietf.org/doc/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)
199
+ end
200
+ end
201
+ end
202
+ 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
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class TokenResponse
4
- attr_accessor :token
6
+ attr_reader :token
5
7
 
6
8
  def initialize(token)
7
9
  @token = token
@@ -9,12 +11,12 @@ module Doorkeeper
9
11
 
10
12
  def body
11
13
  {
12
- 'access_token' => token.token,
13
- 'token_type' => token.token_type,
14
- 'expires_in' => token.expires_in_seconds,
15
- 'refresh_token' => token.refresh_token,
16
- 'scope' => token.scopes_string,
17
- 'created_at' => token.created_at.to_i
14
+ "access_token" => token.plaintext_token,
15
+ "token_type" => token.token_type,
16
+ "expires_in" => token.expires_in_seconds,
17
+ "refresh_token" => token.plaintext_refresh_token,
18
+ "scope" => token.scopes_string,
19
+ "created_at" => token.created_at.to_i,
18
20
  }.reject { |_, value| value.blank? }
19
21
  end
20
22
 
@@ -23,9 +25,11 @@ module Doorkeeper
23
25
  end
24
26
 
25
27
  def headers
26
- { 'Cache-Control' => 'no-store',
27
- 'Pragma' => 'no-cache',
28
- 'Content-Type' => 'application/json; charset=utf-8' }
28
+ {
29
+ "Cache-Control" => "no-store",
30
+ "Pragma" => "no-cache",
31
+ "Content-Type" => "application/json; charset=utf-8",
32
+ }
29
33
  end
30
34
  end
31
35
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module OAuth
5
+ GRANT_TYPES = [
6
+ AUTHORIZATION_CODE = "authorization_code",
7
+ IMPLICIT = "implicit",
8
+ PASSWORD = "password",
9
+ CLIENT_CREDENTIALS = "client_credentials",
10
+ REFRESH_TOKEN = "refresh_token",
11
+ ].freeze
12
+ end
13
+ end
@@ -1,7 +1,9 @@
1
- module Doorkeeper
2
- class AccessGrant < ActiveRecord::Base
3
- self.table_name = "#{table_name_prefix}oauth_access_grants#{table_name_suffix}".to_sym
1
+ # frozen_string_literal: true
2
+
3
+ require "doorkeeper/orm/active_record/mixins/access_grant"
4
4
 
5
- include AccessGrantMixin
5
+ module Doorkeeper
6
+ class AccessGrant < ::ActiveRecord::Base
7
+ include Doorkeeper::Orm::ActiveRecord::Mixins::AccessGrant
6
8
  end
7
9
  end
@@ -1,46 +1,9 @@
1
- module Doorkeeper
2
- class AccessToken < ActiveRecord::Base
3
- self.table_name = "#{table_name_prefix}oauth_access_tokens#{table_name_suffix}".to_sym
4
-
5
- include AccessTokenMixin
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
1
+ # frozen_string_literal: true
18
2
 
19
- # Searches for not revoked Access Tokens associated with the
20
- # specific Resource Owner.
21
- #
22
- # @param resource_owner [ActiveRecord::Base]
23
- # Resource Owner model instance
24
- #
25
- # @return [ActiveRecord::Relation]
26
- # active Access Tokens for Resource Owner
27
- #
28
- def self.active_for(resource_owner)
29
- where(resource_owner_id: resource_owner.id, revoked_at: nil)
30
- end
3
+ require "doorkeeper/orm/active_record/mixins/access_token"
31
4
 
32
- # ORM-specific order method.
33
- def self.order_method
34
- :order
35
- end
36
-
37
- def self.refresh_token_revoked_on_use?
38
- column_names.include?('previous_refresh_token')
39
- end
40
-
41
- # ORM-specific DESC order for `:created_at` column.
42
- def self.created_at_desc
43
- 'created_at desc'
44
- end
5
+ module Doorkeeper
6
+ class AccessToken < ::ActiveRecord::Base
7
+ include Doorkeeper::Orm::ActiveRecord::Mixins::AccessToken
45
8
  end
46
9
  end
@@ -1,24 +1,10 @@
1
- module Doorkeeper
2
- class Application < ActiveRecord::Base
3
- self.table_name = "#{table_name_prefix}oauth_applications#{table_name_suffix}".to_sym
4
-
5
- include ApplicationMixin
1
+ # frozen_string_literal: true
6
2
 
7
- has_many :authorized_tokens, -> { where(revoked_at: nil) }, class_name: 'AccessToken'
8
- has_many :authorized_applications, through: :authorized_tokens, source: :application
3
+ require "doorkeeper/orm/active_record/redirect_uri_validator"
4
+ require "doorkeeper/orm/active_record/mixins/application"
9
5
 
10
- # Returns Applications associated with active (not revoked) Access Tokens
11
- # that are owned by the specific Resource Owner.
12
- #
13
- # @param resource_owner [ActiveRecord::Base]
14
- # Resource Owner model instance
15
- #
16
- # @return [ActiveRecord::Relation]
17
- # Applications authorized for the Resource Owner
18
- #
19
- def self.authorized_for(resource_owner)
20
- resource_access_tokens = AccessToken.active_for(resource_owner)
21
- where(id: resource_access_tokens.select(:application_id).distinct)
22
- end
6
+ module Doorkeeper
7
+ class Application < ::ActiveRecord::Base
8
+ include ::Doorkeeper::Orm::ActiveRecord::Mixins::Application
23
9
  end
24
10
  end