doorkeeper 5.1.0 → 5.5.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of doorkeeper might be problematic. Click here for more details.

Files changed (265) hide show
  1. checksums.yaml +4 -4
  2. data/{NEWS.md → CHANGELOG.md} +234 -25
  3. data/README.md +21 -11
  4. data/app/controllers/doorkeeper/application_controller.rb +2 -2
  5. data/app/controllers/doorkeeper/application_metal_controller.rb +3 -2
  6. data/app/controllers/doorkeeper/applications_controller.rb +8 -7
  7. data/app/controllers/doorkeeper/authorizations_controller.rb +56 -19
  8. data/app/controllers/doorkeeper/authorized_applications_controller.rb +5 -5
  9. data/app/controllers/doorkeeper/token_info_controller.rb +12 -2
  10. data/app/controllers/doorkeeper/tokens_controller.rb +93 -25
  11. data/app/views/doorkeeper/applications/_form.html.erb +1 -7
  12. data/app/views/doorkeeper/applications/show.html.erb +35 -14
  13. data/app/views/doorkeeper/authorizations/form_post.html.erb +11 -0
  14. data/config/locales/en.yml +13 -3
  15. data/lib/doorkeeper/config/abstract_builder.rb +28 -0
  16. data/lib/doorkeeper/config/option.rb +20 -2
  17. data/lib/doorkeeper/config/validations.rb +53 -0
  18. data/lib/doorkeeper/config.rb +291 -121
  19. data/lib/doorkeeper/engine.rb +1 -1
  20. data/lib/doorkeeper/errors.rb +13 -18
  21. data/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
  22. data/lib/doorkeeper/grant_flow/flow.rb +44 -0
  23. data/lib/doorkeeper/grant_flow/registry.rb +50 -0
  24. data/lib/doorkeeper/grant_flow.rb +45 -0
  25. data/lib/doorkeeper/grape/helpers.rb +7 -3
  26. data/lib/doorkeeper/helpers/controller.rb +36 -11
  27. data/lib/doorkeeper/models/access_grant_mixin.rb +22 -18
  28. data/lib/doorkeeper/models/access_token_mixin.rb +194 -51
  29. data/lib/doorkeeper/models/application_mixin.rb +8 -7
  30. data/lib/doorkeeper/models/concerns/ownership.rb +1 -1
  31. data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
  32. data/lib/doorkeeper/models/concerns/reusable.rb +1 -1
  33. data/lib/doorkeeper/models/concerns/revocable.rb +1 -28
  34. data/lib/doorkeeper/models/concerns/scopes.rb +5 -1
  35. data/lib/doorkeeper/models/concerns/secret_storable.rb +1 -3
  36. data/lib/doorkeeper/oauth/authorization/code.rb +25 -14
  37. data/lib/doorkeeper/oauth/authorization/context.rb +5 -5
  38. data/lib/doorkeeper/oauth/authorization/token.rb +24 -19
  39. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +4 -4
  40. data/lib/doorkeeper/oauth/authorization_code_request.rb +40 -21
  41. data/lib/doorkeeper/oauth/base_request.rb +21 -23
  42. data/lib/doorkeeper/oauth/client/credentials.rb +2 -4
  43. data/lib/doorkeeper/oauth/client.rb +8 -9
  44. data/lib/doorkeeper/oauth/client_credentials/creator.rb +45 -5
  45. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +10 -8
  46. data/lib/doorkeeper/oauth/client_credentials/{validation.rb → validator.rb} +13 -3
  47. data/lib/doorkeeper/oauth/client_credentials_request.rb +8 -7
  48. data/lib/doorkeeper/oauth/code_request.rb +6 -12
  49. data/lib/doorkeeper/oauth/code_response.rb +24 -14
  50. data/lib/doorkeeper/oauth/error.rb +1 -1
  51. data/lib/doorkeeper/oauth/error_response.rb +10 -11
  52. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +8 -12
  53. data/lib/doorkeeper/oauth/helpers/unique_token.rb +8 -5
  54. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +19 -5
  55. data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
  56. data/lib/doorkeeper/oauth/invalid_request_response.rb +43 -0
  57. data/lib/doorkeeper/oauth/invalid_token_response.rb +7 -4
  58. data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
  59. data/lib/doorkeeper/oauth/password_access_token_request.rb +32 -10
  60. data/lib/doorkeeper/oauth/pre_authorization.rb +111 -42
  61. data/lib/doorkeeper/oauth/refresh_token_request.rb +45 -33
  62. data/lib/doorkeeper/oauth/token.rb +6 -7
  63. data/lib/doorkeeper/oauth/token_introspection.rb +24 -18
  64. data/lib/doorkeeper/oauth/token_request.rb +6 -20
  65. data/lib/doorkeeper/oauth/token_response.rb +1 -1
  66. data/lib/doorkeeper/orm/active_record/access_grant.rb +4 -43
  67. data/lib/doorkeeper/orm/active_record/access_token.rb +4 -35
  68. data/lib/doorkeeper/orm/active_record/application.rb +5 -83
  69. data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +68 -0
  70. data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +59 -0
  71. data/lib/doorkeeper/orm/active_record/mixins/application.rb +198 -0
  72. data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +66 -0
  73. data/lib/doorkeeper/orm/active_record.rb +20 -6
  74. data/lib/doorkeeper/rails/helpers.rb +4 -4
  75. data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
  76. data/lib/doorkeeper/rails/routes/mapper.rb +2 -2
  77. data/lib/doorkeeper/rails/routes/registry.rb +45 -0
  78. data/lib/doorkeeper/rails/routes.rb +17 -25
  79. data/lib/doorkeeper/rake/db.rake +6 -6
  80. data/lib/doorkeeper/rake/setup.rake +5 -0
  81. data/lib/doorkeeper/request/authorization_code.rb +5 -3
  82. data/lib/doorkeeper/request/client_credentials.rb +2 -2
  83. data/lib/doorkeeper/request/password.rb +2 -2
  84. data/lib/doorkeeper/request/refresh_token.rb +5 -4
  85. data/lib/doorkeeper/request/strategy.rb +2 -2
  86. data/lib/doorkeeper/request.rb +49 -17
  87. data/lib/doorkeeper/server.rb +7 -11
  88. data/lib/doorkeeper/stale_records_cleaner.rb +6 -2
  89. data/lib/doorkeeper/version.rb +1 -5
  90. data/lib/doorkeeper.rb +114 -79
  91. data/lib/generators/doorkeeper/application_owner_generator.rb +1 -1
  92. data/lib/generators/doorkeeper/confidential_applications_generator.rb +2 -2
  93. data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
  94. data/lib/generators/doorkeeper/migration_generator.rb +1 -1
  95. data/lib/generators/doorkeeper/pkce_generator.rb +1 -1
  96. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +7 -7
  97. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +3 -1
  98. data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +2 -0
  99. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +2 -0
  100. data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
  101. data/lib/generators/doorkeeper/templates/initializer.rb +205 -43
  102. data/lib/generators/doorkeeper/templates/migration.rb.erb +18 -6
  103. metadata +43 -310
  104. data/.coveralls.yml +0 -1
  105. data/.github/ISSUE_TEMPLATE.md +0 -25
  106. data/.github/PULL_REQUEST_TEMPLATE.md +0 -17
  107. data/.gitignore +0 -20
  108. data/.gitlab-ci.yml +0 -16
  109. data/.hound.yml +0 -3
  110. data/.rspec +0 -1
  111. data/.rubocop.yml +0 -50
  112. data/.travis.yml +0 -35
  113. data/Appraisals +0 -40
  114. data/CODE_OF_CONDUCT.md +0 -46
  115. data/CONTRIBUTING.md +0 -47
  116. data/Dangerfile +0 -67
  117. data/Gemfile +0 -24
  118. data/RELEASING.md +0 -10
  119. data/Rakefile +0 -28
  120. data/SECURITY.md +0 -15
  121. data/UPGRADE.md +0 -2
  122. data/app/validators/redirect_uri_validator.rb +0 -50
  123. data/bin/console +0 -16
  124. data/doorkeeper.gemspec +0 -34
  125. data/gemfiles/rails_5_0.gemfile +0 -17
  126. data/gemfiles/rails_5_1.gemfile +0 -17
  127. data/gemfiles/rails_5_2.gemfile +0 -17
  128. data/gemfiles/rails_6_0.gemfile +0 -17
  129. data/gemfiles/rails_master.gemfile +0 -17
  130. data/spec/controllers/application_metal_controller_spec.rb +0 -64
  131. data/spec/controllers/applications_controller_spec.rb +0 -180
  132. data/spec/controllers/authorizations_controller_spec.rb +0 -527
  133. data/spec/controllers/protected_resources_controller_spec.rb +0 -353
  134. data/spec/controllers/token_info_controller_spec.rb +0 -50
  135. data/spec/controllers/tokens_controller_spec.rb +0 -330
  136. data/spec/dummy/Rakefile +0 -9
  137. data/spec/dummy/app/assets/config/manifest.js +0 -2
  138. data/spec/dummy/app/controllers/application_controller.rb +0 -5
  139. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +0 -9
  140. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +0 -14
  141. data/spec/dummy/app/controllers/home_controller.rb +0 -18
  142. data/spec/dummy/app/controllers/metal_controller.rb +0 -13
  143. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +0 -13
  144. data/spec/dummy/app/helpers/application_helper.rb +0 -7
  145. data/spec/dummy/app/models/user.rb +0 -7
  146. data/spec/dummy/app/views/home/index.html.erb +0 -0
  147. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  148. data/spec/dummy/config/application.rb +0 -47
  149. data/spec/dummy/config/boot.rb +0 -7
  150. data/spec/dummy/config/database.yml +0 -15
  151. data/spec/dummy/config/environment.rb +0 -5
  152. data/spec/dummy/config/environments/development.rb +0 -31
  153. data/spec/dummy/config/environments/production.rb +0 -64
  154. data/spec/dummy/config/environments/test.rb +0 -45
  155. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -9
  156. data/spec/dummy/config/initializers/doorkeeper.rb +0 -121
  157. data/spec/dummy/config/initializers/secret_token.rb +0 -10
  158. data/spec/dummy/config/initializers/session_store.rb +0 -10
  159. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -16
  160. data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
  161. data/spec/dummy/config/routes.rb +0 -13
  162. data/spec/dummy/config.ru +0 -6
  163. data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -11
  164. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -7
  165. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +0 -69
  166. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +0 -9
  167. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +0 -13
  168. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +0 -8
  169. data/spec/dummy/db/migrate/20180210183654_add_confidential_to_applications.rb +0 -13
  170. data/spec/dummy/db/schema.rb +0 -68
  171. data/spec/dummy/public/404.html +0 -26
  172. data/spec/dummy/public/422.html +0 -26
  173. data/spec/dummy/public/500.html +0 -26
  174. data/spec/dummy/public/favicon.ico +0 -0
  175. data/spec/dummy/script/rails +0 -9
  176. data/spec/factories.rb +0 -30
  177. data/spec/generators/application_owner_generator_spec.rb +0 -28
  178. data/spec/generators/confidential_applications_generator_spec.rb +0 -29
  179. data/spec/generators/install_generator_spec.rb +0 -36
  180. data/spec/generators/migration_generator_spec.rb +0 -28
  181. data/spec/generators/pkce_generator_spec.rb +0 -28
  182. data/spec/generators/previous_refresh_token_generator_spec.rb +0 -44
  183. data/spec/generators/templates/routes.rb +0 -4
  184. data/spec/generators/views_generator_spec.rb +0 -29
  185. data/spec/grape/grape_integration_spec.rb +0 -137
  186. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -26
  187. data/spec/lib/config_spec.rb +0 -697
  188. data/spec/lib/doorkeeper_spec.rb +0 -27
  189. data/spec/lib/models/expirable_spec.rb +0 -61
  190. data/spec/lib/models/reusable_spec.rb +0 -40
  191. data/spec/lib/models/revocable_spec.rb +0 -59
  192. data/spec/lib/models/scopes_spec.rb +0 -53
  193. data/spec/lib/models/secret_storable_spec.rb +0 -135
  194. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -39
  195. data/spec/lib/oauth/authorization_code_request_spec.rb +0 -156
  196. data/spec/lib/oauth/base_request_spec.rb +0 -205
  197. data/spec/lib/oauth/base_response_spec.rb +0 -47
  198. data/spec/lib/oauth/client/credentials_spec.rb +0 -90
  199. data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -94
  200. data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -112
  201. data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -59
  202. data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -29
  203. data/spec/lib/oauth/client_credentials_request_spec.rb +0 -109
  204. data/spec/lib/oauth/client_spec.rb +0 -38
  205. data/spec/lib/oauth/code_request_spec.rb +0 -47
  206. data/spec/lib/oauth/code_response_spec.rb +0 -36
  207. data/spec/lib/oauth/error_response_spec.rb +0 -66
  208. data/spec/lib/oauth/error_spec.rb +0 -23
  209. data/spec/lib/oauth/forbidden_token_response_spec.rb +0 -22
  210. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -98
  211. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -21
  212. data/spec/lib/oauth/helpers/uri_checker_spec.rb +0 -247
  213. data/spec/lib/oauth/invalid_token_response_spec.rb +0 -55
  214. data/spec/lib/oauth/password_access_token_request_spec.rb +0 -192
  215. data/spec/lib/oauth/pre_authorization_spec.rb +0 -215
  216. data/spec/lib/oauth/refresh_token_request_spec.rb +0 -177
  217. data/spec/lib/oauth/scopes_spec.rb +0 -148
  218. data/spec/lib/oauth/token_request_spec.rb +0 -150
  219. data/spec/lib/oauth/token_response_spec.rb +0 -86
  220. data/spec/lib/oauth/token_spec.rb +0 -158
  221. data/spec/lib/request/strategy_spec.rb +0 -54
  222. data/spec/lib/secret_storing/base_spec.rb +0 -60
  223. data/spec/lib/secret_storing/bcrypt_spec.rb +0 -49
  224. data/spec/lib/secret_storing/plain_spec.rb +0 -44
  225. data/spec/lib/secret_storing/sha256_hash_spec.rb +0 -48
  226. data/spec/lib/server_spec.rb +0 -61
  227. data/spec/lib/stale_records_cleaner_spec.rb +0 -89
  228. data/spec/models/doorkeeper/access_grant_spec.rb +0 -144
  229. data/spec/models/doorkeeper/access_token_spec.rb +0 -591
  230. data/spec/models/doorkeeper/application_spec.rb +0 -367
  231. data/spec/requests/applications/applications_request_spec.rb +0 -259
  232. data/spec/requests/applications/authorized_applications_spec.rb +0 -32
  233. data/spec/requests/endpoints/authorization_spec.rb +0 -73
  234. data/spec/requests/endpoints/token_spec.rb +0 -75
  235. data/spec/requests/flows/authorization_code_errors_spec.rb +0 -78
  236. data/spec/requests/flows/authorization_code_spec.rb +0 -447
  237. data/spec/requests/flows/client_credentials_spec.rb +0 -128
  238. data/spec/requests/flows/implicit_grant_errors_spec.rb +0 -34
  239. data/spec/requests/flows/implicit_grant_spec.rb +0 -90
  240. data/spec/requests/flows/password_spec.rb +0 -259
  241. data/spec/requests/flows/refresh_token_spec.rb +0 -233
  242. data/spec/requests/flows/revoke_token_spec.rb +0 -143
  243. data/spec/requests/flows/skip_authorization_spec.rb +0 -66
  244. data/spec/requests/protected_resources/metal_spec.rb +0 -16
  245. data/spec/requests/protected_resources/private_api_spec.rb +0 -83
  246. data/spec/routing/custom_controller_routes_spec.rb +0 -133
  247. data/spec/routing/default_routes_spec.rb +0 -41
  248. data/spec/routing/scoped_routes_spec.rb +0 -47
  249. data/spec/spec_helper.rb +0 -57
  250. data/spec/spec_helper_integration.rb +0 -4
  251. data/spec/support/dependencies/factory_bot.rb +0 -4
  252. data/spec/support/doorkeeper_rspec.rb +0 -22
  253. data/spec/support/helpers/access_token_request_helper.rb +0 -13
  254. data/spec/support/helpers/authorization_request_helper.rb +0 -43
  255. data/spec/support/helpers/config_helper.rb +0 -11
  256. data/spec/support/helpers/model_helper.rb +0 -78
  257. data/spec/support/helpers/request_spec_helper.rb +0 -98
  258. data/spec/support/helpers/url_helper.rb +0 -62
  259. data/spec/support/http_method_shim.rb +0 -29
  260. data/spec/support/orm/active_record.rb +0 -5
  261. data/spec/support/shared/controllers_shared_context.rb +0 -123
  262. data/spec/support/shared/hashing_shared_context.rb +0 -36
  263. data/spec/support/shared/models_shared_examples.rb +0 -54
  264. data/spec/validators/redirect_uri_validator_spec.rb +0 -158
  265. data/spec/version/version_spec.rb +0 -17
