doorkeeper 5.0.0 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (241) hide show
  1. checksums.yaml +5 -5
  2. data/.hound.yml +2 -1
  3. data/.rubocop.yml +37 -4
  4. data/.travis.yml +16 -21
  5. data/Appraisals +29 -7
  6. data/Dangerfile +67 -0
  7. data/Gemfile +19 -5
  8. data/NEWS.md +107 -10
  9. data/README.md +75 -470
  10. data/Rakefile +10 -8
  11. data/app/controllers/doorkeeper/application_controller.rb +3 -2
  12. data/app/controllers/doorkeeper/application_metal_controller.rb +4 -13
  13. data/app/controllers/doorkeeper/applications_controller.rb +21 -7
  14. data/app/controllers/doorkeeper/authorizations_controller.rb +3 -3
  15. data/app/controllers/doorkeeper/authorized_applications_controller.rb +2 -0
  16. data/app/controllers/doorkeeper/token_info_controller.rb +4 -2
  17. data/app/controllers/doorkeeper/tokens_controller.rb +13 -11
  18. data/app/helpers/doorkeeper/dashboard_helper.rb +3 -1
  19. data/app/validators/redirect_uri_validator.rb +7 -2
  20. data/app/views/doorkeeper/applications/_form.html.erb +6 -0
  21. data/app/views/doorkeeper/applications/show.html.erb +1 -1
  22. data/app/views/layouts/doorkeeper/admin.html.erb +5 -3
  23. data/bin/console +16 -0
  24. data/config/locales/en.yml +1 -0
  25. data/doorkeeper.gemspec +28 -24
  26. data/gemfiles/rails_5_0.gemfile +9 -4
  27. data/gemfiles/rails_5_1.gemfile +9 -4
  28. data/gemfiles/rails_5_2.gemfile +10 -5
  29. data/gemfiles/rails_6_0.gemfile +17 -0
  30. data/gemfiles/rails_master.gemfile +9 -9
  31. data/lib/doorkeeper/config/option.rb +64 -0
  32. data/lib/doorkeeper/config.rb +197 -76
  33. data/lib/doorkeeper/engine.rb +3 -1
  34. data/lib/doorkeeper/errors.rb +17 -0
  35. data/lib/doorkeeper/grape/authorization_decorator.rb +6 -4
  36. data/lib/doorkeeper/grape/helpers.rb +5 -3
  37. data/lib/doorkeeper/helpers/controller.rb +5 -2
  38. data/lib/doorkeeper/models/access_grant_mixin.rb +25 -6
  39. data/lib/doorkeeper/models/access_token_mixin.rb +68 -22
  40. data/lib/doorkeeper/models/application_mixin.rb +45 -1
  41. data/lib/doorkeeper/models/concerns/accessible.rb +2 -0
  42. data/lib/doorkeeper/models/concerns/expirable.rb +6 -2
  43. data/lib/doorkeeper/models/concerns/orderable.rb +2 -0
  44. data/lib/doorkeeper/models/concerns/ownership.rb +3 -6
  45. data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
  46. data/lib/doorkeeper/models/concerns/revocable.rb +4 -1
  47. data/lib/doorkeeper/models/concerns/scopes.rb +7 -1
  48. data/lib/doorkeeper/models/concerns/secret_storable.rb +108 -0
  49. data/lib/doorkeeper/oauth/authorization/code.rb +4 -2
  50. data/lib/doorkeeper/oauth/authorization/context.rb +2 -0
  51. data/lib/doorkeeper/oauth/authorization/token.rb +14 -7
  52. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +3 -1
  53. data/lib/doorkeeper/oauth/authorization_code_request.rb +8 -4
  54. data/lib/doorkeeper/oauth/base_request.rb +2 -0
  55. data/lib/doorkeeper/oauth/base_response.rb +2 -0
  56. data/lib/doorkeeper/oauth/client/credentials.rb +2 -0
  57. data/lib/doorkeeper/oauth/client.rb +3 -1
  58. data/lib/doorkeeper/oauth/client_credentials/creator.rb +2 -0
  59. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +2 -0
  60. data/lib/doorkeeper/oauth/client_credentials/validation.rb +7 -4
  61. data/lib/doorkeeper/oauth/client_credentials_request.rb +3 -1
  62. data/lib/doorkeeper/oauth/code_request.rb +2 -0
  63. data/lib/doorkeeper/oauth/code_response.rb +4 -2
  64. data/lib/doorkeeper/oauth/error.rb +2 -0
  65. data/lib/doorkeeper/oauth/error_response.rb +20 -6
  66. data/lib/doorkeeper/oauth/forbidden_token_response.rb +10 -3
  67. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +25 -8
  68. data/lib/doorkeeper/oauth/helpers/unique_token.rb +15 -1
  69. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +42 -3
  70. data/lib/doorkeeper/oauth/invalid_token_response.rb +22 -0
  71. data/lib/doorkeeper/oauth/password_access_token_request.rb +9 -2
  72. data/lib/doorkeeper/oauth/pre_authorization.rb +13 -5
  73. data/lib/doorkeeper/oauth/refresh_token_request.rb +15 -4
  74. data/lib/doorkeeper/oauth/scopes.rb +7 -3
  75. data/lib/doorkeeper/oauth/token.rb +4 -2
  76. data/lib/doorkeeper/oauth/token_introspection.rb +76 -8
  77. data/lib/doorkeeper/oauth/token_request.rb +2 -0
  78. data/lib/doorkeeper/oauth/token_response.rb +11 -9
  79. data/lib/doorkeeper/oauth.rb +5 -5
  80. data/lib/doorkeeper/orm/active_record/access_grant.rb +27 -13
  81. data/lib/doorkeeper/orm/active_record/access_token.rb +6 -13
  82. data/lib/doorkeeper/orm/active_record/application.rb +26 -7
  83. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +10 -3
  84. data/lib/doorkeeper/orm/active_record.rb +8 -6
  85. data/lib/doorkeeper/rails/helpers.rb +5 -1
  86. data/lib/doorkeeper/rails/routes/mapper.rb +2 -0
  87. data/lib/doorkeeper/rails/routes/mapping.rb +9 -7
  88. data/lib/doorkeeper/rails/routes.rb +19 -12
  89. data/lib/doorkeeper/rake/db.rake +17 -17
  90. data/lib/doorkeeper/rake.rb +1 -1
  91. data/lib/doorkeeper/request/authorization_code.rb +2 -0
  92. data/lib/doorkeeper/request/client_credentials.rb +2 -0
  93. data/lib/doorkeeper/request/code.rb +2 -0
  94. data/lib/doorkeeper/request/password.rb +2 -0
  95. data/lib/doorkeeper/request/refresh_token.rb +2 -0
  96. data/lib/doorkeeper/request/strategy.rb +2 -0
  97. data/lib/doorkeeper/request/token.rb +2 -0
  98. data/lib/doorkeeper/request.rb +3 -1
  99. data/lib/doorkeeper/secret_storing/base.rb +64 -0
  100. data/lib/doorkeeper/secret_storing/bcrypt.rb +60 -0
  101. data/lib/doorkeeper/secret_storing/plain.rb +33 -0
  102. data/lib/doorkeeper/secret_storing/sha256_hash.rb +26 -0
  103. data/lib/doorkeeper/server.rb +2 -0
  104. data/lib/doorkeeper/stale_records_cleaner.rb +20 -0
  105. data/lib/doorkeeper/validations.rb +2 -0
  106. data/lib/doorkeeper/version.rb +4 -2
  107. data/lib/doorkeeper.rb +69 -59
  108. data/lib/generators/doorkeeper/application_owner_generator.rb +10 -9
  109. data/lib/generators/doorkeeper/confidential_applications_generator.rb +10 -9
  110. data/lib/generators/doorkeeper/install_generator.rb +11 -9
  111. data/lib/generators/doorkeeper/migration_generator.rb +9 -9
  112. data/lib/generators/doorkeeper/pkce_generator.rb +10 -9
  113. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +10 -9
  114. data/lib/generators/doorkeeper/templates/initializer.rb +138 -13
  115. data/lib/generators/doorkeeper/templates/migration.rb.erb +17 -10
  116. data/lib/generators/doorkeeper/views_generator.rb +6 -4
  117. data/spec/controllers/application_metal_controller_spec.rb +24 -10
  118. data/spec/controllers/applications_controller_spec.rb +76 -78
  119. data/spec/controllers/authorizations_controller_spec.rb +189 -142
  120. data/spec/controllers/protected_resources_controller_spec.rb +111 -67
  121. data/spec/controllers/token_info_controller_spec.rb +14 -12
  122. data/spec/controllers/tokens_controller_spec.rb +170 -112
  123. data/spec/dummy/Rakefile +3 -1
  124. data/spec/dummy/app/controllers/application_controller.rb +3 -1
  125. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +3 -1
  126. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +4 -2
  127. data/spec/dummy/app/controllers/home_controller.rb +6 -5
  128. data/spec/dummy/app/controllers/metal_controller.rb +2 -0
  129. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +4 -2
  130. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  131. data/spec/dummy/app/models/user.rb +2 -0
  132. data/spec/dummy/config/application.rb +26 -2
  133. data/spec/dummy/config/boot.rb +2 -4
  134. data/spec/dummy/config/environment.rb +1 -1
  135. data/spec/dummy/config/environments/development.rb +2 -0
  136. data/spec/dummy/config/environments/production.rb +2 -0
  137. data/spec/dummy/config/environments/test.rb +4 -2
  138. data/spec/dummy/config/initializers/backtrace_silencers.rb +2 -0
  139. data/spec/dummy/config/initializers/doorkeeper.rb +7 -3
  140. data/spec/dummy/config/initializers/secret_token.rb +3 -1
  141. data/spec/dummy/config/initializers/session_store.rb +3 -1
  142. data/spec/dummy/config/initializers/wrap_parameters.rb +2 -0
  143. data/spec/dummy/config.ru +3 -1
  144. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +20 -13
  145. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +1 -1
  146. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +2 -0
  147. data/spec/dummy/db/schema.rb +1 -1
  148. data/spec/dummy/script/rails +7 -4
  149. data/spec/factories.rb +11 -9
  150. data/spec/generators/application_owner_generator_spec.rb +13 -26
  151. data/spec/generators/confidential_applications_generator_spec.rb +12 -28
  152. data/spec/generators/install_generator_spec.rb +19 -14
  153. data/spec/generators/migration_generator_spec.rb +13 -26
  154. data/spec/generators/pkce_generator_spec.rb +11 -26
  155. data/spec/generators/previous_refresh_token_generator_spec.rb +16 -29
  156. data/spec/generators/templates/routes.rb +2 -1
  157. data/spec/generators/views_generator_spec.rb +14 -12
  158. data/spec/grape/grape_integration_spec.rb +35 -33
  159. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +9 -7
  160. data/spec/lib/config_spec.rb +290 -104
  161. data/spec/lib/doorkeeper_spec.rb +8 -6
  162. data/spec/lib/models/expirable_spec.rb +22 -8
  163. data/spec/lib/models/reusable_spec.rb +40 -0
  164. data/spec/lib/models/revocable_spec.rb +8 -6
  165. data/spec/lib/models/scopes_spec.rb +27 -13
  166. data/spec/lib/models/secret_storable_spec.rb +135 -0
  167. data/spec/lib/oauth/authorization/uri_builder_spec.rb +17 -15
  168. data/spec/lib/oauth/authorization_code_request_spec.rb +43 -17
  169. data/spec/lib/oauth/base_request_spec.rb +24 -12
  170. data/spec/lib/oauth/base_response_spec.rb +3 -1
  171. data/spec/lib/oauth/client/credentials_spec.rb +26 -24
  172. data/spec/lib/oauth/client_credentials/creator_spec.rb +56 -10
  173. data/spec/lib/oauth/client_credentials/issuer_spec.rb +27 -20
  174. data/spec/lib/oauth/client_credentials/validation_spec.rb +21 -15
  175. data/spec/lib/oauth/client_credentials_integration_spec.rb +8 -6
  176. data/spec/lib/oauth/client_credentials_request_spec.rb +27 -21
  177. data/spec/lib/oauth/client_spec.rb +15 -13
  178. data/spec/lib/oauth/code_request_spec.rb +10 -8
  179. data/spec/lib/oauth/code_response_spec.rb +9 -7
  180. data/spec/lib/oauth/error_response_spec.rb +19 -11
  181. data/spec/lib/oauth/error_spec.rb +4 -2
  182. data/spec/lib/oauth/forbidden_token_response_spec.rb +7 -5
  183. data/spec/lib/oauth/helpers/scope_checker_spec.rb +68 -31
  184. data/spec/lib/oauth/helpers/unique_token_spec.rb +8 -6
  185. data/spec/lib/oauth/helpers/uri_checker_spec.rb +124 -93
  186. data/spec/lib/oauth/invalid_token_response_spec.rb +3 -1
  187. data/spec/lib/oauth/password_access_token_request_spec.rb +95 -34
  188. data/spec/lib/oauth/pre_authorization_spec.rb +80 -54
  189. data/spec/lib/oauth/refresh_token_request_spec.rb +46 -39
  190. data/spec/lib/oauth/scopes_spec.rb +63 -61
  191. data/spec/lib/oauth/token_request_spec.rb +80 -25
  192. data/spec/lib/oauth/token_response_spec.rb +40 -38
  193. data/spec/lib/oauth/token_spec.rb +64 -45
  194. data/spec/lib/request/strategy_spec.rb +3 -1
  195. data/spec/lib/secret_storing/base_spec.rb +60 -0
  196. data/spec/lib/secret_storing/bcrypt_spec.rb +49 -0
  197. data/spec/lib/secret_storing/plain_spec.rb +44 -0
  198. data/spec/lib/secret_storing/sha256_hash_spec.rb +48 -0
  199. data/spec/lib/server_spec.rb +20 -18
  200. data/spec/lib/{orm/active_record/stale_records_cleaner_spec.rb → stale_records_cleaner_spec.rb} +28 -18
  201. data/spec/models/doorkeeper/access_grant_spec.rb +80 -15
  202. data/spec/models/doorkeeper/access_token_spec.rb +212 -83
  203. data/spec/models/doorkeeper/application_spec.rb +146 -49
  204. data/spec/requests/applications/applications_request_spec.rb +100 -68
  205. data/spec/requests/applications/authorized_applications_spec.rb +20 -18
  206. data/spec/requests/endpoints/authorization_spec.rb +27 -25
  207. data/spec/requests/endpoints/token_spec.rb +38 -36
  208. data/spec/requests/flows/authorization_code_errors_spec.rb +27 -25
  209. data/spec/requests/flows/authorization_code_spec.rb +260 -158
  210. data/spec/requests/flows/client_credentials_spec.rb +54 -52
  211. data/spec/requests/flows/implicit_grant_errors_spec.rb +11 -9
  212. data/spec/requests/flows/implicit_grant_spec.rb +27 -25
  213. data/spec/requests/flows/password_spec.rb +64 -56
  214. data/spec/requests/flows/refresh_token_spec.rb +91 -32
  215. data/spec/requests/flows/revoke_token_spec.rb +49 -63
  216. data/spec/requests/flows/skip_authorization_spec.rb +23 -21
  217. data/spec/requests/protected_resources/metal_spec.rb +7 -5
  218. data/spec/requests/protected_resources/private_api_spec.rb +37 -35
  219. data/spec/routing/custom_controller_routes_spec.rb +71 -65
  220. data/spec/routing/default_routes_spec.rb +22 -20
  221. data/spec/routing/scoped_routes_spec.rb +20 -18
  222. data/spec/spec_helper.rb +15 -13
  223. data/spec/spec_helper_integration.rb +3 -1
  224. data/spec/support/dependencies/factory_bot.rb +3 -1
  225. data/spec/support/doorkeeper_rspec.rb +5 -2
  226. data/spec/support/helpers/access_token_request_helper.rb +3 -1
  227. data/spec/support/helpers/authorization_request_helper.rb +4 -2
  228. data/spec/support/helpers/config_helper.rb +2 -0
  229. data/spec/support/helpers/model_helper.rb +11 -5
  230. data/spec/support/helpers/request_spec_helper.rb +5 -3
  231. data/spec/support/helpers/url_helper.rb +20 -18
  232. data/spec/support/http_method_shim.rb +4 -9
  233. data/spec/support/orm/active_record.rb +3 -1
  234. data/spec/support/shared/controllers_shared_context.rb +68 -10
  235. data/spec/support/shared/hashing_shared_context.rb +36 -0
  236. data/spec/support/shared/models_shared_examples.rb +12 -10
  237. data/spec/validators/redirect_uri_validator_spec.rb +76 -47
  238. data/spec/version/version_spec.rb +7 -5
  239. metadata +70 -21
  240. data/gemfiles/rails_4_2.gemfile +0 -13
  241. data/spec/dummy/config/initializers/new_framework_defaults.rb +0 -10
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class ClientCredentialsRequest < BaseRequest
@@ -28,13 +30,14 @@ module Doorkeeper
28
30
  application_scopes = if @client.present?
