doorkeeper 5.1.2 → 5.6.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. checksums.yaml +4 -4
  2. data/{NEWS.md → CHANGELOG.md} +314 -27
  3. data/README.md +39 -22
  4. data/app/controllers/doorkeeper/application_controller.rb +3 -2
  5. data/app/controllers/doorkeeper/application_metal_controller.rb +3 -2
  6. data/app/controllers/doorkeeper/applications_controller.rb +5 -4
  7. data/app/controllers/doorkeeper/authorizations_controller.rb +76 -25
  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 +99 -28
  11. data/app/helpers/doorkeeper/dashboard_helper.rb +1 -1
  12. data/app/views/doorkeeper/applications/_form.html.erb +1 -7
  13. data/app/views/doorkeeper/applications/show.html.erb +35 -14
  14. data/app/views/doorkeeper/authorizations/error.html.erb +3 -1
  15. data/app/views/doorkeeper/authorizations/form_post.html.erb +15 -0
  16. data/app/views/doorkeeper/authorizations/new.html.erb +16 -14
  17. data/config/locales/en.yml +16 -3
  18. data/lib/doorkeeper/config/abstract_builder.rb +28 -0
  19. data/lib/doorkeeper/config/option.rb +20 -2
  20. data/lib/doorkeeper/config/validations.rb +53 -0
  21. data/lib/doorkeeper/config.rb +300 -136
  22. data/lib/doorkeeper/engine.rb +10 -3
  23. data/lib/doorkeeper/errors.rb +13 -18
  24. data/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
  25. data/lib/doorkeeper/grant_flow/flow.rb +44 -0
  26. data/lib/doorkeeper/grant_flow/registry.rb +50 -0
  27. data/lib/doorkeeper/grant_flow.rb +45 -0
  28. data/lib/doorkeeper/grape/helpers.rb +7 -3
  29. data/lib/doorkeeper/helpers/controller.rb +36 -11
  30. data/lib/doorkeeper/models/access_grant_mixin.rb +23 -19
  31. data/lib/doorkeeper/models/access_token_mixin.rb +195 -52
  32. data/lib/doorkeeper/models/application_mixin.rb +8 -7
  33. data/lib/doorkeeper/models/concerns/expirable.rb +1 -1
  34. data/lib/doorkeeper/models/concerns/expiration_time_sql_math.rb +88 -0
  35. data/lib/doorkeeper/models/concerns/ownership.rb +1 -1
  36. data/lib/doorkeeper/models/concerns/polymorphic_resource_owner.rb +30 -0
  37. data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
  38. data/lib/doorkeeper/models/concerns/reusable.rb +1 -1
  39. data/lib/doorkeeper/models/concerns/revocable.rb +1 -28
  40. data/lib/doorkeeper/models/concerns/scopes.rb +5 -1
  41. data/lib/doorkeeper/models/concerns/secret_storable.rb +1 -3
  42. data/lib/doorkeeper/oauth/authorization/code.rb +31 -14
  43. data/lib/doorkeeper/oauth/authorization/context.rb +5 -5
  44. data/lib/doorkeeper/oauth/authorization/token.rb +30 -19
  45. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +4 -4
  46. data/lib/doorkeeper/oauth/authorization_code_request.rb +51 -22
  47. data/lib/doorkeeper/oauth/base_request.rb +21 -22
  48. data/lib/doorkeeper/oauth/client/credentials.rb +2 -4
  49. data/lib/doorkeeper/oauth/client.rb +8 -9
  50. data/lib/doorkeeper/oauth/client_credentials/creator.rb +42 -5
  51. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +10 -8
  52. data/lib/doorkeeper/oauth/client_credentials/{validation.rb → validator.rb} +14 -5
  53. data/lib/doorkeeper/oauth/client_credentials_request.rb +8 -7
  54. data/lib/doorkeeper/oauth/code_request.rb +6 -12
  55. data/lib/doorkeeper/oauth/code_response.rb +24 -14
  56. data/lib/doorkeeper/oauth/error.rb +1 -1
  57. data/lib/doorkeeper/oauth/error_response.rb +11 -13
  58. data/lib/doorkeeper/oauth/forbidden_token_response.rb +2 -1
  59. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +8 -12
  60. data/lib/doorkeeper/oauth/helpers/unique_token.rb +10 -7
  61. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +19 -23
  62. data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
  63. data/lib/doorkeeper/oauth/invalid_request_response.rb +43 -0
  64. data/lib/doorkeeper/oauth/invalid_token_response.rb +7 -4
  65. data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
  66. data/lib/doorkeeper/oauth/password_access_token_request.rb +34 -11
  67. data/lib/doorkeeper/oauth/pre_authorization.rb +114 -44
  68. data/lib/doorkeeper/oauth/refresh_token_request.rb +54 -34
  69. data/lib/doorkeeper/oauth/token.rb +6 -7
  70. data/lib/doorkeeper/oauth/token_introspection.rb +28 -22
  71. data/lib/doorkeeper/oauth/token_request.rb +6 -20
  72. data/lib/doorkeeper/oauth/token_response.rb +2 -3
  73. data/lib/doorkeeper/orm/active_record/access_grant.rb +4 -43
  74. data/lib/doorkeeper/orm/active_record/access_token.rb +4 -35
  75. data/lib/doorkeeper/orm/active_record/application.rb +5 -149
  76. data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +63 -0
  77. data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +77 -0
  78. data/lib/doorkeeper/orm/active_record/mixins/application.rb +210 -0
  79. data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +66 -0
  80. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +5 -2
  81. data/lib/doorkeeper/orm/active_record.rb +29 -22
  82. data/lib/doorkeeper/rails/helpers.rb +4 -4
  83. data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
  84. data/lib/doorkeeper/rails/routes/mapper.rb +2 -2
  85. data/lib/doorkeeper/rails/routes/registry.rb +45 -0
  86. data/lib/doorkeeper/rails/routes.rb +28 -27
  87. data/lib/doorkeeper/rake/db.rake +6 -6
  88. data/lib/doorkeeper/request/authorization_code.rb +5 -3
  89. data/lib/doorkeeper/request/client_credentials.rb +2 -2
  90. data/lib/doorkeeper/request/password.rb +3 -2
  91. data/lib/doorkeeper/request/refresh_token.rb +5 -4
  92. data/lib/doorkeeper/request/strategy.rb +2 -2
  93. data/lib/doorkeeper/request.rb +49 -17
  94. data/lib/doorkeeper/server.rb +7 -11
  95. data/lib/doorkeeper/stale_records_cleaner.rb +6 -2
  96. data/lib/doorkeeper/version.rb +2 -6
  97. data/lib/doorkeeper.rb +183 -80
  98. data/lib/generators/doorkeeper/application_owner_generator.rb +1 -1
  99. data/lib/generators/doorkeeper/confidential_applications_generator.rb +2 -2
  100. data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
  101. data/lib/generators/doorkeeper/migration_generator.rb +1 -1
  102. data/lib/generators/doorkeeper/pkce_generator.rb +1 -1
  103. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +7 -7
  104. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +3 -1
  105. data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +2 -0
  106. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +2 -0
  107. data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
  108. data/lib/generators/doorkeeper/templates/initializer.rb +230 -50
  109. data/lib/generators/doorkeeper/templates/migration.rb.erb +31 -9
  110. metadata +61 -327
  111. data/.coveralls.yml +0 -1
  112. data/.github/ISSUE_TEMPLATE.md +0 -25
  113. data/.github/PULL_REQUEST_TEMPLATE.md +0 -17
  114. data/.gitignore +0 -20
  115. data/.gitlab-ci.yml +0 -16
  116. data/.hound.yml +0 -3
  117. data/.rspec +0 -1
  118. data/.rubocop.yml +0 -50
  119. data/.travis.yml +0 -35
  120. data/Appraisals +0 -40
  121. data/CODE_OF_CONDUCT.md +0 -46
  122. data/CONTRIBUTING.md +0 -47
  123. data/Dangerfile +0 -67
  124. data/Gemfile +0 -24
  125. data/RELEASING.md +0 -10
  126. data/Rakefile +0 -28
  127. data/SECURITY.md +0 -15
  128. data/UPGRADE.md +0 -2
  129. data/app/validators/redirect_uri_validator.rb +0 -50
  130. data/bin/console +0 -16
  131. data/doorkeeper.gemspec +0 -34
  132. data/gemfiles/rails_5_0.gemfile +0 -17
  133. data/gemfiles/rails_5_1.gemfile +0 -17
  134. data/gemfiles/rails_5_2.gemfile +0 -17
  135. data/gemfiles/rails_6_0.gemfile +0 -17
  136. data/gemfiles/rails_master.gemfile +0 -17
  137. data/spec/controllers/application_metal_controller_spec.rb +0 -64
  138. data/spec/controllers/applications_controller_spec.rb +0 -180
  139. data/spec/controllers/authorizations_controller_spec.rb +0 -527
  140. data/spec/controllers/protected_resources_controller_spec.rb +0 -353
  141. data/spec/controllers/token_info_controller_spec.rb +0 -50
  142. data/spec/controllers/tokens_controller_spec.rb +0 -330
  143. data/spec/dummy/Rakefile +0 -9
  144. data/spec/dummy/app/assets/config/manifest.js +0 -2
  145. data/spec/dummy/app/controllers/application_controller.rb +0 -5
  146. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +0 -9
  147. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +0 -14
  148. data/spec/dummy/app/controllers/home_controller.rb +0 -18
  149. data/spec/dummy/app/controllers/metal_controller.rb +0 -13
  150. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +0 -13
  151. data/spec/dummy/app/helpers/application_helper.rb +0 -7
  152. data/spec/dummy/app/models/user.rb +0 -7
  153. data/spec/dummy/app/views/home/index.html.erb +0 -0
  154. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  155. data/spec/dummy/config/application.rb +0 -47
  156. data/spec/dummy/config/boot.rb +0 -7
  157. data/spec/dummy/config/database.yml +0 -15
  158. data/spec/dummy/config/environment.rb +0 -5
  159. data/spec/dummy/config/environments/development.rb +0 -31
  160. data/spec/dummy/config/environments/production.rb +0 -64
  161. data/spec/dummy/config/environments/test.rb +0 -45
  162. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -9
  163. data/spec/dummy/config/initializers/doorkeeper.rb +0 -121
  164. data/spec/dummy/config/initializers/secret_token.rb +0 -10
  165. data/spec/dummy/config/initializers/session_store.rb +0 -10
  166. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -16
  167. data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
  168. data/spec/dummy/config/routes.rb +0 -13
  169. data/spec/dummy/config.ru +0 -6
  170. data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -11
  171. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -7
  172. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +0 -69
  173. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +0 -9
  174. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +0 -13
  175. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +0 -8
  176. data/spec/dummy/db/migrate/20180210183654_add_confidential_to_applications.rb +0 -13
  177. data/spec/dummy/db/schema.rb +0 -68
  178. data/spec/dummy/public/404.html +0 -26
  179. data/spec/dummy/public/422.html +0 -26
  180. data/spec/dummy/public/500.html +0 -26
  181. data/spec/dummy/public/favicon.ico +0 -0
  182. data/spec/dummy/script/rails +0 -9
  183. data/spec/factories.rb +0 -30
  184. data/spec/generators/application_owner_generator_spec.rb +0 -28
  185. data/spec/generators/confidential_applications_generator_spec.rb +0 -29
  186. data/spec/generators/install_generator_spec.rb +0 -36
  187. data/spec/generators/migration_generator_spec.rb +0 -28
  188. data/spec/generators/pkce_generator_spec.rb +0 -28
  189. data/spec/generators/previous_refresh_token_generator_spec.rb +0 -44
  190. data/spec/generators/templates/routes.rb +0 -4
  191. data/spec/generators/views_generator_spec.rb +0 -29
  192. data/spec/grape/grape_integration_spec.rb +0 -137
  193. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -26
  194. data/spec/lib/config_spec.rb +0 -697
  195. data/spec/lib/doorkeeper_spec.rb +0 -27
  196. data/spec/lib/models/expirable_spec.rb +0 -61
  197. data/spec/lib/models/reusable_spec.rb +0 -40
  198. data/spec/lib/models/revocable_spec.rb +0 -59
  199. data/spec/lib/models/scopes_spec.rb +0 -53
  200. data/spec/lib/models/secret_storable_spec.rb +0 -135
  201. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -39
  202. data/spec/lib/oauth/authorization_code_request_spec.rb +0 -156
  203. data/spec/lib/oauth/base_request_spec.rb +0 -205
  204. data/spec/lib/oauth/base_response_spec.rb +0 -47
  205. data/spec/lib/oauth/client/credentials_spec.rb +0 -90
  206. data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -94
  207. data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -112
  208. data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -59
  209. data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -29
  210. data/spec/lib/oauth/client_credentials_request_spec.rb +0 -109
  211. data/spec/lib/oauth/client_spec.rb +0 -38
  212. data/spec/lib/oauth/code_request_spec.rb +0 -47
  213. data/spec/lib/oauth/code_response_spec.rb +0 -36
  214. data/spec/lib/oauth/error_response_spec.rb +0 -66
  215. data/spec/lib/oauth/error_spec.rb +0 -23
  216. data/spec/lib/oauth/forbidden_token_response_spec.rb +0 -22
  217. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -98
  218. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -21
  219. data/spec/lib/oauth/helpers/uri_checker_spec.rb +0 -247
  220. data/spec/lib/oauth/invalid_token_response_spec.rb +0 -55
  221. data/spec/lib/oauth/password_access_token_request_spec.rb +0 -192
  222. data/spec/lib/oauth/pre_authorization_spec.rb +0 -215
  223. data/spec/lib/oauth/refresh_token_request_spec.rb +0 -177
  224. data/spec/lib/oauth/scopes_spec.rb +0 -148
  225. data/spec/lib/oauth/token_request_spec.rb +0 -150
  226. data/spec/lib/oauth/token_response_spec.rb +0 -86
  227. data/spec/lib/oauth/token_spec.rb +0 -158
  228. data/spec/lib/request/strategy_spec.rb +0 -54
  229. data/spec/lib/secret_storing/base_spec.rb +0 -60
  230. data/spec/lib/secret_storing/bcrypt_spec.rb +0 -49
  231. data/spec/lib/secret_storing/plain_spec.rb +0 -44
  232. data/spec/lib/secret_storing/sha256_hash_spec.rb +0 -48
  233. data/spec/lib/server_spec.rb +0 -61
  234. data/spec/lib/stale_records_cleaner_spec.rb +0 -89
  235. data/spec/models/doorkeeper/access_grant_spec.rb +0 -144
  236. data/spec/models/doorkeeper/access_token_spec.rb +0 -591
  237. data/spec/models/doorkeeper/application_spec.rb +0 -472
  238. data/spec/requests/applications/applications_request_spec.rb +0 -259
  239. data/spec/requests/applications/authorized_applications_spec.rb +0 -32
  240. data/spec/requests/endpoints/authorization_spec.rb +0 -73
  241. data/spec/requests/endpoints/token_spec.rb +0 -75
  242. data/spec/requests/flows/authorization_code_errors_spec.rb +0 -78
  243. data/spec/requests/flows/authorization_code_spec.rb +0 -447
  244. data/spec/requests/flows/client_credentials_spec.rb +0 -128
  245. data/spec/requests/flows/implicit_grant_errors_spec.rb +0 -34
  246. data/spec/requests/flows/implicit_grant_spec.rb +0 -90
  247. data/spec/requests/flows/password_spec.rb +0 -259
  248. data/spec/requests/flows/refresh_token_spec.rb +0 -233
  249. data/spec/requests/flows/revoke_token_spec.rb +0 -143
  250. data/spec/requests/flows/skip_authorization_spec.rb +0 -66
  251. data/spec/requests/protected_resources/metal_spec.rb +0 -16
  252. data/spec/requests/protected_resources/private_api_spec.rb +0 -83
  253. data/spec/routing/custom_controller_routes_spec.rb +0 -133
  254. data/spec/routing/default_routes_spec.rb +0 -41
  255. data/spec/routing/scoped_routes_spec.rb +0 -47
  256. data/spec/spec_helper.rb +0 -57
  257. data/spec/spec_helper_integration.rb +0 -4
  258. data/spec/support/dependencies/factory_bot.rb +0 -4
  259. data/spec/support/doorkeeper_rspec.rb +0 -22
  260. data/spec/support/helpers/access_token_request_helper.rb +0 -13
  261. data/spec/support/helpers/authorization_request_helper.rb +0 -43
  262. data/spec/support/helpers/config_helper.rb +0 -11
  263. data/spec/support/helpers/model_helper.rb +0 -78
  264. data/spec/support/helpers/request_spec_helper.rb +0 -98
  265. data/spec/support/helpers/url_helper.rb +0 -62
  266. data/spec/support/http_method_shim.rb +0 -29
  267. data/spec/support/orm/active_record.rb +0 -5
  268. data/spec/support/shared/controllers_shared_context.rb +0 -123
  269. data/spec/support/shared/hashing_shared_context.rb +0 -36
  270. data/spec/support/shared/models_shared_examples.rb +0 -54
  271. data/spec/validators/redirect_uri_validator_spec.rb +0 -158
  272. data/spec/version/version_spec.rb +0 -17