@@ -12,6 +12,7 @@ module Doorkeeper
12
12
  include Models::Orderable
13
13
  include Models::SecretStorable
14
14
  include Models::Scopes
15
+ include Models::ResourceOwnerable
15
16
 
16
17
  module ClassMethods
17
18
  # Returns an instance of the Doorkeeper::AccessToken with
@@ -40,18 +41,35 @@ module Doorkeeper
40
41
  find_by_plaintext_token(:refresh_token, refresh_token)
41
42
  end
42
43
 
44
+ # Returns an instance of the Doorkeeper::AccessToken
45
+ # found by previous refresh token. Keep in mind that value
46
+ # of the previous_refresh_token isn't encrypted using
47
+ # secrets strategy.
48
+ #
49
+ # @param previous_refresh_token [#to_s]
50
+ # previous refresh token value (any object that responds to `#to_s`)
51
+ #
52
+ # @return [Doorkeeper::AccessToken, nil] AccessToken object or nil
53
+ # if there is no record with such refresh token
54
+ #
55
+ def by_previous_refresh_token(previous_refresh_token)
56
+ find_by(refresh_token: previous_refresh_token)
57
+ end
58
+
43
59
  # Revokes AccessToken records that have not been revoked and associated
44
60
  # with the specific Application and Resource Owner.
