doorkeeper 4.4.3 → 5.0.3

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 (223) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.gitlab-ci.yml +16 -0
  4. data/.travis.yml +7 -0
  5. data/Appraisals +2 -2
  6. data/Dangerfile +64 -0
  7. data/Gemfile +1 -1
  8. data/NEWS.md +98 -8
  9. data/README.md +110 -12
  10. data/Rakefile +6 -0
  11. data/UPGRADE.md +2 -0
  12. data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
  13. data/app/controllers/doorkeeper/application_controller.rb +6 -3
  14. data/app/controllers/doorkeeper/application_metal_controller.rb +6 -0
  15. data/app/controllers/doorkeeper/applications_controller.rb +46 -24
  16. data/app/controllers/doorkeeper/authorizations_controller.rb +55 -12
  17. data/app/controllers/doorkeeper/authorized_applications_controller.rb +21 -2
  18. data/app/controllers/doorkeeper/token_info_controller.rb +2 -0
  19. data/app/controllers/doorkeeper/tokens_controller.rb +4 -6
  20. data/app/helpers/doorkeeper/dashboard_helper.rb +9 -7
  21. data/app/validators/redirect_uri_validator.rb +5 -2
  22. data/app/views/doorkeeper/applications/_delete_form.html.erb +3 -1
  23. data/app/views/doorkeeper/applications/_form.html.erb +25 -24
  24. data/app/views/doorkeeper/applications/edit.html.erb +1 -1
  25. data/app/views/doorkeeper/applications/index.html.erb +17 -7
  26. data/app/views/doorkeeper/applications/new.html.erb +1 -1
  27. data/app/views/doorkeeper/applications/show.html.erb +6 -6
  28. data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
  29. data/app/views/doorkeeper/authorizations/new.html.erb +4 -0
  30. data/app/views/layouts/doorkeeper/admin.html.erb +15 -15
  31. data/config/locales/en.yml +10 -1
  32. data/doorkeeper.gemspec +25 -26
  33. data/gemfiles/rails_5_2.gemfile +1 -1
  34. data/gemfiles/rails_master.gemfile +4 -1
  35. data/lib/doorkeeper/config.rb +81 -40
  36. data/lib/doorkeeper/engine.rb +6 -0
  37. data/lib/doorkeeper/errors.rb +17 -3
  38. data/lib/doorkeeper/grape/authorization_decorator.rb +2 -0
  39. data/lib/doorkeeper/grape/helpers.rb +3 -1
  40. data/lib/doorkeeper/helpers/controller.rb +9 -2
  41. data/lib/doorkeeper/models/access_grant_mixin.rb +73 -0
  42. data/lib/doorkeeper/models/access_token_mixin.rb +44 -25
  43. data/lib/doorkeeper/models/application_mixin.rb +2 -0
  44. data/lib/doorkeeper/models/concerns/accessible.rb +2 -0
  45. data/lib/doorkeeper/models/concerns/expirable.rb +2 -0
  46. data/lib/doorkeeper/models/concerns/orderable.rb +2 -0
  47. data/lib/doorkeeper/models/concerns/ownership.rb +2 -0
  48. data/lib/doorkeeper/models/concerns/revocable.rb +2 -0
  49. data/lib/doorkeeper/models/concerns/scopes.rb +3 -1
  50. data/lib/doorkeeper/oauth/authorization/code.rb +33 -8
  51. data/lib/doorkeeper/oauth/authorization/context.rb +17 -0
  52. data/lib/doorkeeper/oauth/authorization/token.rb +38 -14
  53. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +2 -0
  54. data/lib/doorkeeper/oauth/authorization_code_request.rb +29 -2
  55. data/lib/doorkeeper/oauth/base_request.rb +22 -9
  56. data/lib/doorkeeper/oauth/base_response.rb +2 -0
  57. data/lib/doorkeeper/oauth/client/credentials.rb +3 -1
  58. data/lib/doorkeeper/oauth/client.rb +1 -1
  59. data/lib/doorkeeper/oauth/client_credentials/creator.rb +4 -1
  60. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +7 -2
  61. data/lib/doorkeeper/oauth/client_credentials/validation.rb +5 -5
  62. data/lib/doorkeeper/oauth/client_credentials_request.rb +1 -3
  63. data/lib/doorkeeper/oauth/code_request.rb +2 -0
  64. data/lib/doorkeeper/oauth/code_response.rb +2 -0
  65. data/lib/doorkeeper/oauth/error.rb +2 -0
  66. data/lib/doorkeeper/oauth/error_response.rb +21 -3
  67. data/lib/doorkeeper/oauth/forbidden_token_response.rb +9 -2
  68. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +2 -8
  69. data/lib/doorkeeper/oauth/helpers/unique_token.rb +2 -0
  70. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +5 -2
  71. data/lib/doorkeeper/oauth/invalid_token_response.rb +18 -0
  72. data/lib/doorkeeper/oauth/password_access_token_request.rb +9 -4
  73. data/lib/doorkeeper/oauth/pre_authorization.rb +43 -11
  74. data/lib/doorkeeper/oauth/refresh_token_request.rb +16 -3
  75. data/lib/doorkeeper/oauth/scopes.rb +3 -1
  76. data/lib/doorkeeper/oauth/token.rb +7 -2
  77. data/lib/doorkeeper/oauth/token_introspection.rb +4 -2
  78. data/lib/doorkeeper/oauth/token_request.rb +2 -0
  79. data/lib/doorkeeper/oauth/token_response.rb +6 -2
  80. data/lib/doorkeeper/oauth.rb +13 -0
  81. data/lib/doorkeeper/orm/active_record/application.rb +75 -12
  82. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +26 -0
  83. data/lib/doorkeeper/orm/active_record.rb +4 -0
  84. data/lib/doorkeeper/rails/helpers.rb +6 -4
  85. data/lib/doorkeeper/rails/routes/mapper.rb +2 -0
  86. data/lib/doorkeeper/rails/routes/mapping.rb +2 -0
  87. data/lib/doorkeeper/rails/routes.rb +23 -8
  88. data/lib/doorkeeper/rake/db.rake +40 -0
  89. data/lib/doorkeeper/rake/setup.rake +6 -0
  90. data/lib/doorkeeper/rake.rb +14 -0
  91. data/lib/doorkeeper/request/authorization_code.rb +1 -1
  92. data/lib/doorkeeper/request/client_credentials.rb +1 -1
  93. data/lib/doorkeeper/request/code.rb +1 -1
  94. data/lib/doorkeeper/request/password.rb +1 -1
  95. data/lib/doorkeeper/request/refresh_token.rb +1 -1
  96. data/lib/doorkeeper/request/strategy.rb +2 -0
  97. data/lib/doorkeeper/request/token.rb +1 -1
  98. data/lib/doorkeeper/request.rb +29 -34
  99. data/lib/doorkeeper/server.rb +2 -0
  100. data/lib/doorkeeper/stale_records_cleaner.rb +20 -0
  101. data/lib/doorkeeper/validations.rb +2 -0
  102. data/lib/doorkeeper/version.rb +6 -24
  103. data/lib/doorkeeper.rb +20 -17
  104. data/lib/generators/doorkeeper/application_owner_generator.rb +23 -18
  105. data/lib/generators/doorkeeper/confidential_applications_generator.rb +32 -0
  106. data/lib/generators/doorkeeper/install_generator.rb +17 -9
  107. data/lib/generators/doorkeeper/migration_generator.rb +23 -18
  108. data/lib/generators/doorkeeper/pkce_generator.rb +32 -0
  109. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +29 -24
  110. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  111. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +6 -0
  112. data/lib/generators/doorkeeper/templates/initializer.rb +96 -13
  113. data/lib/generators/doorkeeper/templates/migration.rb.erb +2 -3
  114. data/lib/generators/doorkeeper/views_generator.rb +3 -1
  115. data/spec/controllers/application_metal_controller_spec.rb +50 -0
  116. data/spec/controllers/applications_controller_spec.rb +123 -14
  117. data/spec/controllers/authorizations_controller_spec.rb +334 -51
  118. data/spec/controllers/protected_resources_controller_spec.rb +60 -18
  119. data/spec/controllers/token_info_controller_spec.rb +4 -12
  120. data/spec/controllers/tokens_controller_spec.rb +17 -20
  121. data/spec/dummy/Rakefile +1 -1
  122. data/spec/dummy/app/assets/config/manifest.js +2 -0
  123. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +1 -1
  124. data/spec/dummy/app/controllers/home_controller.rb +1 -2
  125. data/spec/dummy/config/application.rb +1 -1
  126. data/spec/dummy/config/boot.rb +2 -4
  127. data/spec/dummy/config/environment.rb +1 -1
  128. data/spec/dummy/config/environments/test.rb +5 -6
  129. data/spec/dummy/config/initializers/doorkeeper.rb +12 -6
  130. data/spec/dummy/config/initializers/new_framework_defaults.rb +2 -0
  131. data/spec/dummy/config/initializers/secret_token.rb +1 -1
  132. data/spec/dummy/config/routes.rb +3 -42
  133. data/spec/dummy/config.ru +1 -1
  134. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +4 -4
  135. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +1 -1
  136. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +6 -0
  137. data/spec/dummy/db/migrate/{20180210183654_add_confidential_to_application.rb → 20180210183654_add_confidential_to_applications.rb} +1 -1
  138. data/spec/dummy/db/schema.rb +36 -36
  139. data/spec/dummy/script/rails +4 -3
  140. data/spec/factories.rb +6 -6
  141. data/spec/generators/application_owner_generator_spec.rb +1 -1
  142. data/spec/generators/confidential_applications_generator_spec.rb +45 -0
  143. data/spec/generators/install_generator_spec.rb +5 -2
  144. data/spec/generators/migration_generator_spec.rb +1 -1
  145. data/spec/generators/pkce_generator_spec.rb +43 -0
  146. data/spec/generators/previous_refresh_token_generator_spec.rb +1 -1
  147. data/spec/generators/templates/routes.rb +0 -1
  148. data/spec/generators/views_generator_spec.rb +2 -2
  149. data/spec/grape/grape_integration_spec.rb +2 -2
  150. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +1 -1
  151. data/spec/lib/config_spec.rb +105 -39
  152. data/spec/lib/doorkeeper_spec.rb +6 -131
  153. data/spec/lib/models/expirable_spec.rb +0 -3
  154. data/spec/lib/models/revocable_spec.rb +0 -2
  155. data/spec/lib/models/scopes_spec.rb +0 -4
  156. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -4
  157. data/spec/lib/oauth/authorization_code_request_spec.rb +17 -7
  158. data/spec/lib/oauth/base_request_spec.rb +49 -11
  159. data/spec/lib/oauth/base_response_spec.rb +1 -1
  160. data/spec/lib/oauth/client/credentials_spec.rb +2 -4
  161. data/spec/lib/oauth/client_credentials/creator_spec.rb +5 -1
  162. data/spec/lib/oauth/client_credentials/issuer_spec.rb +24 -7
  163. data/spec/lib/oauth/client_credentials/validation_spec.rb +4 -4
  164. data/spec/lib/oauth/client_credentials_integration_spec.rb +2 -2
  165. data/spec/lib/oauth/client_credentials_request_spec.rb +3 -5
  166. data/spec/lib/oauth/client_spec.rb +0 -3
  167. data/spec/lib/oauth/code_request_spec.rb +5 -3
  168. data/spec/lib/oauth/code_response_spec.rb +1 -1
  169. data/spec/lib/oauth/error_response_spec.rb +0 -3
  170. data/spec/lib/oauth/error_spec.rb +0 -2
  171. data/spec/lib/oauth/forbidden_token_response_spec.rb +1 -4
  172. data/spec/lib/oauth/helpers/scope_checker_spec.rb +8 -11
  173. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -1
  174. data/spec/lib/oauth/helpers/uri_checker_spec.rb +22 -13
  175. data/spec/lib/oauth/invalid_token_response_spec.rb +1 -4
  176. data/spec/lib/oauth/password_access_token_request_spec.rb +53 -6
  177. data/spec/lib/oauth/pre_authorization_spec.rb +33 -4
  178. data/spec/lib/oauth/refresh_token_request_spec.rb +22 -14
  179. data/spec/lib/oauth/scopes_spec.rb +0 -3
  180. data/spec/lib/oauth/token_request_spec.rb +8 -9
  181. data/spec/lib/oauth/token_response_spec.rb +0 -1
  182. data/spec/lib/oauth/token_spec.rb +40 -14
  183. data/spec/lib/request/strategy_spec.rb +0 -1
  184. data/spec/lib/server_spec.rb +7 -7
  185. data/spec/lib/stale_records_cleaner_spec.rb +89 -0
  186. data/spec/models/doorkeeper/access_grant_spec.rb +44 -1
  187. data/spec/models/doorkeeper/access_token_spec.rb +80 -32
  188. data/spec/models/doorkeeper/application_spec.rb +293 -221
  189. data/spec/requests/applications/applications_request_spec.rb +134 -1
  190. data/spec/requests/applications/authorized_applications_spec.rb +1 -1
  191. data/spec/requests/endpoints/authorization_spec.rb +3 -3
  192. data/spec/requests/endpoints/token_spec.rb +7 -5
  193. data/spec/requests/flows/authorization_code_errors_spec.rb +2 -2
  194. data/spec/requests/flows/authorization_code_spec.rb +258 -2
  195. data/spec/requests/flows/client_credentials_spec.rb +46 -6
  196. data/spec/requests/flows/implicit_grant_errors_spec.rb +3 -3
  197. data/spec/requests/flows/implicit_grant_spec.rb +38 -11
  198. data/spec/requests/flows/password_spec.rb +61 -3
  199. data/spec/requests/flows/refresh_token_spec.rb +59 -2
  200. data/spec/requests/flows/revoke_token_spec.rb +20 -20
  201. data/spec/requests/flows/skip_authorization_spec.rb +16 -11
  202. data/spec/requests/protected_resources/metal_spec.rb +1 -1
  203. data/spec/requests/protected_resources/private_api_spec.rb +3 -3
  204. data/spec/routing/custom_controller_routes_spec.rb +59 -7
  205. data/spec/routing/default_routes_spec.rb +2 -2
  206. data/spec/routing/scoped_routes_spec.rb +16 -2
  207. data/spec/spec_helper.rb +54 -3
  208. data/spec/spec_helper_integration.rb +2 -74
  209. data/spec/support/dependencies/{factory_girl.rb → factory_bot.rb} +0 -0
  210. data/spec/support/doorkeeper_rspec.rb +20 -0
  211. data/spec/support/helpers/authorization_request_helper.rb +4 -4
  212. data/spec/support/helpers/model_helper.rb +8 -4
  213. data/spec/support/helpers/request_spec_helper.rb +10 -2
  214. data/spec/support/helpers/url_helper.rb +18 -14
  215. data/spec/support/http_method_shim.rb +12 -16
  216. data/spec/support/shared/controllers_shared_context.rb +56 -0
  217. data/spec/validators/redirect_uri_validator_spec.rb +9 -3
  218. data/spec/version/version_spec.rb +3 -3
  219. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  220. metadata +54 -35
  221. data/lib/generators/doorkeeper/add_client_confidentiality_generator.rb +0 -31
  222. data/lib/generators/doorkeeper/templates/add_confidential_to_application_migration.rb.erb +0 -11
  223. data/spec/controllers/application_metal_controller.rb +0 -10
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module Models
3
5
  module Revocable
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module Models
3
5
  module Scopes
