doorkeeper 4.2.0 → 5.6.8

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 (273) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1119 -0
  3. data/README.md +112 -349
  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 +115 -18
  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 +118 -38
  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 +4 -2
  20. data/app/views/doorkeeper/authorizations/form_post.html.erb +15 -0
  21. data/app/views/doorkeeper/authorizations/new.html.erb +17 -11
  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 +36 -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 +551 -155
  30. data/lib/doorkeeper/engine.rb +19 -6
  31. data/lib/doorkeeper/errors.rb +55 -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 +383 -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/expiration_time_sql_math.rb +88 -0
  45. data/lib/doorkeeper/models/concerns/orderable.rb +15 -0
  46. data/lib/doorkeeper/models/concerns/ownership.rb +4 -7
  47. data/lib/doorkeeper/models/concerns/polymorphic_resource_owner.rb +30 -0
  48. data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
  49. data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
  50. data/lib/doorkeeper/models/concerns/revocable.rb +12 -18
  51. data/lib/doorkeeper/models/concerns/scopes.rb +12 -2
  52. data/lib/doorkeeper/models/concerns/secret_storable.rb +106 -0
  53. data/lib/doorkeeper/oauth/authorization/code.rb +54 -12
  54. data/lib/doorkeeper/oauth/authorization/context.rb +17 -0
  55. data/lib/doorkeeper/oauth/authorization/token.rb +72 -28
  56. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +22 -18
  57. data/lib/doorkeeper/oauth/authorization_code_request.rb +77 -17
  58. data/lib/doorkeeper/oauth/base_request.rb +67 -0
  59. data/lib/doorkeeper/oauth/base_response.rb +31 -0
  60. data/lib/doorkeeper/oauth/client/credentials.rb +23 -10
  61. data/lib/doorkeeper/oauth/client.rb +10 -12
  62. data/lib/doorkeeper/oauth/client_credentials/creator.rb +44 -4
  63. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +21 -13
  64. data/lib/doorkeeper/oauth/client_credentials/validator.rb +55 -0
  65. data/lib/doorkeeper/oauth/client_credentials_request.rb +20 -16
  66. data/lib/doorkeeper/oauth/code_request.rb +9 -13
  67. data/lib/doorkeeper/oauth/code_response.rb +28 -15
  68. data/lib/doorkeeper/oauth/error.rb +5 -3
  69. data/lib/doorkeeper/oauth/error_response.rb +43 -20
  70. data/lib/doorkeeper/oauth/forbidden_token_response.rb +11 -3
  71. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +23 -18
  72. data/lib/doorkeeper/oauth/helpers/unique_token.rb +20 -3
  73. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +53 -3
  74. data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
  75. data/lib/doorkeeper/oauth/invalid_request_response.rb +47 -0
  76. data/lib/doorkeeper/oauth/invalid_token_response.rb +31 -5
  77. data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
  78. data/lib/doorkeeper/oauth/password_access_token_request.rb +46 -14
  79. data/lib/doorkeeper/oauth/pre_authorization.rb +138 -28
  80. data/lib/doorkeeper/oauth/refresh_token_request.rb +74 -41
  81. data/lib/doorkeeper/oauth/scopes.rb +26 -12
  82. data/lib/doorkeeper/oauth/token.rb +25 -23
  83. data/lib/doorkeeper/oauth/token_introspection.rb +204 -0
  84. data/lib/doorkeeper/oauth/token_request.rb +9 -22
  85. data/lib/doorkeeper/oauth/token_response.rb +13 -10
  86. data/lib/doorkeeper/oauth.rb +13 -0
  87. data/lib/doorkeeper/orm/active_record/access_grant.rb +6 -4
  88. data/lib/doorkeeper/orm/active_record/access_token.rb +5 -25
  89. data/lib/doorkeeper/orm/active_record/application.rb +6 -15
  90. data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +63 -0
  91. data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +77 -0
  92. data/lib/doorkeeper/orm/active_record/mixins/application.rb +210 -0
  93. data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +66 -0
  94. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +36 -0
  95. data/lib/doorkeeper/orm/active_record.rb +34 -12
  96. data/lib/doorkeeper/rails/helpers.rb +14 -15
  97. data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
  98. data/lib/doorkeeper/rails/routes/mapper.rb +3 -1
  99. data/lib/doorkeeper/rails/routes/mapping.rb +10 -8
  100. data/lib/doorkeeper/rails/routes/registry.rb +45 -0
  101. data/lib/doorkeeper/rails/routes.rb +50 -29
  102. data/lib/doorkeeper/rake/db.rake +40 -0
  103. data/lib/doorkeeper/rake/setup.rake +6 -0
  104. data/lib/doorkeeper/rake.rb +14 -0
  105. data/lib/doorkeeper/request/authorization_code.rb +12 -4
  106. data/lib/doorkeeper/request/client_credentials.rb +3 -3
  107. data/lib/doorkeeper/request/code.rb +1 -1
  108. data/lib/doorkeeper/request/password.rb +5 -14
  109. data/lib/doorkeeper/request/refresh_token.rb +6 -5
  110. data/lib/doorkeeper/request/strategy.rb +4 -2
  111. data/lib/doorkeeper/request/token.rb +1 -1
  112. data/lib/doorkeeper/request.rb +62 -29
  113. data/lib/doorkeeper/secret_storing/base.rb +64 -0
  114. data/lib/doorkeeper/secret_storing/bcrypt.rb +60 -0
  115. data/lib/doorkeeper/secret_storing/plain.rb +33 -0
  116. data/lib/doorkeeper/secret_storing/sha256_hash.rb +26 -0
  117. data/lib/doorkeeper/server.rb +9 -19
  118. data/lib/doorkeeper/stale_records_cleaner.rb +24 -0
  119. data/lib/doorkeeper/validations.rb +5 -2
  120. data/lib/doorkeeper/version.rb +12 -1
  121. data/lib/doorkeeper.rb +180 -57
  122. data/lib/generators/doorkeeper/application_owner_generator.rb +28 -13
  123. data/lib/generators/doorkeeper/confidential_applications_generator.rb +33 -0
  124. data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
  125. data/lib/generators/doorkeeper/install_generator.rb +19 -9
  126. data/lib/generators/doorkeeper/migration_generator.rb +27 -10
  127. data/lib/generators/doorkeeper/pkce_generator.rb +33 -0
  128. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +31 -19
  129. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  130. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +9 -0
  131. data/lib/generators/doorkeeper/templates/{add_previous_refresh_token_to_access_tokens.rb → add_previous_refresh_token_to_access_tokens.rb.erb} +3 -1
  132. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +8 -0
  133. data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
  134. data/lib/generators/doorkeeper/templates/initializer.rb +436 -33
  135. data/lib/generators/doorkeeper/templates/migration.rb.erb +98 -0
  136. data/lib/generators/doorkeeper/views_generator.rb +8 -4
  137. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  138. metadata +129 -281
  139. data/.gitignore +0 -14
  140. data/.hound.yml +0 -13
  141. data/.rspec +0 -1
  142. data/.travis.yml +0 -20
  143. data/CONTRIBUTING.md +0 -47
  144. data/Gemfile +0 -14
  145. data/NEWS.md +0 -593
  146. data/RELEASING.md +0 -17
  147. data/Rakefile +0 -20
  148. data/app/validators/redirect_uri_validator.rb +0 -34
  149. data/doorkeeper.gemspec +0 -28
  150. data/lib/doorkeeper/oauth/client/methods.rb +0 -18
  151. data/lib/doorkeeper/oauth/client_credentials/validation.rb +0 -45
  152. data/lib/doorkeeper/oauth/request_concern.rb +0 -48
  153. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb +0 -7
  154. data/lib/generators/doorkeeper/templates/migration.rb +0 -68
  155. data/spec/controllers/application_metal_controller.rb +0 -10
  156. data/spec/controllers/applications_controller_spec.rb +0 -58
  157. data/spec/controllers/authorizations_controller_spec.rb +0 -189
  158. data/spec/controllers/protected_resources_controller_spec.rb +0 -300
  159. data/spec/controllers/token_info_controller_spec.rb +0 -52
  160. data/spec/controllers/tokens_controller_spec.rb +0 -88
  161. data/spec/dummy/Rakefile +0 -7
  162. data/spec/dummy/app/controllers/application_controller.rb +0 -3
  163. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +0 -7
  164. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +0 -12
  165. data/spec/dummy/app/controllers/home_controller.rb +0 -17
  166. data/spec/dummy/app/controllers/metal_controller.rb +0 -11
  167. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +0 -11
  168. data/spec/dummy/app/helpers/application_helper.rb +0 -5
  169. data/spec/dummy/app/models/user.rb +0 -5
  170. data/spec/dummy/app/views/home/index.html.erb +0 -0
  171. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  172. data/spec/dummy/config/application.rb +0 -23
  173. data/spec/dummy/config/boot.rb +0 -9
  174. data/spec/dummy/config/database.yml +0 -15
  175. data/spec/dummy/config/environment.rb +0 -5
  176. data/spec/dummy/config/environments/development.rb +0 -29
  177. data/spec/dummy/config/environments/production.rb +0 -62
  178. data/spec/dummy/config/environments/test.rb +0 -44
  179. data/spec/dummy/config/initializers/active_record_belongs_to_required_by_default.rb +0 -6
  180. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  181. data/spec/dummy/config/initializers/doorkeeper.rb +0 -96
  182. data/spec/dummy/config/initializers/secret_token.rb +0 -9
  183. data/spec/dummy/config/initializers/session_store.rb +0 -8
  184. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
  185. data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
  186. data/spec/dummy/config/routes.rb +0 -52
  187. data/spec/dummy/config.ru +0 -4
  188. data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -9
  189. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -5
  190. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +0 -60
  191. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +0 -7
  192. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +0 -11
  193. data/spec/dummy/db/schema.rb +0 -67
  194. data/spec/dummy/public/404.html +0 -26
  195. data/spec/dummy/public/422.html +0 -26
  196. data/spec/dummy/public/500.html +0 -26
  197. data/spec/dummy/public/favicon.ico +0 -0
  198. data/spec/dummy/script/rails +0 -6
  199. data/spec/factories.rb +0 -28
  200. data/spec/generators/application_owner_generator_spec.rb +0 -22
  201. data/spec/generators/install_generator_spec.rb +0 -31
  202. data/spec/generators/migration_generator_spec.rb +0 -20
  203. data/spec/generators/templates/routes.rb +0 -3
  204. data/spec/generators/views_generator_spec.rb +0 -27
  205. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -24
  206. data/spec/lib/config_spec.rb +0 -334
  207. data/spec/lib/doorkeeper_spec.rb +0 -28
  208. data/spec/lib/models/expirable_spec.rb +0 -51
  209. data/spec/lib/models/revocable_spec.rb +0 -59
  210. data/spec/lib/models/scopes_spec.rb +0 -43
  211. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -42
  212. data/spec/lib/oauth/authorization_code_request_spec.rb +0 -80
  213. data/spec/lib/oauth/client/credentials_spec.rb +0 -47
  214. data/spec/lib/oauth/client/methods_spec.rb +0 -54
  215. data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -44
  216. data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -86
  217. data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -54
  218. data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -27
  219. data/spec/lib/oauth/client_credentials_request_spec.rb +0 -104
  220. data/spec/lib/oauth/client_spec.rb +0 -39
  221. data/spec/lib/oauth/code_request_spec.rb +0 -45
  222. data/spec/lib/oauth/code_response_spec.rb +0 -34
  223. data/spec/lib/oauth/error_response_spec.rb +0 -61
  224. data/spec/lib/oauth/error_spec.rb +0 -23
  225. data/spec/lib/oauth/forbidden_token_response_spec.rb +0 -23
  226. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -64
  227. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -20
  228. data/spec/lib/oauth/helpers/uri_checker_spec.rb +0 -104
  229. data/spec/lib/oauth/invalid_token_response_spec.rb +0 -28
  230. data/spec/lib/oauth/password_access_token_request_spec.rb +0 -90
  231. data/spec/lib/oauth/pre_authorization_spec.rb +0 -155
  232. data/spec/lib/oauth/refresh_token_request_spec.rb +0 -154
  233. data/spec/lib/oauth/scopes_spec.rb +0 -122
  234. data/spec/lib/oauth/token_request_spec.rb +0 -98
  235. data/spec/lib/oauth/token_response_spec.rb +0 -85
  236. data/spec/lib/oauth/token_spec.rb +0 -116
  237. data/spec/lib/request/strategy_spec.rb +0 -53
  238. data/spec/lib/server_spec.rb +0 -52
  239. data/spec/models/doorkeeper/access_grant_spec.rb +0 -36
  240. data/spec/models/doorkeeper/access_token_spec.rb +0 -394
  241. data/spec/models/doorkeeper/application_spec.rb +0 -179
  242. data/spec/requests/applications/applications_request_spec.rb +0 -94
  243. data/spec/requests/applications/authorized_applications_spec.rb +0 -30
  244. data/spec/requests/endpoints/authorization_spec.rb +0 -72
  245. data/spec/requests/endpoints/token_spec.rb +0 -64
  246. data/spec/requests/flows/authorization_code_errors_spec.rb +0 -66
  247. data/spec/requests/flows/authorization_code_spec.rb +0 -156
  248. data/spec/requests/flows/client_credentials_spec.rb +0 -58
  249. data/spec/requests/flows/implicit_grant_errors_spec.rb +0 -32
  250. data/spec/requests/flows/implicit_grant_spec.rb +0 -61
  251. data/spec/requests/flows/password_spec.rb +0 -115
  252. data/spec/requests/flows/refresh_token_spec.rb +0 -174
  253. data/spec/requests/flows/revoke_token_spec.rb +0 -157
  254. data/spec/requests/flows/skip_authorization_spec.rb +0 -59
  255. data/spec/requests/protected_resources/metal_spec.rb +0 -14
  256. data/spec/requests/protected_resources/private_api_spec.rb +0 -81
  257. data/spec/routing/custom_controller_routes_spec.rb +0 -71
  258. data/spec/routing/default_routes_spec.rb +0 -35
  259. data/spec/routing/scoped_routes_spec.rb +0 -31
  260. data/spec/spec_helper.rb +0 -2
  261. data/spec/spec_helper_integration.rb +0 -59
  262. data/spec/support/dependencies/factory_girl.rb +0 -2
  263. data/spec/support/helpers/access_token_request_helper.rb +0 -11
  264. data/spec/support/helpers/authorization_request_helper.rb +0 -41
  265. data/spec/support/helpers/config_helper.rb +0 -9
  266. data/spec/support/helpers/model_helper.rb +0 -67
  267. data/spec/support/helpers/request_spec_helper.rb +0 -76
  268. data/spec/support/helpers/url_helper.rb +0 -55
  269. data/spec/support/http_method_shim.rb +0 -24
  270. data/spec/support/orm/active_record.rb +0 -3
  271. data/spec/support/shared/controllers_shared_context.rb +0 -69
  272. data/spec/support/shared/models_shared_examples.rb +0 -52
  273. data/spec/validators/redirect_uri_validator_spec.rb +0 -78
