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,49 +1,65 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class BaseRequest
4
6
  include Validations
5
7
 
8
+ attr_reader :grant_type, :server
9
+
10
+ delegate :default_scopes, to: :server
11
+
6
12
  def authorize
7
- validate
8
13
  if valid?
9
14
  before_successful_response
10
15
  @response = TokenResponse.new(access_token)
11
16
  after_successful_response
12
17
  @response
18
+ elsif error == :invalid_request
19
+ @response = InvalidRequestResponse.from_request(self)
13
20
  else
14
21
  @response = ErrorResponse.from_request(self)
15
22
  end
16
23
  end
17
24
 
18
25
  def scopes
19
- @scopes ||= if @original_scopes.present?
20
- OAuth::Scopes.from_string(@original_scopes)
21
- else
22
- default_scopes
23
- end
26
+ @scopes ||= build_scopes
24
27
  end
25
28
 
26
- def default_scopes
27
- server.default_scopes
29
+ def find_or_create_access_token(client, resource_owner, scopes, server)
30
+ context = Authorization::Token.build_context(client, grant_type, scopes, resource_owner)
31
+ @access_token = server_config.access_token_model.find_or_create_for(
32
+ application: client,
33
+ resource_owner: resource_owner,
34
+ scopes: scopes,
35
+ expires_in: Authorization::Token.access_token_expires_in(server, context),
36
+ use_refresh_token: Authorization::Token.refresh_token_enabled?(server, context),
37
+ )
28
38
  end
29
39
 
30
- def valid?
31
- error.nil?
40
+ def before_successful_response
41
+ server_config.before_successful_strategy_response.call(self)
32
42
  end
33
43
 
34
- def find_or_create_access_token(client, resource_owner_id, scopes, server)
35
- @access_token = AccessToken.find_or_create_for(
36
- client,
37
- resource_owner_id,
38
- scopes,
39
- Authorization::Token.access_token_expires_in(server, client),
40
- server.refresh_token_enabled?)
44
+ def after_successful_response
45
+ server_config.after_successful_strategy_response.call(self, @response)
41
46
  end
42
47
 
43
- def before_successful_response
48
+ def server_config
49
+ Doorkeeper.config
44
50
  end
45
51
 
46
- def after_successful_response
52
+ private
53
+
54
+ def build_scopes
55
+ if @original_scopes.present?
56
+ OAuth::Scopes.from_string(@original_scopes)
57
+ else
58
+ client_scopes = @client&.scopes
59
+ return default_scopes if client_scopes.blank?
60
+
61
+ default_scopes & client_scopes
62
+ end
47
63
  end
48
64
  end
49
65
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class BaseResponse
@@ -1,13 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class Client
4
- class Credentials < Struct.new(:uid, :secret)
6
+ Credentials = Struct.new(:uid, :secret) do
5
7
  class << self
6
8
  def from_request(request, *credentials_methods)
7
- credentials_methods.inject(nil) do |credentials, method|
9
+ credentials_methods.inject(nil) do |_, method|
8
10
  method = self.method(method) if method.is_a?(Symbol)
9
11
  credentials = Credentials.new(*method.call(request))
10
- break credentials unless credentials.blank?
12
+ break credentials if credentials.present?
11
13
  end
12
14
  end
13
15
 
@@ -18,14 +20,14 @@ module Doorkeeper
18
20
  def from_basic(request)
19
21
  authorization = request.authorization
20
22
  if authorization.present? && authorization =~ /^Basic (.*)/m
21
- Base64.decode64($1).split(/:/, 2)
23
+ Base64.decode64(Regexp.last_match(1)).split(/:/, 2)
22
24
  end
23
25
  end
24
26
  end
25
27
 
26
- def blank?
27
- uid.blank? || secret.blank?
28
- end
28
+ # Public clients may have their secret blank, but "credentials" are
29
+ # still present
30
+ delegate :blank?, to: :uid
29
31
  end
30
32
  end
31
33
  end
@@ -1,9 +1,9 @@
1
- require 'doorkeeper/oauth/client/credentials'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Doorkeeper
4
4
  module OAuth
5
5
  class Client
6
- attr_accessor :application
6
+ attr_reader :application
7
7
 
8
8
  delegate :id, :name, :uid, :redirect_uri, :scopes, to: :@application
9
9
 