@@ -10,7 +12,7 @@ module Doorkeeper
10
12
  end
11
13
 
12
14
  def includes_scope?(*required_scopes)
13
- required_scopes.blank? || required_scopes.any? { |s| scopes.exists?(s.to_s) }
15
+ required_scopes.blank? || required_scopes.any? { |scope| scopes.exists?(scope.to_s) }
14
16
  end
15
17
  end
16
18
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  module Authorization
@@ -5,18 +7,12 @@ module Doorkeeper
5
7
  attr_accessor :pre_auth, :resource_owner, :token
6
8
 
7
9
  def initialize(pre_auth, resource_owner)
8
- @pre_auth = pre_auth
10
+ @pre_auth = pre_auth
9
11
  @resource_owner = resource_owner
10
12
  end
11
13
 
12
14
  def issue_token
13
- @token ||= AccessGrant.create!(
14
- application_id: pre_auth.client.id,
15
- resource_owner_id: resource_owner.id,
16
- expires_in: configuration.authorization_code_expires_in,
17
- redirect_uri: pre_auth.redirect_uri,
18
- scopes: pre_auth.scopes.to_s
19
- )
15
+ @token ||= AccessGrant.create! access_grant_attributes
20
16
  end
21
17
 
22
18
  def native_redirect
@@ -26,6 +22,35 @@ module Doorkeeper
26
22
  def configuration