@@ -1,40 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Doorkeeper
4
- class AccessToken < ActiveRecord::Base
5
- self.table_name = "#{table_name_prefix}oauth_access_tokens#{table_name_suffix}"
6
-
7
- include AccessTokenMixin
8
-
9
- belongs_to :application, class_name: "Doorkeeper::Application",
10
- inverse_of: :access_tokens, optional: true
11
-
12
- validates :token, presence: true, uniqueness: true
13
- validates :refresh_token, uniqueness: true, if: :use_refresh_token?
3
+ require "doorkeeper/orm/active_record/mixins/access_token"
14
4
 
15
- # @attr_writer [Boolean, nil] use_refresh_token
16
- # indicates the possibility of using refresh token
17
- attr_writer :use_refresh_token
18
-
19
- before_validation :generate_token, on: :create
20
- before_validation :generate_refresh_token,
21
- on: :create, if: :use_refresh_token?
22
-
23
- # Searches for not revoked Access Tokens associated with the
24
- # specific Resource Owner.
25
- #
26
- # @param resource_owner [ActiveRecord::Base]
27
- # Resource Owner model instance
28
- #
29
- # @return [ActiveRecord::Relation]
30
- # active Access Tokens for Resource Owner
31
- #
32
- def self.active_for(resource_owner)
33
- where(resource_owner_id: resource_owner.id, revoked_at: nil)
34
- end
35
-
36
- def self.refresh_token_revoked_on_use?
37
- column_names.include?("previous_refresh_token")
38
- end
5
+ module Doorkeeper
6
+ class AccessToken < ::ActiveRecord::Base
7
+ include Doorkeeper::Orm::ActiveRecord::Mixins::AccessToken
39
8
  end
