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
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module Models
5
+ module Orderable
6
+ extend ActiveSupport::Concern
7
+
8
+ module ClassMethods
9
+ def ordered_by(attribute, direction = :asc)
10
+ order(attribute => direction)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,20 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module Models
3
5
  module Ownership
4
6
  extend ActiveSupport::Concern
5
7
 
6
8
  included do
7
- belongs_to_options = { polymorphic: true }
8
- if defined?(ActiveRecord::Base) && ActiveRecord::VERSION::MAJOR >= 5
9
- belongs_to_options[:optional] = true
10
- end
11
-
12
- belongs_to :owner, belongs_to_options
9
+ belongs_to :owner, polymorphic: true, optional: true
13
10
  validates :owner, presence: true, if: :validate_owner?
14
11
  end
15
12
 
16
13
  def validate_owner?
17
- Doorkeeper.configuration.confirm_application_owner?
14
+ Doorkeeper.config.confirm_application_owner?
18
15
  end
19
16
  end
20
17
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module Models
5
+ module ResourceOwnerable
6
+ extend ActiveSupport::Concern
7
+
8
+ module ClassMethods
9
+ # Searches for record by Resource Owner considering Doorkeeper
10
+ # configuration for resource owner association.
11
+ #
12
+ # @param resource_owner [ActiveRecord::Base, Integer]
13
+ # resource owner
14
+ #
15
+ # @return [Doorkeeper::AccessGrant, Doorkeeper::AccessToken]
16
+ # collection of records
17
+ #
18
+ def by_resource_owner(resource_owner)
19
+ if Doorkeeper.configuration.polymorphic_resource_owner?
20
+ where(resource_owner: resource_owner)
21
+ else
22
+ where(resource_owner_id: resource_owner_id_for(resource_owner))
23
+ end
24
+ end
25
+
26
+ protected
27
+
28
+ # Backward compatible way to retrieve resource owner itself (if
29
+ # polymorphic association enabled) or just it's ID.
30
+ #
31
+ # @param resource_owner [ActiveRecord::Base, Integer]
32
+ # resource owner
33
+ #
34
+ # @return [ActiveRecord::Base, Integer]
35
+ # instance of Resource Owner or it's ID
36
+ #
37
+ def resource_owner_id_for(resource_owner)
38
+ if resource_owner.respond_to?(:to_key)
39
+ resource_owner.id
40
+ else
41
+ resource_owner
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module Models
5
+ module Reusable
6
+ # Indicates whether the object is reusable (i.e. It is not expired and
7
+ # has not crossed reuse_limit).
8
+ #
9
+ # @return [Boolean] true if can be reused and false in other case
10
+ def reusable?
11
+ return false if expired?
12
+ return true unless expires_in
13
+
14
+ threshold_limit = 100 - Doorkeeper.config.token_reuse_limit
15
+ expires_in_seconds >= threshold_limit * expires_in / 100
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module Models
3
5
  module Revocable
@@ -7,7 +9,7 @@ module Doorkeeper
7
9
  # @param clock [Time] time object
8
10
  #
9
11
  def revoke(clock = Time)
10
- update_attribute :revoked_at, clock.now.utc
12
+ update_attribute(:revoked_at, clock.now.utc)
11
13
  end
12
14
 
13
15
  # Indicates whether the object has been revoked.
@@ -17,32 +19,6 @@ module Doorkeeper
17
19
  def revoked?
18
20
  !!(revoked_at && revoked_at <= Time.now.utc)
19
21
  end
20
-
21
- # Revokes token with `:refresh_token` equal to `:previous_refresh_token`
22
- # and clears `:previous_refresh_token` attribute.
23
- #
24
- def revoke_previous_refresh_token!
25
- return unless refresh_token_revoked_on_use?
26
- old_refresh_token.revoke if old_refresh_token
27
- update_attribute :previous_refresh_token, ""
28
- end
29
-
30
- private
31
-
32
- # Searches for Access Token record with `:refresh_token` equal to
33
- # `:previous_refresh_token` value.
34
- #
35
- # @return [Doorkeeper::AccessToken, nil]
36
- # Access Token record or nil if nothing found
37
- #
38
- def old_refresh_token
39
- @old_refresh_token ||=
40
- AccessToken.by_refresh_token(previous_refresh_token)
41
- end
42
-
43
- def refresh_token_revoked_on_use?
44
- AccessToken.refresh_token_revoked_on_use?
45
- end
46
22
  end