27
23
  Doorkeeper.configuration
28
24
  end
25
+
26
+ private
27
+
28
+ def authorization_code_expires_in
29
+ configuration.authorization_code_expires_in
30
+ end
31
+
32
+ def access_grant_attributes
33
+ pkce_attributes.merge application_id: pre_auth.client.id,
34
+ resource_owner_id: resource_owner.id,
35
+ expires_in: authorization_code_expires_in,
36
+ redirect_uri: pre_auth.redirect_uri,
37
+ scopes: pre_auth.scopes.to_s
38
+ end
39
+
40
+ def pkce_attributes
41
+ return {} unless pkce_supported?
42
+
43
+ {
44
+ code_challenge: pre_auth.code_challenge,
45
+ code_challenge_method: pre_auth.code_challenge_method
46
+ }
47
+ end
48
+
49
+ # ensures firstly, if migration with additional pcke columns was
50
+ # generated and migrated
51
+ def pkce_supported?
52
+ Doorkeeper::AccessGrant.pkce_supported?
53
+ end
29
54
  end
30
55
  end
31
56
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module OAuth
5
+ module Authorization
6
+ class Context
7
+ attr_reader :client, :grant_type, :scopes
8
+
9
+ def initialize(client, grant_type, scopes)
10
+ @client = client
11
+ @grant_type = grant_type
12
+ @scopes = scopes
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  module Authorization
@@ -5,24 +7,34 @@ module Doorkeeper
5
7
  attr_accessor :pre_auth, :resource_owner, :token
