doorkeeper 4.2.0 → 5.5.2

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

Potentially problematic release.


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

Files changed (271) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1038 -0
  3. data/README.md +110 -348
  4. data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
  5. data/app/controllers/doorkeeper/application_controller.rb +6 -7
  6. data/app/controllers/doorkeeper/application_metal_controller.rb +7 -11
  7. data/app/controllers/doorkeeper/applications_controller.rb +65 -20
  8. data/app/controllers/doorkeeper/authorizations_controller.rb +97 -17
  9. data/app/controllers/doorkeeper/authorized_applications_controller.rb +22 -3
  10. data/app/controllers/doorkeeper/token_info_controller.rb +16 -4
  11. data/app/controllers/doorkeeper/tokens_controller.rb +112 -35
  12. data/app/helpers/doorkeeper/dashboard_helper.rb +10 -6
  13. data/app/views/doorkeeper/applications/_delete_form.html.erb +4 -3
  14. data/app/views/doorkeeper/applications/_form.html.erb +33 -21
  15. data/app/views/doorkeeper/applications/edit.html.erb +1 -1
  16. data/app/views/doorkeeper/applications/index.html.erb +18 -6
  17. data/app/views/doorkeeper/applications/new.html.erb +1 -1
  18. data/app/views/doorkeeper/applications/show.html.erb +40 -16
  19. data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
  20. data/app/views/doorkeeper/authorizations/form_post.html.erb +15 -0
  21. data/app/views/doorkeeper/authorizations/new.html.erb +7 -1
  22. data/app/views/doorkeeper/authorized_applications/_delete_form.html.erb +1 -2
  23. data/app/views/doorkeeper/authorized_applications/index.html.erb +0 -1
  24. data/app/views/layouts/doorkeeper/admin.html.erb +16 -14
  25. data/config/locales/en.yml +33 -9
  26. data/lib/doorkeeper/config/abstract_builder.rb +28 -0
  27. data/lib/doorkeeper/config/option.rb +82 -0
  28. data/lib/doorkeeper/config/validations.rb +53 -0
  29. data/lib/doorkeeper/config.rb +545 -143
  30. data/lib/doorkeeper/engine.rb +11 -5
  31. data/lib/doorkeeper/errors.rb +37 -10
  32. data/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
  33. data/lib/doorkeeper/grant_flow/flow.rb +44 -0
  34. data/lib/doorkeeper/grant_flow/registry.rb +50 -0
  35. data/lib/doorkeeper/grant_flow.rb +45 -0
  36. data/lib/doorkeeper/grape/authorization_decorator.rb +6 -4
  37. data/lib/doorkeeper/grape/helpers.rb +24 -12
  38. data/lib/doorkeeper/helpers/controller.rb +49 -27
  39. data/lib/doorkeeper/models/access_grant_mixin.rb +100 -21
  40. data/lib/doorkeeper/models/access_token_mixin.rb +379 -75
  41. data/lib/doorkeeper/models/application_mixin.rb +72 -25
  42. data/lib/doorkeeper/models/concerns/accessible.rb +6 -0
  43. data/lib/doorkeeper/models/concerns/expirable.rb +20 -6
  44. data/lib/doorkeeper/models/concerns/orderable.rb +15 -0
  45. data/lib/doorkeeper/models/concerns/ownership.rb +4 -7
  46. data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
  47. data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
  48. data/lib/doorkeeper/models/concerns/revocable.rb +12 -18
  49. data/lib/doorkeeper/models/concerns/scopes.rb +12 -2
  50. data/lib/doorkeeper/models/concerns/secret_storable.rb +106 -0
  51. data/lib/doorkeeper/oauth/authorization/code.rb +48 -12
  52. data/lib/doorkeeper/oauth/authorization/context.rb +17 -0
  53. data/lib/doorkeeper/oauth/authorization/token.rb +66 -28
  54. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +22 -18
  55. data/lib/doorkeeper/oauth/authorization_code_request.rb +64 -14
  56. data/lib/doorkeeper/oauth/base_request.rb +66 -0
  57. data/lib/doorkeeper/oauth/base_response.rb +31 -0
  58. data/lib/doorkeeper/oauth/client/credentials.rb +23 -10
  59. data/lib/doorkeeper/oauth/client.rb +10 -12
  60. data/lib/doorkeeper/oauth/client_credentials/creator.rb +47 -4
  61. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +16 -9
  62. data/lib/doorkeeper/oauth/client_credentials/validator.rb +56 -0
  63. data/lib/doorkeeper/oauth/client_credentials_request.rb +11 -15
  64. data/lib/doorkeeper/oauth/code_request.rb +8 -12
  65. data/lib/doorkeeper/oauth/code_response.rb +28 -15
  66. data/lib/doorkeeper/oauth/error.rb +5 -3
  67. data/lib/doorkeeper/oauth/error_response.rb +41 -20
  68. data/lib/doorkeeper/oauth/forbidden_token_response.rb +10 -3
  69. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +23 -18
  70. data/lib/doorkeeper/oauth/helpers/unique_token.rb +20 -3
  71. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +53 -3
  72. data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
  73. data/lib/doorkeeper/oauth/invalid_request_response.rb +43 -0
  74. data/lib/doorkeeper/oauth/invalid_token_response.rb +31 -5
  75. data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
  76. data/lib/doorkeeper/oauth/password_access_token_request.rb +45 -13
  77. data/lib/doorkeeper/oauth/pre_authorization.rb +135 -26
  78. data/lib/doorkeeper/oauth/refresh_token_request.rb +61 -36
  79. data/lib/doorkeeper/oauth/scopes.rb +26 -12
  80. data/lib/doorkeeper/oauth/token.rb +25 -23
  81. data/lib/doorkeeper/oauth/token_introspection.rb +202 -0
  82. data/lib/doorkeeper/oauth/token_request.rb +8 -21
  83. data/lib/doorkeeper/oauth/token_response.rb +14 -10
  84. data/lib/doorkeeper/oauth.rb +13 -0
  85. data/lib/doorkeeper/orm/active_record/access_grant.rb +6 -4
  86. data/lib/doorkeeper/orm/active_record/access_token.rb +5 -25
  87. data/lib/doorkeeper/orm/active_record/application.rb +6 -15
  88. data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +68 -0
  89. data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +59 -0
  90. data/lib/doorkeeper/orm/active_record/mixins/application.rb +198 -0
  91. data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +66 -0
  92. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +33 -0
  93. data/lib/doorkeeper/orm/active_record.rb +37 -8
  94. data/lib/doorkeeper/rails/helpers.rb +14 -15
  95. data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
  96. data/lib/doorkeeper/rails/routes/mapper.rb +3 -1
  97. data/lib/doorkeeper/rails/routes/mapping.rb +10 -8
  98. data/lib/doorkeeper/rails/routes/registry.rb +45 -0
  99. data/lib/doorkeeper/rails/routes.rb +42 -30
  100. data/lib/doorkeeper/rake/db.rake +40 -0
  101. data/lib/doorkeeper/rake/setup.rake +11 -0
  102. data/lib/doorkeeper/rake.rb +14 -0
  103. data/lib/doorkeeper/request/authorization_code.rb +12 -4
  104. data/lib/doorkeeper/request/client_credentials.rb +3 -3
  105. data/lib/doorkeeper/request/code.rb +1 -1
  106. data/lib/doorkeeper/request/password.rb +5 -14
  107. data/lib/doorkeeper/request/refresh_token.rb +6 -5
  108. data/lib/doorkeeper/request/strategy.rb +4 -2
  109. data/lib/doorkeeper/request/token.rb +1 -1
  110. data/lib/doorkeeper/request.rb +62 -29
  111. data/lib/doorkeeper/secret_storing/base.rb +64 -0
  112. data/lib/doorkeeper/secret_storing/bcrypt.rb +60 -0
  113. data/lib/doorkeeper/secret_storing/plain.rb +33 -0
  114. data/lib/doorkeeper/secret_storing/sha256_hash.rb +26 -0
  115. data/lib/doorkeeper/server.rb +9 -19
  116. data/lib/doorkeeper/stale_records_cleaner.rb +24 -0
  117. data/lib/doorkeeper/validations.rb +5 -2
  118. data/lib/doorkeeper/version.rb +12 -1
  119. data/lib/doorkeeper.rb +111 -56
  120. data/lib/generators/doorkeeper/application_owner_generator.rb +28 -13
  121. data/lib/generators/doorkeeper/confidential_applications_generator.rb +33 -0
  122. data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
  123. data/lib/generators/doorkeeper/install_generator.rb +19 -9
  124. data/lib/generators/doorkeeper/migration_generator.rb +27 -10
  125. data/lib/generators/doorkeeper/pkce_generator.rb +33 -0
  126. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +31 -19
  127. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  128. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +9 -0
  129. data/lib/generators/doorkeeper/templates/{add_previous_refresh_token_to_access_tokens.rb → add_previous_refresh_token_to_access_tokens.rb.erb} +3 -1
  130. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +8 -0
  131. data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
  132. data/lib/generators/doorkeeper/templates/initializer.rb +410 -31
  133. data/lib/generators/doorkeeper/templates/migration.rb.erb +88 -0
  134. data/lib/generators/doorkeeper/views_generator.rb +8 -4
  135. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  136. metadata +132 -286
  137. data/.gitignore +0 -14
  138. data/.hound.yml +0 -13
  139. data/.rspec +0 -1
  140. data/.travis.yml +0 -20
  141. data/CONTRIBUTING.md +0 -47
  142. data/Gemfile +0 -14
  143. data/NEWS.md +0 -593
  144. data/RELEASING.md +0 -17
  145. data/Rakefile +0 -20
  146. data/app/validators/redirect_uri_validator.rb +0 -34
  147. data/doorkeeper.gemspec +0 -28
  148. data/lib/doorkeeper/oauth/client/methods.rb +0 -18
  149. data/lib/doorkeeper/oauth/client_credentials/validation.rb +0 -45
  150. data/lib/doorkeeper/oauth/request_concern.rb +0 -48
  151. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb +0 -7
  152. data/lib/generators/doorkeeper/templates/migration.rb +0 -68
  153. data/spec/controllers/application_metal_controller.rb +0 -10
  154. data/spec/controllers/applications_controller_spec.rb +0 -58
  155. data/spec/controllers/authorizations_controller_spec.rb +0 -189
  156. data/spec/controllers/protected_resources_controller_spec.rb +0 -300
  157. data/spec/controllers/token_info_controller_spec.rb +0 -52
  158. data/spec/controllers/tokens_controller_spec.rb +0 -88
  159. data/spec/dummy/Rakefile +0 -7
  160. data/spec/dummy/app/controllers/application_controller.rb +0 -3
  161. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +0 -7
  162. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +0 -12
  163. data/spec/dummy/app/controllers/home_controller.rb +0 -17
  164. data/spec/dummy/app/controllers/metal_controller.rb +0 -11
  165. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +0 -11
  166. data/spec/dummy/app/helpers/application_helper.rb +0 -5
  167. data/spec/dummy/app/models/user.rb +0 -5
  168. data/spec/dummy/app/views/home/index.html.erb +0 -0
  169. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  170. data/spec/dummy/config/application.rb +0 -23
  171. data/spec/dummy/config/boot.rb +0 -9
  172. data/spec/dummy/config/database.yml +0 -15
  173. data/spec/dummy/config/environment.rb +0 -5
  174. data/spec/dummy/config/environments/development.rb +0 -29
  175. data/spec/dummy/config/environments/production.rb +0 -62
  176. data/spec/dummy/config/environments/test.rb +0 -44
  177. data/spec/dummy/config/initializers/active_record_belongs_to_required_by_default.rb +0 -6
  178. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  179. data/spec/dummy/config/initializers/doorkeeper.rb +0 -96
  180. data/spec/dummy/config/initializers/secret_token.rb +0 -9
  181. data/spec/dummy/config/initializers/session_store.rb +0 -8
  182. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
  183. data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
  184. data/spec/dummy/config/routes.rb +0 -52
  185. data/spec/dummy/config.ru +0 -4
  186. data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -9
  187. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -5
  188. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +0 -60
  189. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +0 -7
  190. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +0 -11
  191. data/spec/dummy/db/schema.rb +0 -67
  192. data/spec/dummy/public/404.html +0 -26
  193. data/spec/dummy/public/422.html +0 -26
  194. data/spec/dummy/public/500.html +0 -26
  195. data/spec/dummy/public/favicon.ico +0 -0
  196. data/spec/dummy/script/rails +0 -6
  197. data/spec/factories.rb +0 -28
  198. data/spec/generators/application_owner_generator_spec.rb +0 -22
  199. data/spec/generators/install_generator_spec.rb +0 -31
  200. data/spec/generators/migration_generator_spec.rb +0 -20
  201. data/spec/generators/templates/routes.rb +0 -3
  202. data/spec/generators/views_generator_spec.rb +0 -27
  203. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -24
  204. data/spec/lib/config_spec.rb +0 -334
  205. data/spec/lib/doorkeeper_spec.rb +0 -28
  206. data/spec/lib/models/expirable_spec.rb +0 -51
  207. data/spec/lib/models/revocable_spec.rb +0 -59
  208. data/spec/lib/models/scopes_spec.rb +0 -43
  209. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -42
  210. data/spec/lib/oauth/authorization_code_request_spec.rb +0 -80
  211. data/spec/lib/oauth/client/credentials_spec.rb +0 -47
  212. data/spec/lib/oauth/client/methods_spec.rb +0 -54
  213. data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -44
  214. data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -86
  215. data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -54
  216. data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -27
  217. data/spec/lib/oauth/client_credentials_request_spec.rb +0 -104
  218. data/spec/lib/oauth/client_spec.rb +0 -39
  219. data/spec/lib/oauth/code_request_spec.rb +0 -45
  220. data/spec/lib/oauth/code_response_spec.rb +0 -34
  221. data/spec/lib/oauth/error_response_spec.rb +0 -61
  222. data/spec/lib/oauth/error_spec.rb +0 -23
  223. data/spec/lib/oauth/forbidden_token_response_spec.rb +0 -23
  224. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -64
  225. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -20
  226. data/spec/lib/oauth/helpers/uri_checker_spec.rb +0 -104
  227. data/spec/lib/oauth/invalid_token_response_spec.rb +0 -28
  228. data/spec/lib/oauth/password_access_token_request_spec.rb +0 -90
  229. data/spec/lib/oauth/pre_authorization_spec.rb +0 -155
  230. data/spec/lib/oauth/refresh_token_request_spec.rb +0 -154
  231. data/spec/lib/oauth/scopes_spec.rb +0 -122
  232. data/spec/lib/oauth/token_request_spec.rb +0 -98
  233. data/spec/lib/oauth/token_response_spec.rb +0 -85
  234. data/spec/lib/oauth/token_spec.rb +0 -116
  235. data/spec/lib/request/strategy_spec.rb +0 -53
  236. data/spec/lib/server_spec.rb +0 -52
  237. data/spec/models/doorkeeper/access_grant_spec.rb +0 -36
  238. data/spec/models/doorkeeper/access_token_spec.rb +0 -394
  239. data/spec/models/doorkeeper/application_spec.rb +0 -179
  240. data/spec/requests/applications/applications_request_spec.rb +0 -94
  241. data/spec/requests/applications/authorized_applications_spec.rb +0 -30
  242. data/spec/requests/endpoints/authorization_spec.rb +0 -72
  243. data/spec/requests/endpoints/token_spec.rb +0 -64
  244. data/spec/requests/flows/authorization_code_errors_spec.rb +0 -66
  245. data/spec/requests/flows/authorization_code_spec.rb +0 -156
  246. data/spec/requests/flows/client_credentials_spec.rb +0 -58
  247. data/spec/requests/flows/implicit_grant_errors_spec.rb +0 -32
  248. data/spec/requests/flows/implicit_grant_spec.rb +0 -61
  249. data/spec/requests/flows/password_spec.rb +0 -115
  250. data/spec/requests/flows/refresh_token_spec.rb +0 -174
  251. data/spec/requests/flows/revoke_token_spec.rb +0 -157
  252. data/spec/requests/flows/skip_authorization_spec.rb +0 -59
  253. data/spec/requests/protected_resources/metal_spec.rb +0 -14
  254. data/spec/requests/protected_resources/private_api_spec.rb +0 -81
  255. data/spec/routing/custom_controller_routes_spec.rb +0 -71
  256. data/spec/routing/default_routes_spec.rb +0 -35
  257. data/spec/routing/scoped_routes_spec.rb +0 -31
  258. data/spec/spec_helper.rb +0 -2
  259. data/spec/spec_helper_integration.rb +0 -59
  260. data/spec/support/dependencies/factory_girl.rb +0 -2
  261. data/spec/support/helpers/access_token_request_helper.rb +0 -11
  262. data/spec/support/helpers/authorization_request_helper.rb +0 -41
  263. data/spec/support/helpers/config_helper.rb +0 -9
  264. data/spec/support/helpers/model_helper.rb +0 -67
  265. data/spec/support/helpers/request_spec_helper.rb +0 -76
  266. data/spec/support/helpers/url_helper.rb +0 -55
  267. data/spec/support/http_method_shim.rb +0 -24
  268. data/spec/support/orm/active_record.rb +0 -3
  269. data/spec/support/shared/controllers_shared_context.rb +0 -69
  270. data/spec/support/shared/models_shared_examples.rb +0 -52
  271. data/spec/validators/redirect_uri_validator_spec.rb +0 -78