@@ -11,18 +11,17 @@ module Doorkeeper
11
11
  @application = application
12
12
  end
13
13
 
14
- def self.find(uid, method = Application.method(:by_uid))
15
- if application = method.call(uid)
16
- new(application)
17
- end
14
+ def self.find(uid, method = Doorkeeper.config.application_model.method(:by_uid))
15
+ return unless (application = method.call(uid))
16
+
17
+ new(application)
18
18
  end
19
19
 
20
- def self.authenticate(credentials, method = Application.method(:by_uid_and_secret))
21
- return false if credentials.blank?
20
+ def self.authenticate(credentials, method = Doorkeeper.config.application_model.method(:by_uid_and_secret))
21
+ return if credentials.blank?
22
+ return unless (application = method.call(credentials.uid, credentials.secret))
22
23
 
23
- if application = method.call(credentials.uid, credentials.secret)
24
- new(application)
25
- end
24
+ new(application)
26
25
  end
27
26
  end
28
27
  end
@@ -1,11 +1,54 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
- class ClientCredentialsRequest < BaseRequest
5
+ module ClientCredentials
4
6
  class Creator
5
7
  def call(client, scopes, attributes = {})
6
- AccessToken.find_or_create_for(
7
- client, nil, scopes, attributes[:expires_in],
8
- attributes[:use_refresh_token])
8
+ existing_token = nil
9
+
10
+ if lookup_existing_token?
11
+ existing_token = find_existing_token_for(client, scopes)
12
+ return existing_token if server_config.reuse_access_token && existing_token&.reusable?
13
+ end
14
+
15
+ with_revocation(existing_token: existing_token) do
16
+ server_config.access_token_model.find_or_create_for(
17
+ application: client,
18
+ resource_owner: nil,
19
+ scopes: scopes,
20
+ **attributes,
21
+ )
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def with_revocation(existing_token:)
28
+ if existing_token && server_config.revoke_previous_client_credentials_token?
29
+ existing_token.with_lock do
30
+ raise Errors::DoorkeeperError, :invalid_token_reuse if existing_token.revoked?
31
+
32
+ existing_token.revoke
33
+
34
+ yield
35
+ end
36
+ else
37
+ yield
38
+ end
39
+ end
40
+
41
+ def lookup_existing_token?
42
+ server_config.reuse_access_token ||
43
+ server_config.revoke_previous_client_credentials_token?
44
+ end
45
+
46
+ def find_existing_token_for(client, scopes)
47
+ server_config.access_token_model.matching_token_for(client, nil, scopes)
48
+ end
49
+
50
+ def server_config
51
+ Doorkeeper.config
9
52
  end
10
53
  end
11
54
  end
@@ -1,37 +1,44 @@
1
- require 'doorkeeper/oauth/client_credentials/validation'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Doorkeeper
4
4
  module OAuth
5
- class ClientCredentialsRequest < BaseRequest
5
+ module ClientCredentials
6
6
  class Issuer
7
- attr_accessor :token, :validation, :error
7
+ attr_reader :token, :validator, :error
8
8
 
9
- def initialize(server, validation)
9
+ def initialize(server, validator)
10
10
  @server = server
11
- @validation = validation
11
+ @validator = validator
12
12
  end
13
13
 
14
14
  def create(client, scopes, creator = Creator.new)
15
- if validation.valid?
15
+ if validator.valid?
16
16
  @token = create_token(client, scopes, creator)
17
17
  @error = :server_error unless @token
18
18
  else
19
19
  @token = false
20
- @error = validation.error
20
+ @error = validator.error
21
21
  end
22
+
22
23
  @token
23
24
  end
24
25
 
25
26
  private
26
27
 
27
28
  def create_token(client, scopes, creator)
28
- ttl = Authorization::Token.access_token_expires_in(@server, client)
29
+ context = Authorization::Token.build_context(
30
+ client,
31
+ Doorkeeper::OAuth::CLIENT_CREDENTIALS,
32
+ scopes,
33
+ nil,
34
+ )
35
+ ttl = Authorization::Token.access_token_expires_in(@server, context)
29
36
 
30
37
  creator.call(
31
38
  client,
32
39
  scopes,
33
40
  use_refresh_token: false,
34
- expires_in: ttl
41
+ expires_in: ttl,
35
42
  )
36
43
  end
