doorkeeper 4.4.0 → 5.6.6

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