@@ -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,27 +1,54 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module Errors
3
5
  class DoorkeeperError < StandardError
4
- end
5
-
6
- class InvalidAuthorizationStrategy < DoorkeeperError
7
- end
8
-
9
- class InvalidTokenReuse < DoorkeeperError
6
+ def type
7
+ message
8
+ end
10
9
  end
11
10
 
12
11
  class InvalidGrantReuse < DoorkeeperError
12
+ def type
13
+ :invalid_grant
14
+ end
13
15
  end
14
16
 
15
17
  class InvalidTokenStrategy < DoorkeeperError
18
+ def type
19
+ :unsupported_grant_type
20
+ end
16
21
  end
17
22
 
18
- class MissingRequestStrategy < DoorkeeperError
19
- end
23
+ class MissingRequiredParameter < DoorkeeperError
24
+ attr_reader :missing_param
25
+
26
+ def initialize(missing_param)
27
+ super
28
+ @missing_param = missing_param
29
+ end
20
30
 
21
- class UnableToGenerateToken < DoorkeeperError
31
+ def type
32
+ :invalid_request
33
+ end
22
34
  end
23
35
 
24
- class TokenGeneratorNotFound < DoorkeeperError
36
+ class BaseResponseError < DoorkeeperError
37
+ attr_reader :response
38
+
39
+ def initialize(response)
40
+ @response = response
41
+ end
25
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)
26
53
  end