47
23
  end
48
24
  end
@@ -1,8 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module Models
3
5
  module Scopes
4
6
  def scopes
5
- OAuth::Scopes.from_string(self[:scopes])
7
+ OAuth::Scopes.from_string(scopes_string)
8
+ end
9
+
10
+ def scopes=(value)
11
+ if value.is_a?(Array)
12
+ super(Doorkeeper::OAuth::Scopes.from_array(value).to_s)
13
+ else
14
+ super(Doorkeeper::OAuth::Scopes.from_string(value.to_s).to_s)
15
+ end
6
16
  end
7
17
 
8
18
  def scopes_string
@@ -10,7 +20,7 @@ module Doorkeeper
10
20
  end
11
21
 
12
22
  def includes_scope?(*required_scopes)
13
- required_scopes.blank? || required_scopes.any? { |s| scopes.exists?(s.to_s) }
23
+ required_scopes.blank? || required_scopes.any? { |scope| scopes.exists?(scope.to_s) }
14
24
  end
15
25
  end
16
26
  end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module Models
5
+ ##
6
+ # Storable finder to provide lookups for input plaintext values which are
7
+ # mapped to their stored versions (e.g., hashing, encryption) before lookup.
8
+ module SecretStorable
9
+ extend ActiveSupport::Concern
10
+
11
+ delegate :secret_strategy,
12
+ :fallback_secret_strategy,
13
+ to: :class
14
+
15
+ # :nodoc
16
+ module ClassMethods
17
+ # Compare the given plaintext with the secret
18
+ #
19
+ # @param input [String]
20
+ # The plain input to compare.
21
+ #
22
+ # @param secret [String]
23
+ # The secret value to compare with.
24
+ #
25
+ # @return [Boolean]
26
+ # Whether input matches secret as per the secret strategy
27
+ #
28
+ delegate :secret_matches?, to: :secret_strategy
29
+
30
+ # Returns an instance of the Doorkeeper::AccessToken with
31
+ # specific token value.
32
+ #
33
+ # @param attr [Symbol]
34
+ # The token attribute we're looking with.
35
+ #
36
+ # @param token [#to_s]
37
+ # token value (any object that responds to `#to_s`)
38
+ #
39
+ # @return [Doorkeeper::AccessToken, nil] AccessToken object or nil
40
+ # if there is no record with such token
41
+ #
42
+ def find_by_plaintext_token(attr, token)
43
+ token = token.to_s
44
+
45
+ find_by(attr => secret_strategy.transform_secret(token)) ||
46
+ find_by_fallback_token(attr, token)
47
+ end
48
+
49
+ # Allow looking up previously plain tokens as a fallback
50
+ # IFF a fallback strategy has been defined
51
+ #
52
+ # @param attr [Symbol]
53
+ # The token attribute we're looking with.
54
+ #
55
+ # @param plain_secret [#to_s]
56
+ # plain secret value (any object that responds to `#to_s`)
57
+ #
58
+ # @return [Doorkeeper::AccessToken, nil] AccessToken object or nil
59
+ # if there is no record with such token
60
+ #
61
+ def find_by_fallback_token(attr, plain_secret)
62
+ return nil unless fallback_secret_strategy
63
+
64
+ # Use the previous strategy to look up
65
+ stored_token = fallback_secret_strategy.transform_secret(plain_secret)
66
+ find_by(attr => stored_token).tap do |resource|
67
+ return nil unless resource
68
+
69
+ upgrade_fallback_value resource, attr, plain_secret
70
+ end
71
+ end
72
+
73
+ # Allow implementations in ORMs to replace a plain
74
+ # value falling back to to avoid it remaining as plain text.
75
+ #
76
+ # @param instance
77
+ # An instance of this model with a plain value token.
78
+ #
79
+ # @param attr
80
+ # The secret attribute name to upgrade.
81
+ #
82
+ # @param plain_secret
83
+ # The plain secret to upgrade.
84
+ #
85
+ def upgrade_fallback_value(instance, attr, plain_secret)
86
+ upgraded = secret_strategy.store_secret(instance, attr, plain_secret)
87
+ instance.update(attr => upgraded)
88
+ end
89
+
90
+ ##
91
+ # Determines the secret storing transformer
92
+ # Unless configured otherwise, uses the plain secret strategy
93
+ def secret_strategy
94
+ ::Doorkeeper::SecretStoring::Plain
95
+ end
96
+
97
+ ##
98
+ # Determine the fallback storing strategy
99
+ # Unless configured, there will be no fallback
100
+ def fallback_secret_strategy
101
+ nil
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -1,30 +1,66 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  module Authorization
4
6
  class Code