37
44
  end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module OAuth
5
+ module ClientCredentials
6
+ class Validator
7
+ include Validations
8
+ include OAuth::Helpers
9
+
10
+ validate :client, error: :invalid_client
11
+ validate :client_supports_grant_flow, error: :unauthorized_client
12
+ validate :scopes, error: :invalid_scope
13
+
14
+ def initialize(server, request)
15
+ @server = server
16
+ @request = request
17
+ @client = request.client
18
+
19
+ validate
20
+ end
21
+
22
+ private
23
+
24
+ def validate_client
25
+ @client.present?
26
+ end
27
+
28
+ def validate_client_supports_grant_flow
29
+ return if @client.blank?
30
+
31
+ Doorkeeper.config.allow_grant_flow_for_client?(
32
+ Doorkeeper::OAuth::CLIENT_CREDENTIALS,
33
+ @client.application,
34
+ )
35
+ end
36
+
37
+ def validate_scopes
38
+ return true if @request.scopes.blank?
39
+
40
+ application_scopes = if @client.present?
41
+ @client.application.scopes
42
+ else
43
+ ""
44
+ end
45
+
46
+ ScopeChecker.valid?(
47
+ scope_str: @request.scopes.to_s,
48
+ server_scopes: @server.scopes,
49
+ app_scopes: application_scopes,
50
+ grant_type: Doorkeeper::OAuth::CLIENT_CREDENTIALS,
51
+ )
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -1,22 +1,14 @@
1
- require 'doorkeeper/oauth/client_credentials/creator'
2
- require 'doorkeeper/oauth/client_credentials/issuer'
3
- require 'doorkeeper/oauth/client_credentials/validation'
1
+ # frozen_string_literal: true
4
2
 
5
3
  module Doorkeeper
6
4
  module OAuth
7
5
  class ClientCredentialsRequest < BaseRequest
8
- attr_accessor :server, :client, :original_scopes
9
- attr_reader :response
10
- attr_writer :issuer
6
+ attr_reader :client, :original_scopes, :response
11
7
 
12
- alias_method :error_response, :response
8
+ alias error_response response
13
9
 
14
10
  delegate :error, to: :issuer
15
11
 
16
- def issuer
17
- @issuer ||= Issuer.new(server, Validation.new(server, self))
18
- end
19
-
20
12
  def initialize(server, client, parameters = {})
21
13
  @client = client
22
14
  @server = server
@@ -28,6 +20,13 @@ module Doorkeeper
28
20
  issuer.token
29
21
  end
30
22
 
23
+ def issuer
24
+ @issuer ||= ClientCredentials::Issuer.new(
25
+ server,
26
+ ClientCredentials::Validator.new(server, self),
27
+ )
28
+ end
29
+
31
30
  private
32
31
 
33
32
  def valid?
@@ -1,28 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class CodeRequest
4
- attr_accessor :pre_auth, :resource_owner, :client
6
+ attr_reader :pre_auth, :resource_owner
5
7
 
6
8
  def initialize(pre_auth, resource_owner)
7
- @pre_auth = pre_auth
8
- @client = pre_auth.client
9
+ @pre_auth = pre_auth
9
10
  @resource_owner = resource_owner
10
11
  end
11
12
 
12
13
  def authorize
13
- if pre_auth.authorizable?
14
- auth = Authorization::Code.new(pre_auth, resource_owner)
15
- auth.issue_token
16
- @response = CodeResponse.new pre_auth, auth
17
- else
18
- @response = ErrorResponse.from_request pre_auth
19
- end
14
+ auth = Authorization::Code.new(pre_auth, resource_owner)
15
+ auth.issue_token!
16
+ CodeResponse.new(pre_auth, auth, response_on_fragment: pre_auth.response_mode == "fragment")
20
17
  end
21
18
 
22
19
  def deny
23
20
  pre_auth.error = :access_denied
24
- ErrorResponse.from_request pre_auth,
25
- redirect_uri: pre_auth.redirect_uri
21
+ pre_auth.error_response
26
22
  end
27
23
  end
28
24
  end
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class CodeResponse < BaseResponse
4
6
  include OAuth::Helpers
5
7
 
6
- attr_accessor :pre_auth, :auth, :response_on_fragment
8
+ attr_reader :pre_auth, :auth, :response_on_fragment
7
9
 