6
8
 
7
9
  class << self
8
- def access_token_expires_in(server, pre_auth_or_oauth_client)
9
- if (expiration = custom_expiration(server, pre_auth_or_oauth_client))
10
- expiration
11
- else
12
- server.access_token_expires_in
13
- end
14
- end
15
-
16
- private
17
-
18
- def custom_expiration(server, pre_auth_or_oauth_client)
10
+ def build_context(pre_auth_or_oauth_client, grant_type, scopes)
19
11
  oauth_client = if pre_auth_or_oauth_client.respond_to?(:client)
20
12
  pre_auth_or_oauth_client.client
21
13
  else
22
14
  pre_auth_or_oauth_client
23
15
  end
24
16
 
25
- server.custom_access_token_expires_in.call(oauth_client)
17
+ Doorkeeper::OAuth::Authorization::Context.new(
18
+ oauth_client,
19
+ grant_type,
20
+ scopes
21
+ )
22
+ end
23
+
24
+ def access_token_expires_in(server, context)
25
+ if (expiration = server.custom_access_token_expires_in.call(context))
26
+ expiration
27
+ else
28
+ server.access_token_expires_in
29
+ end
30
+ end
31
+
32
+ def refresh_token_enabled?(server, context)
33
+ if server.refresh_token_enabled?.respond_to? :call
34
+ server.refresh_token_enabled?.call(context)
35
+ else
36
+ !!server.refresh_token_enabled?
37
+ end
26
38
  end