27
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,17 +1,24 @@
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
10
+ # These helpers are for grape >= 0.10
6
11
  extend ::Grape::API::Helpers
7
12
  include Doorkeeper::Rails::Helpers
8
13
 
9
14
  # endpoint specific scopes > parameter scopes > default scopes
10
15
  def doorkeeper_authorize!(*scopes)
11
- endpoint_scopes = env['api.endpoint'].options[:route_options][:scopes]
16
+ endpoint_scopes = endpoint.route_setting(:scopes) ||
17
+ endpoint.options[:route_options][:scopes]
18
+
12
19
  scopes = if endpoint_scopes
13
20
  Doorkeeper::OAuth::Scopes.from_array(endpoint_scopes)
14
- elsif scopes && !scopes.empty?
21
+ elsif scopes.present?
15
22
  Doorkeeper::OAuth::Scopes.from_array(scopes)
16
23
  end
17
24
 
@@ -19,28 +26,33 @@ module Doorkeeper
19
26
  end
20
27
 
21
28
  def doorkeeper_render_error_with(error)
22
- status_code = case error.status
23
- when :unauthorized
24
- 401
25
- when :forbidden
26
- 403
27
- end
28
-
29
+ status_code = error_status_codes[error.status]
29
30
  error!({ error: error.description }, status_code, error.headers)
