doorkeeper 4.2.0 → 5.5.2

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

Potentially problematic release.


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

Files changed (271) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1038 -0
  3. data/README.md +110 -348
  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 -20
  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 +112 -35
  12. data/app/helpers/doorkeeper/dashboard_helper.rb +10 -6
  13. data/app/views/doorkeeper/applications/_delete_form.html.erb +4 -3
  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 +7 -1
  22. data/app/views/doorkeeper/authorized_applications/_delete_form.html.erb +1 -2
  23. data/app/views/doorkeeper/authorized_applications/index.html.erb +0 -1
  24. data/app/views/layouts/doorkeeper/admin.html.erb +16 -14
  25. data/config/locales/en.yml +33 -9
  26. data/lib/doorkeeper/config/abstract_builder.rb +28 -0
  27. data/lib/doorkeeper/config/option.rb +82 -0
  28. data/lib/doorkeeper/config/validations.rb +53 -0
  29. data/lib/doorkeeper/config.rb +545 -143
  30. data/lib/doorkeeper/engine.rb +11 -5
  31. data/lib/doorkeeper/errors.rb +37 -10
  32. data/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
  33. data/lib/doorkeeper/grant_flow/flow.rb +44 -0
  34. data/lib/doorkeeper/grant_flow/registry.rb +50 -0
  35. data/lib/doorkeeper/grant_flow.rb +45 -0
  36. data/lib/doorkeeper/grape/authorization_decorator.rb +6 -4
  37. data/lib/doorkeeper/grape/helpers.rb +24 -12
  38. data/lib/doorkeeper/helpers/controller.rb +49 -27
  39. data/lib/doorkeeper/models/access_grant_mixin.rb +100 -21
  40. data/lib/doorkeeper/models/access_token_mixin.rb +379 -75
  41. data/lib/doorkeeper/models/application_mixin.rb +72 -25
  42. data/lib/doorkeeper/models/concerns/accessible.rb +6 -0
  43. data/lib/doorkeeper/models/concerns/expirable.rb +20 -6
  44. data/lib/doorkeeper/models/concerns/orderable.rb +15 -0
  45. data/lib/doorkeeper/models/concerns/ownership.rb +4 -7
  46. data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
  47. data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
  48. data/lib/doorkeeper/models/concerns/revocable.rb +12 -18
  49. data/lib/doorkeeper/models/concerns/scopes.rb +12 -2
  50. data/lib/doorkeeper/models/concerns/secret_storable.rb +106 -0
  51. data/lib/doorkeeper/oauth/authorization/code.rb +48 -12
  52. data/lib/doorkeeper/oauth/authorization/context.rb +17 -0
  53. data/lib/doorkeeper/oauth/authorization/token.rb +66 -28
  54. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +22 -18
  55. data/lib/doorkeeper/oauth/authorization_code_request.rb +64 -14
  56. data/lib/doorkeeper/oauth/base_request.rb +66 -0
  57. data/lib/doorkeeper/oauth/base_response.rb +31 -0
  58. data/lib/doorkeeper/oauth/client/credentials.rb +23 -10
  59. data/lib/doorkeeper/oauth/client.rb +10 -12
  60. data/lib/doorkeeper/oauth/client_credentials/creator.rb +47 -4
  61. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +16 -9
  62. data/lib/doorkeeper/oauth/client_credentials/validator.rb +56 -0
  63. data/lib/doorkeeper/oauth/client_credentials_request.rb +11 -15
  64. data/lib/doorkeeper/oauth/code_request.rb +8 -12
  65. data/lib/doorkeeper/oauth/code_response.rb +28 -15
  66. data/lib/doorkeeper/oauth/error.rb +5 -3
  67. data/lib/doorkeeper/oauth/error_response.rb +41 -20
  68. data/lib/doorkeeper/oauth/forbidden_token_response.rb +10 -3
  69. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +23 -18
  70. data/lib/doorkeeper/oauth/helpers/unique_token.rb +20 -3
  71. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +53 -3
  72. data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
  73. data/lib/doorkeeper/oauth/invalid_request_response.rb +43 -0
  74. data/lib/doorkeeper/oauth/invalid_token_response.rb +31 -5
  75. data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
  76. data/lib/doorkeeper/oauth/password_access_token_request.rb +45 -13
  77. data/lib/doorkeeper/oauth/pre_authorization.rb +135 -26
  78. data/lib/doorkeeper/oauth/refresh_token_request.rb +61 -36
  79. data/lib/doorkeeper/oauth/scopes.rb +26 -12
  80. data/lib/doorkeeper/oauth/token.rb +25 -23
  81. data/lib/doorkeeper/oauth/token_introspection.rb +202 -0
  82. data/lib/doorkeeper/oauth/token_request.rb +8 -21
  83. data/lib/doorkeeper/oauth/token_response.rb +14 -10
  84. data/lib/doorkeeper/oauth.rb +13 -0
  85. data/lib/doorkeeper/orm/active_record/access_grant.rb +6 -4
  86. data/lib/doorkeeper/orm/active_record/access_token.rb +5 -25
  87. data/lib/doorkeeper/orm/active_record/application.rb +6 -15
  88. data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +68 -0
  89. data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +59 -0
  90. data/lib/doorkeeper/orm/active_record/mixins/application.rb +198 -0
  91. data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +66 -0
  92. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +33 -0
  93. data/lib/doorkeeper/orm/active_record.rb +37 -8
  94. data/lib/doorkeeper/rails/helpers.rb +14 -15
  95. data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
  96. data/lib/doorkeeper/rails/routes/mapper.rb +3 -1
  97. data/lib/doorkeeper/rails/routes/mapping.rb +10 -8
  98. data/lib/doorkeeper/rails/routes/registry.rb +45 -0
  99. data/lib/doorkeeper/rails/routes.rb +42 -30
  100. data/lib/doorkeeper/rake/db.rake +40 -0
  101. data/lib/doorkeeper/rake/setup.rake +11 -0
  102. data/lib/doorkeeper/rake.rb +14 -0
  103. data/lib/doorkeeper/request/authorization_code.rb +12 -4
  104. data/lib/doorkeeper/request/client_credentials.rb +3 -3
  105. data/lib/doorkeeper/request/code.rb +1 -1
  106. data/lib/doorkeeper/request/password.rb +5 -14
  107. data/lib/doorkeeper/request/refresh_token.rb +6 -5
  108. data/lib/doorkeeper/request/strategy.rb +4 -2
  109. data/lib/doorkeeper/request/token.rb +1 -1
  110. data/lib/doorkeeper/request.rb +62 -29
  111. data/lib/doorkeeper/secret_storing/base.rb +64 -0
  112. data/lib/doorkeeper/secret_storing/bcrypt.rb +60 -0
  113. data/lib/doorkeeper/secret_storing/plain.rb +33 -0
  114. data/lib/doorkeeper/secret_storing/sha256_hash.rb +26 -0
  115. data/lib/doorkeeper/server.rb +9 -19
  116. data/lib/doorkeeper/stale_records_cleaner.rb +24 -0
  117. data/lib/doorkeeper/validations.rb +5 -2
  118. data/lib/doorkeeper/version.rb +12 -1
  119. data/lib/doorkeeper.rb +111 -56
  120. data/lib/generators/doorkeeper/application_owner_generator.rb +28 -13
  121. data/lib/generators/doorkeeper/confidential_applications_generator.rb +33 -0
  122. data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
  123. data/lib/generators/doorkeeper/install_generator.rb +19 -9
  124. data/lib/generators/doorkeeper/migration_generator.rb +27 -10
  125. data/lib/generators/doorkeeper/pkce_generator.rb +33 -0
  126. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +31 -19
  127. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  128. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +9 -0
  129. data/lib/generators/doorkeeper/templates/{add_previous_refresh_token_to_access_tokens.rb → add_previous_refresh_token_to_access_tokens.rb.erb} +3 -1
  130. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +8 -0
  131. data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
  132. data/lib/generators/doorkeeper/templates/initializer.rb +410 -31
  133. data/lib/generators/doorkeeper/templates/migration.rb.erb +88 -0
  134. data/lib/generators/doorkeeper/views_generator.rb +8 -4
  135. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  136. metadata +132 -286
  137. data/.gitignore +0 -14
  138. data/.hound.yml +0 -13
  139. data/.rspec +0 -1
  140. data/.travis.yml +0 -20
  141. data/CONTRIBUTING.md +0 -47
  142. data/Gemfile +0 -14
  143. data/NEWS.md +0 -593
  144. data/RELEASING.md +0 -17
  145. data/Rakefile +0 -20
  146. data/app/validators/redirect_uri_validator.rb +0 -34
  147. data/doorkeeper.gemspec +0 -28
  148. data/lib/doorkeeper/oauth/client/methods.rb +0 -18
  149. data/lib/doorkeeper/oauth/client_credentials/validation.rb +0 -45
  150. data/lib/doorkeeper/oauth/request_concern.rb +0 -48
  151. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb +0 -7
  152. data/lib/generators/doorkeeper/templates/migration.rb +0 -68
  153. data/spec/controllers/application_metal_controller.rb +0 -10
  154. data/spec/controllers/applications_controller_spec.rb +0 -58
  155. data/spec/controllers/authorizations_controller_spec.rb +0 -189
  156. data/spec/controllers/protected_resources_controller_spec.rb +0 -300
  157. data/spec/controllers/token_info_controller_spec.rb +0 -52
  158. data/spec/controllers/tokens_controller_spec.rb +0 -88
  159. data/spec/dummy/Rakefile +0 -7
  160. data/spec/dummy/app/controllers/application_controller.rb +0 -3
  161. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +0 -7
  162. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +0 -12
  163. data/spec/dummy/app/controllers/home_controller.rb +0 -17
  164. data/spec/dummy/app/controllers/metal_controller.rb +0 -11
  165. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +0 -11
  166. data/spec/dummy/app/helpers/application_helper.rb +0 -5
  167. data/spec/dummy/app/models/user.rb +0 -5
  168. data/spec/dummy/app/views/home/index.html.erb +0 -0
  169. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  170. data/spec/dummy/config/application.rb +0 -23
  171. data/spec/dummy/config/boot.rb +0 -9
  172. data/spec/dummy/config/database.yml +0 -15
  173. data/spec/dummy/config/environment.rb +0 -5
  174. data/spec/dummy/config/environments/development.rb +0 -29
  175. data/spec/dummy/config/environments/production.rb +0 -62
  176. data/spec/dummy/config/environments/test.rb +0 -44
  177. data/spec/dummy/config/initializers/active_record_belongs_to_required_by_default.rb +0 -6
  178. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  179. data/spec/dummy/config/initializers/doorkeeper.rb +0 -96
  180. data/spec/dummy/config/initializers/secret_token.rb +0 -9
  181. data/spec/dummy/config/initializers/session_store.rb +0 -8
  182. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
  183. data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
  184. data/spec/dummy/config/routes.rb +0 -52
  185. data/spec/dummy/config.ru +0 -4
  186. data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -9
  187. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -5
  188. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +0 -60
  189. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +0 -7
  190. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +0 -11
  191. data/spec/dummy/db/schema.rb +0 -67
  192. data/spec/dummy/public/404.html +0 -26
  193. data/spec/dummy/public/422.html +0 -26
  194. data/spec/dummy/public/500.html +0 -26
  195. data/spec/dummy/public/favicon.ico +0 -0
  196. data/spec/dummy/script/rails +0 -6
  197. data/spec/factories.rb +0 -28
  198. data/spec/generators/application_owner_generator_spec.rb +0 -22
  199. data/spec/generators/install_generator_spec.rb +0 -31
  200. data/spec/generators/migration_generator_spec.rb +0 -20
  201. data/spec/generators/templates/routes.rb +0 -3
  202. data/spec/generators/views_generator_spec.rb +0 -27
  203. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -24
  204. data/spec/lib/config_spec.rb +0 -334
  205. data/spec/lib/doorkeeper_spec.rb +0 -28
  206. data/spec/lib/models/expirable_spec.rb +0 -51
  207. data/spec/lib/models/revocable_spec.rb +0 -59
  208. data/spec/lib/models/scopes_spec.rb +0 -43
  209. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -42
  210. data/spec/lib/oauth/authorization_code_request_spec.rb +0 -80
  211. data/spec/lib/oauth/client/credentials_spec.rb +0 -47
  212. data/spec/lib/oauth/client/methods_spec.rb +0 -54
  213. data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -44
  214. data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -86
  215. data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -54
  216. data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -27
  217. data/spec/lib/oauth/client_credentials_request_spec.rb +0 -104
  218. data/spec/lib/oauth/client_spec.rb +0 -39
  219. data/spec/lib/oauth/code_request_spec.rb +0 -45
  220. data/spec/lib/oauth/code_response_spec.rb +0 -34
  221. data/spec/lib/oauth/error_response_spec.rb +0 -61
  222. data/spec/lib/oauth/error_spec.rb +0 -23
  223. data/spec/lib/oauth/forbidden_token_response_spec.rb +0 -23
  224. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -64
  225. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -20
  226. data/spec/lib/oauth/helpers/uri_checker_spec.rb +0 -104
  227. data/spec/lib/oauth/invalid_token_response_spec.rb +0 -28
  228. data/spec/lib/oauth/password_access_token_request_spec.rb +0 -90
  229. data/spec/lib/oauth/pre_authorization_spec.rb +0 -155
  230. data/spec/lib/oauth/refresh_token_request_spec.rb +0 -154
  231. data/spec/lib/oauth/scopes_spec.rb +0 -122
  232. data/spec/lib/oauth/token_request_spec.rb +0 -98
  233. data/spec/lib/oauth/token_response_spec.rb +0 -85
  234. data/spec/lib/oauth/token_spec.rb +0 -116
  235. data/spec/lib/request/strategy_spec.rb +0 -53
  236. data/spec/lib/server_spec.rb +0 -52
  237. data/spec/models/doorkeeper/access_grant_spec.rb +0 -36
  238. data/spec/models/doorkeeper/access_token_spec.rb +0 -394
  239. data/spec/models/doorkeeper/application_spec.rb +0 -179
  240. data/spec/requests/applications/applications_request_spec.rb +0 -94
  241. data/spec/requests/applications/authorized_applications_spec.rb +0 -30
  242. data/spec/requests/endpoints/authorization_spec.rb +0 -72
  243. data/spec/requests/endpoints/token_spec.rb +0 -64
  244. data/spec/requests/flows/authorization_code_errors_spec.rb +0 -66
  245. data/spec/requests/flows/authorization_code_spec.rb +0 -156
  246. data/spec/requests/flows/client_credentials_spec.rb +0 -58
  247. data/spec/requests/flows/implicit_grant_errors_spec.rb +0 -32
  248. data/spec/requests/flows/implicit_grant_spec.rb +0 -61
  249. data/spec/requests/flows/password_spec.rb +0 -115
  250. data/spec/requests/flows/refresh_token_spec.rb +0 -174
  251. data/spec/requests/flows/revoke_token_spec.rb +0 -157
  252. data/spec/requests/flows/skip_authorization_spec.rb +0 -59
  253. data/spec/requests/protected_resources/metal_spec.rb +0 -14
  254. data/spec/requests/protected_resources/private_api_spec.rb +0 -81
  255. data/spec/routing/custom_controller_routes_spec.rb +0 -71
  256. data/spec/routing/default_routes_spec.rb +0 -35
  257. data/spec/routing/scoped_routes_spec.rb +0 -31
  258. data/spec/spec_helper.rb +0 -2
  259. data/spec/spec_helper_integration.rb +0 -59
  260. data/spec/support/dependencies/factory_girl.rb +0 -2
  261. data/spec/support/helpers/access_token_request_helper.rb +0 -11
  262. data/spec/support/helpers/authorization_request_helper.rb +0 -41
  263. data/spec/support/helpers/config_helper.rb +0 -9
  264. data/spec/support/helpers/model_helper.rb +0 -67
  265. data/spec/support/helpers/request_spec_helper.rb +0 -76
  266. data/spec/support/helpers/url_helper.rb +0 -55
  267. data/spec/support/http_method_shim.rb +0 -24
  268. data/spec/support/orm/active_record.rb +0 -3
  269. data/spec/support/shared/controllers_shared_context.rb +0 -69
  270. data/spec/support/shared/models_shared_examples.rb +0 -52
  271. data/spec/validators/redirect_uri_validator_spec.rb +0 -78