27
39
  end
28
40
 
@@ -32,18 +44,23 @@ module Doorkeeper
32
44
  end
33
45
 
34
46
  def issue_token
47
+ context = self.class.build_context(
48
+ pre_auth.client,
49
+ Doorkeeper::OAuth::IMPLICIT,
50
+ pre_auth.scopes
51
+ )
35
52
  @token ||= AccessToken.find_or_create_for(
36
53
  pre_auth.client,
37
54
  resource_owner.id,
38
55
  pre_auth.scopes,
39
- self.class.access_token_expires_in(configuration, pre_auth),
56
+ self.class.access_token_expires_in(configuration, context),
40
57
  false
41
58
  )
42
59
  end
43
60
 
44
61
  def native_redirect
45
62
  {
46
- controller: 'doorkeeper/token_info',
63
+ controller: controller,
47
64
  action: :show,
48
65
  access_token: token.token
49
66
  }
@@ -54,6 +71,13 @@ module Doorkeeper
54
71
  def configuration
55
72
  Doorkeeper.configuration
56
73
  end
74
+
75
+ def controller
76
+ @controller ||= begin
77
+ mapping = Doorkeeper::Rails::Routes.mapping[:token_info] || {}
78
+ mapping[:controllers] || 'doorkeeper/token_info'
79
+ end
80
+ end
57
81
  end
58
82
  end
