doorkeeper 3.0.1 → 3.1.0

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/.hound.yml +4 -0
  3. data/.travis.yml +5 -1
  4. data/NEWS.md +12 -0
  5. data/README.md +8 -11
  6. data/app/assets/stylesheets/doorkeeper/admin/application.css +1 -5
  7. data/app/views/layouts/doorkeeper/admin.html.erb +5 -2
  8. data/doorkeeper.gemspec +1 -1
  9. data/lib/doorkeeper/helpers/controller.rb +2 -0
  10. data/lib/doorkeeper/oauth/client_credentials/creator.rb +3 -4
  11. data/lib/doorkeeper/oauth/error.rb +5 -1
  12. data/lib/doorkeeper/orm/active_record.rb +4 -3
  13. data/lib/doorkeeper/rails/helpers.rb +12 -2
  14. data/lib/doorkeeper/request.rb +18 -8
  15. data/lib/doorkeeper/request/authorization_code.rb +10 -15
  16. data/lib/doorkeeper/request/client_credentials.rb +9 -15
  17. data/lib/doorkeeper/request/code.rb +7 -13
  18. data/lib/doorkeeper/request/password.rb +10 -15
  19. data/lib/doorkeeper/request/refresh_token.rb +11 -13
  20. data/lib/doorkeeper/request/strategy.rb +17 -0
  21. data/lib/doorkeeper/request/token.rb +7 -13
  22. data/lib/doorkeeper/server.rb +2 -2
  23. data/lib/doorkeeper/version.rb +1 -1
  24. data/spec/controllers/protected_resources_controller_spec.rb +95 -1
  25. data/spec/controllers/tokens_controller_spec.rb +30 -0
  26. data/spec/lib/oauth/client_credentials/creator_spec.rb +25 -1
  27. data/spec/lib/oauth/error_response_spec.rb +7 -7
  28. data/spec/lib/oauth/error_spec.rb +9 -5
  29. data/spec/lib/oauth/scopes_spec.rb +1 -1
  30. data/spec/lib/request/strategy_spec.rb +53 -0
  31. data/spec/lib/server_spec.rb +1 -1
  32. data/spec/models/doorkeeper/access_grant_spec.rb +5 -5
  33. data/spec/models/doorkeeper/access_token_spec.rb +2 -2
  34. metadata +8 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6a81fba54edf374cfc12827a6de4b83736c0ad02
4
- data.tar.gz: 90ac8eaf779f57d66a1957bbb245d29fec53ecfa
3
+ metadata.gz: 03417189314de7b84fcfa05699c35a0346a55035
4
+ data.tar.gz: e4026de8e9ed39d2bb270abc9efc4e1ccca20775
5
5
  SHA512:
6
- metadata.gz: b5fe713de5da62552891c73ad8ccd85f07f3e71ec03418c5d9ae363ea762cae8cdb73d1ab976a602af172cca120e4db3845f27ea9307b980ce5ff34ef2fa5c2a
7
- data.tar.gz: 861e8d86128858ca338912e096737267c0254092ae4c5054c97b2193be467c42d7487fd7e464646bca648a8ccc2be631936f65d93a77697d67f1ef4e14864820
6
+ metadata.gz: bbe0a1693809bfc8802a66c50df30a128a527a3f239114ffdc69d46e948ac0516594fe3872f3624157632e91078a0ad64aa1f98932b26bdf389228b22bed246b
7
+ data.tar.gz: 6d434e7dc34b65d1022914f8fd348c9d1c8e6ef41bb30761411eb0c693531ccb12c87c237c1e54fbcbee11a8dd0bf68c82768a6801f273dab2bcaf1fe96afea6
data/.hound.yml CHANGED
@@ -1,3 +1,7 @@
1
+ AllCops:
2
+ Exclude:
3
+ - "spec/dummy/db/*"
4
+
1
5
  LineLength:
2
6
  Exclude:
3
7
  - spec/**/*
data/.travis.yml CHANGED
@@ -1,5 +1,6 @@
1
- language: ruby
2
1
  cache: bundler
2
+ language: ruby
3
+ sudo: false
3
4
 
4
5
  rvm:
5
6
  - 2.0
@@ -13,6 +14,9 @@ env:
13
14
  - rails=4.2.0
14
15
 
15
16
  matrix:
17
+ exclude:
18
+ - env: rails=3.2.0
19
+ rvm: jruby-head
16
20
  exclude:
17
21
  - env: rails=3.2.0
18
22
  rvm: 2.2
data/NEWS.md CHANGED
@@ -4,6 +4,18 @@ User-visible changes worth mentioning.
4
4
 
5
5
  ---
6
6
 