@@ -0,0 +1,198 @@
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
+
10
+ include ::Doorkeeper::ApplicationMixin
11
+
12
+ has_many :access_grants,
13
+ foreign_key: :application_id,
14
+ dependent: :delete_all,
15
+ class_name: Doorkeeper.config.access_grant_class.to_s
16
+
17
+ has_many :access_tokens,
18
+ foreign_key: :application_id,
19
+ dependent: :delete_all,
20
+ class_name: Doorkeeper.config.access_token_class.to_s
21
+
22
+ validates :name, :secret, :uid, presence: true
23
+ validates :uid, uniqueness: { case_sensitive: true }
24
+ validates :redirect_uri, "doorkeeper/redirect_uri": true
25
+ validates :confidential, inclusion: { in: [true, false] }
26
+
27
+ validate :scopes_match_configured, if: :enforce_scopes?
28
+
29
+ before_validation :generate_uid, :generate_secret, on: :create
30
+
31
+ has_many :authorized_tokens,
32
+ -> { where(revoked_at: nil) },
33
+ foreign_key: :application_id,
34
+ class_name: Doorkeeper.config.access_token_class.to_s
35
+
36
+ has_many :authorized_applications,
37
+ through: :authorized_tokens,
38
+ source: :application
39
+
40
+ # Generates a new secret for this application, intended to be used
41
+ # for rotating the secret or in case of compromise.
42
+ #
43
+ # @return [String] new transformed secret value
44
+ #
45
+ def renew_secret
46
+ @raw_secret = Doorkeeper::OAuth::Helpers::UniqueToken.generate
47
+ secret_strategy.store_secret(self, :secret, @raw_secret)
48
+ end
49
+
50
+ # We keep a volatile copy of the raw secret for initial communication
51
+ # The stored refresh_token may be mapped and not available in cleartext.
52
+ #
53
+ # Some strategies allow restoring stored secrets (e.g. symmetric encryption)
54
+ # while hashing strategies do not, so you cannot rely on this value
55
+ # returning a present value for persisted tokens.
56
+ def plaintext_secret
57
+ if secret_strategy.allows_restoring_secrets?
58
+ secret_strategy.restore_secret(self, :secret)
59
+ else
60
+ @raw_secret
61
+ end
62
+ end
63
+
64
+ # Represents client as set of it's attributes in JSON format.
65
+ # This is the right way how we want to override ActiveRecord #to_json.
66
+ #
67
+ # Respects privacy settings and serializes minimum set of attributes
68
+ # for public/private clients and full set for authorized owners.
69
+ #
70
+ # @return [Hash] entity attributes for JSON
71
+ #
72
+ def as_json(options = {})
73
+ # if application belongs to some owner we need to check if it's the same as
74
+ # the one passed in the options or check if we render the client as an owner
75
+ if (respond_to?(:owner) && owner && owner == options[:current_resource_owner]) ||
76
+ options[:as_owner]
77
+ # Owners can see all the client attributes, fallback to ActiveModel serialization
78
+ super
79
+ else
80
+ # if application has no owner or it's owner doesn't match one from the options
81
+ # we render only minimum set of attributes that could be exposed to a public
82
+ only = extract_serializable_attributes(options)
83
+ super(options.merge(only: only))
84
+ end
85
+ end
86
+
87
+ def authorized_for_resource_owner?(resource_owner)
88
+ Doorkeeper.configuration.authorize_resource_owner_for_client.call(self, resource_owner)
89
+ end
90
+
91
+ # We need to hook into this method to allow serializing plan-text secrets
92
+ # when secrets hashing enabled.
93
+ #
94
+ # @param key [String] attribute name
95
+ #
96
+ def read_attribute_for_serialization(key)
97
+ return super unless key.to_s == "secret"
98
+
99
+ plaintext_secret || secret
100
+ end
101
+
102
+ private
103
+
104
+ def generate_uid
105
+ self.uid = Doorkeeper::OAuth::Helpers::UniqueToken.generate if uid.blank?
106
+ end
107
+
108
+ def generate_secret
109
+ return if secret.present?
110
+
111
+ renew_secret
112
+ end
113
+
114
+ def scopes_match_configured
115
+ if scopes.present? && !Doorkeeper::OAuth::Helpers::ScopeChecker.valid?(
116
+ scope_str: scopes.to_s,
117
+ server_scopes: Doorkeeper.config.scopes,
118
+ )
119
+ errors.add(:scopes, :not_match_configured)
120
+ end
121
+ end
122
+
123
+ def enforce_scopes?
124
+ Doorkeeper.config.enforce_configured_scopes?
125
+ end
126
+
127
+ # Helper method to extract collection of serializable attribute names
128
+ # considering serialization options (like `only`, `except` and so on).
129
+ #
130
+ # @param options [Hash] serialization options
131
+ #
132
+ # @return [Array<String>]
133
+ # collection of attributes to be serialized using #as_json
134
+ #
135
+ def extract_serializable_attributes(options = {})
136
+ opts = options.try(:dup) || {}
137
+ only = Array.wrap(opts[:only]).map(&:to_s)
138
+
139
+ only = if only.blank?
140
+ client_serializable_attributes
141
+ else
142
+ only & client_serializable_attributes
143
+ end
144
+
145
+ only -= Array.wrap(opts[:except]).map(&:to_s) if opts.key?(:except)
146
+ only.uniq
147
+ end
148
+
149
+ # Collection of attributes that could be serialized for public.
150
+ # Override this method if you need additional attributes to be serialized.
151
+ #
152
+ # @return [Array<String>] collection of serializable attributes
153
+ #
154
+ # NOTE: `serializable_attributes` method already taken by Rails >= 6
155
+ #
156
+ def client_serializable_attributes
157
+ attributes = %w[id name created_at]
158
+ attributes << "uid" unless confidential?
159
+ attributes
160
+ end
161
+ end
162
+
163
+ module ClassMethods
164
+ # Returns Applications associated with active (not revoked) Access Tokens
165
+ # that are owned by the specific Resource Owner.
166
+ #
167
+ # @param resource_owner [ActiveRecord::Base]
168
+ # Resource Owner model instance
169
+ #
170
+ # @return [ActiveRecord::Relation]
171
+ # Applications authorized for the Resource Owner
172
+ #
173
+ def authorized_for(resource_owner)
174
+ resource_access_tokens = Doorkeeper.config.access_token_model.active_for(resource_owner)
175
+ where(id: resource_access_tokens.select(:application_id).distinct)
176
+ end
177
+
178
+ # Revokes AccessToken and AccessGrant records that have not been revoked and
179
+ # associated with the specific Application and Resource Owner.
180
+ #
181
+ # @param resource_owner [ActiveRecord::Base]
182
+ # instance of the Resource Owner model
183
+ #
184
+ def revoke_tokens_and_grants_for(id, resource_owner)
185
+ Doorkeeper.config.access_token_model.revoke_all_for(id, resource_owner)
186
+ Doorkeeper.config.access_grant_model.revoke_all_for(id, resource_owner)
187
+ end
188
+
189
+ private
190
+
191
+ def compute_doorkeeper_table_name
192
+ table_name = "oauth_application"
193
+ table_name = table_name.pluralize if pluralize_table_names
194
+ "#{table_name_prefix}#{table_name}#{table_name_suffix}"
195
+ end
196
+ end
197
+ end
198
+ 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.nil?
49
+ end
50
+
51
+ def relative_uri?(uri)
52
+ uri.scheme.nil? && uri.host.nil?
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
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module Orm
5
+ module ActiveRecord
6
+ # Helper class to clear stale and non-active tokens and grants.
7
+ # Used by Doorkeeper Rake tasks.
8
+ #
9
+ class StaleRecordsCleaner
10
+ def initialize(base_scope)
11
+ @base_scope = base_scope
12
+ end
13
+
14
+ # Clears revoked records
15
+ def clean_revoked
16
+ table = @base_scope.arel_table
17
+
18
+ @base_scope.where.not(revoked_at: nil)
19
+ .where(table[:revoked_at].lt(Time.current))
20
+ .in_batches(&:delete_all)
21
+ end
22
+
23
+ # Clears expired records
24
+ def clean_expired(ttl)
25
+ table = @base_scope.arel_table
26
+
27
+ @base_scope.where(table[:created_at].lt(Time.current - ttl))
28
+ .in_batches(&:delete_all)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,22 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/lazy_load_hooks"
4
+
1
5
  module Doorkeeper