59
83
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rack/utils'
2
4
 
3
5
  module Doorkeeper
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class AuthorizationCodeRequest < BaseRequest
@@ -6,18 +8,26 @@ module Doorkeeper
6
8
  validate :grant, error: :invalid_grant
7
9
  # @see https://tools.ietf.org/html/rfc6749#section-5.2
8
10
  validate :redirect_uri, error: :invalid_grant
11
+ validate :code_verifier, error: :invalid_grant
9
12
 
10
- attr_accessor :server, :grant, :client, :redirect_uri, :access_token
13
+ attr_accessor :server, :grant, :client, :redirect_uri, :access_token,
14
+ :code_verifier
11
15
 
12
16
  def initialize(server, grant, client, parameters = {})
13
17
  @server = server
14
18
  @client = client
15
19
  @grant = grant
20
+ @grant_type = Doorkeeper::OAuth::AUTHORIZATION_CODE
16
21
  @redirect_uri = parameters[:redirect_uri]
22
+ @code_verifier = parameters[:code_verifier]
17
23
  end
18
24
 
19
25
  private
20
26
 
27
+ def client_by_uid(parameters)
28
+ Doorkeeper::Application.by_uid(parameters[:client_id])
29
+ end
30
+
21
31
  def before_successful_response
22
32
  grant.transaction do
23
33
  grant.lock!
@@ -33,11 +43,13 @@ module Doorkeeper
33
43
  end
34
44
 
35
45
  def validate_attributes
46
+ return false if grant && grant.uses_pkce? && code_verifier.blank?
47
+ return false if grant && !grant.pkce_supported? && !code_verifier.blank?
36
48
  redirect_uri.present?
37
49
  end
38
50
 
39
51
  def validate_client
40
- !!client
52
+ !client.nil?
41
53
  end
42
54
 
43
55
  def validate_grant
@@ -51,6 +63,21 @@ module Doorkeeper
51
63
  grant.redirect_uri
52
64
  )
53
65
  end
66
+
67
+ # if either side (server or client) request pkce, check the verifier
68
+ # against the DB - if pkce is supported
69
+ def validate_code_verifier
70
+ return true unless grant.uses_pkce? || code_verifier
71
+ return false unless grant.pkce_supported?
72
+
73
+ if grant.code_challenge_method == 'S256'
74
+ grant.code_challenge == AccessGrant.generate_code_challenge(code_verifier)
75
+ elsif grant.code_challenge_method == 'plain'
76
+ grant.code_challenge == code_verifier
77
+ else
78
+ false
79
+ end
80
+ end
54
81
  end
55
82
  end
56
83
  end
@@ -1,8 +1,12 @@
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
9
+
6
10
  def authorize
7
11
  validate
8
12
 
@@ -17,11 +21,7 @@ module Doorkeeper
17
21
  end
18
22
 
19
23
  def scopes
20
- @scopes ||= if @original_scopes.present?
21
- OAuth::Scopes.from_string(@original_scopes)
22
- else
23
- default_scopes
24
- end
24
+ @scopes ||= build_scopes
25
25
  end
26
26
 
27
27
  def default_scopes
@@ -33,12 +33,13 @@ module Doorkeeper
33
33
  end
34
34
 
35
35
  def find_or_create_access_token(client, resource_owner_id, scopes, server)
36
+ context = Authorization::Token.build_context(client, grant_type, scopes)
36
37
  @access_token = AccessToken.find_or_create_for(
37
38
  client,
38
39
  resource_owner_id,
39
40
  scopes,
40
- Authorization::Token.access_token_expires_in(server, client),
41
- server.refresh_token_enabled?
41
+ Authorization::Token.access_token_expires_in(server, context),
42
+ Authorization::Token.refresh_token_enabled?(server, context)
42
43
  )
43
44
  end
44
45
 
@@ -47,8 +48,20 @@ module Doorkeeper
47
48
  end
48
49
 
49
50
  def after_successful_response
50
- Doorkeeper.configuration.after_successful_strategy_response.
51
- call(self, @response)
51
+ Doorkeeper.configuration.after_successful_strategy_response.call(self, @response)
52
+ end
53
+
54
+ private
55
+
56
+ def build_scopes
57
+ if @original_scopes.present?
58
+ OAuth::Scopes.from_string(@original_scopes)
59
+ else
60
+ client_scopes = @client.try(:scopes)
61
+ return default_scopes if client_scopes.blank?
62
+
63
+ default_scopes & @client.scopes
64
+ end
52
65
  end
