doorkeeper 3.1.0 → 5.6.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 (270) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1079 -0
  3. data/README.md +114 -326
  4. data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
  5. data/app/controllers/doorkeeper/application_controller.rb +7 -6
  6. data/app/controllers/doorkeeper/application_metal_controller.rb +9 -12
  7. data/app/controllers/doorkeeper/applications_controller.rb +66 -21
  8. data/app/controllers/doorkeeper/authorizations_controller.rb +100 -18
  9. data/app/controllers/doorkeeper/authorized_applications_controller.rb +23 -4
  10. data/app/controllers/doorkeeper/token_info_controller.rb +16 -4
  11. data/app/controllers/doorkeeper/tokens_controller.rb +138 -22
  12. data/app/helpers/doorkeeper/dashboard_helper.rb +15 -9
  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 +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 +37 -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 +602 -142
  30. data/lib/doorkeeper/engine.rb +22 -7
  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 +99 -16
  40. data/lib/doorkeeper/models/access_token_mixin.rb +386 -77
  41. data/lib/doorkeeper/models/application_mixin.rb +73 -30
  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 -2
  47. data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
  48. data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
  49. data/lib/doorkeeper/models/concerns/revocable.rb +13 -2
  50. data/lib/doorkeeper/models/concerns/scopes.rb +12 -2
  51. data/lib/doorkeeper/models/concerns/secret_storable.rb +106 -0
  52. data/lib/doorkeeper/oauth/authorization/code.rb +48 -12
  53. data/lib/doorkeeper/oauth/authorization/context.rb +17 -0
  54. data/lib/doorkeeper/oauth/authorization/token.rb +72 -28
  55. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +22 -18
  56. data/lib/doorkeeper/oauth/authorization_code_request.rb +64 -14
  57. data/lib/doorkeeper/oauth/base_request.rb +66 -0
  58. data/lib/doorkeeper/oauth/base_response.rb +31 -0
  59. data/lib/doorkeeper/oauth/client/credentials.rb +23 -10
  60. data/lib/doorkeeper/oauth/client.rb +10 -12
  61. data/lib/doorkeeper/oauth/client_credentials/creator.rb +48 -4
  62. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +17 -9
  63. data/lib/doorkeeper/oauth/client_credentials/validator.rb +55 -0
  64. data/lib/doorkeeper/oauth/client_credentials_request.rb +14 -15
  65. data/lib/doorkeeper/oauth/code_request.rb +8 -12
  66. data/lib/doorkeeper/oauth/code_response.rb +31 -19
  67. data/lib/doorkeeper/oauth/error.rb +5 -3
  68. data/lib/doorkeeper/oauth/error_response.rb +41 -20
  69. data/lib/doorkeeper/oauth/forbidden_token_response.rb +11 -3
  70. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +24 -19
  71. data/lib/doorkeeper/oauth/helpers/unique_token.rb +20 -3
  72. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +55 -4
  73. data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
  74. data/lib/doorkeeper/oauth/invalid_request_response.rb +43 -0
  75. data/lib/doorkeeper/oauth/invalid_token_response.rb +31 -5
  76. data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
  77. data/lib/doorkeeper/oauth/password_access_token_request.rb +46 -18
  78. data/lib/doorkeeper/oauth/pre_authorization.rb +135 -26
  79. data/lib/doorkeeper/oauth/refresh_token_request.rb +67 -30
  80. data/lib/doorkeeper/oauth/scopes.rb +26 -12
  81. data/lib/doorkeeper/oauth/token.rb +28 -25
  82. data/lib/doorkeeper/oauth/token_introspection.rb +202 -0
  83. data/lib/doorkeeper/oauth/token_request.rb +8 -21
  84. data/lib/doorkeeper/oauth/token_response.rb +14 -10
  85. data/lib/doorkeeper/oauth.rb +13 -0
  86. data/lib/doorkeeper/orm/active_record/access_grant.rb +6 -4
  87. data/lib/doorkeeper/orm/active_record/access_token.rb +5 -17
  88. data/lib/doorkeeper/orm/active_record/application.rb +6 -20
  89. data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +69 -0
  90. data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +81 -0
  91. data/lib/doorkeeper/orm/active_record/mixins/application.rb +214 -0
  92. data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +66 -0
  93. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +33 -0
  94. data/lib/doorkeeper/orm/active_record.rb +36 -26
  95. data/lib/doorkeeper/rails/helpers.rb +14 -15
  96. data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
  97. data/lib/doorkeeper/rails/routes/mapper.rb +4 -2
  98. data/lib/doorkeeper/rails/routes/mapping.rb +10 -8
  99. data/lib/doorkeeper/rails/routes/registry.rb +45 -0
  100. data/lib/doorkeeper/rails/routes.rb +45 -28
  101. data/lib/doorkeeper/rake/db.rake +40 -0
  102. data/lib/doorkeeper/rake/setup.rake +6 -0
  103. data/lib/doorkeeper/rake.rb +14 -0
  104. data/lib/doorkeeper/request/authorization_code.rb +12 -4
  105. data/lib/doorkeeper/request/client_credentials.rb +3 -3
  106. data/lib/doorkeeper/request/code.rb +1 -1
  107. data/lib/doorkeeper/request/password.rb +5 -4
  108. data/lib/doorkeeper/request/refresh_token.rb +6 -5
  109. data/lib/doorkeeper/request/strategy.rb +4 -2
  110. data/lib/doorkeeper/request/token.rb +1 -1
  111. data/lib/doorkeeper/request.rb +62 -29
  112. data/lib/doorkeeper/secret_storing/base.rb +64 -0
  113. data/lib/doorkeeper/secret_storing/bcrypt.rb +60 -0
  114. data/lib/doorkeeper/secret_storing/plain.rb +33 -0
  115. data/lib/doorkeeper/secret_storing/sha256_hash.rb +26 -0
  116. data/lib/doorkeeper/server.rb +9 -19
  117. data/lib/doorkeeper/stale_records_cleaner.rb +24 -0
  118. data/lib/doorkeeper/validations.rb +5 -2
  119. data/lib/doorkeeper/version.rb +12 -1
  120. data/lib/doorkeeper.rb +112 -56
  121. data/lib/generators/doorkeeper/application_owner_generator.rb +28 -13
  122. data/lib/generators/doorkeeper/confidential_applications_generator.rb +33 -0
  123. data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
  124. data/lib/generators/doorkeeper/install_generator.rb +19 -9
  125. data/lib/generators/doorkeeper/migration_generator.rb +27 -10
  126. data/lib/generators/doorkeeper/pkce_generator.rb +33 -0
  127. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +41 -0
  128. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  129. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +9 -0
  130. data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +13 -0
  131. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +8 -0
  132. data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
  133. data/lib/generators/doorkeeper/templates/initializer.rb +417 -32
  134. data/lib/generators/doorkeeper/templates/migration.rb.erb +88 -0
  135. data/lib/generators/doorkeeper/views_generator.rb +8 -4
  136. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  137. metadata +163 -280
  138. data/.gitignore +0 -14
  139. data/.hound.yml +0 -13
  140. data/.rspec +0 -1
  141. data/.travis.yml +0 -22
  142. data/CONTRIBUTING.md +0 -45
  143. data/Gemfile +0 -10
  144. data/NEWS.md +0 -525
  145. data/RELEASING.md +0 -17
  146. data/Rakefile +0 -20
  147. data/app/validators/redirect_uri_validator.rb +0 -34
  148. data/doorkeeper.gemspec +0 -27
  149. data/lib/doorkeeper/oauth/client/methods.rb +0 -18
  150. data/lib/doorkeeper/oauth/client_credentials/validation.rb +0 -45
  151. data/lib/doorkeeper/oauth/request_concern.rb +0 -48
  152. data/lib/generators/doorkeeper/application_scopes_generator.rb +0 -34
  153. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb +0 -7
  154. data/lib/generators/doorkeeper/templates/add_scopes_to_oauth_applications.rb +0 -5
  155. data/lib/generators/doorkeeper/templates/migration.rb +0 -50
  156. data/spec/controllers/applications_controller_spec.rb +0 -58
  157. data/spec/controllers/authorizations_controller_spec.rb +0 -203
  158. data/spec/controllers/protected_resources_controller_spec.rb +0 -271
  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 -9
  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 -57
  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 -55
  179. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  180. data/spec/dummy/config/initializers/doorkeeper.rb +0 -96
  181. data/spec/dummy/config/initializers/secret_token.rb +0 -9
  182. data/spec/dummy/config/initializers/session_store.rb +0 -8
  183. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
  184. data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
  185. data/spec/dummy/config/routes.rb +0 -52
  186. data/spec/dummy/config.ru +0 -4
  187. data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -9
  188. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -5
  189. data/spec/dummy/db/migrate/20130902165751_create_doorkeeper_tables.rb +0 -41
  190. data/spec/dummy/db/migrate/20130902175349_add_owner_to_application.rb +0 -7
  191. data/spec/dummy/db/migrate/20141209001746_add_scopes_to_oauth_applications.rb +0 -5
  192. data/spec/dummy/db/schema.rb +0 -66
  193. data/spec/dummy/public/404.html +0 -26
  194. data/spec/dummy/public/422.html +0 -26
  195. data/spec/dummy/public/500.html +0 -26
  196. data/spec/dummy/public/favicon.ico +0 -0
  197. data/spec/dummy/script/rails +0 -6
  198. data/spec/factories.rb +0 -26
  199. data/spec/generators/application_owner_generator_spec.rb +0 -22
  200. data/spec/generators/install_generator_spec.rb +0 -31
  201. data/spec/generators/migration_generator_spec.rb +0 -20
  202. data/spec/generators/templates/routes.rb +0 -3
  203. data/spec/generators/views_generator_spec.rb +0 -27
  204. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -24
  205. data/spec/lib/config_spec.rb +0 -317
  206. data/spec/lib/doorkeeper_spec.rb +0 -28
  207. data/spec/lib/models/expirable_spec.rb +0 -51
  208. data/spec/lib/models/revocable_spec.rb +0 -36
  209. data/spec/lib/models/scopes_spec.rb +0 -43
  210. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -42
  211. data/spec/lib/oauth/authorization_code_request_spec.rb +0 -80
  212. data/spec/lib/oauth/client/credentials_spec.rb +0 -47
  213. data/spec/lib/oauth/client/methods_spec.rb +0 -54
  214. data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -44
  215. data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -86
  216. data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -54
  217. data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -27
  218. data/spec/lib/oauth/client_credentials_request_spec.rb +0 -104
  219. data/spec/lib/oauth/client_spec.rb +0 -39
  220. data/spec/lib/oauth/code_request_spec.rb +0 -45
  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 -123
  231. data/spec/lib/oauth/scopes_spec.rb +0 -123
  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 -109
  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 -350
  239. data/spec/models/doorkeeper/application_spec.rb +0 -187
  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 -94
  250. data/spec/requests/flows/refresh_token_spec.rb +0 -104
  251. data/spec/requests/flows/revoke_token_spec.rb +0 -143
  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 -56
  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 -45
  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/orm/active_record.rb +0 -3
  268. data/spec/support/shared/controllers_shared_context.rb +0 -60
  269. data/spec/support/shared/models_shared_examples.rb +0 -52
  270. data/spec/validators/redirect_uri_validator_spec.rb +0 -78