29
31
  @client.application.scopes
30
32
  else
31
- ''
33
+ ""
32
34
  end
33
35
 
34
36
  ScopeChecker.valid?(
35
- @request.scopes.to_s,
36
- @server.scopes,
37
- application_scopes
37
+ scope_str: @request.scopes.to_s,
38
+ server_scopes: @server.scopes,
39
+ app_scopes: application_scopes,
40
+ grant_type: Doorkeeper::OAuth::CLIENT_CREDENTIALS
38
41
  )
39
42
  end
40
43
  end
@@ -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,7 @@ module Doorkeeper
5
7
  attr_reader :response
6
8
  attr_writer :issuer
7
9
 
8
- alias_method :error_response, :response
10
+ alias error_response response
9
11
 
10
12
  delegate :error, to: :issuer
11
13
 
@@ -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
@@ -21,7 +23,7 @@ module Doorkeeper
21
23
  elsif response_on_fragment
22
24
  Authorization::URIBuilder.uri_with_fragment(
23
25
  pre_auth.redirect_uri,
24
- access_token: auth.token.token,
26
+ access_token: auth.token.plaintext_token,
25
27
  token_type: auth.token.token_type,
26
28
  expires_in: auth.token.expires_in_seconds,
27
29
  state: pre_auth.state
@@ -29,7 +31,7 @@ module Doorkeeper
29
31
  else
30
32
  Authorization::URIBuilder.uri_with_query(
31
33
  pre_auth.redirect_uri,
32
- code: auth.token.token,
34
+ code: auth.token.plaintext_token,
33
35
  state: pre_auth.state
34
36
  )
35
37
  end
@@ -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,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class ErrorResponse < BaseResponse
@@ -25,12 +27,16 @@ module Doorkeeper
25
27
  {
26
28
  error: name,
27
29
  error_description: description,
28
- state: state
30
+ state: state,
29
31
  }.reject { |_, v| v.blank? }
30
32
  end
31
33
 
32
34
  def status
33
- :unauthorized
35
+ if name == :invalid_client
36
+ :unauthorized
37
+ else
38
+ :bad_request
39
+ end
34
40
  end
35
41
 
36
42
  def redirectable?
@@ -48,13 +54,17 @@ module Doorkeeper
48
54
 
49
55
  def headers
50
56
  {
51
- 'Cache-Control' => 'no-store',
52
- 'Pragma' => 'no-cache',
53
- 'Content-Type' => 'application/json; charset=utf-8',
54
- 'WWW-Authenticate' => authenticate_info
57
+ "Cache-Control" => "no-store",
58
+ "Pragma" => "no-cache",
59
+ "Content-Type" => "application/json; charset=utf-8",
60
+ "WWW-Authenticate" => authenticate_info,
55
61
  }
56
62
  end
57
63
 
64
+ def raise_exception!
65
+ raise exception_class.new(self), description
66
+ end
67
+
58
68
  protected
59
69
 
60
70
  delegate :realm, to: :configuration
@@ -63,6 +73,10 @@ module Doorkeeper
63
73
  Doorkeeper.configuration
64
74
  end
65
75
 
76
+ def exception_class
77
+ raise NotImplementedError, "error response must define #exception_class"
78
+ end
79
+
66
80
  private
67
81
 
68
82
  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
@@ -16,13 +18,18 @@ 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: %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
@@ -5,31 +7,46 @@ 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
+ if grant_type
16
+ @scopes_by_grant_type = Doorkeeper.configuration.scopes_by_grant_type[grant_type.to_sym]
17
+ end
12
18
  end
13
19
 
14
20
  def valid?
15
21
  scope_str.present? &&
16
22
  scope_str !~ /[\n\r\t]/ &&
17
- @valid_scopes.has_scopes?(parsed_scopes)
23
+ @valid_scopes.has_scopes?(parsed_scopes) &&
24
+ permitted_to_grant_type?
18
25
  end
19
26
 
20
27
  private
21
28
 
22
- def valid_scopes(server_scopes, application_scopes)
23
- if application_scopes.present?
24
- application_scopes
29
+ def valid_scopes(server_scopes, app_scopes)
30
+ if app_scopes.present?
31
+ app_scopes
25
32
  else
26
33
  server_scopes
27
34
  end
28
35
  end
36
+
37
+ def permitted_to_grant_type?
38
+ return true unless @scopes_by_grant_type
39
+
40
+ OAuth::Scopes.from_array(@scopes_by_grant_type)
41
+ .has_scopes?(parsed_scopes)
42
+ end
29
43
  end
30
44
 
31
- def self.valid?(scope_str, server_scopes, application_scopes = nil)
32
- Validator.new(scope_str, server_scopes, application_scopes).valid?
45
+ def self.valid?(scope_str:, server_scopes:, app_scopes: nil, grant_type: nil)
46
+ Validator.new(scope_str,
47
+ server_scopes,
48
+ app_scopes,
49
+ grant_type).valid?
33
50
  end
34
51
  end
35
52
  end
@@ -1,12 +1,26 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  module Helpers
4
6
  module UniqueToken
5
7
  def self.generate(options = {})
6
- generator_method = options.delete(:generator) || SecureRandom.method(:hex)
8
+ # Access Token value must be 1*VSCHAR or
9
+ # 1*( ALPHA / DIGIT / "-" / "." / "_" / "~" / "+" / "/" ) *"="
10
+ #
11
+ # @see https://tools.ietf.org/html/rfc6749#appendix-A.12
12
+ # @see https://tools.ietf.org/html/rfc6750#section-2.1
13
+ #
14
+ generator_method = options.delete(:generator) || SecureRandom.method(self.generator_method)
7
15
  token_size = options.delete(:size) || 32
8
16
  generator_method.call(token_size)
9
17
  end
18
+
19
+ # Generator method for default generator class (SecureRandom)
20
+ #
21
+ def self.generator_method
22
+ Doorkeeper.configuration.default_generator_method
23
+ end
10
24
  end
11
25
  end
12
26
  end
@@ -1,9 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ipaddr"
4
+
1
5
  module Doorkeeper
6
+ module IPAddrLoopback
7
+ def loopback?
8
+ case @family
9
+ when Socket::AF_INET
10
+ @addr & 0xff000000 == 0x7f000000
11
+ when Socket::AF_INET6
12
+ @addr == 1
13
+ else
14
+ raise AddressFamilyError, "unsupported address family"
15
+ end
16
+ end
17
+ end
18
+
19
+ # For backward compatibility with old rubies
20
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.5.0")
21
+ IPAddr.send(:include, Doorkeeper::IPAddrLoopback)
22
+ end
23
+
2
24
  module OAuth
3
25
  module Helpers
4
26
  module URIChecker
5
27
  def self.valid?(url)
6
28
  return true if native_uri?(url)
29
+
7
30
  uri = as_uri(url)
8
31
  uri.fragment.nil? && !uri.host.nil? && !uri.scheme.nil?
9
32
  rescue URI::InvalidURIError
@@ -14,16 +37,31 @@ module Doorkeeper
14
37
  url = as_uri(url)
15
38
  client_url = as_uri(client_url)
16
39
 
17
- if client_url.query.present?
40
+ unless client_url.query.nil?
18
41
  return false unless query_matches?(url.query, client_url.query)
42
+
19
43
  # Clear out queries so rest of URI can be tested. This allows query
20
44
  # params to be in the request but order not mattering.
21
45
  client_url.query = nil
22
46
  end
47
+
48
+ # RFC8252, Paragraph 7.3
49
+ # @see https://tools.ietf.org/html/rfc8252#section-7.3
50
+ if loopback_uri?(url) && loopback_uri?(client_url)
51
+ url.port = nil
52
+ client_url.port = nil
53
+ end
54
+
23
55
  url.query = nil
24
56
  url == client_url
25
57
  end
26
58
 
59
+ def self.loopback_uri?(uri)
60
+ IPAddr.new(uri.host).loopback?
61
+ rescue IPAddr::Error
62
+ false
63
+ end
64
+
27
65
  def self.valid_for_authorization?(url, client_url)
28
66
  valid?(url) && client_url.split.any? { |other_url| matches?(url, other_url) }
29
67
  end
@@ -33,10 +71,11 @@ module Doorkeeper
33
71
  end
34
72
 
35
73
  def self.query_matches?(query, client_query)
36
- return true if client_query.nil? && query.nil?
74
+ return true if client_query.blank? && query.blank?
37
75
  return false if client_query.nil? || query.nil?
76
+
38
77
  # Will return true independent of query order
39
- client_query.split('&').sort == query.split('&').sort
78
+ client_query.split("&").sort == query.split("&").sort
40
79
  end
41
80
 
42
81
  def self.native_uri?(url)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class InvalidTokenResponse < ErrorResponse
@@ -20,10 +22,30 @@ module Doorkeeper
20
22
  @reason = attributes[:reason] || :unknown
21
23
  end
22
24
 
25
+ def status
26
+ :unauthorized
27
+ end
28
+
23
29
  def description
24
30
  scope = { scope: %i[doorkeeper errors messages invalid_token] }
25
31
  @description ||= I18n.translate @reason, scope
26
32
  end
33
+
34
+ protected
35
+
36
+ def exception_class
37
+ errors_mapping.fetch(reason)
38
+ end
39
+
40
+ private
41
+
42
+ def errors_mapping
43
+ {
44
+ expired: Doorkeeper::Errors::TokenExpired,
45
+ revoked: Doorkeeper::Errors::TokenRevoked,
46
+ unknown: Doorkeeper::Errors::TokenUnknown,
47
+ }
48
+ end
27
49
  end
28
50
  end
29
51
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class PasswordAccessTokenRequest < BaseRequest
@@ -30,7 +32,12 @@ module Doorkeeper
30
32
  client_scopes = client.try(:scopes)
31
33
  return true if scopes.blank?
32
34
 
33
- ScopeChecker.valid?(scopes.to_s, server.scopes, client_scopes)
35
+ ScopeChecker.valid?(
36
+ scope_str: scopes.to_s,
37
+ server_scopes: server.scopes,
38
+ app_scopes: client_scopes,
39
+ grant_type: grant_type
40
+ )
34
41
  end
35
42
 
36
43
  def validate_resource_owner
@@ -38,7 +45,7 @@ module Doorkeeper
38
45
  end
39
46
 
40
47
  def validate_client
41
- !parameters[:client_id] || !client.nil?
48
+ !parameters[:client_id] || client.present?
42
49
  end
43
50
  end
44
51
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class PreAuthorization
@@ -48,7 +50,7 @@ module Doorkeeper
48
50
  response_type: response_type,
49
51
  scope: scope,
50
52
  client_name: client.name,
51
- status: I18n.t('doorkeeper.pre_authorization.status')
53
+ status: I18n.t("doorkeeper.pre_authorization.status"),
52
54
  }