7
+ ## 3.1.0
8
+
9
+ - [#736] Existing valid tokens are now reused in client_credentials flow
10
+ - [#749] Allow user to raise authorization error with custom messages.
11
+ Under `resource_owner_authenticator` block a user can
12
+ `raise Doorkeeper::Errors::DoorkeeperError.new('custom_message')`
13
+ - [#762] Check doesn’t abort the actual migration, so it runs
14
+ - [#722] `doorkeeper_forbidden_render_options` now supports returning a 404 by
15
+ specifying `respond_not_found_when_forbidden: true` in the
16
+ `doorkeeper_forbidden_render_options` method.
17
+ - [#734] Simplify and remove duplication in request strategy classes
18
+
7
19
  ## 3.0.1
8
20
 
9
21
  - [#712] Wrap exchange of grant token for access token and access token refresh
data/README.md CHANGED
@@ -14,10 +14,12 @@ functionality to your Rails or Grape application.
14
14
  ## Documentation valid for `master` branch
15
15
 
16
16
  Please check the documentation for the version of doorkeeper you are using in:
17
- https://github.com/doorkeeper-gem/doorkeeper/releases.
17
+ https://github.com/doorkeeper-gem/doorkeeper/releases
18
18
 
19
19
  ## Table of Contents
20
20
 
21
+ <!-- START doctoc generated TOC please keep comment here to allow auto update -->
22
+ <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
21
23
  - [Useful links](#useful-links)
22
24
  - [Installation](#installation)
23
25
  - [Configuration](#configuration)
@@ -39,12 +41,12 @@ https://github.com/doorkeeper-gem/doorkeeper/releases.
39
41
  - [Contributing](#contributing)
40
42
  - [Other resources](#other-resources)
41
43
  - [Wiki](#wiki)
42
- - [Live demo](#live-demo)
43
44
  - [Screencast](#screencast)
44
45
  - [Client applications](#client-applications)
45
46
  - [Contributors](#contributors)
46
47
  - [IETF Standards](#ietf-standards)
47
48
  - [License](#license)
49
+ <!-- END doctoc generated TOC please keep comment here to allow auto update -->
48
50
 
49
51
 
50
52
  ## Useful links
@@ -259,7 +261,7 @@ have both `:admin` and `:write` scopes.
259
261
 
260
262
  ### Custom Access Token Generator
261
263
 
262
- By default a 32 bit access token will be generated. If you require a custom
264
+ By default a 128 bit access token will be generated. If you require a custom
263
265
  token, such as [JWT](http://jwt.io), specify an object that responds to
264
266
  `.generate(options = {})` and returns a string to be used as the token.
265
267
 
@@ -333,6 +335,8 @@ notes](https://github.com/doorkeeper-gem/doorkeeper/wiki/Migration-from-old-vers
333
335
  and take a look at the
334
336
  [changelog](https://github.com/doorkeeper-gem/doorkeeper/blob/master/NEWS.md).
335
337
 
338
+ Doorkeeper follows [semantic versioning](http://semver.org/).
339
+
336
340
  ## Development
337
341
 
338
342
  To run the local engine server:
@@ -369,12 +373,6 @@ page](https://github.com/doorkeeper-gem/doorkeeper/wiki/Contributing).
369
373
  You can find everything about doorkeeper in our [wiki
370
374
  here](https://github.com/doorkeeper-gem/doorkeeper/wiki).
371
375
 
372
- ### Live demo
373
-
374
- Check out this [live demo](http://doorkeeper-provider.herokuapp.com) hosted on
375
- heroku. For more demos check out [the
376
- wiki](https://github.com/doorkeeper-gem/doorkeeper/wiki/Example-Applications).
377
-
378
376
  ### Screencast
379
377
 
380
378
  Check out this screencast from [railscasts.com](http://railscasts.com/): [#353
@@ -392,7 +390,7 @@ here](https://github.com/doorkeeper-gem/doorkeeper/wiki/Testing-your-provider-wi
392
390
  ### Contributors
393
391
 
394
392
  Thanks to all our [awesome
395
- contributors](https://github.com/doorkeeper-gem/doorkeeper/contributors)!
393
+ contributors](https://github.com/doorkeeper-gem/doorkeeper/graphs/contributors)!
396
394
 
397
395
 
398
396
  ### IETF Standards
@@ -404,4 +402,3 @@ contributors](https://github.com/doorkeeper-gem/doorkeeper/contributors)!
404
402
  ### License
405
403
 
406
404
  MIT License. Copyright 2011 Applicake.
407
- [http://applicake.com](http://applicake.com)
@@ -5,10 +5,6 @@
5
5
  *= require_tree .
6
6
  */
7
7
 
8
- body {
9
- padding-top: 60px;
10
- }
11
-
12
8
  td {
13
- vertical-align: middle !important;
9
+ vertical-align: middle !important;
14
10
  }
@@ -9,8 +9,8 @@
9
9
  <%= csrf_meta_tags %>
10
10
  </head>
11
11
  <body>
12
- <div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
13
- <div class="container">
12
+ <div class="navbar navbar-inverse navbar-static-top" role="navigation">
13
+ <div class="container-fluid">
14
14
  <div class="navbar-header">
15
15
  <%= link_to t('doorkeeper.layouts.admin.nav.oauth2_provider'), oauth_applications_path, class: 'navbar-brand' %>
16
16
  </div>
@@ -18,6 +18,9 @@
18
18
  <%= content_tag :li, class: "#{'active' if request.path == oauth_applications_path}" do %>
19
19
  <%= link_to t('doorkeeper.layouts.admin.nav.applications'), oauth_applications_path %>
20
20
  <% end %>
21
+ <%= content_tag :li do %>
22
+ <%= link_to 'Home', root_path %>
23
+ <% end %>
21
24
  </ul>
22
25
  </div>
23
26
  </div>
data/doorkeeper.gemspec CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
18
18
 
19
19
  s.add_dependency "railties", ">= 3.2"
20
20
 
21
- s.add_development_dependency "rspec-rails", "~> 3.2.0"
21
+ s.add_development_dependency "rspec-rails", "~> 3.4.0"
22
22
  s.add_development_dependency "capybara", "~> 2.3.0"
23
23
  s.add_development_dependency "generator_spec", "~> 0.9.0"
24
24
  s.add_development_dependency "factory_girl", "~> 4.5.0"
@@ -45,6 +45,8 @@ module Doorkeeper
45
45
  :invalid_request
46
46
  when Errors::InvalidGrantReuse
47
47
  :invalid_grant
48
+ when Errors::DoorkeeperError
49
+ exception.message
48
50
  end
49
51
 
50
52
  OAuth::ErrorResponse.new name: error_name, state: params[:state]
@@ -3,10 +3,9 @@ module Doorkeeper
3
3
  class ClientCredentialsRequest
4
4
  class Creator
5
5
  def call(client, scopes, attributes = {})
6
- AccessToken.create(attributes.merge(
7
- application_id: client.id,
8
- scopes: scopes.to_s
9
- ))
6
+ AccessToken.find_or_create_for(
7
+ client, nil, scopes, attributes[:expires_in],
8
+ attributes[:use_refresh_token])
10
9
  end
11
10
  end
12
11
  end
@@ -2,7 +2,11 @@ module Doorkeeper
2
2
  module OAuth
3
3
  class Error < Struct.new(:name, :state)
4
4
  def description
5
- I18n.translate name, scope: [:doorkeeper, :errors, :messages]
5
+ I18n.translate(
6
+ name,
7
+ scope: [:doorkeeper, :errors, :messages],
8
+ default: :server_error
9
+ )
6
10
  end
7
11
  end
8
12
  end
@@ -25,11 +25,12 @@ module Doorkeeper
25
25
  Doorkeeper::Application.table_name
26
26
  )
27
27
  unless Doorkeeper::Application.new.attributes.include?("scopes")
28
- fail <<-MSG.squish
28
+ migration_path = '../../../generators/doorkeeper/templates/add_scopes_to_oauth_applications.rb'
29
+ puts <<-MSG.squish
29
30
  [doorkeeper] Missing column: `oauth_applications.scopes`.
30
- Run `rails generate doorkeeper:application_scopes
31
- && rake db:migrate` to add it.
31
+ Create the following migration and run `rake db:migrate`.
32
32
  MSG
33
+ puts File.read(File.expand_path(migration_path, __FILE__))
33
34
  end
34
35
  end
35
36
  end
@@ -31,10 +31,12 @@ module Doorkeeper
31
31
 
32
32
  def doorkeeper_render_error_with(error)
33
33
  options = doorkeeper_render_options(error) || {}
34
+ status = doorkeeper_status_for_error(
35
+ error, options.delete(:respond_not_found_when_forbidden))
34
36
  if options.blank?
35
- head error.status
37
+ head status
36
38
  else
37
- options[:status] = error.status
39
+ options[:status] = status
38
40
  options[:layout] = false if options[:layout].nil?
39
41
  render options
40
42
  end
@@ -56,6 +58,14 @@ module Doorkeeper
56
58
  end
57
59
  end
58
60
 
61
+ def doorkeeper_status_for_error(error, respond_not_found_when_forbidden)
62
+ if respond_not_found_when_forbidden && error.status == :forbidden
63
+ :not_found
64
+ else
65
+ error.status
66
+ end
67
+ end
68
+
59
69
  def doorkeeper_invalid_token_response?
60
70
  !doorkeeper_token || !doorkeeper_token.accessible?
61
71
  end
@@ -9,22 +9,32 @@ module Doorkeeper
9
9
  module Request
10
10
  module_function
11
11
 
12
- def authorization_strategy(strategy)
13
- get_strategy strategy, Doorkeeper.configuration.authorization_response_types
12
+ def authorization_strategy(response_type)
13
+ get_strategy response_type, authorization_response_types
14
14
  rescue NameError
15
15
  raise Errors::InvalidAuthorizationStrategy
16
16
  end
17
17
 
18
- def token_strategy(strategy)
19
- get_strategy strategy, Doorkeeper.configuration.token_grant_types
18
+ def token_strategy(grant_type)
19
+ get_strategy grant_type, token_grant_types
20
20
  rescue NameError
21
21
  raise Errors::InvalidTokenStrategy
22
22
  end
23
23
 
24
- def get_strategy(strategy, available)
25
- fail Errors::MissingRequestStrategy unless strategy.present?
26
- fail NameError unless available.include?(strategy.to_s)
27
- "Doorkeeper::Request::#{strategy.to_s.camelize}".constantize
24
+ def get_strategy(grant_or_request_type, available)
25
+ fail Errors::MissingRequestStrategy unless grant_or_request_type.present?
26
+ fail NameError unless available.include?(grant_or_request_type.to_s)
27
+ "Doorkeeper::Request::#{grant_or_request_type.to_s.camelize}".constantize
28
28
  end
29
+
30
+ def authorization_response_types
31
+ Doorkeeper.configuration.authorization_response_types
32
+ end
33
+ private_class_method :authorization_response_types
34
+
35
+ def token_grant_types
36
+ Doorkeeper.configuration.token_grant_types
37
+ end
38
+ private_class_method :token_grant_types
29
39
  end
30
40
  end
@@ -1,22 +1,17 @@
1
+ require 'doorkeeper/request/strategy'
2
+
1
3
  module Doorkeeper
2
4
  module Request
3
- class AuthorizationCode
4
- def self.build(server)
5
- new(server.grant, server.client, server)
6
- end
7
-
8
- attr_accessor :grant, :client, :server
9
-
10
- def initialize(grant, client, server)
11
- @grant, @client, @server = grant, client, server
12
- end
5
+ class AuthorizationCode < Strategy
6
+ delegate :grant, :client, :parameters, to: :server
13
7
 
14
8
  def request
15
- @request ||= OAuth::AuthorizationCodeRequest.new(Doorkeeper.configuration, grant, client, server.parameters)
16
- end
17
-
18
- def authorize
19
- request.authorize
9
+ @request ||= OAuth::AuthorizationCodeRequest.new(
10
+ Doorkeeper.configuration,
11
+ grant,
12
+ client,
13
+ parameters
14
+ )
20
15
  end
21
16
  end
22
17
  end
@@ -1,22 +1,16 @@
1
+ require 'doorkeeper/request/strategy'
2
+
1
3
  module Doorkeeper
2
4
  module Request
3
- class ClientCredentials
4
- def self.build(server)
5
- new(server.client, server)
6
- end
7
-
8
- attr_accessor :client, :server
9
-
10
- def initialize(client, server)
11
- @client, @server = client, server
12
- end
5
+ class ClientCredentials < Strategy
6
+ delegate :client, :parameters, to: :server
13
7
 
14
8
  def request
15
- @request ||= OAuth::ClientCredentialsRequest.new(Doorkeeper.configuration, client, server.parameters)
16
- end
17
-
18
- def authorize
19
- request.authorize
9
+ @request ||= OAuth::ClientCredentialsRequest.new(
10
+ Doorkeeper.configuration,
11
+ client,
12
+ parameters
13
+ )
20
14
  end
21
15
  end
22
16
  end
@@ -1,22 +1,16 @@
1
+ require 'doorkeeper/request/strategy'
2
+
1
3
  module Doorkeeper
2
4
  module Request
3
- class Code
4
- def self.build(server)
5
- new(server.context.send(:pre_auth), server)
6
- end
7
-
8
- attr_accessor :pre_auth, :server
5
+ class Code < Strategy
6
+ delegate :current_resource_owner, to: :server
9
7
 
10
- def initialize(pre_auth, server)
11
- @pre_auth, @server = pre_auth, server
8
+ def pre_auth
9
+ server.context.send(:pre_auth)
12
10
  end
13
11
 
14
12
  def request
15
- @request ||= OAuth::CodeRequest.new(pre_auth, server.current_resource_owner)
16
- end
17
-
18
- def authorize
19
- request.authorize
13
+ @request ||= OAuth::CodeRequest.new(pre_auth, current_resource_owner)
20
14
  end
21
15
  end
22
16
  end
@@ -1,22 +1,17 @@
1
+ require 'doorkeeper/request/strategy'
2
+
1
3
  module Doorkeeper
2
4
  module Request
3
- class Password
4
- def self.build(server)
5
- new(server.credentials, server.resource_owner, server)
6
- end
7
-
8
- attr_accessor :credentials, :resource_owner, :server
9
-
10
- def initialize(credentials, resource_owner, server)
11
- @credentials, @resource_owner, @server = credentials, resource_owner, server
12
- end
5
+ class Password < Strategy
6
+ delegate :credentials, :resource_owner, :parameters, to: :server
13
7
 
14
8
  def request
15
- @request ||= OAuth::PasswordAccessTokenRequest.new(Doorkeeper.configuration, credentials, resource_owner, server.parameters)
16
- end
17
-
18
- def authorize
19
- request.authorize
9
+ @request ||= OAuth::PasswordAccessTokenRequest.new(
10
+ Doorkeeper.configuration,
11
+ credentials,
12
+ resource_owner,
13
+ parameters
14
+ )
20
15
  end
21
16
  end
22
17
  end
@@ -1,22 +1,20 @@
1
+ require 'doorkeeper/request/strategy'
2
+
1
3
  module Doorkeeper
2
4
  module Request
3
- class RefreshToken
4
- def self.build(server)
5
- new(server.current_refresh_token, server.credentials, server)
6
- end
7
-
8
- attr_accessor :refresh_token, :credentials, :server
5
+ class RefreshToken < Strategy
6
+ delegate :credentials, :parameters, to: :server
9
7
 
10
- def initialize(refresh_token, credentials, server)
11
- @refresh_token, @credentials, @server = refresh_token, credentials, server
8
+ def refresh_token
9
+ server.current_refresh_token
12
10
  end
13
11
 
14
12
  def request
15
- @request ||= OAuth::RefreshTokenRequest.new(Doorkeeper.configuration, refresh_token, credentials, server.parameters)
16
- end
17
-
18
- def authorize
19
- request.authorize
13
+ @request ||= OAuth::RefreshTokenRequest.new(
14
+ Doorkeeper.configuration,
15
+ refresh_token, credentials,
16
+ parameters
17
+ )
20
18
  end
21
19
  end
22
20
  end
@@ -0,0 +1,17 @@
1
+ module Doorkeeper
2
+ module Request
3
+ class Strategy
4
+ attr_accessor :server
5
+
6
+ delegate :authorize, to: :request
7
+
8
+ def initialize(server)
9
+ self.server = server
10
+ end
11
+
12
+ def request
13
+ raise NotImplementedError, "request strategies must define #request"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,22 +1,16 @@
1
+ require 'doorkeeper/request/strategy'
2
+
1
3
  module Doorkeeper
2
4
  module Request
3
- class Token
4
- def self.build(server)
5
- new(server.context.send(:pre_auth), server)
6
- end
7
-
8
- attr_accessor :pre_auth, :server
5
+ class Token < Strategy
6
+ delegate :current_resource_owner, to: :server
9
7
 
10
- def initialize(pre_auth, server)
11
- @pre_auth, @server = pre_auth, server
8
+ def pre_auth
9
+ server.context.send(:pre_auth)
12
10
  end
13
11
 
14
12
  def request
15
- @request ||= OAuth::TokenRequest.new(pre_auth, server.current_resource_owner)
16
- end
17
-
18
- def authorize
19
- request.authorize
13
+ @request ||= OAuth::TokenRequest.new(pre_auth, current_resource_owner)
20
14
  end
21
15
  end
22
16
  end
@@ -8,12 +8,12 @@ module Doorkeeper
8
8
 
9
9
  def authorization_request(strategy)
10
10
  klass = Request.authorization_strategy strategy
11
- klass.build self
11
+ klass.new self
12
12
  end
13
13
 
14
14
  def token_request(strategy)
15
15
  klass = Request.token_strategy strategy
16
- klass.build self
16
+ klass.new self
17
17
  end
18
18
 
19
19
  # TODO: context should be the request
@@ -1,3 +1,3 @@
1
1
  module Doorkeeper
2
- VERSION = '3.0.1'
2
+ VERSION = "3.1.0"
3
3
  end
@@ -165,7 +165,7 @@ describe 'doorkeeper authorize filter' do
165
165
  end
166
166
  end
167
167
 
168
- it 'it renders a custom JSON response', token: :invalid do
168
+ it 'it renders a custom text response', token: :invalid do
169
169
  get :index, access_token: token_string
170
170
  expect(response.status).to eq 401
171
171
  expect(response.content_type).to eq('text/html')
@@ -174,4 +174,98 @@ describe 'doorkeeper authorize filter' do
174
174
  end
175
175
  end
176
176
  end
177
+
178
+ context 'when custom forbidden render options are configured' do
179
+ before do
180
+ expect(Doorkeeper::AccessToken).to receive(:by_token).with(token_string).and_return(token)
181
+ expect(token).to receive(:acceptable?).with([:write]).and_return(false)
182
+ end
183
+
184
+ after do
185
+ module ControllerActions
186
+ def doorkeeper_forbidden_render_options(*)
187
+ end
188
+ end
189
+ end
190
+
191
+ controller do
192
+ before_filter -> { doorkeeper_authorize! :write }
193
+
194
+ include ControllerActions
195
+ end
196
+
197
+ let(:token) do
198
+ double(Doorkeeper::AccessToken,
199
+ accessible?: true, scopes: ['public'], revoked?: false, expired?: false)
200
+ end
201
+ let(:token_string) { '1A2DUWE' }
202
+
203
+ context 'with a JSON custom render' do
204
+ before do
205
+ module ControllerActions
206
+ def doorkeeper_forbidden_render_options(*)
207
+ { json: { error_message: 'Forbidden' } }
208
+ end
209
+ end
210
+ end
211
+
212
+ it 'renders a custom JSON response' do
213
+ get :index, access_token: token_string
214
+ expect(response.header).to_not include('WWW-Authenticate')
215
+ expect(response.content_type).to eq('application/json')
216
+ expect(response.status).to eq 403
217
+ parsed_body = JSON.parse(response.body)
218
+ expect(parsed_body).not_to be_nil
219
+ expect(parsed_body['error_message']).to match('Forbidden')
220
+ end
221
+ end
222
+
223
+ context 'with a status and JSON custom render' do
224
+ before do
225
+ module ControllerActions
226
+ def doorkeeper_forbidden_render_options(*)
227
+ { json: { error_message: 'Not Found' },
228
+ respond_not_found_when_forbidden: true }
229
+ end
230
+ end
231
+ end
232
+
233
+ it 'overrides the default status code' do
234
+ get :index, access_token: token_string
235
+ expect(response.status).to eq 404
236
+ end
237
+ end
238
+
239
+ context 'with a text custom render' do
240
+ before do
241
+ module ControllerActions
242
+ def doorkeeper_forbidden_render_options(*)
243
+ { text: 'Forbidden' }
244
+ end
245
+ end
246
+ end
247
+
248
+ it 'renders a custom status code and text response' do
249
+ get :index, access_token: token_string
250
+ expect(response.header).to_not include('WWW-Authenticate')
251
+ expect(response.status).to eq 403
252
+ expect(response.body).to eq('Forbidden')
253
+ end
254
+ end
255
+
256
+ context 'with a status and text custom render' do
257
+ before do
258
+ module ControllerActions
259
+ def doorkeeper_forbidden_render_options(*)
260
+ { respond_not_found_when_forbidden: true, text: 'Not Found' }
261
+ end
262
+ end
263
+ end
264
+
265
+ it 'overrides the default status code' do
266
+ get :index, access_token: token_string
267
+ expect(response.status).to eq 404
268
+ end
269
+ end
270
+ end
177
271
  end
@@ -31,6 +31,36 @@ describe Doorkeeper::TokensController do
31
31
  end
32
32
  end
33
33
 
34
+ describe 'when there is a failure due to a custom error' do
35
+ it 'returns the error response with a custom message' do
36
+ # I18n looks for `doorkeeper.errors.messages.custom_message` in locale files
37
+ custom_message = "my_message"
38
+ allow(I18n).to receive(:translate).
39
+ with(
40
+ custom_message,
41
+ hash_including(scope: [:doorkeeper, :errors, :messages]),
42
+ ).
43
+ and_return('Authorization custom message')
44
+
45
+ doorkeeper_error = Doorkeeper::Errors::DoorkeeperError.new(custom_message)
46
+
47
+ strategy = double(:strategy)
48
+ request = double(token_request: strategy)
49
+ allow(strategy).to receive(:authorize).and_raise(doorkeeper_error)
50
+ allow(controller).to receive(:server).and_return(request)
51
+
52
+ post :create
53
+
54
+ expected_response_body = {
55
+ "error" => custom_message,
56
+ "error_description" => "Authorization custom message"
57
+ }
58
+ expect(response.status).to eq 401
59
+ expect(response.headers['WWW-Authenticate']).to match(/Bearer/)
60
+ expect(JSON.load(response.body)).to eq expected_response_body
61
+ end
62
+ end
63
+
34
64
  describe 'when revoke authorization has failed' do
35
65
  # http://tools.ietf.org/html/rfc7009#section-2.2
36
66
  it 'returns no error response' do
@@ -11,8 +11,32 @@ class Doorkeeper::OAuth::ClientCredentialsRequest
11
11
  end.to change { Doorkeeper::AccessToken.count }.by(1)
12
12
  end
13
13
 
14
+ context "when reuse_access_token is true" do
15
+ it "returns the existing valid token" do
16
+ allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
17
+ existing_token = subject.call(client, scopes)
18
+
19
+ result = subject.call(client, scopes)
20
+
21
+ expect(Doorkeeper::AccessToken.count).to eq(1)
22
+ expect(result).to eq(existing_token)
23
+ end
24
+ end
25
+
26
+ context "when reuse_access_token is false" do
27
+ it "returns a new token" do
28
+ allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(false)
29
+ existing_token = subject.call(client, scopes)
30
+
31
+ result = subject.call(client, scopes)
32
+
33
+ expect(Doorkeeper::AccessToken.count).to eq(2)
34
+ expect(result).not_to eq(existing_token)
35
+ end
36
+ end
37
+
14
38
  it 'returns false if creation fails' do
15
- expect(Doorkeeper::AccessToken).to receive(:create).and_return(false)
39
+ expect(Doorkeeper::AccessToken).to receive(:find_or_create_for).and_return(false)
16
40
  created = subject.call(client, scopes)
17
41
  expect(created).to be_falsey
18
42
  end
@@ -37,9 +37,9 @@ module Doorkeeper::OAuth
37
37
  subject { ErrorResponse.new(name: :some_error, state: :some_state).body }
38
38
 
39
39
  describe '#body' do
40
- it { should have_key(:error) }
41
- it { should have_key(:error_description) }
42
- it { should have_key(:state) }
40
+ it { expect(subject).to have_key(:error) }
41
+ it { expect(subject).to have_key(:error_description) }
42
+ it { expect(subject).to have_key(:state) }
43
43
  end
44
44
  end
45
45
 
@@ -47,15 +47,15 @@ module Doorkeeper::OAuth
47
47
  let(:error_response) { ErrorResponse.new(name: :some_error, state: :some_state) }
48
48
  subject { error_response.authenticate_info }
49
49
 
50
- it { should include("realm=\"#{error_response.realm}\"") }
51
- it { should include("error=\"#{error_response.name}\"") }
52
- it { should include("error_description=\"#{error_response.description}\"") }
50
+ it { expect(subject).to include("realm=\"#{error_response.realm}\"") }
51
+ it { expect(subject).to include("error=\"#{error_response.name}\"") }
52
+ it { expect(subject).to include("error_description=\"#{error_response.description}\"") }
53
53
  end
54
54
 
55
55
  describe '.headers' do
56
56
  subject { ErrorResponse.new(name: :some_error, state: :some_state).headers }
57
57
 
58
- it { should include 'WWW-Authenticate' }
58
+ it { expect(subject).to include 'WWW-Authenticate' }
59
59
  end
60
60
  end
61
61
  end
@@ -4,15 +4,19 @@ require 'doorkeeper/oauth/error'
4
4
 
5
5
  module Doorkeeper::OAuth
6
6
  describe Error do
7
- subject { Error.new(:some_error, :some_state) }
7
+ subject(:error) { Error.new(:some_error, :some_state) }
8
8
 
9
- it { should respond_to(:name) }
10
- it { should respond_to(:state) }
9
+ it { expect(subject).to respond_to(:name) }
10
+ it { expect(subject).to respond_to(:state) }
11
11
 
12
12
  describe :description do
13
13
  it 'is translated from translation messages' do
14
- expect(I18n).to receive(:translate).with(:some_error, scope: [:doorkeeper, :errors, :messages])
15
- subject.description
14
+ expect(I18n).to receive(:translate).with(
15
+ :some_error,
16
+ scope: [:doorkeeper, :errors, :messages],
17
+ default: :server_error
18
+ )
19
+ error.description
16
20
  end
17
21
  end
18
22
  end
@@ -47,7 +47,7 @@ module Doorkeeper::OAuth
47
47
 
48
48
  subject { Scopes.from_string(string) }
49
49
 
50
- it { should be_a(Scopes) }
50
+ it { expect(subject).to be_a(Scopes) }
51
51
 
52
52
  describe '#all' do
53
53
  it 'should be an array of the expected scopes' do
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+ require 'doorkeeper/request/strategy'
3
+
4
+ module Doorkeeper
5
+ module Request
6
+ describe Strategy do
7
+ let(:server) { double }
8
+ subject(:strategy) { Strategy.new(server) }
9
+
10
+ describe :initialize do
11
+ it "sets the server attribute" do
12
+ expect(strategy.server).to eq server
13
+ end
14
+ end
15
+
16
+ describe :request do
17
+ it "requires an implementation" do
18
+ expect { strategy.request }.to raise_exception NotImplementedError
19
+ end
20
+ end
21
+
22
+ describe "a sample Strategy subclass" do
23
+ let(:fake_request) { double }
24
+
25
+ let(:strategy_class) do
26
+ subclass = Class.new(Strategy) do
27
+ class << self
28
+ attr_accessor :fake_request
29
+ end
30
+
31
+ def request
32
+ self.class.fake_request
33
+ end
34
+ end
35
+
36
+ subclass.fake_request = fake_request
37
+ subclass
38
+ end
39
+
40
+ subject(:strategy) { strategy_class.new(server) }
41
+
42
+ it "provides a request implementation" do
43
+ expect(strategy.request).to eq fake_request
44
+ end
45
+
46
+ it "authorizes the request" do
47
+ expect(fake_request).to receive :authorize
48
+ strategy.authorize
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -45,7 +45,7 @@ describe Doorkeeper::Server do
45
45
 
46
46
  it 'builds the request with selected strategy' do
47
47
  stub_const 'Doorkeeper::Request::Code', fake_class
48
- expect(fake_class).to receive(:build).with(subject)
48
+ expect(fake_class).to receive(:new).with(subject)
49
49
  subject.authorization_request :code
50
50
  end
51
51
  end
@@ -3,7 +3,7 @@ require 'spec_helper_integration'
3
3
  describe Doorkeeper::AccessGrant do
4
4
  subject { FactoryGirl.build(:access_grant) }
5
5
 
6
- it { should be_valid }
6
+ it { expect(subject).to be_valid }
7
7
 
8
8
  it_behaves_like 'an accessible token'
9
9
  it_behaves_like 'a revocable token'
@@ -14,23 +14,23 @@ describe Doorkeeper::AccessGrant do
14
14
  describe 'validations' do
15
15
  it 'is invalid without resource_owner_id' do
16
16
  subject.resource_owner_id = nil
17
- should_not be_valid
17
+ expect(subject).not_to be_valid
18
18
  end
19
19
 
20
20
  it 'is invalid without application_id' do
21
21
  subject.application_id = nil
22
- should_not be_valid
22
+ expect(subject).not_to be_valid
23
23
  end
24
24
 
25
25
  it 'is invalid without token' do
26
26
  subject.save
27
27
  subject.token = nil
28
- should_not be_valid
28
+ expect(subject).not_to be_valid
29
29
  end
30
30
 
31
31
  it 'is invalid without expires_in' do
32
32
  subject.expires_in = nil
33
- should_not be_valid
33
+ expect(subject).not_to be_valid
34
34
  end
35
35
  end
36
36
  end
@@ -4,7 +4,7 @@ module Doorkeeper
4
4
  describe AccessToken do
5
5
  subject { FactoryGirl.build(:access_token) }
6
6
 
7
- it { should be_valid }
7
+ it { expect(subject).to be_valid }
8
8
 
9
9
  it_behaves_like 'an accessible token'
10
10
  it_behaves_like 'a revocable token'
@@ -141,7 +141,7 @@ module Doorkeeper
141
141
  it 'is valid without resource_owner_id' do
142
142
  # For client credentials flow
143
143
  subject.resource_owner_id = nil
144
- should be_valid
144
+ expect(subject).to be_valid
145
145
  end
146
146
  end
147
147
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: doorkeeper
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.1
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Felipe Elias Philipp
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-09-24 00:00:00.000000000 Z
12
+ date: 2015-12-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: railties
@@ -31,14 +31,14 @@ dependencies:
31
31
  requirements:
32
32
  - - "~>"
33
33
  - !ruby/object:Gem::Version
34
- version: 3.2.0
34
+ version: 3.4.0
35
35
  type: :development
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - "~>"
40
40
  - !ruby/object:Gem::Version
41
- version: 3.2.0
41
+ version: 3.4.0
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: capybara
44
44
  requirement: !ruby/object:Gem::Requirement
@@ -210,6 +210,7 @@ files:
210
210
  - lib/doorkeeper/request/code.rb
211
211
  - lib/doorkeeper/request/password.rb
212
212
  - lib/doorkeeper/request/refresh_token.rb
213
+ - lib/doorkeeper/request/strategy.rb
213
214
  - lib/doorkeeper/request/token.rb
214
215
  - lib/doorkeeper/server.rb
215
216
  - lib/doorkeeper/validations.rb
@@ -303,6 +304,7 @@ files:
303
304
  - spec/lib/oauth/token_request_spec.rb
304
305
  - spec/lib/oauth/token_response_spec.rb
305
306
  - spec/lib/oauth/token_spec.rb
307
+ - spec/lib/request/strategy_spec.rb
306
308
  - spec/lib/server_spec.rb
307
309
  - spec/models/doorkeeper/access_grant_spec.rb
308
310
  - spec/models/doorkeeper/access_token_spec.rb
@@ -359,7 +361,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
359
361
  version: '0'
360
362
  requirements: []
361
363
  rubyforge_project:
362
- rubygems_version: 2.4.5.1
364
+ rubygems_version: 2.5.1
363
365
  signing_key:
364
366
  specification_version: 4
365
367
  summary: OAuth 2 provider for Rails and Grape
@@ -443,6 +445,7 @@ test_files:
443
445
  - spec/lib/oauth/token_request_spec.rb
444
446
  - spec/lib/oauth/token_response_spec.rb
445
447
  - spec/lib/oauth/token_spec.rb
448
+ - spec/lib/request/strategy_spec.rb
446
449
  - spec/lib/server_spec.rb
447
450
  - spec/models/doorkeeper/access_grant_spec.rb
448
451
  - spec/models/doorkeeper/access_token_spec.rb