5
- attr_accessor :pre_auth, :resource_owner, :token
7
+ attr_reader :pre_auth, :resource_owner, :token
6
8
 
7
9
  def initialize(pre_auth, resource_owner)
8
- @pre_auth = pre_auth
10
+ @pre_auth = pre_auth
9
11
  @resource_owner = resource_owner
10
12
  end
11
13
 
12
- def issue_token
13
- @token ||= AccessGrant.create!(
14
+ def issue_token!
15
+ return @token if defined?(@token)
16
+
17
+ @token = Doorkeeper.config.access_grant_model.create!(access_grant_attributes)
18
+ end
19
+
20
+ def oob_redirect
21
+ { action: :show, code: token.plaintext_token }
22
+ end
23
+
24
+ def access_grant?
25
+ true
26
+ end
27
+
28
+ private
29
+
30
+ def authorization_code_expires_in
31
+ Doorkeeper.config.authorization_code_expires_in
32
+ end
33
+
34
+ def access_grant_attributes
35
+ attributes = {
14
36
  application_id: pre_auth.client.id,
15
- resource_owner_id: resource_owner.id,
16
- expires_in: configuration.authorization_code_expires_in,
37
+ expires_in: authorization_code_expires_in,
17
38
  redirect_uri: pre_auth.redirect_uri,
18
- scopes: pre_auth.scopes.to_s
19
- )
39
+ scopes: pre_auth.scopes.to_s,
40
+ }
41
+
42
+ if Doorkeeper.config.polymorphic_resource_owner?
43
+ attributes[:resource_owner] = resource_owner
44
+ else
45
+ attributes[:resource_owner_id] = resource_owner.id
46
+ end
47
+
48
+ pkce_attributes.merge(attributes)
20
49
  end
21
50
 
22
- def native_redirect
23
- { action: :show, code: token.token }
51
+ def pkce_attributes
52
+ return {} unless pkce_supported?
53
+
54
+ {
55
+ code_challenge: pre_auth.code_challenge,
56
+ code_challenge_method: pre_auth.code_challenge_method,
57
+ }
24
58
  end
25
59
 
26
- def configuration
27
- Doorkeeper.configuration
60
+ # Ensures firstly, if migration with additional PKCE columns was
61
+ # generated and migrated
62
+ def pkce_supported?
63
+ Doorkeeper.config.access_grant_model.pkce_supported?
28
64
  end
29
65
  end
30
66
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module OAuth
5
+ module Authorization
6
+ class Context
7
+ attr_reader :client, :grant_type, :resource_owner, :scopes
8
+
9
+ def initialize(**attributes)
10
+ attributes.each do |name, value|
11
+ instance_variable_set(:"@#{name}", value) if respond_to?(name)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,54 +1,92 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  module Authorization
4
6
  class Token