40
9
  end
@@ -1,154 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Doorkeeper
4
- class Application < ActiveRecord::Base
5
- self.table_name = "#{table_name_prefix}oauth_applications#{table_name_suffix}"
6
-
7
- include ApplicationMixin
8
-
9
- has_many :access_grants, dependent: :delete_all, class_name: "Doorkeeper::AccessGrant"
10
- has_many :access_tokens, dependent: :delete_all, class_name: "Doorkeeper::AccessToken"
11
-
12
- validates :name, :secret, :uid, presence: true
13
- validates :uid, uniqueness: true
14
- validates :redirect_uri, redirect_uri: true
15
- validates :confidential, inclusion: { in: [true, false] }
16
-
17
- validate :scopes_match_configured, if: :enforce_scopes?
18
-
19
- before_validation :generate_uid, :generate_secret, on: :create
20
-
21
- has_many :authorized_tokens, -> { where(revoked_at: nil) }, class_name: "AccessToken"
22
- has_many :authorized_applications, through: :authorized_tokens, source: :application
23
-
24
- # Returns Applications associated with active (not revoked) Access Tokens
25
- # that are owned by the specific Resource Owner.
26
- #
27
- # @param resource_owner [ActiveRecord::Base]
28
- # Resource Owner model instance
29
- #
30
- # @return [ActiveRecord::Relation]
31
- # Applications authorized for the Resource Owner
32
- #
33
- def self.authorized_for(resource_owner)
34
- resource_access_tokens = AccessToken.active_for(resource_owner)
35
- where(id: resource_access_tokens.select(:application_id).distinct)
36
- end
37
-
38
- # Revokes AccessToken and AccessGrant records that have not been revoked and
39
- # associated with the specific Application and Resource Owner.
40
- #
41
- # @param resource_owner [ActiveRecord::Base]
42
- # instance of the Resource Owner model
43
- #
44
- def self.revoke_tokens_and_grants_for(id, resource_owner)
45
- AccessToken.revoke_all_for(id, resource_owner)
46
- AccessGrant.revoke_all_for(id, resource_owner)
47
- end
48
-
49
- # We keep a volatile copy of the raw secret for initial communication
50
- # The stored refresh_token may be mapped and not available in cleartext.
51
- #
52
- # Some strategies allow restoring stored secrets (e.g. symmetric encryption)
53
- # while hashing strategies do not, so you cannot rely on this value
54
- # returning a present value for persisted tokens.
55
- def plaintext_secret
56
- if secret_strategy.allows_restoring_secrets?
57
- secret_strategy.restore_secret(self, :secret)
58
- else
59
- @raw_secret
60
- end
61
- end
62
-
63
- # Represents client as set of it's attributes in JSON format.
64
- # This is the right way how we want to override ActiveRecord #to_json.
65
- #
66
- # Respects privacy settings and serializes minimum set of attributes
67
- # for public/private clients and full set for authorized owners.
68
- #
69
- # @return [Hash] entity attributes for JSON
70
- #
71
- def as_json(options = {})
72
- # if application belongs to some owner we need to check if it's the same as
73
- # the one passed in the options or check if we render the client as an owner
74
- if (respond_to?(:owner) && owner && owner == options[:current_resource_owner]) ||
75
- options[:as_owner]
76
- # Owners can see all the client attributes, fallback to ActiveModel serialization
77
- super
78
- else
79
- # if application has no owner or it's owner doesn't match one from the options
80
- # we render only minimum set of attributes that could be exposed to a public
81
- only = extract_serializable_attributes(options)
82
- super(options.merge(only: only))
83
- end
84
- end
85
-
86
- # We need to hook into this method to allow serializing plan-text secrets
87
- # when secrets hashing enabled.
88
- #
89
- # @param key [String] attribute name
90
- #
91
- def read_attribute_for_serialization(key)
92
- return super unless key.to_s == "secret"
3
+ require "doorkeeper/orm/active_record/redirect_uri_validator"
4
+ require "doorkeeper/orm/active_record/mixins/application"
93
5
 
