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
data/doorkeeper.gemspec CHANGED
@@ -1,32 +1,31 @@
1
- $LOAD_PATH.push File.expand_path("../lib", __FILE__)
1
+ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
2
2
 
3
- require "doorkeeper/version"
3
+ require 'doorkeeper/version'
4
4
 
5
- Gem::Specification.new do |s|
6
- s.name = "doorkeeper"
7
- s.version = Doorkeeper.gem_version
8
- s.authors = ["Felipe Elias Philipp", "Tute Costa", "Jon Moss", "Nikita Bulai"]
9
- s.email = %w(bulaj.nikita@gmail.com)
10
- s.homepage = "https://github.com/doorkeeper-gem/doorkeeper"
11
- s.summary = "OAuth 2 provider for Rails and Grape"
12
- s.description = "Doorkeeper is an OAuth 2 provider for Rails and Grape."
13
- s.license = 'MIT'
5
+ Gem::Specification.new do |gem|
6
+ gem.name = 'doorkeeper'
7
+ gem.version = Doorkeeper.gem_version
8
+ gem.authors = ['Felipe Elias Philipp', 'Tute Costa', 'Jon Moss', 'Nikita Bulai']
9
+ gem.email = %w(bulaj.nikita@gmail.com)
10
+ gem.homepage = 'https://github.com/doorkeeper-gem/doorkeeper'
11
+ gem.summary = 'OAuth 2 provider for Rails and Grape'
12
+ gem.description = 'Doorkeeper is an OAuth 2 provider for Rails and Grape.'
13
+ gem.license = 'MIT'
14
14
 
15
- s.files = `git ls-files`.split("\n")
16
- s.test_files = `git ls-files -- spec/*`.split("\n")
17
- s.require_paths = ["lib"]
15
+ gem.files = `git ls-files`.split("\n")
16
+ gem.test_files = `git ls-files -- spec/*`.split("\n")
17
+ gem.require_paths = ['lib']
18
18
 
19
- s.add_dependency "railties", ">= 4.2"
20
- s.required_ruby_version = ">= 2.1"
19
+ gem.add_dependency 'railties', '>= 4.2'
20
+ gem.required_ruby_version = '>= 2.1'
21
21
 
22
- s.add_development_dependency "capybara"
23
- s.add_development_dependency "coveralls"
24
- s.add_development_dependency "grape"
25
- s.add_development_dependency "database_cleaner", "~> 1.6"
26
- s.add_development_dependency "factory_bot", "~> 4.8"
27
- s.add_development_dependency "generator_spec", "~> 0.9.3"
28
- s.add_development_dependency "rake", ">= 11.3.0"
29
- s.add_development_dependency "rspec-rails"
30
-
31
- s.post_install_message = Doorkeeper::CVE_2018_1000211_WARNING
22
+ gem.add_development_dependency 'capybara', '~> 2.18'
23
+ gem.add_development_dependency 'coveralls'
24
+ gem.add_development_dependency 'danger', '~> 5.0'
25
+ gem.add_development_dependency 'grape'
26
+ gem.add_development_dependency 'database_cleaner', '~> 1.6'
27
+ gem.add_development_dependency 'factory_bot', '~> 4.8'
28
+ gem.add_development_dependency 'generator_spec', '~> 0.9.3'
29
+ gem.add_development_dependency 'rake', '>= 11.3.0'
30
+ gem.add_development_dependency 'rspec-rails'
32
31
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "rails", "5.2.0.rc1"
5
+ gem "rails", "5.2.0"
6
6
  gem "appraisal"
7
7
  gem "activerecord-jdbcsqlite3-adapter", platforms: :jruby
8
8
  gem "sqlite3", platforms: [:ruby, :mswin, :mingw, :x64_mingw]
@@ -9,6 +9,9 @@ gem "appraisal"
9
9
  gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
10
10
  gem "sqlite3", platform: [:ruby, :mswin, :mingw, :x64_mingw]
11
11
  gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw]
12
- gem "rspec-rails", "~> 3.7"
12
+
13
+ %w[rspec-core rspec-expectations rspec-mocks rspec-rails rspec-support].each do |lib|
14
+ gem lib, git: "https://github.com/rspec/#{lib}.git", branch: 'master'
15
+ end
13
16
 
14
17
  gemspec path: "../"
@@ -15,19 +15,19 @@ module Doorkeeper
15
15
  end
16
16
 
17
17
  def self.configuration
18
- @config || (fail MissingConfiguration)
18
+ @config || (raise MissingConfiguration)
19
19
  end