45
61
  #
46
62
  # @param application_id [Integer]
47
63
  # ID of the Application
48
- # @param resource_owner [ActiveRecord::Base]
49
- # instance of the Resource Owner model
64
+ # @param resource_owner [ActiveRecord::Base, Integer]
65
+ # instance of the Resource Owner model or it's ID
50
66
  #
51
67
  def revoke_all_for(application_id, resource_owner, clock = Time)
52
- where(application_id: application_id,
53
- resource_owner_id: resource_owner.id,
54
- revoked_at: nil)
68
+ by_resource_owner(resource_owner)
69
+ .where(
70
+ application_id: application_id,
71
+ revoked_at: nil,
72
+ )
55
73
  .update_all(revoked_at: clock.now.utc)
56
74
  end
57
75
 
@@ -60,7 +78,7 @@ module Doorkeeper
60
78
  #
61
79
  # @param application [Doorkeeper::Application]
62
80
  # Application instance
63
- # @param resource_owner_or_id [ActiveRecord::Base, Integer]
81
+ # @param resource_owner [ActiveRecord::Base, Integer]
64
82
  # Resource Owner model instance or it's ID
65
83
  # @param scopes [String, Doorkeeper::OAuth::Scopes]
66
84
  # set of scopes
@@ -68,17 +86,53 @@ module Doorkeeper
68
86
  # @return [Doorkeeper::AccessToken, nil] Access Token instance or