53
66
  end
54
67
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class BaseResponse
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class Client
4
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
12
  break credentials unless credentials.blank?
@@ -1,4 +1,4 @@
1
- require 'doorkeeper/oauth/client/credentials'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Doorkeeper
4
4
  module OAuth
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class ClientCredentialsRequest < BaseRequest
@@ -5,7 +7,8 @@ module Doorkeeper
5
7
  def call(client, scopes, attributes = {})
6
8
  AccessToken.find_or_create_for(
7
9
  client, nil, scopes, attributes[:expires_in],
8
- attributes[:use_refresh_token])
10
+ attributes[:use_refresh_token]
11
+ )
9
12
  end
10
13
  end
11
14
  end
@@ -1,4 +1,4 @@
1
- require 'doorkeeper/oauth/client_credentials/validation'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Doorkeeper
4
4
  module OAuth
@@ -25,7 +25,12 @@ module Doorkeeper
25
25
  private
26
26
 
27
27
  def create_token(client, scopes, creator)
28
- ttl = Authorization::Token.access_token_expires_in(@server, client)
28
+ context = Authorization::Token.build_context(
29
+ client,
30
+ Doorkeeper::OAuth::CLIENT_CREDENTIALS,
31
+ scopes
32
+ )
33
+ ttl = Authorization::Token.access_token_expires_in(@server, context)
29
34
 