@@ -0,0 +1,214 @@
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
+ if Doorkeeper.config.enable_application_owner?
14
+ include ::Doorkeeper::Models::Ownership
15
+ end
16
+
17
+ has_many :access_grants,
18
+ foreign_key: :application_id,
19
+ dependent: :delete_all,
20
+ class_name: Doorkeeper.config.access_grant_class.to_s
21
+
22
+ has_many :access_tokens,
23
+ foreign_key: :application_id,
24
+ dependent: :delete_all,
25
+ class_name: Doorkeeper.config.access_token_class.to_s
26
+
27
+ validates :name, :secret, :uid, presence: true
28
+ validates :uid, uniqueness: { case_sensitive: true }
29
+ validates :redirect_uri, "doorkeeper/redirect_uri": true
30
+ validates :confidential, inclusion: { in: [true, false] }
31
+
32
+ validate :scopes_match_configured, if: :enforce_scopes?
33
+
34
+ before_validation :generate_uid, :generate_secret, on: :create
35
+
36
+ has_many :authorized_tokens,
37
+ -> { where(revoked_at: nil) },
38
+ foreign_key: :application_id,
39
+ class_name: Doorkeeper.config.access_token_class.to_s
40
+
41
+ has_many :authorized_applications,
42
+ through: :authorized_tokens,
43
+ source: :application
44
+
45
+ # Generates a new secret for this application, intended to be used
46
+ # for rotating the secret or in case of compromise.
47
+ #
48
+ # @return [String] new transformed secret value
49
+ #
50
+ def renew_secret
51
+ @raw_secret = secret_generator.generate
52
+ secret_strategy.store_secret(self, :secret, @raw_secret)
53
+ end
54
+
55
+ # We keep a volatile copy of the raw secret for initial communication
56
+ # The stored refresh_token may be mapped and not available in cleartext.
57
+ #
58
+ # Some strategies allow restoring stored secrets (e.g. symmetric encryption)
59
+ # while hashing strategies do not, so you cannot rely on this value
60
+ # returning a present value for persisted tokens.
61
+ def plaintext_secret
62
+ if secret_strategy.allows_restoring_secrets?
63
+ secret_strategy.restore_secret(self, :secret)
64
+ else
65
+ @raw_secret
66
+ end
67
+ end
68
+
69
+ # Represents client as set of it's attributes in JSON format.
70
+ # This is the right way how we want to override ActiveRecord #to_json.
71
+ #
72
+ # Respects privacy settings and serializes minimum set of attributes
73
+ # for public/private clients and full set for authorized owners.
74
+ #
75
+ # @return [Hash] entity attributes for JSON
76
+ #
77
+ def as_json(options = {})
78
+ # if application belongs to some owner we need to check if it's the same as
79
+ # the one passed in the options or check if we render the client as an owner
80
+ if (respond_to?(:owner) && owner && owner == options[:current_resource_owner]) ||
81
+ options[:as_owner]
82
+ # Owners can see all the client attributes, fallback to ActiveModel serialization
83
+ super
84
+ else
85
+ # if application has no owner or it's owner doesn't match one from the options
86
+ # we render only minimum set of attributes that could be exposed to a public
87
+ only = extract_serializable_attributes(options)
88
+ super(options.merge(only: only))
89
+ end
90
+ end
91
+
92
+ def authorized_for_resource_owner?(resource_owner)
93
+ Doorkeeper.configuration.authorize_resource_owner_for_client.call(self, resource_owner)
94
+ end
95
+
96
+ # We need to hook into this method to allow serializing plan-text secrets
97
+ # when secrets hashing enabled.
98
+ #
99
+ # @param key [String] attribute name
100
+ #
101
+ def read_attribute_for_serialization(key)
102
+ return super unless key.to_s == "secret"
103
+
104
+ plaintext_secret || secret
105
+ end
106
+
107
+ private
108
+
109
+ def secret_generator
110
+ generator_name = Doorkeeper.config.application_secret_generator
111
+ generator = generator_name.constantize
112
+
113
+ return generator if generator.respond_to?(:generate)
114
+
115
+ raise Errors::UnableToGenerateToken, "#{generator} does not respond to `.generate`."
116
+ rescue NameError
117
+ raise Errors::TokenGeneratorNotFound, "#{generator_name} not found"
118
+ end
119
+
120
+ def generate_uid
121
+ self.uid = Doorkeeper::OAuth::Helpers::UniqueToken.generate if uid.blank?
122
+ end
123
+
124
+ def generate_secret
125
+ return if secret.present?
126
+
127
+ renew_secret
128
+ end
129
+
130
+ def scopes_match_configured
131
+ if scopes.present? && !Doorkeeper::OAuth::Helpers::ScopeChecker.valid?(
132
+ scope_str: scopes.to_s,
133
+ server_scopes: Doorkeeper.config.scopes,
134
+ )
135
+ errors.add(:scopes, :not_match_configured)
136
+ end
137
+ end
138
+
139
+ def enforce_scopes?
140
+ Doorkeeper.config.enforce_configured_scopes?
141
+ end
142
+
143
+ # Helper method to extract collection of serializable attribute names
144
+ # considering serialization options (like `only`, `except` and so on).
145
+ #
146
+ # @param options [Hash] serialization options
147
+ #
148
+ # @return [Array<String>]
149
+ # collection of attributes to be serialized using #as_json
150
+ #
151
+ def extract_serializable_attributes(options = {})
152
+ opts = options.try(:dup) || {}
153
+ only = Array.wrap(opts[:only]).map(&:to_s)
154
+
155
+ only = if only.blank?
156
+ client_serializable_attributes
157
+ else
158
+ only & client_serializable_attributes
159
+ end
160
+
161
+ only -= Array.wrap(opts[:except]).map(&:to_s) if opts.key?(:except)
162
+ only.uniq
163
+ end
164
+
165
+ # Collection of attributes that could be serialized for public.
166
+ # Override this method if you need additional attributes to be serialized.
167
+ #
168
+ # @return [Array<String>] collection of serializable attributes
169
+ #
170
+ # NOTE: `serializable_attributes` method already taken by Rails >= 6
171
+ #
172
+ def client_serializable_attributes
173
+ attributes = %w[id name created_at]
174
+ attributes << "uid" unless confidential?
175
+ attributes
176
+ end
177
+ end
178
+
179
+ module ClassMethods
180
+ # Returns Applications associated with active (not revoked) Access Tokens
181
+ # that are owned by the specific Resource Owner.
182
+ #
183
+ # @param resource_owner [ActiveRecord::Base]
184
+ # Resource Owner model instance
185
+ #
186
+ # @return [ActiveRecord::Relation]
187
+ # Applications authorized for the Resource Owner
188
+ #
189
+ def authorized_for(resource_owner)
190
+ resource_access_tokens = Doorkeeper.config.access_token_model.active_for(resource_owner)
191
+ where(id: resource_access_tokens.select(:application_id).distinct)
192
+ end
193
+
194
+ # Revokes AccessToken and AccessGrant records that have not been revoked and
195
+ # associated with the specific Application and Resource Owner.
196
+ #
197
+ # @param resource_owner [ActiveRecord::Base]
198
+ # instance of the Resource Owner model
199
+ #
200
+ def revoke_tokens_and_grants_for(id, resource_owner)
201
+ Doorkeeper.config.access_token_model.revoke_all_for(id, resource_owner)
202
+ Doorkeeper.config.access_grant_model.revoke_all_for(id, resource_owner)
203
+ end
204
+
205
+ private
206
+
207
+ def compute_doorkeeper_table_name
208
+ table_name = "oauth_application"
209
+ table_name = table_name.pluralize if pluralize_table_names
210
+ "#{table_name_prefix}#{table_name}#{table_name_suffix}"
211
+ end
212
+ end
213
+ end
214
+ 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,38 +1,48 @@
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"
14
29
  end