20
20
 
21
21
  def self.setup_orm_adapter
22
22
  @orm_adapter = "doorkeeper/orm/#{configuration.orm}".classify.constantize
23
- rescue NameError => e
24
- fail e, "ORM adapter not found (#{configuration.orm})", <<-ERROR_MSG.squish
25
- [doorkeeper] ORM adapter not found (#{configuration.orm}), or there was an error
26
- trying to load it.
27
-
28
- You probably need to add the related gem for this adapter to work with
29
- doorkeeper.
30
- ERROR_MSG
23
+ rescue NameError => error
24
+ raise error, "ORM adapter not found (#{configuration.orm})", <<-ERROR_MSG.strip_heredoc
25
+ [doorkeeper] ORM adapter not found (#{configuration.orm}), or there was an error
26
+ trying to load it.
27
+
28
+ You probably need to add the related gem for this adapter to work with
29
+ doorkeeper.
30
+ ERROR_MSG
31
31
  end
32
32
 
33
33
  def self.setup_orm_models
@@ -90,7 +90,7 @@ doorkeeper.
90
90
  #
91
91
  # @param methods [Array] Define client credentials
92
92
  def client_credentials(*methods)
93
- @config.instance_variable_set(:@client_credentials, methods)
93
+ @config.instance_variable_set(:@client_credentials_methods, methods)
94
94
  end
95
95
 
96
96
  # Change the way access token is authenticated from the request object.
@@ -103,9 +103,12 @@ doorkeeper.
103
103
  @config.instance_variable_set(:@access_token_methods, methods)
104
104
  end
105
105
 
106
- # Issue access tokens with refresh token (disabled by default)
107
- def use_refresh_token
108
- @config.instance_variable_set(:@refresh_token_enabled, true)
106
+ # Issue access tokens with refresh token (disabled if not set)
107
+ def use_refresh_token(enabled = true, &block)
108
+ @config.instance_variable_set(
109
+ :@refresh_token_enabled,
110
+ block || enabled
111
+ )
109
112
  end
110
113
 
111
114
  # Reuse access token for the same resource owner within an application
@@ -115,13 +118,23 @@ doorkeeper.
115
118
  @config.instance_variable_set(:@reuse_access_token, true)
116
119
  end
117
120
 
118
- # Opt out of breaking api change to the native authorization code flow.
119
- # Opting out sets the authorization code response route for native
120
- # redirect uris to oauth/authorize/<code>. The default is
121
- # oauth/authorize/native?code=<code>.
122
- # Rationale: https://github.com/doorkeeper-gem/doorkeeper/issues/1143
123
- def opt_out_native_route_change
124
- @config.instance_variable_set(:@opt_out_native_route_change, true)
121
+ # Use an API mode for applications generated with --api argument
122
+ # It will skip applications controller, disable forgery protection
123
+ def api_only
124
+ @config.instance_variable_set(:@api_only, true)
125
+ end
126
+
127
+ # Forbids creating/updating applications with arbitrary scopes that are
128
+ # not in configuration, i.e. `default_scopes` or `optional_scopes`.
129
+ # (disabled by default)
130
+ def enforce_configured_scopes
131
+ @config.instance_variable_set(:@enforce_configured_scopes, true)
132
+ end
133
+
134
+ # Enforce request content type as the spec requires:
135
+ # disabled by default for backward compatibility.
136
+ def enforce_content_type
137
+ @config.instance_variable_set(:@enforce_content_type, true)
125
138
  end
126
139
  end
127
140
 
@@ -164,7 +177,7 @@ doorkeeper.
164
177
  value = if attribute_builder
165
178
  attribute_builder.new(&block).build
166
179
  else
167
- block ? block : args.first
180
+ block || args.first
168
181
  end
169
182
 
170
183
  @config.instance_variable_set(:"@#{attribute}", value)
@@ -188,30 +201,45 @@ doorkeeper.
188
201
  option :resource_owner_authenticator,
189
202
  as: :authenticate_resource_owner,
190
203
  default: (lambda do |_routes|
191
- ::Rails.logger.warn(I18n.t('doorkeeper.errors.messages.resource_owner_authenticator_not_configured'))
204
+ ::Rails.logger.warn(
205
+ I18n.t('doorkeeper.errors.messages.resource_owner_authenticator_not_configured')
206
+ )
207
+
192
208
  nil
193
209
  end)
194
210
 
195
211
  option :admin_authenticator,
196
212
  as: :authenticate_admin,
197
- default: ->(_routes) {}
213
+ default: (lambda do |_routes|
214
+ ::Rails.logger.warn(
215
+ I18n.t('doorkeeper.errors.messages.admin_authenticator_not_configured')
216
+ )
217
+
218
+ head :forbidden
219
+ end)
198
220
 
199
221
  option :resource_owner_from_credentials,
200
222
  default: (lambda do |_routes|
201
- ::Rails.logger.warn(I18n.t('doorkeeper.errors.messages.credential_flow_not_configured'))
223
+ ::Rails.logger.warn(
224
+ I18n.t('doorkeeper.errors.messages.credential_flow_not_configured')
225
+ )
226
+
202
227
  nil
203
228
  end)
229
+ option :before_successful_authorization, default: ->(_context) {}
230
+ option :after_successful_authorization, default: ->(_context) {}
204
231
  option :before_successful_strategy_response, default: ->(_request) {}
205
232
  option :after_successful_strategy_response,
206
233
  default: ->(_request, _response) {}
207
234
  option :skip_authorization, default: ->(_routes) {}
208
235
  option :access_token_expires_in, default: 7200
209
- option :custom_access_token_expires_in, default: ->(_app) { nil }
236
+ option :custom_access_token_expires_in, default: ->(_context) { nil }
210
237
  option :authorization_code_expires_in, default: 600
211
238
  option :orm, default: :active_record
212
239
  option :native_redirect_uri, default: 'urn:ietf:wg:oauth:2.0:oob'
213
240
  option :active_record_options, default: {}
214
241
  option :grant_flows, default: %w[authorization_code client_credentials]
242
+ option :handle_auth_errors, default: :render
215
243
 
216
244
  # Allows to forbid specific Application redirect URI's by custom rules.
217
245
  # Doesn't forbid any URI by default.
@@ -241,7 +269,6 @@ doorkeeper.
241
269
  #
242
270
  option :force_ssl_in_redirect_uri, default: !Rails.env.development?
243
271
 
244
-
245
272
  # Use a custom class for generating the access token.
246
273
  # https://github.com/doorkeeper-gem/doorkeeper#custom-access-token-generator
247
274
  #
@@ -260,20 +287,39 @@ doorkeeper.
260
287
  default: 'ActionController::Base'
261
288
 
262
289
  attr_reader :reuse_access_token
290
+ attr_reader :api_only
291
+ attr_reader :enforce_content_type
292
+
293
+ def api_only
294
+ @api_only ||= false
295
+ end
296
+
297
+ def enforce_content_type
298
+ @enforce_content_type ||= false
299
+ end
263
300
 
264
301
  def refresh_token_enabled?
265
- @refresh_token_enabled ||= false
266
- !!@refresh_token_enabled
302
+ if defined?(@refresh_token_enabled)
303
+ @refresh_token_enabled
304
+ else
305
+ false
306
+ end
307
+ end
308
+
309
+ def enforce_configured_scopes?
310
+ !!(defined?(@enforce_configured_scopes) && @enforce_configured_scopes)
267
311
  end
268
312
 
269
313
  def enable_application_owner?
270
- @enable_application_owner ||= false
271
- !!@enable_application_owner
314
+ !!(defined?(@enable_application_owner) && @enable_application_owner)
272
315
  end
273
316
 
274
317
  def confirm_application_owner?
275
- @confirm_application_owner ||= false
276
- !!@confirm_application_owner
318
+ !!(defined?(@confirm_application_owner) && @confirm_application_owner)
319
+ end
320
+
321
+ def raise_on_errors?
322
+ handle_auth_errors == :raise
277
323
  end
278
324
 
279
325
  def default_scopes
@@ -289,7 +335,7 @@ doorkeeper.
289
335
  end
290
336
 
291
337
  def client_credentials_methods
292
- @client_credentials ||= %i[from_basic from_params]
338
+ @client_credentials_methods ||= %i[from_basic from_params]
293
339
  end
294
340
 
295
341
  def access_token_methods
@@ -297,16 +343,11 @@ doorkeeper.
297
343
  end
298
344
 
299
345
  def authorization_response_types
300
- @authorization_response_types ||= calculate_authorization_response_types
346
+ @authorization_response_types ||= calculate_authorization_response_types.freeze
301
347
  end
302
348
 
303
349
  def token_grant_types
304
- @token_grant_types ||= calculate_token_grant_types
305
- end
306
-
307
- def native_authorization_code_route
308
- @opt_out_native_route_change ||= false
309
- @opt_out_native_route_change ? '/:code' : '/native'
350
+ @token_grant_types ||= calculate_token_grant_types.freeze
310
351
  end
311
352
 
312
353
  private
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  class Engine < Rails::Engine
3
5
  initializer "doorkeeper.params.filter" do |app|
@@ -17,6 +19,10 @@ module Doorkeeper
17
19
 
18
20
  if defined?(Sprockets) && Sprockets::VERSION.chr.to_i >= 4
19
21
  initializer 'doorkeeper.assets.precompile' do |app|
22
+ # Force users to use:
23
+ # //= link doorkeeper/admin/application.css
24
+ # in Doorkeeper 5 for Sprockets 4 instead of precompile.
25
+ # Add note to official docs & Wiki
20
26
  app.config.assets.precompile += %w[
21
27
  doorkeeper/application.css
22
28
  doorkeeper/admin/application.css
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module Errors
3
5
  class DoorkeeperError < StandardError
@@ -36,10 +38,22 @@ module Doorkeeper
36
38
  end
37
39
  end
38
40
 
39
- class UnableToGenerateToken < DoorkeeperError
40
- end
41
+ class BaseResponseError < DoorkeeperError
42
+ attr_reader :response
41
43
 
42
- class TokenGeneratorNotFound < DoorkeeperError
44
+ def initialize(response)
45
+ @response = response
46
+ end
43
47
  end
48
+
49
+ UnableToGenerateToken = Class.new(DoorkeeperError)
50
+ TokenGeneratorNotFound = Class.new(DoorkeeperError)
51
+ NoOrmCleaner = Class.new(DoorkeeperError)
52
+
53
+ InvalidToken = Class.new BaseResponseError
54
+ TokenExpired = Class.new InvalidToken
55
+ TokenRevoked = Class.new InvalidToken
56
+ TokenUnknown = Class.new InvalidToken
57
+ TokenForbidden = Class.new InvalidToken
44
58
  end
45
59
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module Grape
3
5
  class AuthorizationDecorator < SimpleDelegator
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'doorkeeper/grape/authorization_decorator'
2
4
 
3
5
  module Doorkeeper
@@ -31,7 +33,7 @@ module Doorkeeper
31
33
  end
32
34
 
33
35
  def doorkeeper_token
34
- @_doorkeeper_token ||= OAuth::Token.authenticate(
36
+ @doorkeeper_token ||= OAuth::Token.authenticate(
35
37
  decorated_request,
36
38
  *Doorkeeper.configuration.access_token_methods
37
39
  )
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Define methods that can be called in any controller that inherits from
2
4
  # Doorkeeper::ApplicationMetalController or Doorkeeper::ApplicationController
3
5
  module Doorkeeper
@@ -30,11 +32,11 @@ module Doorkeeper
30
32
 
31
33
  # :doc:
32
34
  def doorkeeper_token
33
- @token ||= OAuth::Token.authenticate request, *config_methods
35
+ @doorkeeper_token ||= OAuth::Token.authenticate request, *config_methods
34
36
  end
35
37
 
36
38
  def config_methods
37
- @methods ||= Doorkeeper.configuration.access_token_methods
39
+ @config_methods ||= Doorkeeper.configuration.access_token_methods
38
40
  end
39
41
 
40
42
  def get_error_response_from_exception(exception)
@@ -51,6 +53,11 @@ module Doorkeeper
51
53
  def skip_authorization?
52
54
  !!instance_exec([@server.current_resource_owner, @pre_auth.client], &Doorkeeper.configuration.skip_authorization)
53
55
  end
56
+
57
+ def enforce_content_type
58
+ return if request.content_type == 'application/x-www-form-urlencoded'
59
+ render json: {}, status: :unsupported_media_type
60
+ end
54
61
  end
55
62
  end
56
63
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module AccessGrantMixin
3
5
  extend ActiveSupport::Concern
@@ -9,6 +11,15 @@ module Doorkeeper
9
11
  include Models::Orderable
10
12
  include Models::Scopes
11
13
 
14
+ # never uses pkce, if pkce migrations were not generated
15
+ def uses_pkce?
16
+ pkce_supported? && code_challenge.present?
17
+ end
18
+
19
+ def pkce_supported?
20
+ respond_to? :code_challenge
21
+ end
22
+
12
23
  module ClassMethods
13
24
  # Searches for Doorkeeper::AccessGrant record with the
14
25
  # specific token value.
@@ -21,6 +32,68 @@ module Doorkeeper
21
32
  def by_token(token)
22
33
  find_by(token: token.to_s)
23
34
  end
35
+
36
+ # Revokes AccessGrant records that have not been revoked and associated
37
+ # with the specific Application and Resource Owner.
38
+ #
39
+ # @param application_id [Integer]
40
+ # ID of the Application
41
+ # @param resource_owner [ActiveRecord::Base]
42
+ # instance of the Resource Owner model
43
+ #
44
+ def revoke_all_for(application_id, resource_owner, clock = Time)
45
+ where(application_id: application_id,
46
+ resource_owner_id: resource_owner.id,
47
+ revoked_at: nil)
48
+ .update_all(revoked_at: clock.now.utc)
49
+ end
50
+
51
+ # Implements PKCE code_challenge encoding without base64 padding as described in the spec.
52
+ # https://tools.ietf.org/html/rfc7636#appendix-A
53
+ # Appendix A. Notes on Implementing Base64url Encoding without Padding
54
+ #
55
+ # This appendix describes how to implement a base64url-encoding
56
+ # function without padding, based upon the standard base64-encoding
57
+ # function that uses padding.
58
+ #
59
+ # To be concrete, example C# code implementing these functions is shown
60
+ # below. Similar code could be used in other languages.
61
+ #
62
+ # static string base64urlencode(byte [] arg)
63
+ # {
64
+ # string s = Convert.ToBase64String(arg); // Regular base64 encoder
65
+ # s = s.Split('=')[0]; // Remove any trailing '='s
66
+ # s = s.Replace('+', '-'); // 62nd char of encoding
67
+ # s = s.Replace('/', '_'); // 63rd char of encoding
68
+ # return s;
69
+ # }
70
+ #
71
+ # An example correspondence between unencoded and encoded values
72
+ # follows. The octet sequence below encodes into the string below,
73
+ # which when decoded, reproduces the octet sequence.
74
+ #
75
+ # 3 236 255 224 193
76
+ #
77
+ # A-z_4ME
78
+ #
79
+ # https://ruby-doc.org/stdlib-2.1.3/libdoc/base64/rdoc/Base64.html#method-i-urlsafe_encode64
80
+ #
81
+ # urlsafe_encode64(bin)
82
+ # Returns the Base64-encoded version of bin. This method complies with
83
+ # "Base 64 Encoding with URL and Filename Safe Alphabet" in RFC 4648.
84
+ # The alphabet uses '-' instead of '+' and '_' instead of '/'.
85
+
86
+ # @param code_verifier [#to_s] a one time use value (any object that responds to `#to_s`)
87
+ #
88
+ # @return [#to_s] An encoded code challenge based on the provided verifier suitable for PKCE validation
89
+ def generate_code_challenge(code_verifier)
90
+ padded_result = Base64.urlsafe_encode64(Digest::SHA256.digest(code_verifier))
91
+ padded_result.split('=')[0] # Remove any trailing '='
92
+ end
93
+
94
+ def pkce_supported?
95
+ new.pkce_supported?
96
+ end
24
97
  end
25
98
  end
26
99
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module AccessTokenMixin
3
5
  extend ActiveSupport::Concern
@@ -47,11 +49,11 @@ module Doorkeeper
47
49
  def revoke_all_for(application_id, resource_owner, clock = Time)
48
50
  where(application_id: application_id,
49
51
  resource_owner_id: resource_owner.id,
50
- revoked_at: nil).
51
- update_all(revoked_at: clock.now.utc)
52
+ revoked_at: nil)
53
+ .update_all(revoked_at: clock.now.utc)
52
54
  end
53
55
 
54
- # Looking for not expired Access Token with a matching set of scopes
56
+ # Looking for not revoked Access Token with a matching set of scopes
55
57
  # that belongs to specific Application and Resource Owner.
56
58
  #
57
59
  # @param application [Doorkeeper::Application]
@@ -70,30 +72,34 @@ module Doorkeeper
70
72
  else
71
73
  resource_owner_or_id
72
74
  end
73
- token = last_authorized_token_for(application.try(:id), resource_owner_id)
74
- if token && scopes_match?(token.scopes, scopes, application.try(:scopes))
75
- token
75
+
76
+ tokens = authorized_tokens_for(application.try(:id), resource_owner_id)
77
+ tokens.detect do |token|
78
+ scopes_match?(token.scopes, scopes, application.try(:scopes))
76
79
  end
77
80
  end
78
81
 
79
- # Checks whether the token scopes match the scopes from the parameters or
80
- # Application scopes (if present).
82
+ # Checks whether the token scopes match the scopes from the parameters
81
83
  #
82
84
  # @param token_scopes [#to_s]
83
85
  # set of scopes (any object that responds to `#to_s`)
84
- # @param param_scopes [String]
86
+ # @param param_scopes [Doorkeeper::OAuth::Scopes]
85
87
  # scopes from params
86
- # @param app_scopes [String]
88
+ # @param app_scopes [Doorkeeper::OAuth::Scopes]
87
89
  # Application scopes
88
90
  #
89
- # @return [Boolean] true if all scopes are blank or matches
91
+ # @return [Boolean] true if the param scopes match the token scopes,
92
+ # and all the param scopes are defined in the application (or in the
93
+ # server configuration if the application doesn't define any scopes),
90
94
  # and false in other cases
91
95
  #
92
96
  def scopes_match?(token_scopes, param_scopes, app_scopes)
93
- (!token_scopes.present? && !param_scopes.present?) ||
94
- Doorkeeper::OAuth::Helpers::ScopeChecker.match?(
95
- token_scopes.to_s,
96
- param_scopes,
97
+ return true if token_scopes.empty? && param_scopes.empty?
98
+
99
+ (token_scopes.sort == param_scopes.sort) &&
100
+ Doorkeeper::OAuth::Helpers::ScopeChecker.valid?(
101
+ param_scopes.to_s,
102
+ Doorkeeper.configuration.scopes,
97
103
  app_scopes
98
104
  )
99
105
  end
@@ -118,9 +124,8 @@ module Doorkeeper
118
124
  def find_or_create_for(application, resource_owner_id, scopes, expires_in, use_refresh_token)
119
125
  if Doorkeeper.configuration.reuse_access_token
120
126
  access_token = matching_token_for(application, resource_owner_id, scopes)
121
- if access_token && !access_token.expired?
122
- return access_token
123
- end
127
+
128
+ return access_token if access_token && !access_token.expired?
124
129
  end
125
130
 
126
131
  create!(
@@ -132,7 +137,7 @@ module Doorkeeper
132
137
  )
133
138
  end
134
139
 
135
- # Looking for not revoked Access Token record that belongs to specific
140
+ # Looking for not revoked Access Token records that belongs to specific
136
141
  # Application and Resource Owner.
137
142
  #
138
143
  # @param application_id [Integer]
@@ -140,14 +145,28 @@ module Doorkeeper
140
145
  # @param resource_owner_id [Integer]
141
146
  # ID of the Resource Owner model instance
142
147
  #
148
+ # @return [Doorkeeper::AccessToken] array of matching AccessToken objects
149
+ #
150
+ def authorized_tokens_for(application_id, resource_owner_id)
151
+ ordered_by(:created_at, :desc)
152
+ .where(application_id: application_id,
153
+ resource_owner_id: resource_owner_id,
154
+ revoked_at: nil)
155
+ end
156
+
157
+ # Convenience method for backwards-compatibility, return the last
158
+ # matching token for the given Application and Resource Owner.
159
+ #
160
+ # @param application_id [Integer]
161
+ # ID of the Application model instance
162
+ # @param resource_owner_id [Integer]
163
+ # ID of the Resource Owner model instance
164
+ #
143
165
  # @return [Doorkeeper::AccessToken, nil] matching AccessToken object or
144
166
  # nil if nothing was found
145
167
  #
146
168
  def last_authorized_token_for(application_id, resource_owner_id)
147
- ordered_by(:created_at, :desc).
148
- find_by(application_id: application_id,
149
- resource_owner_id: resource_owner_id,
150
- revoked_at: nil)
169
+ authorized_tokens_for(application_id, resource_owner_id).first
151
170
  end
152
171
  end
153
172
 
@@ -170,8 +189,8 @@ module Doorkeeper
170
189
  def as_json(_options = {})
171
190
  {
172
191
  resource_owner_id: resource_owner_id,
173
- scopes: scopes,
174
- expires_in_seconds: expires_in_seconds,
192
+ scope: scopes,
193
+ expires_in: expires_in_seconds,
175
194
  application: { uid: application.try(:uid) },
176
195
  created_at: created_at.to_i
177
196
  }
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module ApplicationMixin
3
5
  extend ActiveSupport::Concern
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module Models
3
5
  module Accessible
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module Models
3
5
  module Expirable
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module Models
3
5
  module Orderable
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module Models
3
5
  module Ownership