8
10
  def initialize(pre_auth, auth, options = {})
9
11
  @pre_auth = pre_auth
@@ -15,23 +17,33 @@ module Doorkeeper
15
17
  true
16
18
  end
17
19
 
18
- def redirect_uri
19
- if URIChecker.native_uri? pre_auth.redirect_uri
20
- auth.native_redirect
21
- elsif response_on_fragment
22
- Authorization::URIBuilder.uri_with_fragment(
23
- pre_auth.redirect_uri,
24
- access_token: auth.token.token,
20
+ def issued_token
21
+ auth.token
22
+ end
23
+
24
+ def body
25
+ if auth.try(:access_token?)
26
+ {
27
+ access_token: auth.token.plaintext_token,
25
28
  token_type: auth.token.token_type,
26
29
  expires_in: auth.token.expires_in_seconds,
27
- state: pre_auth.state
28
- )
30
+ state: pre_auth.state,
31
+ }
32
+ elsif auth.try(:access_grant?)
33
+ {
34
+ code: auth.token.plaintext_token,
35
+ state: pre_auth.state,
36
+ }
37
+ end
38
+ end
39
+
40
+ def redirect_uri
41
+ if URIChecker.oob_uri?(pre_auth.redirect_uri)
42
+ auth.oob_redirect
43
+ elsif response_on_fragment
44
+ Authorization::URIBuilder.uri_with_fragment(pre_auth.redirect_uri, body)
29
45
  else
30
- Authorization::URIBuilder.uri_with_query(
31
- pre_auth.redirect_uri,
32
- code: auth.token.token,
33
- state: pre_auth.state
34
- )
46
+ Authorization::URIBuilder.uri_with_query(pre_auth.redirect_uri, body)
35
47
  end
36
48
  end
37
49
  end
@@ -1,11 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
- class Error < Struct.new(:name, :state)
5
+ Error = Struct.new(:name, :state) do
4
6
  def description
5
7
  I18n.translate(
6
8
  name,
7
- scope: [:doorkeeper, :errors, :messages],
8
- default: :server_error
9
+ scope: %i[doorkeeper errors messages],
10
+ default: :server_error,
9
11
  )
10
12
  end
11
13
  end
@@ -1,11 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class ErrorResponse < BaseResponse
4
6
  include OAuth::Helpers
5
7
 
8
+ NON_REDIRECTABLE_STATES = %i[invalid_redirect_uri invalid_client unauthorized_client].freeze
9
+
6
10
  def self.from_request(request, attributes = {})
7
- state = request.state if request.respond_to?(:state)
8
- new(attributes.merge(name: request.error, state: state))
11
+ new(
12
+ attributes.merge(
13
+ name: request.error,
14
+ state: request.try(:state),
15
+ redirect_uri: request.try(:redirect_uri),
16
+ ),
17
+ )
9
18
  end
10
19
 
11
20
  delegate :name, :description, :state, to: :@error
@@ -20,40 +29,51 @@ module Doorkeeper
20
29
  {
21
30
  error: name,
22
31
  error_description: description,
23
- state: state
32
+ state: state,
24
33
  }.reject { |_, v| v.blank? }
25
34
  end
26
35
 
27
36
  def status
28
- :unauthorized
37
+ if name == :invalid_client || name == :unauthorized_client
38
+ :unauthorized
39
+ else
40
+ :bad_request
41
+ end
29
42
  end
30
43
 
31
44
  def redirectable?
32
- name != :invalid_redirect_uri && name != :invalid_client &&
33
- !URIChecker.native_uri?(@redirect_uri)
45
+ !NON_REDIRECTABLE_STATES.include?(name) && !URIChecker.oob_uri?(@redirect_uri)
34
46
  end
35
47
 
36
48
  def redirect_uri
37
49
  if @response_on_fragment
38
- Authorization::URIBuilder.uri_with_fragment @redirect_uri, body
50
+ Authorization::URIBuilder.uri_with_fragment(@redirect_uri, body)
39
51
  else
40
- Authorization::URIBuilder.uri_with_query @redirect_uri, body
52
+ Authorization::URIBuilder.uri_with_query(@redirect_uri, body)
41
53
  end
42
54
  end
43
55
 
44
56
  def headers