69
87
  # nil if matching record was not found
70
88
  #
71
- def matching_token_for(application, resource_owner_or_id, scopes)
72
- resource_owner_id = if resource_owner_or_id.respond_to?(:to_key)
73
- resource_owner_or_id.id
74
- else
75
- resource_owner_or_id
76
- end
89
+ def matching_token_for(application, resource_owner, scopes)
90
+ tokens = authorized_tokens_for(application&.id, resource_owner)
91
+ find_matching_token(tokens, application, scopes)
92
+ end
77
93
 
78
- tokens = authorized_tokens_for(application.try(:id), resource_owner_id)
79
- tokens.detect do |token|
80
- scopes_match?(token.scopes, scopes, application.try(:scopes))
94
+ # Interface to enumerate access token records in batches in order not
95
+ # to bloat the memory. Could be overloaded in any ORM extension.
96
+ #
97
+ def find_access_token_in_batches(relation, **args, &block)
98
+ relation.find_in_batches(**args, &block)
99
+ end
100
+
101
+ # Enumerates AccessToken records in batches to find a matching token.
102
+ # Batching is required in order not to pollute the memory if Application
103
+ # has huge amount of associated records.
104
+ #
105
+ # ActiveRecord 5.x - 6.x ignores custom ordering so we can't perform a
106
+ # database sort by created_at, so we need to load all the matching records,
107
+ # sort them and find latest one. Probably it would be better to rewrite this
108
+ # query using Time math if possible, but we n eed to consider ORM and
109
+ # different databases support.
110
+ #
111
+ # @param relation [ActiveRecord::Relation]
112
+ # Access tokens relation
113
+ # @param application [Doorkeeper::Application]
114
+ # Application instance
115
+ # @param scopes [String, Doorkeeper::OAuth::Scopes]
116
+ # set of scopes
117
+ #
118
+ # @return [Doorkeeper::AccessToken, nil] Access Token instance or
119
+ # nil if matching record was not found
120
+ #
121
+ def find_matching_token(relation, application, scopes)
122
+ return nil unless relation
123
+
124
+ matching_tokens = []
125
+ batch_size = Doorkeeper.configuration.token_lookup_batch_size
126
+
127
+ find_access_token_in_batches(relation, batch_size: batch_size) do |batch|
128
+ tokens = batch.select do |token|
129
+ scopes_match?(token.scopes, scopes, application&.scopes)
130
+ end
131
+
132
+ matching_tokens.concat(tokens)
81
133
  end