53
55
  end
54
56
 
@@ -75,12 +77,17 @@ module Doorkeeper
75
77
  return true if scope.blank?
76
78
 
77
79
  Helpers::ScopeChecker.valid?(
78
- scope,
79
- server.scopes,
80
- client.application.scopes
80
+ scope_str: scope,
81
+ server_scopes: server.scopes,
82
+ app_scopes: client.application.scopes,
83
+ grant_type: grant_type
81
84
  )
82
85
  end
83
86
 
87
+ def grant_type
88
+ response_type == "code" ? AUTHORIZATION_CODE : IMPLICIT
89
+ end
90
+
84
91
  def validate_redirect_uri
85
92
  return false if redirect_uri.blank?
86
93
 
@@ -91,7 +98,8 @@ module Doorkeeper
91
98
  end
92
99
 
93
100
  def validate_code_challenge_method
94
- !code_challenge.present? || (code_challenge_method.present? && code_challenge_method =~ /^plain$|^S256$/)
101
+ code_challenge.blank? ||
102
+ (code_challenge_method.present? && code_challenge_method =~ /^plain$|^S256$/)
95
103
  end
96
104
  end
97
105
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class RefreshTokenRequest < BaseRequest
@@ -56,7 +58,7 @@ module Doorkeeper
56
58
  resource_owner_id: refresh_token.resource_owner_id,