2
6
  module Orm
7
+ # ActiveRecord ORM for Doorkeeper entity models.
8
+ # Consists of three main OAuth entities:
9
+ # * Access Token
10
+ # * Access Grant
11
+ # * Application (client)
12
+ #
13
+ # Do a lazy loading of all the required and configured stuff.
14
+ #
3
15
  module ActiveRecord
4
16
  def self.initialize_models!
5
- require 'doorkeeper/orm/active_record/access_grant'
6
- require 'doorkeeper/orm/active_record/access_token'
7
- require 'doorkeeper/orm/active_record/application'
17
+ lazy_load do
18
+ require "doorkeeper/orm/active_record/stale_records_cleaner"
19
+ require "doorkeeper/orm/active_record/access_grant"
20
+ require "doorkeeper/orm/active_record/access_token"
21
+ require "doorkeeper/orm/active_record/application"
8
22
 
9
- if Doorkeeper.configuration.active_record_options[:establish_connection]
10
- [Doorkeeper::AccessGrant, Doorkeeper::AccessToken, Doorkeeper::Application].each do |c|
11
- c.send :establish_connection, Doorkeeper.configuration.active_record_options[:establish_connection]
23
+ if (options = Doorkeeper.config.active_record_options[:establish_connection])
24
+ Doorkeeper::Orm::ActiveRecord.models.each do |model|
25
+ model.establish_connection(options)
26
+ end
12
27
  end