@@ -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_with Doorkeeper::RedirectUriValidator, attributes: [:redirect_uri]
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
@@ -0,0 +1,36 @@
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
19
+ .where.not(revoked_at: nil)
20
+ .where(table[:revoked_at].lt(Time.current))
21
+ .in_batches(&:delete_all)
22
+ end
23
+
24
+ # Clears expired records
25
+ def clean_expired(ttl)
26
+ table = @base_scope.arel_table
27
+
28
+ @base_scope
29
+ .where.not(expires_in: nil)
30
+ .where(table[:created_at].lt(Time.current - ttl))
31
+ .in_batches(&:delete_all)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -1,22 +1,44 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
4
+ autoload :AccessGrant, "doorkeeper/orm/active_record/access_grant"
5
+ autoload :AccessToken, "doorkeeper/orm/active_record/access_token"
6
+ autoload :Application, "doorkeeper/orm/active_record/application"
7
+ autoload :RedirectUriValidator, "doorkeeper/orm/active_record/redirect_uri_validator"
8
+
9
+ module Models
10
+ autoload :Ownership, "doorkeeper/models/concerns/ownership"
11
+ end
12
+
13
+ # ActiveRecord ORM for Doorkeeper entity models.
14
+ # Consists of three main OAuth entities:
15
+ # * Access Token
16
+ # * Access Grant
17
+ # * Application (client)
18
+ #
19
+ # Do a lazy loading of all the required and configured stuff.
20
+ #
2
21
  module Orm