5
- attr_accessor :pre_auth, :resource_owner, :token
7
+ attr_reader :pre_auth, :resource_owner, :token
8
+
9
+ class << self
10
+ def build_context(pre_auth_or_oauth_client, grant_type, scopes, resource_owner)
11
+ oauth_client = if pre_auth_or_oauth_client.respond_to?(:application)
12
+ pre_auth_or_oauth_client.application
13
+ elsif pre_auth_or_oauth_client.respond_to?(:client)
14
+ pre_auth_or_oauth_client.client
15
+ else
16
+ pre_auth_or_oauth_client
17
+ end
18
+
19
+ Doorkeeper::OAuth::Authorization::Context.new(
20
+ client: oauth_client,
21
+ grant_type: grant_type,
22
+ scopes: scopes,
23
+ resource_owner: resource_owner,
24
+ )
25
+ end
26
+
27
+ def access_token_expires_in(configuration, context)
28
+ if configuration.option_defined?(:custom_access_token_expires_in)
29
+ expiration = configuration.custom_access_token_expires_in.call(context)
30
+ return nil if expiration == Float::INFINITY
31
+
32
+ expiration || configuration.access_token_expires_in
33
+ else
34
+ configuration.access_token_expires_in
35
+ end
36
+ end
37
+
38
+ def refresh_token_enabled?(server, context)
39
+ if server.refresh_token_enabled?.respond_to?(:call)
40
+ server.refresh_token_enabled?.call(context)
41
+ else
42
+ !!server.refresh_token_enabled?
43
+ end
44
+ end
45
+ end
6
46
 
7
47
  def initialize(pre_auth, resource_owner)
8
48
  @pre_auth = pre_auth
9
49
  @resource_owner = resource_owner
10
50
  end
11
51
 
12
- def self.access_token_expires_in(server, pre_auth_or_oauth_client)
13
- if expiration = custom_expiration(server, pre_auth_or_oauth_client)
14
- expiration
15
- else
16
- server.access_token_expires_in
17
- end
18
- end
52
+ def issue_token!
53
+ return @token if defined?(@token)
19
54
 