134
+
135
+ matching_tokens.max_by(&:created_at)
82
136
  end
83
137
 
84
138
  # Checks whether the token scopes match the scopes from the parameters
@@ -101,8 +155,8 @@ module Doorkeeper
101
155
  (token_scopes.sort == param_scopes.sort) &&
102
156
  Doorkeeper::OAuth::Helpers::ScopeChecker.valid?(
103
157
  scope_str: param_scopes.to_s,
104
- server_scopes: Doorkeeper.configuration.scopes,
105
- app_scopes: app_scopes
158
+ server_scopes: Doorkeeper.config.scopes,
159
+ app_scopes: app_scopes,
106
160
  )
107
161
  end
108
162
 
@@ -112,48 +166,81 @@ module Doorkeeper
112
166
  #
113
167
  # @param application [Doorkeeper::Application]
114
168
  # Application instance
115
- # @param resource_owner_id [ActiveRecord::Base, Integer]
169
+ # @param resource_owner [ActiveRecord::Base, Integer]
116
170
  # Resource Owner model instance or it's ID
117
171
  # @param scopes [#to_s]
118
172
  # set of scopes (any object that responds to `#to_s`)
119
- # @param expires_in [Integer]
173
+ # @param token_attributes [Hash]
174
+ # Additional attributes to use when creating a token
175
+ # @option token_attributes [Integer] :expires_in
120
176
  # token lifetime in seconds
121
- # @param use_refresh_token [Boolean]
177
+ # @option token_attributes [Boolean] :use_refresh_token
122
178
  # whether to use the refresh token
123
179
  #
124
180
  # @return [Doorkeeper::AccessToken] existing record or a new one
125
181
  #
126
- def find_or_create_for(application, resource_owner_id, scopes, expires_in, use_refresh_token)
127
- if Doorkeeper.configuration.reuse_access_token
128
- access_token = matching_token_for(application, resource_owner_id, scopes)
182
+ def find_or_create_for(application:, resource_owner:, scopes:, **token_attributes)
183
+ if Doorkeeper.config.reuse_access_token
184
+ access_token = matching_token_for(application, resource_owner, scopes)
129
185
 
130
186
  return access_token if access_token&.reusable?
131
187
  end
132
188
 