30
31
  end
31
32
 
32
33
  private
33
34
 
35
+ def endpoint
36
+ env["api.endpoint"]
37
+ end
38
+
34
39
  def doorkeeper_token
35
- @_doorkeeper_token ||= OAuth::Token.authenticate(
40
+ @doorkeeper_token ||= OAuth::Token.authenticate(
36
41
  decorated_request,
37
- *Doorkeeper.configuration.access_token_methods
42
+ *Doorkeeper.config.access_token_methods,
38
43
  )
39
44
  end
40
45
 
41
46
  def decorated_request
42
47
  AuthorizationDecorator.new(request)
43
48
  end
49
+
50
+ def error_status_codes
51
+ {
52
+ unauthorized: 401,
53
+ forbidden: 403,
54
+ }
55
+ end
44
56
  end
45
57
  end
46
58
  end
@@ -1,66 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Define methods that can be called in any controller that inherits from
4
+ # Doorkeeper::ApplicationMetalController or Doorkeeper::ApplicationController
1
5
  module Doorkeeper
2
6
  module Helpers
7
+ # Rails controller helpers.
8
+ #
3
9
  module Controller
4
- extend ActiveSupport::Concern
5
-
6
10
  private
7
11
 
12
+ # :doc:
8
13
  def authenticate_resource_owner!
9
14
  current_resource_owner
10
15
  end
11
16
 
17
+ # :doc:
12
18
  def current_resource_owner
13
- instance_eval(&Doorkeeper.configuration.authenticate_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
 
30
+ # :doc:
20
31
  def authenticate_admin!
21
- instance_eval(&Doorkeeper.configuration.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
 
39
+ # :doc:
28
40
  def doorkeeper_token
29
- @token ||= OAuth::Token.authenticate request, *config_methods
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
- error_name = case exception
38
- when Errors::InvalidTokenStrategy
39
- :unsupported_grant_type
40
- when Errors::InvalidAuthorizationStrategy
41
- :unsupported_response_type
42
- when Errors::MissingRequestStrategy
43
- :invalid_request
44
- when Errors::InvalidTokenReuse
45
- :invalid_request
46
- when Errors::InvalidGrantReuse
47
- :invalid_grant
48
- when Errors::DoorkeeperError
49
- exception.message
50
- end
51
-
52
- OAuth::ErrorResponse.new name: error_name, 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
53
62
  end
54
63
 
55
64
  def handle_token_exception(exception)
56
- error = get_error_response_from_exception exception
57
- headers.merge! error.headers
65
+ error = get_error_response_from_exception(exception)
66
+ headers.merge!(error.headers)
58
67
  self.response_body = error.body.to_json
59
- self.status = error.status
68
+ self.status = error.status
60
69
  end
61
70
 
62
71
  def skip_authorization?
63
- !!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"
64
86
  end
65
87
  end
66
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,36 +8,113 @@ 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
22
+ # Searches for Doorkeeper::AccessGrant record with the
23
+ # specific token value.
24
+ #
25
+ # @param token [#to_s] token value (any object that responds to `#to_s`)
26
+ #
27
+ # @return [Doorkeeper::AccessGrant, nil]
28
+ # AccessGrant object or nil if there is no record with such token
29
+ #
30
30
  def by_token(token)
31
- 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)
32
49
  end
33
- end
34
50
 
35
- private
51
+ # Implements PKCE code_challenge encoding without base64 padding as described in the spec.
52
+ # https://tools.ietf.org/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 '/'.
36
85
 
37
- def generate_token
38
- self.token = UniqueToken.generate
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)
93
+ end
94
+
95
+ def pkce_supported?
96
+ column_names.include?("code_challenge")
97
+ end
98
+
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
39
118
  end
40
119
  end
41
120
  end