doorkeeper 4.2.6 → 5.5.4

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 (274) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1049 -0
  3. data/README.md +110 -353
  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 -16
  8. data/app/controllers/doorkeeper/authorizations_controller.rb +97 -17
  9. data/app/controllers/doorkeeper/authorized_applications_controller.rb +22 -3
  10. data/app/controllers/doorkeeper/token_info_controller.rb +16 -4
  11. data/app/controllers/doorkeeper/tokens_controller.rb +115 -38
  12. data/app/helpers/doorkeeper/dashboard_helper.rb +10 -6
  13. data/app/views/doorkeeper/applications/_delete_form.html.erb +3 -1
  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 +6 -0
  22. data/app/views/doorkeeper/authorized_applications/index.html.erb +0 -1
  23. data/app/views/layouts/doorkeeper/admin.html.erb +16 -14
  24. data/config/locales/en.yml +34 -7
  25. data/lib/doorkeeper/config/abstract_builder.rb +28 -0
  26. data/lib/doorkeeper/config/option.rb +82 -0
  27. data/lib/doorkeeper/config/validations.rb +53 -0
  28. data/lib/doorkeeper/config.rb +514 -167
  29. data/lib/doorkeeper/engine.rb +11 -5
  30. data/lib/doorkeeper/errors.rb +25 -16
  31. data/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
  32. data/lib/doorkeeper/grant_flow/flow.rb +44 -0
  33. data/lib/doorkeeper/grant_flow/registry.rb +50 -0
  34. data/lib/doorkeeper/grant_flow.rb +45 -0
  35. data/lib/doorkeeper/grape/authorization_decorator.rb +6 -4
  36. data/lib/doorkeeper/grape/helpers.rb +23 -12
  37. data/lib/doorkeeper/helpers/controller.rb +51 -14
  38. data/lib/doorkeeper/models/access_grant_mixin.rb +94 -27
  39. data/lib/doorkeeper/models/access_token_mixin.rb +284 -96
  40. data/lib/doorkeeper/models/application_mixin.rb +58 -27
  41. data/lib/doorkeeper/models/concerns/accessible.rb +2 -0
  42. data/lib/doorkeeper/models/concerns/expirable.rb +12 -6
  43. data/lib/doorkeeper/models/concerns/orderable.rb +15 -0
  44. data/lib/doorkeeper/models/concerns/ownership.rb +4 -7
  45. data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
  46. data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
  47. data/lib/doorkeeper/models/concerns/revocable.rb +3 -27
  48. data/lib/doorkeeper/models/concerns/scopes.rb +12 -2
  49. data/lib/doorkeeper/models/concerns/secret_storable.rb +106 -0
  50. data/lib/doorkeeper/oauth/authorization/code.rb +48 -12
  51. data/lib/doorkeeper/oauth/authorization/context.rb +17 -0
  52. data/lib/doorkeeper/oauth/authorization/token.rb +66 -28
  53. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +7 -5
  54. data/lib/doorkeeper/oauth/authorization_code_request.rb +63 -10
  55. data/lib/doorkeeper/oauth/base_request.rb +35 -19
  56. data/lib/doorkeeper/oauth/base_response.rb +2 -0
  57. data/lib/doorkeeper/oauth/client/credentials.rb +9 -7
  58. data/lib/doorkeeper/oauth/client.rb +10 -11
  59. data/lib/doorkeeper/oauth/client_credentials/creator.rb +47 -4
  60. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +16 -9
  61. data/lib/doorkeeper/oauth/client_credentials/validator.rb +56 -0
  62. data/lib/doorkeeper/oauth/client_credentials_request.rb +10 -11
  63. data/lib/doorkeeper/oauth/code_request.rb +8 -12
  64. data/lib/doorkeeper/oauth/code_response.rb +27 -15
  65. data/lib/doorkeeper/oauth/error.rb +5 -3
  66. data/lib/doorkeeper/oauth/error_response.rb +35 -15
  67. data/lib/doorkeeper/oauth/forbidden_token_response.rb +11 -3
  68. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +23 -18
  69. data/lib/doorkeeper/oauth/helpers/unique_token.rb +20 -3
  70. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +53 -3
  71. data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
  72. data/lib/doorkeeper/oauth/invalid_request_response.rb +43 -0
  73. data/lib/doorkeeper/oauth/invalid_token_response.rb +29 -5
  74. data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
  75. data/lib/doorkeeper/oauth/password_access_token_request.rb +44 -10
  76. data/lib/doorkeeper/oauth/pre_authorization.rb +135 -26
  77. data/lib/doorkeeper/oauth/refresh_token_request.rb +60 -31
  78. data/lib/doorkeeper/oauth/scopes.rb +26 -12
  79. data/lib/doorkeeper/oauth/token.rb +13 -9
  80. data/lib/doorkeeper/oauth/token_introspection.rb +202 -0
  81. data/lib/doorkeeper/oauth/token_request.rb +8 -20
  82. data/lib/doorkeeper/oauth/token_response.rb +14 -10
  83. data/lib/doorkeeper/oauth.rb +13 -0
  84. data/lib/doorkeeper/orm/active_record/access_grant.rb +6 -4
  85. data/lib/doorkeeper/orm/active_record/access_token.rb +5 -42
  86. data/lib/doorkeeper/orm/active_record/application.rb +6 -20
  87. data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +69 -0
  88. data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +60 -0
  89. data/lib/doorkeeper/orm/active_record/mixins/application.rb +199 -0
  90. data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +66 -0
  91. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +33 -0
  92. data/lib/doorkeeper/orm/active_record.rb +37 -8
  93. data/lib/doorkeeper/rails/helpers.rb +14 -13
  94. data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
  95. data/lib/doorkeeper/rails/routes/mapper.rb +4 -2
  96. data/lib/doorkeeper/rails/routes/mapping.rb +9 -7
  97. data/lib/doorkeeper/rails/routes/registry.rb +45 -0
  98. data/lib/doorkeeper/rails/routes.rb +41 -28
  99. data/lib/doorkeeper/rake/db.rake +40 -0
  100. data/lib/doorkeeper/rake/setup.rake +11 -0
  101. data/lib/doorkeeper/rake.rb +14 -0
  102. data/lib/doorkeeper/request/authorization_code.rb +6 -4
  103. data/lib/doorkeeper/request/client_credentials.rb +3 -3
  104. data/lib/doorkeeper/request/code.rb +1 -1
  105. data/lib/doorkeeper/request/password.rb +5 -14
  106. data/lib/doorkeeper/request/refresh_token.rb +6 -5
  107. data/lib/doorkeeper/request/strategy.rb +4 -2
  108. data/lib/doorkeeper/request/token.rb +1 -1
  109. data/lib/doorkeeper/request.rb +62 -29
  110. data/lib/doorkeeper/secret_storing/base.rb +64 -0
  111. data/lib/doorkeeper/secret_storing/bcrypt.rb +60 -0
  112. data/lib/doorkeeper/secret_storing/plain.rb +33 -0
  113. data/lib/doorkeeper/secret_storing/sha256_hash.rb +26 -0
  114. data/lib/doorkeeper/server.rb +9 -11
  115. data/lib/doorkeeper/stale_records_cleaner.rb +24 -0
  116. data/lib/doorkeeper/validations.rb +5 -2
  117. data/lib/doorkeeper/version.rb +12 -1
  118. data/lib/doorkeeper.rb +111 -62
  119. data/lib/generators/doorkeeper/application_owner_generator.rb +28 -13
  120. data/lib/generators/doorkeeper/confidential_applications_generator.rb +33 -0
  121. data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
  122. data/lib/generators/doorkeeper/install_generator.rb +19 -9
  123. data/lib/generators/doorkeeper/migration_generator.rb +27 -10
  124. data/lib/generators/doorkeeper/pkce_generator.rb +33 -0
  125. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +31 -19
  126. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  127. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +9 -0
  128. data/{spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb → lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb} +3 -1
  129. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +8 -0
  130. data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
  131. data/lib/generators/doorkeeper/templates/initializer.rb +412 -33
  132. data/lib/generators/doorkeeper/templates/migration.rb.erb +88 -0
  133. data/lib/generators/doorkeeper/views_generator.rb +8 -4
  134. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  135. metadata +114 -276
  136. data/.coveralls.yml +0 -1
  137. data/.gitignore +0 -19
  138. data/.hound.yml +0 -13
  139. data/.rspec +0 -1
  140. data/.travis.yml +0 -26
  141. data/Appraisals +0 -14
  142. data/CONTRIBUTING.md +0 -47
  143. data/Gemfile +0 -10
  144. data/NEWS.md +0 -606
  145. data/RELEASING.md +0 -10
  146. data/Rakefile +0 -20
  147. data/app/validators/redirect_uri_validator.rb +0 -34
  148. data/doorkeeper.gemspec +0 -29
  149. data/gemfiles/rails_4_2.gemfile +0 -11
  150. data/gemfiles/rails_5_0.gemfile +0 -12
  151. data/gemfiles/rails_5_1.gemfile +0 -13
  152. data/lib/doorkeeper/oauth/client_credentials/validation.rb +0 -45
  153. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb +0 -7
  154. data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb +0 -11
  155. data/lib/generators/doorkeeper/templates/migration.rb +0 -68
  156. data/spec/controllers/application_metal_controller.rb +0 -10
  157. data/spec/controllers/applications_controller_spec.rb +0 -58
  158. data/spec/controllers/authorizations_controller_spec.rb +0 -218
  159. data/spec/controllers/protected_resources_controller_spec.rb +0 -300
  160. data/spec/controllers/token_info_controller_spec.rb +0 -52
  161. data/spec/controllers/tokens_controller_spec.rb +0 -88
  162. data/spec/dummy/Rakefile +0 -7
  163. data/spec/dummy/app/controllers/application_controller.rb +0 -3
  164. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +0 -7
  165. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +0 -12
  166. data/spec/dummy/app/controllers/home_controller.rb +0 -17
  167. data/spec/dummy/app/controllers/metal_controller.rb +0 -11
  168. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +0 -11
  169. data/spec/dummy/app/helpers/application_helper.rb +0 -5
  170. data/spec/dummy/app/models/user.rb +0 -5
  171. data/spec/dummy/app/views/home/index.html.erb +0 -0
  172. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  173. data/spec/dummy/config/application.rb +0 -23
  174. data/spec/dummy/config/boot.rb +0 -9
  175. data/spec/dummy/config/database.yml +0 -15
  176. data/spec/dummy/config/environment.rb +0 -5
  177. data/spec/dummy/config/environments/development.rb +0 -29
  178. data/spec/dummy/config/environments/production.rb +0 -62
  179. data/spec/dummy/config/environments/test.rb +0 -44
  180. data/spec/dummy/config/initializers/active_record_belongs_to_required_by_default.rb +0 -6
  181. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  182. data/spec/dummy/config/initializers/doorkeeper.rb +0 -96
  183. data/spec/dummy/config/initializers/secret_token.rb +0 -9
  184. data/spec/dummy/config/initializers/session_store.rb +0 -8
  185. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
  186. data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
  187. data/spec/dummy/config/routes.rb +0 -52
  188. data/spec/dummy/config.ru +0 -4
  189. data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -9
  190. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -5
  191. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +0 -60
  192. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +0 -7
  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 -150
  208. data/spec/lib/models/expirable_spec.rb +0 -50
  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 -41
  212. data/spec/lib/oauth/authorization_code_request_spec.rb +0 -80
  213. data/spec/lib/oauth/base_request_spec.rb +0 -160
  214. data/spec/lib/oauth/base_response_spec.rb +0 -45
  215. data/spec/lib/oauth/client/credentials_spec.rb +0 -88
  216. data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -44
  217. data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -86
  218. data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -54
  219. data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -27
  220. data/spec/lib/oauth/client_credentials_request_spec.rb +0 -104
  221. data/spec/lib/oauth/client_spec.rb +0 -39
  222. data/spec/lib/oauth/code_request_spec.rb +0 -45
  223. data/spec/lib/oauth/code_response_spec.rb +0 -34
  224. data/spec/lib/oauth/error_response_spec.rb +0 -61
  225. data/spec/lib/oauth/error_spec.rb +0 -23
  226. data/spec/lib/oauth/forbidden_token_response_spec.rb +0 -23
  227. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -64
  228. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -20
  229. data/spec/lib/oauth/helpers/uri_checker_spec.rb +0 -104
  230. data/spec/lib/oauth/invalid_token_response_spec.rb +0 -56
  231. data/spec/lib/oauth/password_access_token_request_spec.rb +0 -90
  232. data/spec/lib/oauth/pre_authorization_spec.rb +0 -155
  233. data/spec/lib/oauth/refresh_token_request_spec.rb +0 -154
  234. data/spec/lib/oauth/scopes_spec.rb +0 -122
  235. data/spec/lib/oauth/token_request_spec.rb +0 -98
  236. data/spec/lib/oauth/token_response_spec.rb +0 -85
  237. data/spec/lib/oauth/token_spec.rb +0 -116
  238. data/spec/lib/request/strategy_spec.rb +0 -53
  239. data/spec/lib/server_spec.rb +0 -49
  240. data/spec/models/doorkeeper/access_grant_spec.rb +0 -36
  241. data/spec/models/doorkeeper/access_token_spec.rb +0 -394
  242. data/spec/models/doorkeeper/application_spec.rb +0 -179
  243. data/spec/requests/applications/applications_request_spec.rb +0 -94
  244. data/spec/requests/applications/authorized_applications_spec.rb +0 -30
  245. data/spec/requests/endpoints/authorization_spec.rb +0 -71
  246. data/spec/requests/endpoints/token_spec.rb +0 -64
  247. data/spec/requests/flows/authorization_code_errors_spec.rb +0 -76
  248. data/spec/requests/flows/authorization_code_spec.rb +0 -148
  249. data/spec/requests/flows/client_credentials_spec.rb +0 -58
  250. data/spec/requests/flows/implicit_grant_errors_spec.rb +0 -32
  251. data/spec/requests/flows/implicit_grant_spec.rb +0 -61
  252. data/spec/requests/flows/password_spec.rb +0 -115
  253. data/spec/requests/flows/refresh_token_spec.rb +0 -174
  254. data/spec/requests/flows/revoke_token_spec.rb +0 -157
  255. data/spec/requests/flows/skip_authorization_spec.rb +0 -59
  256. data/spec/requests/protected_resources/metal_spec.rb +0 -14
  257. data/spec/requests/protected_resources/private_api_spec.rb +0 -81
  258. data/spec/routing/custom_controller_routes_spec.rb +0 -71
  259. data/spec/routing/default_routes_spec.rb +0 -35
  260. data/spec/routing/scoped_routes_spec.rb +0 -31
  261. data/spec/spec_helper.rb +0 -4
  262. data/spec/spec_helper_integration.rb +0 -63
  263. data/spec/support/dependencies/factory_girl.rb +0 -2
  264. data/spec/support/helpers/access_token_request_helper.rb +0 -11
  265. data/spec/support/helpers/authorization_request_helper.rb +0 -41
  266. data/spec/support/helpers/config_helper.rb +0 -9
  267. data/spec/support/helpers/model_helper.rb +0 -67
  268. data/spec/support/helpers/request_spec_helper.rb +0 -84
  269. data/spec/support/helpers/url_helper.rb +0 -55
  270. data/spec/support/http_method_shim.rb +0 -38
  271. data/spec/support/orm/active_record.rb +0 -3
  272. data/spec/support/shared/controllers_shared_context.rb +0 -69
  273. data/spec/support/shared/models_shared_examples.rb +0 -52
  274. data/spec/validators/redirect_uri_validator_spec.rb +0 -78
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  class Engine < Rails::Engine
3
5
  initializer "doorkeeper.params.filter" do |app|