94
- plaintext_secret || secret
95
- end
96
-
97
- private
98
-
99
- def generate_uid
100
- self.uid = UniqueToken.generate if uid.blank?
101
- end
102
-
103
- def generate_secret
104
- return unless secret.blank?
105
-
106
- @raw_secret = UniqueToken.generate
107
- secret_strategy.store_secret(self, :secret, @raw_secret)
108
- end
109
-
110
- def scopes_match_configured
111
- if scopes.present? &&
112
- !ScopeChecker.valid?(scope_str: scopes.to_s,
113
- server_scopes: Doorkeeper.configuration.scopes)
114
- errors.add(:scopes, :not_match_configured)
115
- end
116
- end
117
-
118
- def enforce_scopes?
119
- Doorkeeper.configuration.enforce_configured_scopes?
120
- end
121
-
122
- # Helper method to extract collection of serializable attribute names
123
- # considering serialization options (like `only`, `except` and so on).
124
- #
125
- # @param options [Hash] serialization options
126
- #
127
- # @return [Array<String>]
128
- # collection of attributes to be serialized using #as_json
129
- #
130
- def extract_serializable_attributes(options = {})
131
- opts = options.try(:dup) || {}
132
- only = Array.wrap(opts[:only]).map(&:to_s)
133
-
134
- only = if only.blank?
135
- serializable_attributes
136
- else
137
- only & serializable_attributes
138
- end
139
-
140
- only -= Array.wrap(opts[:except]).map(&:to_s) if opts.key?(:except)
141
- only.uniq
142
- end
143
-
144
- # Collection of attributes that could be serialized for public.
145
- # Override this method if you need additional attributes to be serialized.
146
- #
147
- # @return [Array<String>] collection of serializable attributes
148
- def serializable_attributes
149
- attributes = %w[id name created_at]
150
- attributes << "uid" unless confidential?
151
- attributes
152
- end
6
+ module Doorkeeper
7
+ class Application < ::ActiveRecord::Base
8
+ include ::Doorkeeper::Orm::ActiveRecord::Mixins::Application
153
9
  end