13
28
  end
14
29
  end
15
30
 
16
31
  def self.initialize_application_owner!
17
- require 'doorkeeper/models/concerns/ownership'
32
+ lazy_load do
33
+ require "doorkeeper/models/concerns/ownership"
34
+
35
+ Doorkeeper.config.application_model.include(Doorkeeper::Models::Ownership)
36
+ end
37
+ end
38
+
39
+ def self.lazy_load(&block)
40
+ ActiveSupport.on_load(:active_record, {}, &block)
41
+ end
18
42
 
19
- Doorkeeper::Application.send :include, Doorkeeper::Models::Ownership
43
+ def self.models
44
+ [
45
+ Doorkeeper.config.access_grant_model,
46
+ Doorkeeper.config.access_token_model,
47
+ Doorkeeper.config.application_model,
48
+ ]
20
49
  end
21
50
  end
22
51
  end
@@ -1,38 +1,37 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module Rails
3
5
  module Helpers
4
- extend ActiveSupport::Concern
5
-
6
6
  def doorkeeper_authorize!(*scopes)
7
- @_doorkeeper_scopes = scopes.presence || Doorkeeper.configuration.default_scopes
7
+ @_doorkeeper_scopes = scopes.presence || Doorkeeper.config.default_scopes
8
8
 