20
- def issue_token
21
- @token ||= AccessToken.find_or_create_for(
55
+ context = self.class.build_context(
22
56
  pre_auth.client,
23
- resource_owner.id,
57
+ Doorkeeper::OAuth::IMPLICIT,
24
58
  pre_auth.scopes,
25
- self.class.access_token_expires_in(configuration, pre_auth),
26
- false
59
+ resource_owner,
60
+ )
61
+
62
+ @token = Doorkeeper.config.access_token_model.find_or_create_for(
63
+ application: pre_auth.client,
64
+ resource_owner: resource_owner,
65
+ scopes: pre_auth.scopes,
66
+ expires_in: self.class.access_token_expires_in(Doorkeeper.config, context),
67
+ use_refresh_token: false,
27
68
  )
28
69
  end
29
70
 
30
- def native_redirect
71
+ def oob_redirect
31
72
  {
32
- controller: 'doorkeeper/token_info',
73
+ controller: controller,
33
74
  action: :show,
34
- access_token: token.token
75
+ access_token: token.plaintext_token,
35
76
  }
36
77
  end
37
78
 
38
- private
39
-
40
- def self.custom_expiration(server, pre_auth_or_oauth_client)
41
- oauth_client = if pre_auth_or_oauth_client.respond_to?(:client)
42
- pre_auth_or_oauth_client.client
43
- else
44
- pre_auth_or_oauth_client
45
- end
46
-
47
- server.custom_access_token_expires_in.call(oauth_client)
79
+ def access_token?
80
+ true
48
81
  end
49
82
 
50
- def configuration
51
- Doorkeeper.configuration
83
+ private
84
+
85
+ def controller
86
+ @controller ||= begin
87
+ mapping = Doorkeeper::Rails::Routes.mapping[:token_info] || {}
88
+ mapping[:controllers] || "doorkeeper/token_info"
89
+ end
52
90
  end
53
91
  end
54
92
  end
@@ -1,4 +1,6 @@
1
- require 'rack/utils'
1
+ # frozen_string_literal: true
2
+
3
+ require "rack/utils"
2
4
 
3
5
  module Doorkeeper
4
6
  module OAuth
@@ -6,9 +8,9 @@ module Doorkeeper
6
8
  class URIBuilder
7
9
  class << self
8
10
  def uri_with_query(url, parameters = {})
9
- uri = URI.parse(url)
11
+ uri = URI.parse(url)
10
12
  original_query = Rack::Utils.parse_query(uri.query)
11
- uri.query = build_query(original_query.merge(parameters))
13
+ uri.query = build_query(original_query.merge(parameters))
12
14
  uri.to_s
13
15
  end
14
16
 
@@ -21,8 +23,8 @@ module Doorkeeper
21
23
  private
22
24
 
23
25
  def build_query(parameters = {})
24
- parameters = parameters.reject { |_, v| v.blank? }
25
- Rack::Utils.build_query parameters
26
+ parameters.reject! { |_, value| value.blank? }
27
+ Rack::Utils.build_query(parameters)
26
28
  end
27
29
  end
28
30
  end
@@ -1,18 +1,25 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class AuthorizationCodeRequest < BaseRequest
4
- validate :attributes, error: :invalid_request
6
+ validate :params, error: :invalid_request
5
7
  validate :client, error: :invalid_client
6
8
  validate :grant, error: :invalid_grant
9
+ # @see https://datatracker.ietf.org/doc/html/rfc6749#section-5.2
7
10
  validate :redirect_uri, error: :invalid_grant
11
+ validate :code_verifier, error: :invalid_grant
8
12
 
9
- attr_accessor :server, :grant, :client, :redirect_uri, :access_token
13
+ attr_reader :grant, :client, :redirect_uri, :access_token, :code_verifier,
14
+ :invalid_request_reason, :missing_param
10
15
 
11
16
  def initialize(server, grant, client, parameters = {})
12
17
  @server = server
13
18
  @client = client
14
19
  @grant = grant
20
+ @grant_type = Doorkeeper::OAuth::AUTHORIZATION_CODE
15
21
  @redirect_uri = parameters[:redirect_uri]
22
+ @code_verifier = parameters[:code_verifier]
16
23
  end
17
24
 
18
25
  private
@@ -23,28 +30,74 @@ module Doorkeeper
23
30
  raise Errors::InvalidGrantReuse if grant.revoked?
24
31
 
25
32
  grant.revoke
26
- find_or_create_access_token(grant.application,
27
- grant.resource_owner_id,
28
- grant.scopes,
29
- server)
33
+
34
+ find_or_create_access_token(
35
+ grant.application,
36
+ resource_owner,
37
+ grant.scopes,
38
+ server,
39
+ )
40
+ end
41
+
42
+ super
43
+ end
44
+
45
+ def resource_owner
46
+ if Doorkeeper.config.polymorphic_resource_owner?
47
+ grant.resource_owner
48
+ else
49
+ grant.resource_owner_id
30
50
  end
31
51
  end
32
52
 
33
- def validate_attributes
34
- redirect_uri.present?
53
+ def pkce_supported?
54
+ Doorkeeper.config.access_grant_model.pkce_supported?
55
+ end
56
+
57
+ def validate_params
58
+ @missing_param = if grant&.uses_pkce? && code_verifier.blank?
59
+ :code_verifier
60
+ elsif redirect_uri.blank?
61
+ :redirect_uri
62
+ end
63
+
64
+ @missing_param.nil?
35
65
  end
36
66
 
37
67
  def validate_client
38
- !!client
68
+ client.present?
39
69
  end
40
70
 
41
71
  def validate_grant
42
72
  return false unless grant && grant.application_id == client.id
73
+
43
74
  grant.accessible?
44
75
  end
45
76
 
46
77
  def validate_redirect_uri
47
- grant.redirect_uri == redirect_uri
78
+ Helpers::URIChecker.valid_for_authorization?(
79
+ redirect_uri,
80
+ grant.redirect_uri,
81
+ )
82
+ end
83
+
84
+ # if either side (server or client) request PKCE, check the verifier
85
+ # against the DB - if PKCE is supported
86
+ def validate_code_verifier
87
+ return true unless pkce_supported?
88
+ return grant.code_challenge.blank? if code_verifier.blank?
89
+
90
+ if grant.code_challenge_method == "S256"
91
+ grant.code_challenge == generate_code_challenge(code_verifier)
92
+ elsif grant.code_challenge_method == "plain"
93
+ grant.code_challenge == code_verifier
94
+ else
95
+ false
96
+ end
97
+ end
98
+
99
+ def generate_code_challenge(code_verifier)
100
+ server_config.access_grant_model.generate_code_challenge(code_verifier)
48
101
  end
49
102
  end
50
103
  end