45
- { 'Cache-Control' => 'no-store',
46
- 'Pragma' => 'no-cache',
47
- 'Content-Type' => 'application/json; charset=utf-8',
48
- 'WWW-Authenticate' => authenticate_info }
57
+ {
58
+ "Cache-Control" => "no-store",
59
+ "Pragma" => "no-cache",
60
+ "Content-Type" => "application/json; charset=utf-8",
61
+ "WWW-Authenticate" => authenticate_info,
62
+ }
63
+ end
64
+
65
+ def raise_exception!
66
+ raise exception_class.new(self), description
49
67
  end
50
68
 
51
69
  protected
52
70
 
53
- delegate :realm, to: :configuration
71
+ def realm
72
+ Doorkeeper.config.realm
73
+ end
54
74
 
55
- def configuration
56
- Doorkeeper.configuration
75
+ def exception_class
76
+ raise NotImplementedError, "error response must define #exception_class"
57
77
  end
58
78
 
59
79
  private
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class ForbiddenTokenResponse < ErrorResponse
@@ -16,13 +18,19 @@ module Doorkeeper
16
18
 
17
19
  def headers
18
20
  headers = super
19
- headers.delete 'WWW-Authenticate'
21
+ headers.delete "WWW-Authenticate"
20
22
  headers
21
23
  end
22
24
 
23
25
  def description
24
- scope = { scope: [:doorkeeper, :scopes] }
25
- @description ||= @scopes.map { |r| I18n.translate r, scope }.join('\n')
26
+ @description ||= I18n.t("doorkeeper.errors.messages.forbidden_token.missing_scope",
27
+ oauth_scopes: @scopes.map(&:to_s).join(" "),)
28
+ end
29
+
30
+ protected
31
+
32
+ def exception_class
33
+ Doorkeeper::Errors::TokenForbidden
26
34
  end
27
35
  end
28
36
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  module Helpers
@@ -5,39 +7,42 @@ module Doorkeeper
5
7
  class Validator
6
8
  attr_reader :parsed_scopes, :scope_str
7
9
 
8
- def initialize(scope_str, server_scopes, application_scopes)
10
+ def initialize(scope_str, server_scopes, app_scopes, grant_type)
9
11
  @parsed_scopes = OAuth::Scopes.from_string(scope_str)
10
12
  @scope_str = scope_str
11
- @valid_scopes = valid_scopes(server_scopes, application_scopes)
13
+ @valid_scopes = valid_scopes(server_scopes, app_scopes)
14
+
15
+ @scopes_by_grant_type = Doorkeeper.config.scopes_by_grant_type[grant_type.to_sym] if grant_type
12
16
  end
13
17
 
14
18
  def valid?
15
19
  scope_str.present? &&
16
20
  scope_str !~ /[\n\r\t]/ &&
17
- @valid_scopes.has_scopes?(parsed_scopes)
18
- end
19
-
20
- def match?
21
- valid? && parsed_scopes.has_scopes?(@valid_scopes)
21
+ @valid_scopes.has_scopes?(parsed_scopes) &&
22
+ permitted_to_grant_type?
22
23
  end
23
24
 
24
25
  private
25
26
 
26
- def valid_scopes(server_scopes, application_scopes)
27
- if application_scopes.present?
28
- application_scopes
29
- else
30
- server_scopes
31
- end
27
+ def valid_scopes(server_scopes, app_scopes)
28
+ app_scopes.presence || server_scopes
32
29
  end
33
- end
34
30
 
35
- def self.valid?(scope_str, server_scopes, application_scopes = nil)
36
- Validator.new(scope_str, server_scopes, application_scopes).valid?
31
+ def permitted_to_grant_type?
32
+ return true unless @scopes_by_grant_type
33
+
34
+ OAuth::Scopes.from_array(@scopes_by_grant_type)
35
+ .has_scopes?(parsed_scopes)
36
+ end
37
37
  end
38
38
 
39
- def self.match?(scope_str, server_scopes, application_scopes = nil)
40
- Validator.new(scope_str, server_scopes, application_scopes).match?
39
+ def self.valid?(scope_str:, server_scopes:, app_scopes: nil, grant_type: nil)
40
+ Validator.new(
41
+ scope_str,
42
+ server_scopes,
43
+ app_scopes,
44
+ grant_type,
45
+ ).valid?
41
46
  end
42
47
  end
43
48
  end