3
22
  module ActiveRecord
4
- 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'
23
+ autoload :StaleRecordsCleaner, "doorkeeper/orm/active_record/stale_records_cleaner"
8
24
 
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]
12
- end
13
- end
25
+ module Mixins
26
+ autoload :AccessGrant, "doorkeeper/orm/active_record/mixins/access_grant"
27
+ autoload :AccessToken, "doorkeeper/orm/active_record/mixins/access_token"
28
+ autoload :Application, "doorkeeper/orm/active_record/mixins/application"
29
+ end
30
+
31
+ def self.run_hooks
32
+ initialize_configured_associations
14
33
  end
15
34
 
16
- def self.initialize_application_owner!
17
- require 'doorkeeper/models/concerns/ownership'
35
+ def self.initialize_configured_associations
36
+ if Doorkeeper.config.enable_application_owner?
37
+ Doorkeeper.config.application_model.include ::Doorkeeper::Models::Ownership
38
+ end
18
39
 
19
- Doorkeeper::Application.send :include, Doorkeeper::Models::Ownership
40
+ Doorkeeper.config.access_grant_model.include ::Doorkeeper::Models::PolymorphicResourceOwner::ForAccessGrant
41
+ Doorkeeper.config.access_token_model.include ::Doorkeeper::Models::PolymorphicResourceOwner::ForAccessToken
20
42
  end
21
43
  end
22
44
  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