doorkeeper 5.3.3 → 5.4.0.rc1

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 (120) hide show
  1. checksums.yaml +4 -4
  2. data/Appraisals +0 -14
  3. data/CHANGELOG.md +35 -10
  4. data/Dangerfile +7 -7
  5. data/Dockerfile +2 -2
  6. data/Gemfile +9 -9
  7. data/README.md +6 -4
  8. data/app/controllers/doorkeeper/applications_controller.rb +7 -7
  9. data/app/controllers/doorkeeper/authorizations_controller.rb +31 -12
  10. data/app/controllers/doorkeeper/authorized_applications_controller.rb +3 -3
  11. data/app/controllers/doorkeeper/tokens_controller.rb +57 -20
  12. data/app/views/doorkeeper/applications/show.html.erb +19 -2
  13. data/bin/console +14 -0
  14. data/config/locales/en.yml +3 -1
  15. data/doorkeeper.gemspec +1 -1
  16. data/gemfiles/rails_5_0.gemfile +8 -7
  17. data/gemfiles/rails_5_1.gemfile +8 -7
  18. data/gemfiles/rails_5_2.gemfile +8 -7
  19. data/gemfiles/rails_6_0.gemfile +8 -7
  20. data/gemfiles/rails_master.gemfile +8 -7
  21. data/lib/doorkeeper.rb +106 -79
  22. data/lib/doorkeeper/config.rb +40 -17
  23. data/lib/doorkeeper/config/abstract_builder.rb +28 -0
  24. data/lib/doorkeeper/config/option.rb +28 -14
  25. data/lib/doorkeeper/grape/helpers.rb +1 -1
  26. data/lib/doorkeeper/models/access_grant_mixin.rb +9 -11
  27. data/lib/doorkeeper/models/access_token_mixin.rb +100 -41
  28. data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
  29. data/lib/doorkeeper/models/concerns/revocable.rb +1 -1
  30. data/lib/doorkeeper/models/concerns/scopes.rb +5 -1
  31. data/lib/doorkeeper/models/concerns/secret_storable.rb +1 -3
  32. data/lib/doorkeeper/oauth/authorization/code.rb +14 -5
  33. data/lib/doorkeeper/oauth/authorization/context.rb +2 -2
  34. data/lib/doorkeeper/oauth/authorization/token.rb +7 -11
  35. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +4 -4
  36. data/lib/doorkeeper/oauth/authorization_code_request.rb +18 -8
  37. data/lib/doorkeeper/oauth/base_request.rb +11 -19
  38. data/lib/doorkeeper/oauth/client.rb +1 -1
  39. data/lib/doorkeeper/oauth/client/credentials.rb +2 -4
  40. data/lib/doorkeeper/oauth/client_credentials/creator.rb +25 -7
  41. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +3 -2
  42. data/lib/doorkeeper/oauth/client_credentials/validator.rb +1 -1
  43. data/lib/doorkeeper/oauth/client_credentials_request.rb +8 -7
  44. data/lib/doorkeeper/oauth/code_request.rb +1 -1
  45. data/lib/doorkeeper/oauth/code_response.rb +6 -2
  46. data/lib/doorkeeper/oauth/error_response.rb +2 -4
  47. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +1 -5
  48. data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
  49. data/lib/doorkeeper/oauth/invalid_token_response.rb +2 -2
  50. data/lib/doorkeeper/oauth/password_access_token_request.rb +3 -5
  51. data/lib/doorkeeper/oauth/pre_authorization.rb +32 -27
  52. data/lib/doorkeeper/oauth/refresh_token_request.rb +18 -22
  53. data/lib/doorkeeper/oauth/token.rb +1 -1
  54. data/lib/doorkeeper/oauth/token_introspection.rb +3 -3
  55. data/lib/doorkeeper/oauth/token_request.rb +2 -2
  56. data/lib/doorkeeper/oauth/token_response.rb +1 -1
  57. data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +7 -2
  58. data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +6 -2
  59. data/lib/doorkeeper/orm/active_record/mixins/application.rb +9 -64
  60. data/lib/doorkeeper/rails/routes.rb +13 -17
  61. data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
  62. data/lib/doorkeeper/rails/routes/mapper.rb +2 -2
  63. data/lib/doorkeeper/rails/routes/registry.rb +45 -0
  64. data/lib/doorkeeper/request/strategy.rb +2 -2
  65. data/lib/doorkeeper/server.rb +3 -3
  66. data/lib/doorkeeper/version.rb +3 -3
  67. data/lib/generators/doorkeeper/confidential_applications_generator.rb +1 -1
  68. data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
  69. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +2 -0
  70. data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +2 -0
  71. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +2 -0
  72. data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
  73. data/lib/generators/doorkeeper/templates/initializer.rb +39 -3
  74. data/lib/generators/doorkeeper/templates/migration.rb.erb +2 -0
  75. data/spec/controllers/applications_controller_spec.rb +2 -2
  76. data/spec/controllers/authorizations_controller_spec.rb +165 -30
  77. data/spec/controllers/tokens_controller_spec.rb +6 -5
  78. data/spec/dummy/app/helpers/application_helper.rb +1 -1
  79. data/spec/dummy/app/models/user.rb +5 -1
  80. data/spec/dummy/config/application.rb +6 -4
  81. data/spec/dummy/config/boot.rb +4 -4
  82. data/spec/dummy/config/environment.rb +1 -1
  83. data/spec/dummy/config/routes.rb +4 -4
  84. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +2 -2
  85. data/spec/dummy/db/schema.rb +3 -1
  86. data/spec/factories.rb +1 -1
  87. data/spec/generators/enable_polymorphic_resource_owner_generator_spec.rb +47 -0
  88. data/spec/lib/config_spec.rb +15 -11
  89. data/spec/lib/models/revocable_spec.rb +2 -3
  90. data/spec/lib/models/scopes_spec.rb +8 -0
  91. data/spec/lib/oauth/authorization_code_request_spec.rb +25 -15
  92. data/spec/lib/oauth/base_request_spec.rb +6 -20
  93. data/spec/lib/oauth/client_credentials/creator_spec.rb +90 -89
  94. data/spec/lib/oauth/client_credentials/issuer_spec.rb +84 -86
  95. data/spec/lib/oauth/client_credentials/validation_spec.rb +38 -40
  96. data/spec/lib/oauth/client_credentials_request_spec.rb +5 -4
  97. data/spec/lib/oauth/code_request_spec.rb +1 -1
  98. data/spec/lib/oauth/code_response_spec.rb +5 -1
  99. data/spec/lib/oauth/error_response_spec.rb +1 -1
  100. data/spec/lib/oauth/password_access_token_request_spec.rb +24 -13
  101. data/spec/lib/oauth/pre_authorization_spec.rb +13 -18
  102. data/spec/lib/oauth/refresh_token_request_spec.rb +19 -30
  103. data/spec/lib/oauth/token_request_spec.rb +14 -7
  104. data/spec/lib/option_spec.rb +51 -0
  105. data/spec/lib/stale_records_cleaner_spec.rb +18 -5
  106. data/spec/models/doorkeeper/access_grant_spec.rb +18 -4
  107. data/spec/models/doorkeeper/access_token_spec.rb +507 -479
  108. data/spec/models/doorkeeper/application_spec.rb +22 -62
  109. data/spec/requests/endpoints/token_spec.rb +5 -1
  110. data/spec/requests/flows/authorization_code_errors_spec.rb +4 -1
  111. data/spec/requests/flows/authorization_code_spec.rb +6 -1
  112. data/spec/requests/flows/client_credentials_spec.rb +41 -0
  113. data/spec/requests/flows/refresh_token_spec.rb +16 -8
  114. data/spec/requests/flows/revoke_token_spec.rb +143 -104
  115. data/spec/support/helpers/access_token_request_helper.rb +1 -0
  116. data/spec/support/helpers/authorization_request_helper.rb +4 -4
  117. data/spec/support/helpers/config_helper.rb +1 -1
  118. data/spec/support/shared/controllers_shared_context.rb +2 -2
  119. data/spec/support/shared/models_shared_examples.rb +6 -4
  120. metadata +16 -5
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module Rails
5
+ # Abstract router module that implements base behavior
6
+ # for generating and mapping Rails routes.
7
+ #
8
+ # Could be reused in Doorkeeper extensions.
9
+ #
10
+ module AbstractRouter
11
+ extend ActiveSupport::Concern
12
+
13
+ attr_reader :routes
14
+
15
+ def initialize(routes, mapper = Mapper.new, &block)
16
+ @routes = routes
17
+ @mapping = mapper.map(&block)
18
+ end
19
+
20
+ def generate_routes!(**_options)
21
+ raise NotImplementedError, "must be redefined for #{self.class.name}!"
22
+ end
23
+
24
+ private
25
+
26
+ def map_route(name, method)
27
+ return if @mapping.skipped?(name)
28
+
29
+ send(method, @mapping[name])
30
+
31
+ mapping[name] = @mapping[name]
32
+ end
33
+ end
34
+ end
35
+ end
@@ -4,8 +4,8 @@ module Doorkeeper
4
4
  module Rails