9
- unless valid_doorkeeper_token?
10
- doorkeeper_render_error
11
- end
9
+ doorkeeper_render_error unless valid_doorkeeper_token?
12
10
  end
13
11
 
14
- def doorkeeper_unauthorized_render_options(error: nil)
15
- end
12
+ def doorkeeper_unauthorized_render_options(**); end
16
13
 
17
- def doorkeeper_forbidden_render_options(error: nil)
18
- end
14
+ def doorkeeper_forbidden_render_options(**); end
19
15
 
20
16
  def valid_doorkeeper_token?
21
- doorkeeper_token && doorkeeper_token.acceptable?(@_doorkeeper_scopes)
17
+ doorkeeper_token&.acceptable?(@_doorkeeper_scopes)
22
18
  end
23
19
 
24
20
  private
25
21
 
26
22
  def doorkeeper_render_error
27
23
  error = doorkeeper_error
28
- headers.merge! error.headers.reject { |k| "Content-Type" == k }
24
+ error.raise_exception! if Doorkeeper.config.raise_on_errors?
25
+
26
+ headers.merge!(error.headers.reject { |k| k == "Content-Type" })
29
27
  doorkeeper_render_error_with(error)
30
28
  end
31
29
 
32
30
  def doorkeeper_render_error_with(error)