133
- create!(
134
- application_id: application.try(:id),
135
- resource_owner_id: resource_owner_id,
136
- scopes: scopes.to_s,
137
- expires_in: expires_in,
138
- use_refresh_token: use_refresh_token
189
+ create_for(
190
+ application: application,
191
+ resource_owner: resource_owner,
192
+ scopes: scopes,
193
+ **token_attributes,
139
194
  )
140
195
  end
141
196
 
197
+ # Creates a not expired AccessToken record with a matching set of
198
+ # scopes that belongs to specific Application and Resource Owner.
199
+ #
200
+ # @param application [Doorkeeper::Application]
201
+ # Application instance
202
+ # @param resource_owner [ActiveRecord::Base, Integer]
203
+ # Resource Owner model instance or it's ID
204
+ # @param scopes [#to_s]
205
+ # set of scopes (any object that responds to `#to_s`)
206
+ # @param token_attributes [Hash]
207
+ # Additional attributes to use when creating a token
208
+ # @option token_attributes [Integer] :expires_in
209
+ # token lifetime in seconds
210
+ # @option token_attributes [Boolean] :use_refresh_token
211
+ # whether to use the refresh token
212
+ #
213
+ # @return [Doorkeeper::AccessToken] new access token
214
+ #
215
+ def create_for(application:, resource_owner:, scopes:, **token_attributes)
216
+ token_attributes[:application_id] = application&.id
217
+ token_attributes[:scopes] = scopes.to_s
218
+
219
+ if Doorkeeper.config.polymorphic_resource_owner?
220
+ token_attributes[:resource_owner] = resource_owner
221
+ else
222
+ token_attributes[:resource_owner_id] = resource_owner_id_for(resource_owner)
223
+ end
224
+
225
+ create!(token_attributes)
226
+ end
227
+
142
228
  # Looking for not revoked Access Token records that belongs to specific
143
229
  # Application and Resource Owner.
144
230
  #
145
231
  # @param application_id [Integer]
146
232
  # ID of the Application model instance
147
- # @param resource_owner_id [Integer]
148
- # ID of the Resource Owner model instance
233
+ # @param resource_owner [ActiveRecord::Base, Integer]
234
+ # Resource Owner model instance or it's ID
149
235
  #
150
- # @return [Doorkeeper::AccessToken] array of matching AccessToken objects
236
+ # @return [ActiveRecord::Relation]
237
+ # collection of matching AccessToken objects
151
238
  #
152
- def authorized_tokens_for(application_id, resource_owner_id)
153
- ordered_by(:created_at, :desc)
154
- .where(application_id: application_id,
155
- resource_owner_id: resource_owner_id,
156
- revoked_at: nil)
239
+ def authorized_tokens_for(application_id, resource_owner)
240
+ by_resource_owner(resource_owner).where(
241
+ application_id: application_id,
242
+ revoked_at: nil,
243
+ )
157
244
  end
158
245
 
159
246
  # Convenience method for backwards-compatibility, return the last
@@ -161,28 +248,33 @@ module Doorkeeper
161
248
  #
162
249
  # @param application_id [Integer]
163
250
  # ID of the Application model instance
164
- # @param resource_owner_id [Integer]
251
+ # @param resource_owner [ActiveRecord::Base, Integer]
165
252
  # ID of the Resource Owner model instance
166
253
  #
167
254
  # @return [Doorkeeper::AccessToken, nil] matching AccessToken object or
168
255
  # nil if nothing was found
169
256
  #
170
- def last_authorized_token_for(application_id, resource_owner_id)
171
- authorized_tokens_for(application_id, resource_owner_id).first
257
+ def last_authorized_token_for(application_id, resource_owner)
258
+ authorized_tokens_for(application_id, resource_owner)
259
+ .ordered_by(:created_at, :desc)
260
+ .first
172
261
  end
173
262
 
174
263
  ##
175
264
  # Determines the secret storing transformer
176
265
  # Unless configured otherwise, uses the plain secret strategy
266
+ #
267
+ # @return [Doorkeeper::SecretStoring::Base]
268
+ #
177
269
  def secret_strategy
178
- ::Doorkeeper.configuration.token_secret_strategy
270
+ ::Doorkeeper.config.token_secret_strategy
179
271
  end
180
272
 
181
273
  ##
182
274
  # Determine the fallback storing strategy
183
275
  # Unless configured, there will be no fallback
184
276
  def fallback_secret_strategy
185
- ::Doorkeeper.configuration.token_secret_fallback_strategy
277
+ ::Doorkeeper.config.token_secret_fallback_strategy
186
278
  end
187
279
  end
188
280
 
@@ -209,7 +301,11 @@ module Doorkeeper
209
301
  expires_in: expires_in_seconds,
210
302
  application: { uid: application.try(:uid) },
211
303
  created_at: created_at.to_i,
212
- }
304
+ }.tap do |json|
305
+ if Doorkeeper.configuration.polymorphic_resource_owner?
306
+ json[:resource_owner_type] = resource_owner_type
307
+ end
308
+ end
213
309
  end
214
310
 
215
311
  # Indicates whether the token instance have the same credential
@@ -221,7 +317,22 @@ module Doorkeeper
221
317
  #
222
318
  def same_credential?(access_token)
223
319
  application_id == access_token.application_id &&
320
+ same_resource_owner?(access_token)
321
+ end
322
+
323
+ # Indicates whether the token instance have the same credential
324
+ # as the other Access Token.
325
+ #
326
+ # @param access_token [Doorkeeper::AccessToken] other token
327
+ #
328
+ # @return [Boolean] true if credentials are same of false in other cases
329
+ #
330
+ def same_resource_owner?(access_token)
331
+ if Doorkeeper.configuration.polymorphic_resource_owner?
332
+ resource_owner == access_token.resource_owner
333
+ else
224
334
  resource_owner_id == access_token.resource_owner_id
335
+ end
225
336
  end
226
337
 
227
338
  # Indicates if token is acceptable for specific scopes.
@@ -259,8 +370,28 @@ module Doorkeeper
259
370
  end
260
371
  end
261
372
 
373
+ # Revokes token with `:refresh_token` equal to `:previous_refresh_token`
374
+ # and clears `:previous_refresh_token` attribute.
375
+ #
376
+ def revoke_previous_refresh_token!
377
+ return unless self.class.refresh_token_revoked_on_use?
378
+
379
+ old_refresh_token&.revoke
380
+ update_attribute(:previous_refresh_token, "") if previous_refresh_token.present?
381
+ end
382
+
262
383
  private
263
384
 