30
35
  creator.call(
31
36
  client,
@@ -1,6 +1,4 @@
1
- require 'doorkeeper/validations'
2
- require 'doorkeeper/oauth/scopes'
3
- require 'doorkeeper/oauth/helpers/scope_checker'
1
+ # frozen_string_literal: true
4
2
 
5
3
  module Doorkeeper
6
4
  module OAuth
@@ -13,7 +11,9 @@ module Doorkeeper
13
11
  validate :scopes, error: :invalid_scope
14
12
 
15
13
  def initialize(server, request)
16
- @server, @request, @client = server, request, request.client
14
+ @server = server
15
+ @request = request
16
+ @client = request.client
17
17
 
18
18
  validate
19
19
  end
@@ -25,7 +25,7 @@ module Doorkeeper
25
25
  end
26
26
 
27
27
  def validate_scopes
28
- return true unless @request.scopes.present?
28
+ return true if @request.scopes.blank?
29
29
 
30
30
  application_scopes = if @client.present?
31
31
  @client.application.scopes
@@ -1,6 +1,4 @@
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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class CodeRequest
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class CodeResponse < BaseResponse
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  Error = Struct.new(:name, :state) do
@@ -1,10 +1,18 @@
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
 
6
8
  def self.from_request(request, attributes = {})
7
- new(attributes.merge(name: request.error, state: request.try(:state)))
9
+ new(
10
+ attributes.merge(
11
+ name: request.error,
12
+ state: request.try(:state),
13
+ redirect_uri: request.try(:redirect_uri)
14
+ )
15
+ )
8
16
  end
9
17
 
10
18
  delegate :name, :description, :state, to: :@error
@@ -41,10 +49,16 @@ module Doorkeeper
41
49
  end
42
50
 
43
51
  def headers
44
- { 'Cache-Control' => 'no-store',
52
+ {
53
+ 'Cache-Control' => 'no-store',
45
54
  'Pragma' => 'no-cache',
46
55
  'Content-Type' => 'application/json; charset=utf-8',
47
- 'WWW-Authenticate' => authenticate_info }
56
+ 'WWW-Authenticate' => authenticate_info
57
+ }
58
+ end
59
+
60
+ def raise_exception!
61
+ raise exception_class.new(self), description
48
62
  end
49
63
 
50
64
  protected
@@ -55,6 +69,10 @@ module Doorkeeper
55
69
  Doorkeeper.configuration
56
70
  end
57
71
 
72
+ def exception_class
73
+ raise NotImplementedError, "error response must define #exception_class"
74
+ end
75
+
58
76
  private
59
77
 
60
78
  def authenticate_info
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class ForbiddenTokenResponse < ErrorResponse
@@ -21,8 +23,13 @@ module Doorkeeper
21
23
  end
22
24
 
23
25
  def description
24
- scope = { scope: %i[doorkeeper scopes] }
25
- @description ||= @scopes.map { |r| I18n.translate r, scope }.join('\n')
26
+ @description ||= @scopes.map { |s| I18n.t(s, scope: %i[doorkeeper scopes]) }.join("\n")
27
+ end
28
+
29
+ protected
30
+
31
+ def exception_class
32
+ Doorkeeper::Errors::TokenForbidden
26
33
  end
27
34
  end
28
35
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  module Helpers
@@ -17,10 +19,6 @@ module Doorkeeper
17
19
  @valid_scopes.has_scopes?(parsed_scopes)
18
20
  end
19
21
 
20
- def match?
21
- valid? && parsed_scopes.has_scopes?(@valid_scopes)
22
- end
23
-
24
22
  private
25
23
 
26
24
  def valid_scopes(server_scopes, application_scopes)
@@ -35,10 +33,6 @@ module Doorkeeper
35
33
  def self.valid?(scope_str, server_scopes, application_scopes = nil)
36
34
  Validator.new(scope_str, server_scopes, application_scopes).valid?
37
35
  end
38
-
39
- def self.match?(scope_str, server_scopes, application_scopes = nil)
40
- Validator.new(scope_str, server_scopes, application_scopes).match?
41
- end
42
36
  end
43
37
  end
44
38
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  module Helpers
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  module Helpers
@@ -14,12 +16,13 @@ module Doorkeeper
14
16
  url = as_uri(url)
15
17
  client_url = as_uri(client_url)
16
18
 
17
- if client_url.query.present?
19
+ unless client_url.query.nil?
18
20
  return false unless query_matches?(url.query, client_url.query)
19
21
  # Clear out queries so rest of URI can be tested. This allows query
20
22
  # params to be in the request but order not mattering.
21
23
  client_url.query = nil
22
24
  end
25
+
23
26
  url.query = nil
24
27
  url == client_url
25
28
  end
@@ -33,7 +36,7 @@ module Doorkeeper
33
36
  end
34
37
 
35
38
  def self.query_matches?(query, client_query)
36
- return true if client_query.nil? && query.nil?
39
+ return true if client_query.blank? && query.blank?
37
40
  return false if client_query.nil? || query.nil?
38
41
  # Will return true independent of query order
39
42
  client_query.split('&').sort == query.split('&').sort
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class InvalidTokenResponse < ErrorResponse
@@ -24,6 +26,22 @@ module Doorkeeper
24
26
  scope = { scope: %i[doorkeeper errors messages invalid_token] }
25
27
  @description ||= I18n.translate @reason, scope
26
28
  end
29
+
30
+ protected
31
+
32
+ def exception_class
33
+ errors_mapping.fetch(reason)
34
+ end
35
+
36
+ private
37
+
38
+ def errors_mapping
39
+ {
40
+ expired: Doorkeeper::Errors::TokenExpired,
41
+ revoked: Doorkeeper::Errors::TokenRevoked,
42
+ unknown: Doorkeeper::Errors::TokenUnknown
43
+ }
44
+ end
27
45
  end
28
46
  end
29
47
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class PasswordAccessTokenRequest < BaseRequest
@@ -16,6 +18,7 @@ module Doorkeeper
16
18
  @client = client
17
19
  @parameters = parameters
18
20
  @original_scopes = parameters[:scope]
21
+ @grant_type = Doorkeeper::OAuth::PASSWORD
19
22
  end
20
23
 
21
24
  private
@@ -26,16 +29,18 @@ module Doorkeeper
26
29
  end
27
30
 
28
31
  def validate_scopes
29
- return true unless @original_scopes.present?
30
- ScopeChecker.valid? @original_scopes, server.scopes, client.try(:scopes)
32
+ client_scopes = client.try(:scopes)
33
+ return true if scopes.blank?
34
+
35
+ ScopeChecker.valid?(scopes.to_s, server.scopes, client_scopes)
31
36
  end
32
37
 
33
38
  def validate_resource_owner
34
- !!resource_owner
39
+ !resource_owner.nil?
35
40
  end
36
41
 
37
42
  def validate_client
38
- !parameters[:client_id] || !!client
43
+ !parameters[:client_id] || !client.nil?
39
44
  end
40
45
  end
41
46
  end