33
31
  options = doorkeeper_render_options(error) || {}
34
32
  status = doorkeeper_status_for_error(
35
- error, options.delete(:respond_not_found_when_forbidden))
33
+ error, options.delete(:respond_not_found_when_forbidden),
34
+ )
36
35
  if options.blank?
37
36
  head status
38
37
  else
@@ -71,9 +70,9 @@ module Doorkeeper
71
70
  end
72
71
 
73
72
  def doorkeeper_token
74
- @_doorkeeper_token ||= OAuth::Token.authenticate(
73
+ @doorkeeper_token ||= OAuth::Token.authenticate(
75
74
  request,
76
- *Doorkeeper.configuration.access_token_methods
75
+ *Doorkeeper.config.access_token_methods,
77
76
  )
78
77
  end
79
78
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module Rails
5
+ # Abstract router module that implements base behavior
6
+ # for generating and mapping Rails routes.
7
+ #
8
+ # Could be reused in Doorkeeper extensions.
9
+ #
10
+ module AbstractRouter
11
+ extend ActiveSupport::Concern
12
+
13
+ attr_reader :routes
14
+
15
+ def initialize(routes, mapper = Mapper.new, &block)
16
+ @routes = routes
17
+ @mapping = mapper.map(&block)
18
+ end
19
+
20
+ def generate_routes!(**_options)
21
+ raise NotImplementedError, "must be redefined for #{self.class.name}!"
22
+ end
23
+
24
+ private
25
+
26
+ def map_route(name, method)
27
+ return if @mapping.skipped?(name)
28
+
29
+ send(method, @mapping[name])
30
+
31
+ mapping[name] = @mapping[name]
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module Rails
3
- class Routes
5
+ class Routes # :nodoc:
4
6
  class Mapper
5
7
  def initialize(mapping = Mapping.new)
6
8
  @mapping = mapping
@@ -1,22 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module Rails
3
- class Routes
5
+ class Routes # :nodoc:
4
6
  class Mapping
5
7
  attr_accessor :controllers, :as, :skips
6
8
 
7
9
  def initialize
8
10
  @controllers = {
9
- authorizations: 'doorkeeper/authorizations',
10
- applications: 'doorkeeper/applications',
11
- authorized_applications: 'doorkeeper/authorized_applications',
12
- tokens: 'doorkeeper/tokens',
13
- token_info: 'doorkeeper/token_info'
11
+ authorizations: "doorkeeper/authorizations",
12
+ applications: "doorkeeper/applications",
13
+ authorized_applications: "doorkeeper/authorized_applications",
14
+ tokens: "doorkeeper/tokens",
15
+ token_info: "doorkeeper/token_info",
14
16
  }
15
17
 
16
18
  @as = {
17
19
  authorizations: :authorization,
18
20
  tokens: :token,
19
- token_info: :token_info
21
+ token_info: :token_info,
20
22
  }
21
23
 
22
24
  @skips = []
@@ -25,7 +27,7 @@ module Doorkeeper
25
27
  def [](routes)
26
28
  {
27
29
  controllers: @controllers[routes],
28
- as: @as[routes]
30
+ as: @as[routes],
29
31
  }
30
32
  end
31
33
 
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module Rails
5
+ class Routes
6
+ # Thread-safe registry of any Doorkeeper additional routes.
7
+ # Used to allow implementing of Doorkeeper extensions that must
8
+ # use their own routes.
9
+ #
10
+ module Registry
11
+ ROUTES_ACCESS_LOCK = Mutex.new
12
+ ROUTES_DEFINITION_LOCK = Mutex.new
13
+
14
+ InvalidRouterClass = Class.new(StandardError)
15
+
16
+ # Collection of additional registered routes for Doorkeeper.
17
+ #
18
+ # @return [Array<Object>] set of registered routes
19
+ #
20
+ def registered_routes
21
+ ROUTES_DEFINITION_LOCK.synchronize do
22
+ @registered_routes ||= Set.new
23
+ end
24
+ end
25
+
26
+ # Registers additional routes in the Doorkeeper registry
27
+ #
28
+ # @param [Object] routes
29
+ # routes class
30
+ #
31
+ def register_routes(routes)
32
+ if !routes.is_a?(Module) || !(routes < AbstractRouter)
33
+ raise InvalidRouterClass, "routes class must include Doorkeeper::Rails::AbstractRouter"
34
+ end
35
+
36
+ ROUTES_ACCESS_LOCK.synchronize do
37
+ registered_routes << routes
38
+ end
39
+ end
40
+
41
+ alias register register_routes
42
+ end
43
+ end
44
+ end
45
+ end
@@ -1,33 +1,42 @@
1
- require 'doorkeeper/rails/routes/mapping'
2
- require 'doorkeeper/rails/routes/mapper'
1
+ # frozen_string_literal: true
2
+
3
+ require "doorkeeper/rails/routes/mapping"
4
+ require "doorkeeper/rails/routes/mapper"
5
+ require "doorkeeper/rails/routes/abstract_router"
6
+ require "doorkeeper/rails/routes/registry"
3
7
 
4
8
  module Doorkeeper
5
9
  module Rails
6
- class Routes
10
+ class Routes # :nodoc:
7
11
  module Helper
8
- # TODO: options hash is not being used
9
12
  def use_doorkeeper(options = {}, &block)
10
13
  Doorkeeper::Rails::Routes.new(self, &block).generate_routes!(options)
11
14
  end
12
15
  end
13
16
 
14
- def self.install!
15
- ActionDispatch::Routing::Mapper.send :include, Doorkeeper::Rails::Routes::Helper
17
+ include AbstractRouter
18
+ extend Registry
19
+
20
+ mattr_reader :mapping do
21
+ {}
16
22
  end
17
23
 
18
- attr_accessor :routes
24
+ def self.install!
25
+ ActionDispatch::Routing::Mapper.include Doorkeeper::Rails::Routes::Helper
26
+
27
+ registered_routes.each(&:install!)
28
+ end
19
29
 
20
- def initialize(routes, &block)
21
- @routes = routes
22
- @block = block
30
+ def initialize(routes, mapper = Mapper.new, &block)
31
+ super
23
32
  end
24
33
 
25
34
  def generate_routes!(options)
26
- @mapping = Mapper.new.map(&@block)
27
- routes.scope options[:scope] || 'oauth', as: 'oauth' do
35
+ routes.scope options[:scope] || "oauth", as: "oauth" do
28
36
  map_route(:authorizations, :authorization_routes)
29
37
  map_route(:tokens, :token_routes)
30
38
  map_route(:tokens, :revoke_routes)
39
+ map_route(:tokens, :introspect_routes) unless Doorkeeper.config.allow_token_introspection.is_a?(FalseClass)
31
40
  map_route(:applications, :application_routes)
32
41
  map_route(:authorized_applications, :authorized_applications_routes)
33
42
  map_route(:token_info, :token_info_routes)
@@ -36,53 +45,56 @@ module Doorkeeper
36
45
 
37
46
  private
38
47
 
39
- def map_route(name, method)
40
- unless @mapping.skipped?(name)
41
- send method, @mapping[name]
42
- end
43
- end
44
-
45
48
  def authorization_routes(mapping)
46
49
  routes.resource(
47
50
  :authorization,
48
- path: 'authorize',
49
- only: [:create, :destroy],
51
+ path: "authorize",
52
+ only: %i[create destroy],
50
53
  as: mapping[:as],
51
- controller: mapping[:controllers]
54
+ controller: mapping[:controllers],
52
55
  ) do
53
- routes.get '/:code', action: :show, on: :member
54
- routes.get '/', action: :new, on: :member
56
+ routes.get "/native", action: :show, on: :member
57
+ routes.get "/", action: :new, on: :member
55
58
  end
56
59
  end
57
60
 
58
61
  def token_routes(mapping)
59
62
  routes.resource(
60
63
  :token,
61
- path: 'token',
64
+ path: "token",
62
65
  only: [:create], as: mapping[:as],
63
- controller: mapping[:controllers]
66
+ controller: mapping[:controllers],
64
67
  )
65
68
  end
66
69
 
67
70
  def revoke_routes(mapping)
68
- routes.post 'revoke', controller: mapping[:controllers], action: :revoke
71
+ routes.post "revoke", controller: mapping[:controllers], action: :revoke
72
+ end
73
+
74
+ def introspect_routes(mapping)
75
+ routes.post "introspect", controller: mapping[:controllers], action: :introspect
69
76
  end
70
77
 
71
78
  def token_info_routes(mapping)
72
79
  routes.resource(
73
80
  :token_info,
74
- path: 'token/info',
81
+ path: "token/info",
75
82
  only: [:show], as: mapping[:as],
76
- controller: mapping[:controllers]
83
+ controller: mapping[:controllers],
77
84
  )
78
85
  end
79
86
 
80
87
  def application_routes(mapping)
81
- routes.resources :doorkeeper_applications, controller: mapping[:controllers], as: :applications, path: 'applications'
88
+ routes.resources :doorkeeper_applications,
89
+ controller: mapping[:controllers],
90
+ as: :applications,
91
+ path: "applications"
82
92
  end
83
93
 
84
94
  def authorized_applications_routes(mapping)
85
- routes.resources :authorized_applications, only: [:index, :destroy], controller: mapping[:controllers]
95
+ routes.resources :authorized_applications,
96
+ only: %i[index destroy],
97
+ controller: mapping[:controllers]
86
98
  end
87
99
  end
88
100
  end