57
59
  scopes: scopes.to_s,
58
60
  expires_in: access_token_expires_in,
59
- use_refresh_token: true
61
+ use_refresh_token: true,
60
62
  }.tap do |attributes|
61
63
  if refresh_token_revoked_on_use?
62
64
  attributes[:previous_refresh_token] = refresh_token.refresh_token
@@ -82,16 +84,25 @@ module Doorkeeper
82
84
  end
83
85
 
84
86
  def validate_client
85
- !credentials || !!client
87
+ return true if credentials.blank?
88
+
89
+ client.present?
86
90
  end
87
91
 
92
+ # @see https://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-1.5
93
+ #
88
94
  def validate_client_match
89
- !client || refresh_token.application_id == client.id
95
+ return true if refresh_token.application_id.blank?
96
+
97
+ client && refresh_token.application_id == client.id
90
98
  end
91
99
 
92
100
  def validate_scope
93
101
  if @original_scopes.present?
94
- ScopeChecker.valid?(@original_scopes, refresh_token.scopes)
102
+ ScopeChecker.valid?(
103
+ scope_str: @original_scopes,
104
+ server_scopes: refresh_token.scopes
105
+ )
95
106
  else
96
107
  true
97
108
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class Scopes
@@ -5,7 +7,7 @@ module Doorkeeper
5
7
  include Comparable
6
8
 
7
9
  def self.from_string(string)
8
- string ||= ''
10
+ string ||= ""
9
11
  new.tap do |scope|
10
12
  scope.add(*string.split)
11
13
  end
@@ -37,13 +39,15 @@ module Doorkeeper
37
39
  end
38
40
 
39
41
  def to_s
40
- @scopes.join(' ')
42
+ @scopes.join(" ")
41
43
  end
42
44
 
43
- def has_scopes?(scopes)
45
+ def scopes?(scopes)
44
46
  scopes.all? { |scope| exists?(scope) }
45
47
  end
46
48
 
49
+ alias has_scopes? scopes?
50
+
47
51
  def +(other)
48
52
  self.class.from_array(all + to_array(other))
49
53
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class Token
@@ -53,11 +55,11 @@ module Doorkeeper
53
55
  end
54
56
 
55
57
  def token_from_header(header, pattern)
56
- header.gsub pattern, ''
58
+ header.gsub pattern, ""
57
59
  end
58
60
 
59
61
  def match?(header, pattern)
60
- header && header.match(pattern)
62
+ header&.match(pattern)
61
63
  end
62
64
  end
63
65
  end