15
30
 
16
- def self.initialize_application_owner!
17
- require 'doorkeeper/models/concerns/ownership'
31
+ def self.run_hooks
32
+ # Deprecated, will be removed soon
33
+ return unless (options = Doorkeeper.config.active_record_options[:establish_connection])
18
34
 
19
- Doorkeeper::Application.send :include, Doorkeeper::Models::Ownership
35
+ Doorkeeper::Orm::ActiveRecord.models.each do |model|
36
+ model.establish_connection(options)
37
+ end
20
38
  end
21
39
 
22
- def self.check_requirements!(_config)
23
- if ::ActiveRecord::Base.connected? &&
24
- ::ActiveRecord::Base.connection.table_exists?(
25
- Doorkeeper::Application.table_name
26
- )
27
- unless Doorkeeper::Application.new.attributes.include?("scopes")
28
- migration_path = '../../../generators/doorkeeper/templates/add_scopes_to_oauth_applications.rb'
29
- puts <<-MSG.squish
30
- [doorkeeper] Missing column: `oauth_applications.scopes`.
31
- Create the following migration and run `rake db:migrate`.
32
- MSG
33
- puts File.read(File.expand_path(migration_path, __FILE__))
34
- end
35
- end
40
+ def self.models
41
+ [
42
+ Doorkeeper.config.access_grant_model,
43
+ Doorkeeper.config.access_token_model,
44
+ Doorkeeper.config.application_model,
45
+ ]
36
46
  end
37
47
  end
38
48
  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
- if !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,13 +1,15 @@
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
7
9
  end
8
10
 
9
11
  def map(&block)
10
- self.instance_eval(&block) if block
12
+ instance_eval(&block) if block
11
13
  @mapping
12
14
  end
13
15
 
@@ -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