5
5
  class Routes # :nodoc:
6
6
  class Mapper
7
- def initialize
8
- @mapping = Mapping.new
7
+ def initialize(mapping = Mapping.new)
8
+ @mapping = mapping
9
9
  end
10
10
 
11
11
  def map(&block)
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module Rails
5
+ class Routes
6
+ # Thread-safe registry of any Doorkeeper additional routes.
7
+ # Used to allow implementing of Doorkeeper extensions that must
8
+ # use their own routes.
9
+ #
10
+ module Registry
11
+ ROUTES_ACCESS_LOCK = Mutex.new
12
+ ROUTES_DEFINITION_LOCK = Mutex.new
13
+
14
+ InvalidRouterClass = Class.new(StandardError)
15
+
16
+ # Collection of additional registered routes for Doorkeeper.
17
+ #
18
+ # @return [Array<Object>] set of registered routes
19
+ #
20
+ def registered_routes
21
+ ROUTES_DEFINITION_LOCK.synchronize do
22
+ @registered_routes ||= Set.new
23
+ end
24
+ end
25
+
26
+ # Registers additional routes in the Doorkeeper registry
27
+ #
28
+ # @param [Object] routes
29
+ # routes class
30
+ #
31
+ def register_routes(routes)
32
+ if !routes.is_a?(Module) || !(routes < AbstractRouter)
33
+ raise InvalidRouterClass, "routes class must include Doorkeeper::Rails::AbstractRouter"
34
+ end
35
+
36
+ ROUTES_ACCESS_LOCK.synchronize do
37
+ registered_routes << routes
38
+ end
39
+ end
40
+
41
+ alias register register_routes
42
+ end
43
+ end
44
+ end
45
+ end
@@ -3,12 +3,12 @@
3
3
  module Doorkeeper