385
+ # Searches for Access Token record with `:refresh_token` equal to
386
+ # `:previous_refresh_token` value.
387
+ #
388
+ # @return [Doorkeeper::AccessToken, nil]
389
+ # Access Token record or nil if nothing found
390
+ #
391
+ def old_refresh_token
392
+ @old_refresh_token ||= self.class.by_previous_refresh_token(previous_refresh_token)
393
+ end
394
+
264
395
  # Generates refresh token with UniqueToken generator.
265
396
  #
266
397
  # @return [String] refresh token value
@@ -271,7 +402,7 @@ module Doorkeeper
271
402
  end
272
403
 
273
404
  # Generates and sets the token value with the
274
- # configured Generator class (see Doorkeeper.configuration).
405
+ # configured Generator class (see Doorkeeper.config).
275
406
  #
276
407
  # @return [String] generated token value
277
408
  #
@@ -283,20 +414,32 @@ module Doorkeeper
283
414
  def generate_token
284
415
  self.created_at ||= Time.now.utc
285
416
 
286
- @raw_token = token_generator.generate(
417
+ @raw_token = token_generator.generate(attributes_for_token_generator)
418
+ secret_strategy.store_secret(self, :token, @raw_token)
419
+ @raw_token
420
+ end
421
+
422
+ # Set of attributes that would be passed to token generator to
423
+ # generate unique token based on them.
424
+ #
425
+ # @return [Hash] set of attributes
426
+ #
427
+ def attributes_for_token_generator
428
+ {
287
429
  resource_owner_id: resource_owner_id,
288
430
  scopes: scopes,
289
431
  application: application,
290
432
  expires_in: expires_in,
291
- created_at: created_at
292
- )
293
-
294
- secret_strategy.store_secret(self, :token, @raw_token)
295
- @raw_token
433
+ created_at: created_at,
434
+ }.tap do |attributes|
435
+ if Doorkeeper.config.polymorphic_resource_owner?
436
+ attributes[:resource_owner] = resource_owner
437
+ end
438
+ end
296
439
  end
297
440
 
298
441
  def token_generator
299
- generator_name = Doorkeeper.configuration.access_token_generator
442
+ generator_name = Doorkeeper.config.access_token_generator
300
443
  generator = generator_name.constantize
301
444
 
302
445
  return generator if generator.respond_to?(:generate)
@@ -20,8 +20,8 @@ module Doorkeeper
20
20
  # @param uid [#to_s] UID (any object that responds to `#to_s`)
21
21
  # @param secret [#to_s] secret (any object that responds to `#to_s`)
22
22
  #
23
- # @return [Doorkeeper::Application, nil] Application instance or nil
24
- # if there is no record with such credentials
23
+ # @return [Doorkeeper::Application, nil]
24
+ # Application instance or nil if there is no record with such credentials
25
25
  #
26
26
  def by_uid_and_secret(uid, secret)
27
27
  app = by_uid(uid)
@@ -47,22 +47,23 @@ module Doorkeeper
47
47
  # Determines the secret storing transformer
48
48
  # Unless configured otherwise, uses the plain secret strategy
49
49
  def secret_strategy
50
- ::Doorkeeper.configuration.application_secret_strategy
50
+ ::Doorkeeper.config.application_secret_strategy
51
51
  end
52
52
 
53
53
  ##
54
54
  # Determine the fallback storing strategy
55
55
  # Unless configured, there will be no fallback
56
56
  def fallback_secret_strategy
57
- ::Doorkeeper.configuration.application_secret_fallback_strategy
57
+ ::Doorkeeper.config.application_secret_fallback_strategy
58
58
  end
59
59
  end
60
60
 
61
61
  # Set an application's valid redirect URIs.
62
62
  #
63
- # @param uris [String, Array] Newline-separated string or array the URI(s)
63
+ # @param uris [String, Array<String>] Newline-separated string or array the URI(s)
64
+ #
65
+ # @return [String] The redirect URI(s) separated by newlines.
64
66
  #
65
- # @return [String] The redirect URI(s) seperated by newlines.
66
67
  def redirect_uri=(uris)
67
68
  super(uris.is_a?(Array) ? uris.join("\n") : uris)
68
69
  end
@@ -72,7 +73,7 @@ module Doorkeeper
72
73
  # @param input [#to_s] Plain secret provided by user
73
74
  # (any object that responds to `#to_s`)
74
75
  #
75
- # @return [true] Whether the given secret matches the stored secret
76
+ # @return [Boolean] Whether the given secret matches the stored secret
76
77
  # of this application.
77
78
  #
78
79
  def secret_matches?(input)
@@ -11,7 +11,7 @@ module Doorkeeper
11
11
  end
12
12
 
13
13
  def validate_owner?
14
- Doorkeeper.configuration.confirm_application_owner?
14
+ Doorkeeper.config.confirm_application_owner?
15
15
  end
16
16
  end
17
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
@@ -11,7 +11,7 @@ module Doorkeeper
11
11
  return false if expired?
12
12
  return true unless expires_in
13
13
 
14
- threshold_limit = 100 - Doorkeeper.configuration.token_reuse_limit
14
+ threshold_limit = 100 - Doorkeeper.config.token_reuse_limit
15
15
  expires_in_seconds >= threshold_limit * expires_in / 100
16
16
  end