4
- parameters = %w(client_secret code authentication_token access_token refresh_token)
5
- app.config.filter_parameters << /^(#{Regexp.union parameters})$/
6
+ parameters = %w[client_secret code authentication_token access_token refresh_token]
7
+ app.config.filter_parameters << /^(#{Regexp.union(parameters)})$/
6
8
  end
7
9
 
8
10
  initializer "doorkeeper.routes" do
@@ -16,11 +18,15 @@ module Doorkeeper
16
18
  end
17
19
 
18
20
  if defined?(Sprockets) && Sprockets::VERSION.chr.to_i >= 4
19
- initializer 'doorkeeper.assets.precompile' do |app|
20
- app.config.assets.precompile += %w(
21
+ initializer "doorkeeper.assets.precompile" do |app|
22
+ # Force users to use:
23
+ # //= link doorkeeper/admin/application.css
24
+ # in Doorkeeper 5 for Sprockets 4 instead of precompile.
25
+ # Add note to official docs & Wiki
26
+ app.config.assets.precompile += %w[
21
27
  doorkeeper/application.css
22
28
  doorkeeper/admin/application.css
23
- )
29
+ ]
24
30
  end
25
31
  end
26
32
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module Errors
3
5
  class DoorkeeperError < StandardError
@@ -6,18 +8,6 @@ module Doorkeeper
6
8
  end
7
9
  end
8
10
 
9
- class InvalidAuthorizationStrategy < DoorkeeperError
10
- def type
11
- :unsupported_response_type
12
- end
13
- end
14
-
15
- class InvalidTokenReuse < DoorkeeperError
16
- def type
17
- :invalid_request
18
- end
19
- end
20
-
21
11
  class InvalidGrantReuse < DoorkeeperError
22
12
  def type
23
13
  :invalid_grant
@@ -30,16 +20,35 @@ module Doorkeeper
30
20
  end
31
21
  end
32
22
 
33
- class MissingRequestStrategy < DoorkeeperError
23
+ class MissingRequiredParameter < DoorkeeperError
24
+ attr_reader :missing_param
25
+
26
+ def initialize(missing_param)
27
+ super
28
+ @missing_param = missing_param
29
+ end
30
+
34
31
  def type
35
32
  :invalid_request
36
33
  end
37
34
  end
38
35
 
39
- class UnableToGenerateToken < DoorkeeperError
40
- end
36
+ class BaseResponseError < DoorkeeperError
37
+ attr_reader :response
41
38
 
42
- class TokenGeneratorNotFound < DoorkeeperError
39
+ def initialize(response)
40
+ @response = response
41
+ end
43
42
  end
43
+
44
+ UnableToGenerateToken = Class.new(DoorkeeperError)
45
+ TokenGeneratorNotFound = Class.new(DoorkeeperError)
46
+ NoOrmCleaner = Class.new(DoorkeeperError)
47
+
48
+ InvalidToken = Class.new(BaseResponseError)
49
+ TokenExpired = Class.new(InvalidToken)
50
+ TokenRevoked = Class.new(InvalidToken)
51
+ TokenUnknown = Class.new(InvalidToken)
52
+ TokenForbidden = Class.new(InvalidToken)
44
53
  end
45
54
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module GrantFlow
5
+ class FallbackFlow < Flow
6
+ def handles_grant_type?
7
+ false
8
+ end
9
+
10
+ def handles_response_type?
11
+ false
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module GrantFlow
5
+ class Flow
6
+ attr_reader :name, :grant_type_matches, :grant_type_strategy,
7
+ :response_type_matches, :response_type_strategy,
8
+ :response_mode_matches
9
+
10
+ def initialize(name, **options)
11
+ @name = name
12
+ @grant_type_matches = options[:grant_type_matches]
13
+ @grant_type_strategy = options[:grant_type_strategy]
14
+ @response_type_matches = options[:response_type_matches]
15
+ @response_type_strategy = options[:response_type_strategy]
16
+ @response_mode_matches = options[:response_mode_matches]
17
+ end
18
+
19
+ def handles_grant_type?
20
+ grant_type_matches.present?
21
+ end
22
+
23
+ def handles_response_type?
24
+ response_type_matches.present?
25
+ end
26
+
27
+ def matches_grant_type?(value)
28
+ grant_type_matches === value
29
+ end
30
+
31
+ def matches_response_type?(value)
32
+ response_type_matches === value
33
+ end
34
+
35
+ def default_response_mode
36
+ response_mode_matches[0]
37
+ end
38
+
39
+ def matches_response_mode?(value)
40
+ response_mode_matches.include?(value)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module GrantFlow
5
+ module Registry
6
+ mattr_accessor :flows
7
+ self.flows = {}
8
+
9
+ mattr_accessor :aliases
10
+ self.aliases = {}
11
+
12
+ # Allows to register custom OAuth grant flow so that Doorkeeper
13
+ # could recognize and process it.
14
+ #
15
+ def register(name_or_flow, **options)
16
+ unless name_or_flow.is_a?(Doorkeeper::GrantFlow::Flow)
17
+ name_or_flow = Flow.new(name_or_flow, **options)
18
+ end
19
+
20
+ flow_key = name_or_flow.name.to_sym
21
+
22
+ if flows.key?(flow_key)
23
+ ::Kernel.warn <<~WARNING
24
+ [DOORKEEPER] '#{flow_key}' grant flow already registered and will be overridden
25
+ in #{caller(1..1).first}
26
+ WARNING
27
+ end
28
+
29
+ flows[flow_key] = name_or_flow
30
+ end
31
+
32
+ # Allows to register aliases that could be used in `grant_flows`
33
+ # configuration option. It is possible to have aliases like 1:1 or
34
+ # 1:N, i.e. "implicit_oidc" => ['token', 'id_token', 'id_token token'].
35
+ #
36
+ def register_alias(alias_name, **options)
37
+ aliases[alias_name.to_sym] = Array.wrap(options.fetch(:as))
38
+ end
39
+
40
+ def expand_alias(alias_name)
41
+ aliases.fetch(alias_name.to_sym, [])
42
+ end
43
+
44
+ # [NOTE]: make it to use #fetch after removing fallbacks
45
+ def get(name)
46
+ flows[name.to_sym]
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "doorkeeper/grant_flow/flow"
4
+ require "doorkeeper/grant_flow/fallback_flow"
5
+ require "doorkeeper/grant_flow/registry"
6
+
7
+ module Doorkeeper
8
+ module GrantFlow
9
+ extend Registry
10
+
11
+ register(
12
+ :implicit,
13
+ response_type_matches: "token",
14
+ response_mode_matches: %w[fragment form_post],
15
+ response_type_strategy: Doorkeeper::Request::Token,
16
+ )
17
+
18
+ register(
19
+ :authorization_code,
20
+ response_type_matches: "code",
21
+ response_mode_matches: %w[query fragment form_post],
22
+ response_type_strategy: Doorkeeper::Request::Code,
23
+ grant_type_matches: "authorization_code",
24
+ grant_type_strategy: Doorkeeper::Request::AuthorizationCode,
25
+ )
26
+
27
+ register(
28
+ :client_credentials,
29
+ grant_type_matches: "client_credentials",
30
+ grant_type_strategy: Doorkeeper::Request::ClientCredentials,
31
+ )
32
+
33
+ register(
34
+ :password,
35
+ grant_type_matches: "password",
36
+ grant_type_strategy: Doorkeeper::Request::Password,
37
+ )
38
+
39
+ register(
40
+ :refresh_token,
41
+ grant_type_matches: "refresh_token",
42
+ grant_type_strategy: Doorkeeper::Request::RefreshToken,
43
+ )
44
+ end
45
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module Grape
3
5
  class AuthorizationDecorator < SimpleDelegator
@@ -7,10 +9,10 @@ module Doorkeeper
7
9
 
8
10
  def authorization
9
11
  env = __getobj__.env
10
- env['HTTP_AUTHORIZATION'] ||
11
- env['X-HTTP_AUTHORIZATION'] ||
12
- env['X_HTTP_AUTHORIZATION'] ||
13
- env['REDIRECT_X_HTTP_AUTHORIZATION']
12
+ env["HTTP_AUTHORIZATION"] ||
13
+ env["X-HTTP_AUTHORIZATION"] ||
14
+ env["X_HTTP_AUTHORIZATION"] ||
15
+ env["REDIRECT_X_HTTP_AUTHORIZATION"]
14
16
  end
15
17
  end
16
18
  end
@@ -1,7 +1,11 @@
1
- require 'doorkeeper/grape/authorization_decorator'
1
+ # frozen_string_literal: true
2
+
3
+ require "doorkeeper/grape/authorization_decorator"
2
4
 
3
5
  module Doorkeeper
4
6
  module Grape
7
+ # Doorkeeper helpers for Grape applications.
8
+ # Provides helpers for endpoints authorization based on defined set of scopes.
5
9
  module Helpers
6
10
  # These helpers are for grape >= 0.10
7
11
  extend ::Grape::API::Helpers
@@ -9,10 +13,12 @@ module Doorkeeper
9
13
 
10
14
  # endpoint specific scopes > parameter scopes > default scopes
11
15
  def doorkeeper_authorize!(*scopes)
12
- endpoint_scopes = env["api.endpoint"].route_setting(:scopes)
16
+ endpoint_scopes = endpoint.route_setting(:scopes) ||
17
+ endpoint.options[:route_options][:scopes]
18
+
13
19
  scopes = if endpoint_scopes
14
20
  Doorkeeper::OAuth::Scopes.from_array(endpoint_scopes)
15
- elsif scopes && !scopes.empty?
21
+ elsif scopes.present?
16
22
  Doorkeeper::OAuth::Scopes.from_array(scopes)
17
23
  end
18
24
 
@@ -20,28 +26,33 @@ module Doorkeeper
20
26
  end
21
27
 
22
28
  def doorkeeper_render_error_with(error)
23
- status_code = case error.status
24
- when :unauthorized
25
- 401
26
- when :forbidden
27
- 403
28
- end
29
-
29
+ status_code = error_status_codes[error.status]
30
30
  error!({ error: error.description }, status_code, error.headers)
31
31
  end
32
32
 
33
33
  private
34
34
 
35
+ def endpoint
36
+ env["api.endpoint"]
37
+ end
38
+
35
39
  def doorkeeper_token
36
- @_doorkeeper_token ||= OAuth::Token.authenticate(
40
+ @doorkeeper_token ||= OAuth::Token.authenticate(
37
41
  decorated_request,
38
- *Doorkeeper.configuration.access_token_methods
42
+ *Doorkeeper.config.access_token_methods,
39
43
  )
40
44
  end
41
45
 
42
46
  def decorated_request
43
47
  AuthorizationDecorator.new(request)
44
48
  end
49
+
50
+ def error_status_codes
51
+ {
52
+ unauthorized: 401,
53
+ forbidden: 403,
54
+ }
55
+ end
45
56
  end
46
57
  end
47
58
  end
@@ -1,51 +1,88 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Define methods that can be called in any controller that inherits from
2
4
  # Doorkeeper::ApplicationMetalController or Doorkeeper::ApplicationController
3
5
  module Doorkeeper
4
6
  module Helpers
7
+ # Rails controller helpers.
8
+ #
5
9
  module Controller
6
10
  private
7
11
 
8
- def authenticate_resource_owner! # :doc:
12
+ # :doc:
13
+ def authenticate_resource_owner!
9
14
  current_resource_owner
10
15
  end
11
16
 
12
- def current_resource_owner # :doc:
13
- instance_eval(&Doorkeeper.configuration.authenticate_resource_owner)
17
+ # :doc:
18
+ def current_resource_owner
19
+ return @current_resource_owner if defined?(@current_resource_owner)
20
+
21
+ @current_resource_owner ||= begin
22
+ instance_eval(&Doorkeeper.config.authenticate_resource_owner)
23
+ end
14
24
  end
15
25
 
16
26
  def resource_owner_from_credentials
17
- instance_eval(&Doorkeeper.configuration.resource_owner_from_credentials)
27
+ instance_eval(&Doorkeeper.config.resource_owner_from_credentials)
18
28
  end
19
29
 
20
- def authenticate_admin! # :doc:
21
- instance_eval(&Doorkeeper.configuration.authenticate_admin)
30
+ # :doc:
31
+ def authenticate_admin!
32
+ instance_eval(&Doorkeeper.config.authenticate_admin)
22
33
  end
23
34
 
24
35
  def server
25
36
  @server ||= Server.new(self)
26
37
  end
27
38
 
28
- def doorkeeper_token # :doc:
29
- @token ||= OAuth::Token.authenticate request, *config_methods
39
+ # :doc:
40
+ def doorkeeper_token
41
+ return @doorkeeper_token if defined?(@doorkeeper_token)
42
+
43
+ @doorkeeper_token ||= OAuth::Token.authenticate(request, *config_methods)
30
44
  end
31
45
 
32
46
  def config_methods
33
- @methods ||= Doorkeeper.configuration.access_token_methods
47
+ @config_methods ||= Doorkeeper.config.access_token_methods
34
48
  end
35
49
 
36
50
  def get_error_response_from_exception(exception)
37
- OAuth::ErrorResponse.new name: exception.type, state: params[:state]
51
+ if exception.respond_to?(:response)
52
+ exception.response
53
+ elsif exception.type == :invalid_request
54
+ OAuth::InvalidRequestResponse.new(
55
+ name: exception.type,
56
+ state: params[:state],
57
+ missing_param: exception.missing_param,
58
+ )
59
+ else
60
+ OAuth::ErrorResponse.new(name: exception.type, state: params[:state])
61
+ end
38
62
  end
39
63
 
40
64
  def handle_token_exception(exception)
41
- error = get_error_response_from_exception exception
42
- headers.merge! error.headers
65
+ error = get_error_response_from_exception(exception)
66
+ headers.merge!(error.headers)
43
67
  self.response_body = error.body.to_json
44
- self.status = error.status
68
+ self.status = error.status
45
69
  end
46
70
 
47
71
  def skip_authorization?
48
- !!instance_exec([@server.current_resource_owner, @pre_auth.client], &Doorkeeper.configuration.skip_authorization)
72
+ !!instance_exec(
73
+ [server.current_resource_owner, @pre_auth.client],
74
+ &Doorkeeper.config.skip_authorization
75
+ )
76
+ end
77
+
78
+ def enforce_content_type
79
+ if (request.put? || request.post? || request.patch?) && !x_www_form_urlencoded?
80
+ render json: {}, status: :unsupported_media_type
81
+ end
82
+ end
83
+
84
+ def x_www_form_urlencoded?
85
+ request.content_type == "application/x-www-form-urlencoded"
49
86
  end
50
87
  end
51
88
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module AccessGrantMixin
3
5
  extend ActiveSupport::Concern
@@ -6,24 +8,14 @@ module Doorkeeper
6
8
  include Models::Expirable
7
9
  include Models::Revocable
8
10
  include Models::Accessible
11
+ include Models::Orderable
12
+ include Models::SecretStorable
9
13
  include Models::Scopes
10
- include ActiveModel::MassAssignmentSecurity if defined?(::ProtectedAttributes)
11
-
12
- included do
13
- belongs_to_options = {
14
- class_name: 'Doorkeeper::Application',
15
- inverse_of: :access_grants
16
- }
17
- if defined?(ActiveRecord::Base) && ActiveRecord::VERSION::MAJOR >= 5
18
- belongs_to_options[:optional] = true
19
- end
20
-
21
- belongs_to :application, belongs_to_options
22
-
23
- validates :resource_owner_id, :application_id, :token, :expires_in, :redirect_uri, presence: true
24
- validates :token, uniqueness: true
14
+ include Models::ResourceOwnerable
25
15
 
26
- before_validation :generate_token, on: :create
16
+ # Never uses PKCE if PKCE migrations were not generated
17
+ def uses_pkce?
18
+ self.class.pkce_supported? && code_challenge.present?
27
19
  end
28
20
 
29
21
  module ClassMethods
@@ -32,22 +24,97 @@ module Doorkeeper
32
24
  #
33
25
  # @param token [#to_s] token value (any object that responds to `#to_s`)
34
26
  #
35
- # @return [Doorkeeper::AccessGrant, nil] AccessGrant object or nil
36
- # if there is no record with such token
27
+ # @return [Doorkeeper::AccessGrant, nil]
28
+ # AccessGrant object or nil if there is no record with such token
37
29
  #
38
30
  def by_token(token)
39
- find_by(token: token.to_s)
31
+ find_by_plaintext_token(:token, token)
32
+ end
33
+
34
+ # Revokes AccessGrant records that have not been revoked and associated
35
+ # with the specific Application and Resource Owner.
36
+ #
37
+ # @param application_id [Integer]
38
+ # ID of the Application
39
+ # @param resource_owner [ActiveRecord::Base, Integer]
40
+ # instance of the Resource Owner model or it's ID
41
+ #
42
+ def revoke_all_for(application_id, resource_owner, clock = Time)
43
+ by_resource_owner(resource_owner)
44
+ .where(
45
+ application_id: application_id,
46
+ revoked_at: nil,
47
+ )
48
+ .update_all(revoked_at: clock.now.utc)
49
+ end
50
+
51
+ # Implements PKCE code_challenge encoding without base64 padding as described in the spec.
52
+ # https://datatracker.ietf.org/doc/html/rfc7636#appendix-A
53
+ # Appendix A. Notes on Implementing Base64url Encoding without Padding
54
+ #
55
+ # This appendix describes how to implement a base64url-encoding
56
+ # function without padding, based upon the standard base64-encoding
57
+ # function that uses padding.
58
+ #
59
+ # To be concrete, example C# code implementing these functions is shown
60
+ # below. Similar code could be used in other languages.
61
+ #
62
+ # static string base64urlencode(byte [] arg)
63
+ # {
64
+ # string s = Convert.ToBase64String(arg); // Regular base64 encoder
65
+ # s = s.Split('=')[0]; // Remove any trailing '='s
66
+ # s = s.Replace('+', '-'); // 62nd char of encoding
67
+ # s = s.Replace('/', '_'); // 63rd char of encoding
68
+ # return s;
69
+ # }
70
+ #
71
+ # An example correspondence between unencoded and encoded values
72
+ # follows. The octet sequence below encodes into the string below,
73
+ # which when decoded, reproduces the octet sequence.
74
+ #
75
+ # 3 236 255 224 193
76
+ #
77
+ # A-z_4ME
78
+ #
79
+ # https://ruby-doc.org/stdlib-2.1.3/libdoc/base64/rdoc/Base64.html#method-i-urlsafe_encode64
80
+ #
81
+ # urlsafe_encode64(bin)
82
+ # Returns the Base64-encoded version of bin. This method complies with
83
+ # "Base 64 Encoding with URL and Filename Safe Alphabet" in RFC 4648.
84
+ # The alphabet uses '-' instead of '+' and '_' instead of '/'.
85
+
86
+ # @param code_verifier [#to_s] a one time use value (any object that responds to `#to_s`)
87
+ #
88
+ # @return [#to_s] An encoded code challenge based on the provided verifier
89
+ # suitable for PKCE validation
90
+ #
91
+ def generate_code_challenge(code_verifier)
92
+ Base64.urlsafe_encode64(Digest::SHA256.digest(code_verifier), padding: false)
40
93
  end
41
- end
42
94
 
43
- private
95
+ def pkce_supported?
96
+ column_names.include?("code_challenge")
97
+ end
44
98
 
45
- # Generates token value with UniqueToken class.
46
- #
47
- # @return [String] token value
48
- #
49
- def generate_token
50
- self.token = UniqueToken.generate
99
+ ##
100
+ # Determines the secret storing transformer
101
+ # Unless configured otherwise, uses the plain secret strategy
102
+ #
103
+ # @return [Doorkeeper::SecretStoring::Base]
104
+ #
105
+ def secret_strategy
106
+ ::Doorkeeper.config.token_secret_strategy
107
+ end
108
+
109
+ ##
110
+ # Determine the fallback storing strategy
111
+ # Unless configured, there will be no fallback
112
+ #
113
+ # @return [Doorkeeper::SecretStoring::Base]
114
+ #
115
+ def fallback_secret_strategy
116
+ ::Doorkeeper.config.token_secret_fallback_strategy
117
+ end
51
118
  end
52
119
  end
53
120
  end