4
4
  module Request
5
5
  class Strategy
6
- attr_accessor :server
6
+ attr_reader :server
7
7
 
8
8
  delegate :authorize, to: :request
9
9
 
10
10
  def initialize(server)
11
- self.server = server
11
+ @server = server
12
12
  end
13
13
 
14
14
  def request
@@ -2,19 +2,19 @@
2
2
 
3
3
  module Doorkeeper
4
4
  class Server
5
- attr_accessor :context
5
+ attr_reader :context
6
6
 
7
7
  def initialize(context = nil)
8
8
  @context = context
9
9
  end
10
10
 
11
11
  def authorization_request(strategy)
12
- klass = Request.authorization_strategy strategy
12
+ klass = Request.authorization_strategy(strategy)
13
13
  klass.new(self)
14
14
  end
15
15
 
16
16
  def token_request(strategy)
17
- klass = Request.token_strategy strategy
17
+ klass = Request.token_strategy(strategy)
18
18
  klass.new(self)
19
19
  end
20
20
 
@@ -8,9 +8,9 @@ module Doorkeeper
8
8
  module VERSION
9
9
  # Semantic versioning
10
10
  MAJOR = 5
11
- MINOR = 3
12
- TINY = 3
13
- PRE = nil
11
+ MINOR = 4
12
+ TINY = 0
13
+ PRE = "rc1"
14
14
 
15
15
  # Full version number
16
16
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
@@ -12,7 +12,7 @@ module Doorkeeper
12
12
  source_root File.expand_path("templates", __dir__)
13
13
  desc "Add confidential column to Doorkeeper applications"
14
14
 