17
17
  end
@@ -9,7 +9,7 @@ module Doorkeeper
9
9
  # @param clock [Time] time object
10
10
  #
11
11
  def revoke(clock = Time)
12
- update_attribute :revoked_at, clock.now.utc
12
+ update_attribute(:revoked_at, clock.now.utc)
13
13
  end
14
14
 
15
15
  # Indicates whether the object has been revoked.
@@ -19,33 +19,6 @@ module Doorkeeper
19
19
  def revoked?
20
20
  !!(revoked_at && revoked_at <= Time.now.utc)
21
21
  end
22
-
23
- # Revokes token with `:refresh_token` equal to `:previous_refresh_token`
24
- # and clears `:previous_refresh_token` attribute.
25
- #
26
- def revoke_previous_refresh_token!
27
- return unless refresh_token_revoked_on_use?
28
-
29
- old_refresh_token&.revoke
30
- update_attribute :previous_refresh_token, ""
31
- end
32
-
33
- private
34
-
35
- # Searches for Access Token record with `:refresh_token` equal to
36
- # `:previous_refresh_token` value.
37
- #
38
- # @return [Doorkeeper::AccessToken, nil]
39
- # Access Token record or nil if nothing found
40
- #
41
- def old_refresh_token
42
- @old_refresh_token ||=
43
- AccessToken.by_refresh_token(previous_refresh_token)
44
- end
45
-
46
- def refresh_token_revoked_on_use?
47
- AccessToken.refresh_token_revoked_on_use?
48
- end
49
22
  end
50
23
  end
51
24
  end
@@ -8,7 +8,11 @@ module Doorkeeper
8
8
  end
9
9
 
10
10
  def scopes=(value)
11
- super Array(value).join(" ")
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
12
16
  end
13
17
 
14
18
  def scopes_string
@@ -25,9 +25,7 @@ module Doorkeeper
25
25
  # @return [Boolean]
26
26
  # Whether input matches secret as per the secret strategy
27
27
  #
28
- def secret_matches?(input, secret)
29
- secret_strategy.secret_matches?(input, secret)
30
- end
28
+ delegate :secret_matches?, to: :secret_strategy
31
29
 
32
30
  # Returns an instance of the Doorkeeper::AccessToken with
33
31
  # specific token value.
@@ -4,37 +4,48 @@ module Doorkeeper
4
4
  module OAuth
5
5
  module Authorization
6
6
  class Code
7
- attr_accessor :pre_auth, :resource_owner, :token
7
+ attr_reader :pre_auth, :resource_owner, :token
8
8
 
9
9
  def initialize(pre_auth, resource_owner)
10
10
  @pre_auth = pre_auth
11
11
  @resource_owner = resource_owner
12
12
  end
13
13
 
14
- def issue_token
15
- @token ||= AccessGrant.create! access_grant_attributes
14
+ def issue_token!
15
+ return @token if defined?(@token)
16
+
17
+ @token = Doorkeeper.config.access_grant_model.create!(access_grant_attributes)
16
18
  end
17
19
 
18
- def native_redirect
20
+ def oob_redirect
19
21
  { action: :show, code: token.plaintext_token }
20
22
  end
21
23
 
22
- def configuration
23
- Doorkeeper.configuration
24
+ def access_grant?
25
+ true
24
26
  end
25
27
 
26
28
  private
27
29
 
28
30
  def authorization_code_expires_in
29
- configuration.authorization_code_expires_in
31
+ Doorkeeper.config.authorization_code_expires_in
30
32
  end
31
33
 
32
34
  def access_grant_attributes
33
- pkce_attributes.merge application_id: pre_auth.client.id,
34
- resource_owner_id: resource_owner.id,
35
- expires_in: authorization_code_expires_in,
36
- redirect_uri: pre_auth.redirect_uri,
37
- scopes: pre_auth.scopes.to_s
35
+ attributes = {
36
+ application_id: pre_auth.client.id,
37
+ expires_in: authorization_code_expires_in,
38
+ redirect_uri: pre_auth.redirect_uri,
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)
38
49
  end
39
50
 
40
51
  def pkce_attributes
@@ -46,10 +57,10 @@ module Doorkeeper
46
57
  }
47
58
  end
48
59
 
49
- # ensures firstly, if migration with additional pcke columns was
60
+ # Ensures firstly, if migration with additional PKCE columns was
50
61
  # generated and migrated
51
62
  def pkce_supported?
52
- Doorkeeper::AccessGrant.pkce_supported?
63
+ Doorkeeper.config.access_grant_model.pkce_supported?
53
64
  end
54
65
  end
55
66
  end
@@ -4,12 +4,12 @@ module Doorkeeper
4
4
  module OAuth
5
5
  module Authorization
6
6
  class Context
7
- attr_reader :client, :grant_type, :scopes
7
+ attr_reader :client, :grant_type, :resource_owner, :scopes
8
8
 
9
- def initialize(client, grant_type, scopes)
10
- @client = client
11
- @grant_type = grant_type
12
- @scopes = scopes
9
+ def initialize(**attributes)
10
+ attributes.each do |name, value|
11
+ instance_variable_set(:"@#{name}", value) if respond_to?(name)
12
+ end
13
13
  end
14
14
  end
15
15
  end