154
10
  end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper::Orm::ActiveRecord::Mixins
4
+ module AccessGrant
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ self.table_name = compute_doorkeeper_table_name
9
+ self.strict_loading_by_default = false if respond_to?(:strict_loading_by_default)
10
+
11
+ include ::Doorkeeper::AccessGrantMixin
12
+
13
+ belongs_to :application, class_name: Doorkeeper.config.application_class.to_s,
14
+ optional: true,
15
+ inverse_of: :access_grants
16
+
17
+ validates :application_id,
18
+ :token,
19
+ :expires_in,
20
+ :redirect_uri,
21
+ presence: true
22
+
23
+ validates :token, uniqueness: { case_sensitive: true }
24
+
25
+ before_validation :generate_token, on: :create
26
+
27
+ # We keep a volatile copy of the raw token for initial communication
28
+ # The stored refresh_token may be mapped and not available in cleartext.
29
+ #
30
+ # Some strategies allow restoring stored secrets (e.g. symmetric encryption)
31
+ # while hashing strategies do not, so you cannot rely on this value
32
+ # returning a present value for persisted tokens.
33
+ def plaintext_token
34
+ if secret_strategy.allows_restoring_secrets?
35
+ secret_strategy.restore_secret(self, :token)
36
+ else
37
+ @raw_token
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ # Generates token value with UniqueToken class.
44
+ #
45
+ # @return [String] token value
46
+ #
47
+ def generate_token
48
+ @raw_token = Doorkeeper::OAuth::Helpers::UniqueToken.generate
49
+ secret_strategy.store_secret(self, :token, @raw_token)
50
+ end
51
+ end
52
+
53
+ module ClassMethods
54
+ private
55
+
56
+ def compute_doorkeeper_table_name
57
+ table_name = "oauth_access_grant"
58
+ table_name = table_name.pluralize if pluralize_table_names
59
+ "#{table_name_prefix}#{table_name}#{table_name_suffix}"
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper::Orm::ActiveRecord::Mixins
4
+ module AccessToken
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ self.table_name = compute_doorkeeper_table_name
9
+ self.strict_loading_by_default = false if respond_to?(:strict_loading_by_default)
10
+
11
+ include ::Doorkeeper::AccessTokenMixin
12
+
13
+ belongs_to :application, class_name: Doorkeeper.config.application_class.to_s,
14
+ inverse_of: :access_tokens,
15
+ optional: true
16
+
17
+ validates :token, presence: true, uniqueness: { case_sensitive: true }
18
+ validates :refresh_token, uniqueness: { case_sensitive: true }, if: :use_refresh_token?
19
+
20
+ # @attr_writer [Boolean, nil] use_refresh_token
21
+ # indicates the possibility of using refresh token
22
+ attr_writer :use_refresh_token
23
+
24
+ before_validation :generate_token, on: :create
25
+ before_validation :generate_refresh_token,
26
+ on: :create, if: :use_refresh_token?
27
+ end
28
+
29
+ module ClassMethods
30
+ # Searches for not revoked Access Tokens associated with the
31
+ # specific Resource Owner.
32
+ #
33
+ # @param resource_owner [ActiveRecord::Base]
34
+ # Resource Owner model instance
35
+ #
36
+ # @return [ActiveRecord::Relation]
37
+ # active Access Tokens for Resource Owner
38
+ #
39
+ def active_for(resource_owner)
40
+ by_resource_owner(resource_owner).where(revoked_at: nil)
41
+ end
42
+
43
+ def refresh_token_revoked_on_use?
44
+ column_names.include?("previous_refresh_token")
45
+ end
46
+
47
+ # Returns non-expired and non-revoked access tokens
48
+ def not_expired
49
+ relation = where(revoked_at: nil)
50
+
51
+ if supports_expiration_time_math?
52
+ # have not reached the expiration time or it never expires
53
+ relation.where("#{expiration_time_sql} > ?", Time.now.utc).or(
54
+ relation.where(expires_in: nil)
55
+ )
56
+ else
57
+ ::Kernel.warn <<~WARNING.squish
58
+ [DOORKEEPER] Doorkeeper doesn't support expiration time math for your database adapter (#{adapter_name}).
59
+ Please add a class method `custom_expiration_time_sql` for your AccessToken class/mixin to provide a custom
60
+ SQL expression to calculate access token expiration time. See lib/doorkeeper/orm/active_record/mixins/access_token.rb
61
+ for more details.
62
+ WARNING
63
+
64
+ relation
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ def compute_doorkeeper_table_name
71
+ table_name = "oauth_access_token"
72
+ table_name = table_name.pluralize if pluralize_table_names
73
+ "#{table_name_prefix}#{table_name}#{table_name_suffix}"
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,210 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper::Orm::ActiveRecord::Mixins
4
+ module Application
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ self.table_name = compute_doorkeeper_table_name
9
+ self.strict_loading_by_default = false if respond_to?(:strict_loading_by_default)
10
+
11
+ include ::Doorkeeper::ApplicationMixin
12
+
13
+ has_many :access_grants,
14
+ foreign_key: :application_id,
15
+ dependent: :delete_all,
16
+ class_name: Doorkeeper.config.access_grant_class.to_s
17
+
18
+ has_many :access_tokens,
19
+ foreign_key: :application_id,
20
+ dependent: :delete_all,
21
+ class_name: Doorkeeper.config.access_token_class.to_s
22
+
23
+ validates :name, :secret, :uid, presence: true
24
+ validates :uid, uniqueness: { case_sensitive: true }
25
+ validates :redirect_uri, "doorkeeper/redirect_uri": true
26
+ validates :confidential, inclusion: { in: [true, false] }
27
+
28
+ validate :scopes_match_configured, if: :enforce_scopes?
29
+
30
+ before_validation :generate_uid, :generate_secret, on: :create
31
+
32
+ has_many :authorized_tokens,
33
+ -> { where(revoked_at: nil) },
34
+ foreign_key: :application_id,
35
+ class_name: Doorkeeper.config.access_token_class.to_s
36
+
37
+ has_many :authorized_applications,
38
+ through: :authorized_tokens,
39
+ source: :application
40
+
41
+ # Generates a new secret for this application, intended to be used
42
+ # for rotating the secret or in case of compromise.
43
+ #
44
+ # @return [String] new transformed secret value
45
+ #
46
+ def renew_secret
47
+ @raw_secret = secret_generator.generate
48
+ secret_strategy.store_secret(self, :secret, @raw_secret)
49
+ end
50
+
51
+ # We keep a volatile copy of the raw secret for initial communication
52
+ # The stored refresh_token may be mapped and not available in cleartext.
53
+ #
54
+ # Some strategies allow restoring stored secrets (e.g. symmetric encryption)
55
+ # while hashing strategies do not, so you cannot rely on this value
56
+ # returning a present value for persisted tokens.
57
+ def plaintext_secret
58
+ if secret_strategy.allows_restoring_secrets?
59
+ secret_strategy.restore_secret(self, :secret)
60
+ else
61
+ @raw_secret
62
+ end
63
+ end
64
+
65
+ # Represents client as set of it's attributes in JSON format.
66
+ # This is the right way how we want to override ActiveRecord #to_json.
67
+ #
68
+ # Respects privacy settings and serializes minimum set of attributes
69
+ # for public/private clients and full set for authorized owners.
70
+ #
71
+ # @return [Hash] entity attributes for JSON
72
+ #
73
+ def as_json(options = {})
74
+ # if application belongs to some owner we need to check if it's the same as
75
+ # the one passed in the options or check if we render the client as an owner
76
+ if (respond_to?(:owner) && owner && owner == options[:current_resource_owner]) ||
77
+ options[:as_owner]
78
+ # Owners can see all the client attributes, fallback to ActiveModel serialization
79
+ super
80
+ else
81
+ # if application has no owner or it's owner doesn't match one from the options
82
+ # we render only minimum set of attributes that could be exposed to a public
83
+ only = extract_serializable_attributes(options)
84
+ super(options.merge(only: only))
85
+ end
86
+ end
87
+
88
+ def authorized_for_resource_owner?(resource_owner)
89
+ Doorkeeper.configuration.authorize_resource_owner_for_client.call(self, resource_owner)
90
+ end
91
+
92
+ # We need to hook into this method to allow serializing plan-text secrets
93
+ # when secrets hashing enabled.
94
+ #
95
+ # @param key [String] attribute name
96
+ #
97
+ def read_attribute_for_serialization(key)
98
+ return super unless key.to_s == "secret"
99
+
100
+ plaintext_secret || secret
101
+ end
102
+
103
+ private
104
+
105
+ def secret_generator
106
+ generator_name = Doorkeeper.config.application_secret_generator
107
+ generator = generator_name.constantize
108
+
109
+ return generator if generator.respond_to?(:generate)
110
+
111
+ raise Errors::UnableToGenerateToken, "#{generator} does not respond to `.generate`."
112
+ rescue NameError
113
+ raise Errors::TokenGeneratorNotFound, "#{generator_name} not found"
114
+ end
115
+
116
+ def generate_uid
117
+ self.uid = Doorkeeper::OAuth::Helpers::UniqueToken.generate if uid.blank?
118
+ end
119
+
120
+ def generate_secret
121
+ return if secret.present?
122
+
123
+ renew_secret
124
+ end
125
+
126
+ def scopes_match_configured
127
+ if scopes.present? && !Doorkeeper::OAuth::Helpers::ScopeChecker.valid?(
128
+ scope_str: scopes.to_s,
129
+ server_scopes: Doorkeeper.config.scopes,
130
+ )
131
+ errors.add(:scopes, :not_match_configured)
132
+ end
133
+ end
134
+
135
+ def enforce_scopes?
136
+ Doorkeeper.config.enforce_configured_scopes?
137
+ end
138
+
139
+ # Helper method to extract collection of serializable attribute names
140
+ # considering serialization options (like `only`, `except` and so on).
141
+ #
142
+ # @param options [Hash] serialization options
143
+ #
144
+ # @return [Array<String>]
145
+ # collection of attributes to be serialized using #as_json
146
+ #
147
+ def extract_serializable_attributes(options = {})
148
+ opts = options.try(:dup) || {}
149
+ only = Array.wrap(opts[:only]).map(&:to_s)
150
+
151
+ only = if only.blank?
152
+ client_serializable_attributes
153
+ else
154
+ only & client_serializable_attributes
155
+ end
156
+
157
+ only -= Array.wrap(opts[:except]).map(&:to_s) if opts.key?(:except)
158
+ only.uniq
159
+ end
160
+
161
+ # Collection of attributes that could be serialized for public.
162
+ # Override this method if you need additional attributes to be serialized.
163
+ #
164
+ # @return [Array<String>] collection of serializable attributes
165
+ #
166
+ # NOTE: `serializable_attributes` method already taken by Rails >= 6
167
+ #
168
+ def client_serializable_attributes
169
+ attributes = %w[id name created_at]
170
+ attributes << "uid" unless confidential?
171
+ attributes
172
+ end
173
+ end
174
+
175
+ module ClassMethods
176
+ # Returns Applications associated with active (not revoked) Access Tokens
177
+ # that are owned by the specific Resource Owner.
178
+ #
179
+ # @param resource_owner [ActiveRecord::Base]
180
+ # Resource Owner model instance
181
+ #
182
+ # @return [ActiveRecord::Relation]
183
+ # Applications authorized for the Resource Owner
184
+ #
185
+ def authorized_for(resource_owner)
186
+ resource_access_tokens = Doorkeeper.config.access_token_model.active_for(resource_owner)
187
+ where(id: resource_access_tokens.select(:application_id).distinct)
188
+ end
189
+
190
+ # Revokes AccessToken and AccessGrant records that have not been revoked and
191
+ # associated with the specific Application and Resource Owner.
192
+ #
193
+ # @param resource_owner [ActiveRecord::Base]
194
+ # instance of the Resource Owner model
195
+ #
196
+ def revoke_tokens_and_grants_for(id, resource_owner)
197
+ Doorkeeper.config.access_token_model.revoke_all_for(id, resource_owner)
198
+ Doorkeeper.config.access_grant_model.revoke_all_for(id, resource_owner)
199
+ end
200
+
201
+ private
202
+
203
+ def compute_doorkeeper_table_name
204
+ table_name = "oauth_application"
205
+ table_name = table_name.pluralize if pluralize_table_names
206
+ "#{table_name_prefix}#{table_name}#{table_name_suffix}"
207
+ end
208
+ end
209
+ end
210
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
4
+
5
+ module Doorkeeper
6
+ # ActiveModel validator for redirect URI validation in according
7
+ # to OAuth standards and Doorkeeper configuration.
8
+ class RedirectUriValidator < ActiveModel::EachValidator
9
+ def validate_each(record, attribute, value)
10
+ if value.blank?
11
+ return if Doorkeeper.config.allow_blank_redirect_uri?(record)
12
+
13
+ record.errors.add(attribute, :blank)
14
+ else
15
+ value.split.each do |val|
16
+ next if oob_redirect_uri?(val)
17
+
18
+ uri = ::URI.parse(val)
19
+ record.errors.add(attribute, :forbidden_uri) if forbidden_uri?(uri)
20
+ record.errors.add(attribute, :fragment_present) unless uri.fragment.nil?
21
+ record.errors.add(attribute, :unspecified_scheme) if unspecified_scheme?(uri)
22
+ record.errors.add(attribute, :relative_uri) if relative_uri?(uri)
23
+ record.errors.add(attribute, :secured_uri) if invalid_ssl_uri?(uri)
24
+ record.errors.add(attribute, :invalid_uri) if unspecified_host?(uri)
25
+ end
26
+ end
27
+ rescue URI::InvalidURIError
28
+ record.errors.add(attribute, :invalid_uri)
29
+ end
30
+
31
+ private
32
+
33
+ def oob_redirect_uri?(uri)
34
+ Doorkeeper::OAuth::NonStandard::IETF_WG_OAUTH2_OOB_METHODS.include?(uri)
35
+ end
36
+
37
+ def forbidden_uri?(uri)
38
+ Doorkeeper.config.forbid_redirect_uri.call(uri)
39
+ end
40
+
41
+ def unspecified_scheme?(uri)
42
+ return true if uri.opaque.present?
43
+
44
+ %w[localhost].include?(uri.try(:scheme))
45
+ end
46
+
47
+ def unspecified_host?(uri)
48
+ uri.is_a?(URI::HTTP) && uri.host.blank?
49
+ end
50
+
51
+ def relative_uri?(uri)
52
+ uri.scheme.nil? && uri.host.blank?
53
+ end
54
+
55
+ def invalid_ssl_uri?(uri)
56
+ forces_ssl = Doorkeeper.config.force_ssl_in_redirect_uri
57
+ non_https = uri.try(:scheme) == "http"
58
+
59
+ if forces_ssl.respond_to?(:call)
60
+ forces_ssl.call(uri) && non_https
61
+ else
62
+ forces_ssl && non_https
63
+ end
64
+ end
65
+ end
66
+ end
@@ -15,7 +15,8 @@ module Doorkeeper
15
15
  def clean_revoked
16
16
  table = @base_scope.arel_table
17
17
 
18
- @base_scope.where.not(revoked_at: nil)
18
+ @base_scope
19
+ .where.not(revoked_at: nil)
19
20
  .where(table[:revoked_at].lt(Time.current))
20
21
  .in_batches(&:delete_all)
21
22
  end
@@ -24,7 +25,9 @@ module Doorkeeper
24
25
  def clean_expired(ttl)
25
26
  table = @base_scope.arel_table
26
27
 
27
- @base_scope.where(table[:created_at].lt(Time.current - ttl))
28
+ @base_scope
29
+ .where.not(expires_in: nil)
30
+ .where(table[:created_at].lt(Time.current - ttl))
28
31
  .in_batches(&:delete_all)
29
32
  end
30
33
  end