15
- def pkce
15
+ def confidential_applications
16
16
  migration_template(
17
17
  "add_confidential_to_applications.rb.erb",
18
18
  "db/migrate/add_confidential_to_applications.rb",
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require "rails/generators/active_record"
5
+
6
+ module Doorkeeper
7
+ # Generates migration with polymorphic resource owner required
8
+ # database columns for Doorkeeper Access Token and Access Grant
9
+ # models.
10
+ #
11
+ class EnablePolymorphicResourceOwnerGenerator < ::Rails::Generators::Base
12
+ include ::Rails::Generators::Migration
13
+ source_root File.expand_path("templates", __dir__)
14
+ desc "Provide support for polymorphic Resource Owner."
15
+
16
+ def enable_polymorphic_resource_owner
17
+ migration_template(
18
+ "enable_polymorphic_resource_owner_migration.rb.erb",
19
+ "db/migrate/enable_polymorphic_resource_owner.rb",
20
+ migration_version: migration_version,
21
+ )
22
+ gsub_file(
23
+ "config/initializers/doorkeeper.rb",
24
+ "# use_polymorphic_resource_owner",
25
+ "use_polymorphic_resource_owner",
26
+ )
27
+ end
28
+
29
+ def self.next_migration_number(dirname)
30
+ ActiveRecord::Generators::Base.next_migration_number(dirname)
31
+ end
32
+
33
+ private
34
+
35
+ def migration_version
36
+ "[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
37
+ end
38
+ end
39
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class AddOwnerToApplication < ActiveRecord::Migration<%= migration_version %>
2
4
  def change
3
5
  add_column :oauth_applications, :owner_id, :integer, null: true
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class AddPreviousRefreshTokenToAccessTokens < ActiveRecord::Migration<%= migration_version %>
2
4
  def change
3
5
  add_column(
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class EnablePkce < ActiveRecord::Migration<%= migration_version %>
2
4
  def change
3
5
  add_column :oauth_access_grants, :code_challenge, :string, null: true
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ class EnablePolymorphicResourceOwner < ActiveRecord::Migration<%= migration_version %>
4
+ def change
5
+ add_column :oauth_access_tokens, :resource_owner_type, :string
6
+ add_column :oauth_access_grants, :resource_owner_type, :string
7
+ change_column_null :oauth_access_grants, :resource_owner_type, false
8
+
9
+ add_index :oauth_access_tokens,
10
+ [:resource_owner_id, :resource_owner_type],
11
+ name: 'polymorphic_owner_oauth_access_tokens'
12
+
13
+ add_index :oauth_access_grants,
14
+ [:resource_owner_id, :resource_owner_type],
15
+ name: 'polymorphic_owner_oauth_access_grants'
16
+ end
17
+ end
@@ -58,6 +58,23 @@ Doorkeeper.configure do
58
58
  # end
59
59
  # end
60
60
 
61
+ # Enables polymorphic Resource Owner association for Access Tokens and Access Grants.
62
+ # By default this option is disabled.
63
+ #
64
+ # Make sure you properly setup you database and have all the required columns (run
65
+ # `bundle exec rails generate doorkeeper:enable_polymorphic_resource_owner` and execute Rails
66
+ # migrations).
67
+ #
68
+ # If this option enabled, Doorkeeper will store not only Resource Owner primary key
69
+ # value, but also it's type (class name). See "Polymorphic Associations" section of
70
+ # Rails guides: https://guides.rubyonrails.org/association_basics.html#polymorphic-associations
71
+ #
72
+ # [NOTE] If you apply this option on already existing project don't forget to manually
73
+ # update `resource_owner_type` column in the database and fix migration template as it will
74
+ # set NOT NULL constraint for Access Grants table.
75
+ #
76
+ # use_polymorphic_resource_owner
77
+
61
78
  # If you are planning to use Doorkeeper in Rails 5 API-only application, then you might
62
79
  # want to use API mode that will skip all the views management and change the way how
63
80
  # Doorkeeper responds to a requests.
@@ -360,6 +377,17 @@ Doorkeeper.configure do
360
377
  # client.grant_flows.include?(grant_flow)
361
378
  # end
362
379
 
380
+ # If you need arbitrary Resource Owner-Client authorization you can enable this option
381
+ # and implement the check your need. Config option must respond to #call and return
382
+ # true in case resource owner authorized for the specific application or false in other
383
+ # cases.
384
+ #
385
+ # Be default all Resource Owners are authorized to any Client (application).
386
+ #
387
+ # authorize_resource_owner_for_client do |client, resource_owner|
388
+ # resource_owner.admin? || client.owners_whitelist.include?(resource_owner)
389
+ # end
390
+
363
391
  # Hook into the strategies' request & response life-cycle in case your
364
392
  # application needs advanced customization or logging:
365
393
  #
@@ -372,17 +400,25 @@ Doorkeeper.configure do
372
400
  # end
373
401
 
374
402
  # Hook into Authorization flow in order to implement Single Sign Out
375
- # or add any other functionality.
403
+ # or add any other functionality. Inside the block you have an access
404
+ # to `controller` (authorizations controller instance) and `context`
405
+ # (Doorkeeper::OAuth::Hooks::Context instance) which provides pre auth
406
+ # or auth objects with issued token based on hook type (before or after).
376
407
  #
377
- # before_successful_authorization do |controller|
408
+ # before_successful_authorization do |controller, context|
378
409
  # Rails.logger.info(controller.request.params.inspect)
410
+ #
411
+ # Rails.logger.info(context.pre_auth.inspect)
379
412
  # end
380
413
  #
381
- # after_successful_authorization do |controller|
414
+ # after_successful_authorization do |controller, context|
382
415
  # controller.session[:logout_urls] <<
383
416
  # Doorkeeper::Application
384
417
  # .find_by(controller.request.params.slice(:redirect_uri))
385
418
  # .logout_uri
419
+ #
420
+ # Rails.logger.info(context.auth.inspect)
421
+ # Rails.logger.info(context.issued_token)
386
422
  # end
387
423
 
388
424
  # Under some circumstances you might want to have applications auto-approved,
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class CreateDoorkeeperTables < ActiveRecord::Migration<%= migration_version %>
2
4
  def change
3
5
  create_table :oauth_applications do |t|
@@ -167,8 +167,8 @@ module Doorkeeper
167
167
 
168
168
  # We don't know the application secret here (because its hashed) so we can not assert its text on the page
169
169
  # Instead, we read it from the page and then check if it matches the application secret
170
- code_element = %r{<code.*id="secret".*>(.*)<\/code>}.match(response.body)
171
- secret_from_page = code_element[1]
170
+ code_element = /code.*id="secret">\s*\K([^<]*)/m.match(response.body)
171
+ secret_from_page = code_element[1].strip
172
172
 
173
173
  expect(response.body).to have_selector("code#application_id", text: application.uid)
174
174
  expect(response.body).to have_selector("code#secret")
@@ -16,7 +16,14 @@ describe Doorkeeper::AuthorizationsController, "implicit grant flow" do
16
16
 
17
17
  let(:client) { FactoryBot.create :application }
18
18
  let(:user) { User.create!(name: "Joe", password: "sekret") }
19
- let(:access_token) { FactoryBot.build :access_token, resource_owner_id: user.id, application_id: client.id, scopes: "default" }
19
+
20
+ let(:access_token) do
21
+ FactoryBot.build :access_token,
22
+ resource_owner_id: user.id,
23
+ resource_owner_type: user.class.name,
24
+ application_id: client.id,
25
+ scopes: "default"
26
+ end
20
27
 
21
28
  before do
22
29
  Doorkeeper.configure do
@@ -136,6 +143,37 @@ describe Doorkeeper::AuthorizationsController, "implicit grant flow" do
136
143
  end
137
144
  end
138
145
 
146
+ context "when user cannot access application" do
147
+ before do
148
+ allow(Doorkeeper.configuration).to receive(:authorize_resource_owner_for_client).and_return(->(*_) { false })
149
+ post :create, params: {
150
+ client_id: client.uid,
151
+ response_type: "token",
152
+ redirect_uri: client.redirect_uri,
153
+ }
154
+ end
155
+
156
+ let(:response_json_body) { JSON.parse(response.body) }
157
+
158
+ it "renders 400 error" do
159
+ expect(response.status).to eq 401
160
+ end
161
+
162
+ it "includes error name" do
163
+ expect(response_json_body["error"]).to eq("invalid_client")
164
+ end
165
+
166
+ it "includes error description" do
167
+ expect(response_json_body["error_description"]).to eq(
168
+ translated_error_message(:invalid_client),
169
+ )
170
+ end
171
+
172
+ it "does not issue any access token" do
173
+ expect(Doorkeeper::AccessToken.all).to be_empty
174
+ end
175
+ end
176
+
139
177
  context "when other error happens" do
140
178
  before do
141
179
  default_scopes_exist :public
@@ -207,6 +245,39 @@ describe Doorkeeper::AuthorizationsController, "implicit grant flow" do
207
245
  end
208
246
  end
209
247
 
248
+ context "when user cannot access application" do
249
+ before do
250
+ allow(Doorkeeper.configuration).to receive(:api_only).and_return(true)
251
+ allow(Doorkeeper.configuration).to receive(:authorize_resource_owner_for_client).and_return(->(*_) { false })
252
+
253
+ post :create, params: {
254
+ client_id: client.uid,
255
+ response_type: "token",
256
+ redirect_uri: client.redirect_uri,
257
+ }
258
+ end
259
+
260
+ let(:response_json_body) { JSON.parse(response.body) }
261
+
262
+ it "renders 400 error" do
263
+ expect(response.status).to eq 401
264
+ end
265
+
266
+ it "includes error name" do
267
+ expect(response_json_body["error"]).to eq("invalid_client")
268
+ end
269
+
270
+ it "includes error description" do
271
+ expect(response_json_body["error_description"]).to eq(
272
+ translated_error_message(:invalid_client),
273
+ )
274
+ end
275
+
276
+ it "does not issue any access token" do
277
+ expect(Doorkeeper::AccessToken.all).to be_empty
278
+ end
279
+ end
280
+
210
281
  context "when other error happens" do
211
282
  before do
212
283
  allow(Doorkeeper.config).to receive(:api_only).and_return(true)
@@ -287,12 +358,14 @@ describe Doorkeeper::AuthorizationsController, "implicit grant flow" do
287
358
 
288
359
  it "should call :before_successful_authorization callback" do
289
360
  expect(Doorkeeper.config)
290
- .to receive_message_chain(:before_successful_authorization, :call).with(instance_of(described_class))
361
+ .to receive_message_chain(:before_successful_authorization, :call)
362
+ .with(instance_of(described_class), instance_of(Doorkeeper::OAuth::Hooks::Context))
291
363
  end
292
364
 
293
365
  it "should call :after_successful_authorization callback" do
294
366
  expect(Doorkeeper.config)
295
- .to receive_message_chain(:after_successful_authorization, :call).with(instance_of(described_class))
367
+ .to receive_message_chain(:after_successful_authorization, :call)
368
+ .with(instance_of(described_class), instance_of(Doorkeeper::OAuth::Hooks::Context))
296
369
  end
297
370
  end
298
371
 
@@ -482,46 +555,106 @@ describe Doorkeeper::AuthorizationsController, "implicit grant flow" do
482
555
  end
483
556
 
484
557
  describe "GET #new with errors" do
485
- before do
486
- default_scopes_exist :public
487
- get :new, params: { an_invalid: "request" }
488
- end
558
+ context "without valid params" do
559
+ before do
560
+ default_scopes_exist :public
561
+ get :new, params: { an_invalid: "request" }
562
+ end
489
563
 
490
- it "does not redirect" do
491
- expect(response).to_not be_redirect
564
+ it "does not redirect" do
565
+ expect(response).to_not be_redirect
566
+ end
567
+
568
+ it "does not issue any token" do
569
+ expect(Doorkeeper::AccessGrant.count).to eq 0
570
+ expect(Doorkeeper::AccessToken.count).to eq 0
571
+ end
492
572
  end
493
573
 
494
- it "does not issue any token" do
495
- expect(Doorkeeper::AccessGrant.count).to eq 0
496
- expect(Doorkeeper::AccessToken.count).to eq 0
574
+ context "when user cannot access application" do
575
+ before do
576
+ allow(Doorkeeper.configuration).to receive(:authorize_resource_owner_for_client).and_return(->(*_) { false })
577
+
578
+ get :new, params: {
579
+ client_id: client.uid,
580
+ response_type: "token",
581
+ redirect_uri: client.redirect_uri,
582
+ }
583
+ end
584
+
585
+ it "does not redirect" do
586
+ expect(response).to_not be_redirect
587
+ end
588
+
589
+ it "does not issue any token" do
590
+ expect(Doorkeeper::AccessGrant.count).to eq 0
591
+ expect(Doorkeeper::AccessToken.count).to eq 0
592
+ end
497
593
  end
498
594
  end
499
595
 
500
596
  describe "GET #new in API mode with errors" do
501
- let(:response_json_body) { JSON.parse(response.body) }
502
-
503
597
  before do
504
- default_scopes_exist :public
505
598
  allow(Doorkeeper.configuration).to receive(:api_only).and_return(true)
506
- get :new, params: { an_invalid: "request" }
599
+ default_scopes_exist :public
507
600
  end
508
601
 
509
- it "should render bad request" do
510
- expect(response).to have_http_status(:bad_request)
511
- end
602
+ context "without valid params" do
603
+ before do
604
+ get :new, params: { an_invalid: "request" }
605
+ end
512
606
 
513
- it "includes error in body" do
514
- expect(response_json_body["error"]).to eq("invalid_request")
515
- end
607
+ let(:response_json_body) { JSON.parse(response.body) }
608
+
609
+ it "should render bad request" do
610
+ expect(response).to have_http_status(:bad_request)
611
+ end
612
+
613
+ it "includes error in body" do
614
+ expect(response_json_body["error"]).to eq("invalid_request")
615
+ end
516
616
 
517
- it "includes error description in body" do
518
- expect(response_json_body["error_description"])
519
- .to eq(translated_invalid_request_error_message(:missing_param, :client_id))
617
+ it "includes error description in body" do
618
+ expect(response_json_body["error_description"])
619
+ .to eq(translated_invalid_request_error_message(:missing_param, :client_id))
620
+ end
621
+
622
+ it "does not issue any token" do
623
+ expect(Doorkeeper::AccessGrant.count).to eq 0
624
+ expect(Doorkeeper::AccessToken.count).to eq 0
625
+ end
520
626
  end
521
627
 
522
- it "does not issue any token" do
523
- expect(Doorkeeper::AccessGrant.count).to eq 0
524
- expect(Doorkeeper::AccessToken.count).to eq 0
628
+ context "when user cannot access application" do
629
+ before do
630
+ allow(Doorkeeper.configuration).to receive(:authorize_resource_owner_for_client).and_return(->(*_) { false })
631
+
632
+ get :new, params: {
633
+ client_id: client.uid,
634
+ response_type: "token",
635
+ redirect_uri: client.redirect_uri,
636
+ }
637
+ end
638
+
639
+ let(:response_json_body) { JSON.parse(response.body) }
640
+
641
+ it "should render bad request" do
642
+ expect(response).to have_http_status(:bad_request)
643
+ end
644
+
645
+ it "includes error in body" do
646
+ expect(response_json_body["error"]).to eq("invalid_client")
647
+ end
648
+
649
+ it "includes error description in body" do
650
+ expect(response_json_body["error_description"])
651
+ .to eq(translated_error_message(:invalid_client))
652
+ end
653
+
654
+ it "does not issue any token" do
655
+ expect(Doorkeeper::AccessGrant.count).to eq 0
656
+ expect(Doorkeeper::AccessToken.count).to eq 0
657
+ end
525
658
  end
526
659
  end
527
660
 
@@ -538,12 +671,14 @@ describe Doorkeeper::AuthorizationsController, "implicit grant flow" do
538
671
 
539
672
  it "should call :before_successful_authorization callback" do
540
673
  expect(Doorkeeper.configuration)
541
- .to receive_message_chain(:before_successful_authorization, :call).with(instance_of(described_class))
674
+ .to receive_message_chain(:before_successful_authorization, :call)
675
+ .with(instance_of(described_class), instance_of(Doorkeeper::OAuth::Hooks::Context))
542
676
  end
543
677
 
544
678
  it "should call :after_successful_authorization callback" do
545
679
  expect(Doorkeeper.configuration)
546
- .to receive_message_chain(:after_successful_authorization, :call).with(instance_of(described_class))
680
+ .to receive_message_chain(:after_successful_authorization, :call)
681
+ .with(instance_of(described_class), instance_of(Doorkeeper::OAuth::Hooks::Context))
547
682
  end
548
683
  end
549
684