doorkeeper 1.3.1 → 1.4.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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/.hound.yml +4 -1
  3. data/CHANGELOG.md +18 -0
  4. data/README.md +2 -1
  5. data/app/controllers/doorkeeper/application_metal_controller.rb +16 -0
  6. data/app/controllers/doorkeeper/applications_controller.rb +0 -6
  7. data/app/controllers/doorkeeper/authorizations_controller.rb +14 -15
  8. data/app/controllers/doorkeeper/authorized_applications_controller.rb +10 -8
  9. data/app/controllers/doorkeeper/token_info_controller.rb +1 -1
  10. data/app/controllers/doorkeeper/tokens_controller.rb +3 -11
  11. data/app/validators/redirect_uri_validator.rb +0 -1
  12. data/config/locales/en.yml +0 -3
  13. data/doorkeeper.gemspec +1 -0
  14. data/lib/doorkeeper.rb +1 -0
  15. data/lib/doorkeeper/config.rb +5 -5
  16. data/lib/doorkeeper/doorkeeper_for.rb +7 -17
  17. data/lib/doorkeeper/helpers/controller.rb +11 -8
  18. data/lib/doorkeeper/helpers/filter.rb +35 -13
  19. data/lib/doorkeeper/models/access_grant.rb +5 -5
  20. data/lib/doorkeeper/models/access_token.rb +9 -5
  21. data/lib/doorkeeper/models/active_record/access_grant.rb +1 -1
  22. data/lib/doorkeeper/models/active_record/access_token.rb +1 -1
  23. data/lib/doorkeeper/models/active_record/application.rb +3 -3
  24. data/lib/doorkeeper/models/application.rb +1 -1
  25. data/lib/doorkeeper/models/mongo_mapper/access_grant.rb +0 -3
  26. data/lib/doorkeeper/models/mongo_mapper/access_token.rb +0 -3
  27. data/lib/doorkeeper/models/mongoid2/access_grant.rb +1 -3
  28. data/lib/doorkeeper/models/mongoid2/access_token.rb +1 -3
  29. data/lib/doorkeeper/models/mongoid3_4/access_grant.rb +2 -4
  30. data/lib/doorkeeper/models/mongoid3_4/access_token.rb +2 -4
  31. data/lib/doorkeeper/models/revocable.rb +1 -1
  32. data/lib/doorkeeper/models/scopes.rb +6 -2
  33. data/lib/doorkeeper/oauth/authorization/code.rb +4 -0
  34. data/lib/doorkeeper/oauth/authorization/token.rb +8 -0
  35. data/lib/doorkeeper/oauth/authorization_code_request.rb +2 -2
  36. data/lib/doorkeeper/oauth/client.rb +2 -2
  37. data/lib/doorkeeper/oauth/client_credentials/creator.rb +1 -1
  38. data/lib/doorkeeper/oauth/client_credentials/validation.rb +2 -2
  39. data/lib/doorkeeper/oauth/client_credentials_request.rb +3 -12
  40. data/lib/doorkeeper/oauth/code_response.rb +3 -4
  41. data/lib/doorkeeper/oauth/error_response.rb +3 -3
  42. data/lib/doorkeeper/oauth/forbidden_token_response.rb +29 -0
  43. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +1 -1
  44. data/lib/doorkeeper/oauth/password_access_token_request.rb +5 -5
  45. data/lib/doorkeeper/oauth/pre_authorization.rb +2 -2
  46. data/lib/doorkeeper/oauth/refresh_token_request.rb +6 -6
  47. data/lib/doorkeeper/oauth/request_concern.rb +2 -2
  48. data/lib/doorkeeper/oauth/token.rb +1 -1
  49. data/lib/doorkeeper/server.rb +2 -2
  50. data/lib/doorkeeper/version.rb +1 -1
  51. data/spec/controllers/authorizations_controller_spec.rb +46 -0
  52. data/spec/controllers/protected_resources_controller_spec.rb +13 -6
  53. data/spec/lib/models/revocable_spec.rb +1 -1
  54. data/spec/lib/models/scopes_spec.rb +11 -0
  55. data/spec/lib/oauth/authorization/uri_builder_spec.rb +5 -0
  56. data/spec/lib/oauth/forbidden_token_response_spec.rb +23 -0
  57. data/spec/models/doorkeeper/access_token_spec.rb +30 -0
  58. data/spec/requests/flows/refresh_token_spec.rb +2 -2
  59. data/spec/requests/protected_resources/private_api_spec.rb +5 -5
  60. data/spec/support/shared/controllers_shared_context.rb +2 -2
  61. data/spec/validators/redirect_uri_validator_spec.rb +1 -2
  62. metadata +19 -4
  63. data/lib/doorkeeper/models/mongo_mapper/revocable.rb +0 -15
  64. data/lib/doorkeeper/models/mongoid/revocable.rb +0 -15
@@ -15,7 +15,7 @@ module Doorkeeper
15
15
 
16
16
  def scopes
17
17
  @scopes ||= if @original_scopes.present?
18
- Doorkeeper::OAuth::Scopes.from_string(@original_scopes)
18
+ OAuth::Scopes.from_string(@original_scopes)
19
19
  else
20
20
  default_scopes
21
21
  end
@@ -30,7 +30,7 @@ module Doorkeeper
30
30
  end
31
31
 
32
32
  def find_or_create_access_token(client, resource_owner_id, scopes, server)
33
- @access_token = Doorkeeper::AccessToken.find_or_create_for(
33
+ @access_token = AccessToken.find_or_create_for(
34
34
  client,
35
35
  resource_owner_id,
36
36
  scopes,
@@ -55,7 +55,7 @@ module Doorkeeper
55
55
 
56
56
  def self.authenticate(request, *methods)
57
57
  token = from_request request, *methods
58
- Doorkeeper::AccessToken.authenticate(token) if token
58
+ AccessToken.authenticate(token) if token
59
59
  end
60
60
  end
61
61
  end
@@ -34,11 +34,11 @@ module Doorkeeper
34
34
  end
35
35
 
36
36
  def current_refresh_token
37
- Doorkeeper::AccessToken.by_refresh_token(parameters[:refresh_token])
37
+ AccessToken.by_refresh_token(parameters[:refresh_token])
38
38
  end
39
39
 
40
40
  def grant
41
- Doorkeeper::AccessGrant.authenticate(parameters[:code])
41
+ AccessGrant.authenticate(parameters[:code])
42
42
  end
43
43
 
44
44
  # TODO: Use configuration and evaluate proper context on block
@@ -1,3 +1,3 @@
1
1
  module Doorkeeper
2
- VERSION = '1.3.1'
2
+ VERSION = '1.4.0'
3
3
  end
@@ -98,6 +98,52 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
98
98
  end
99
99
  end
100
100
 
101
+ describe 'GET #new token request with native url and skip_authorization true' do
102
+ before do
103
+ allow(Doorkeeper.configuration).to receive(:skip_authorization).and_return(proc do
104
+ true
105
+ end)
106
+ client.update_attribute :redirect_uri, 'urn:ietf:wg:oauth:2.0:oob'
107
+ get :new, client_id: client.uid, response_type: 'token', redirect_uri: client.redirect_uri
108
+ end
109
+
110
+ it 'should redirect immediately' do
111
+ expect(response).to be_redirect
112
+ expect(response.location).to match(/oauth\/token\/info\?access_token=/)
113
+ end
114
+
115
+ it 'should not issue a grant' do
116
+ expect(Doorkeeper::AccessGrant.count).to be 0
117
+ end
118
+
119
+ it 'should issue a token' do
120
+ expect(Doorkeeper::AccessToken.count).to be 1
121
+ end
122
+ end
123
+
124
+ describe 'GET #new code request with native url and skip_authorization true' do
125
+ before do
126
+ allow(Doorkeeper.configuration).to receive(:skip_authorization).and_return(proc do
127
+ true
128
+ end)
129
+ client.update_attribute :redirect_uri, 'urn:ietf:wg:oauth:2.0:oob'
130
+ get :new, client_id: client.uid, response_type: 'code', redirect_uri: client.redirect_uri
131
+ end
132
+
133
+ it 'should redirect immediately' do
134
+ expect(response).to be_redirect
135
+ expect(response.location).to match(/oauth\/authorize\//)
136
+ end
137
+
138
+ it 'should issue a grant' do
139
+ expect(Doorkeeper::AccessGrant.count).to be 1
140
+ end
141
+
142
+ it 'should not issue a token' do
143
+ expect(Doorkeeper::AccessToken.count).to be 0
144
+ end
145
+ end
146
+
101
147
  describe 'GET #new with skip_authorization true' do
102
148
  before do
103
149
  allow(Doorkeeper.configuration).to receive(:skip_authorization).and_return(proc do
@@ -77,19 +77,22 @@ describe 'Doorkeeper_for helper' do
77
77
  end
78
78
 
79
79
  let(:token_string) { '1A2BC3' }
80
+ let(:token) do
81
+ double(Doorkeeper::AccessToken, acceptable?: true)
82
+ end
80
83
 
81
84
  it 'access_token param' do
82
- expect(Doorkeeper::AccessToken).to receive(:authenticate).with(token_string)
85
+ expect(Doorkeeper::AccessToken).to receive(:authenticate).with(token_string).and_return(token)
83
86
  get :index, access_token: token_string
84
87
  end
85
88
 
86
89
  it 'bearer_token param' do
87
- expect(Doorkeeper::AccessToken).to receive(:authenticate).with(token_string)
90
+ expect(Doorkeeper::AccessToken).to receive(:authenticate).with(token_string).and_return(token)
88
91
  get :index, bearer_token: token_string
89
92
  end
90
93
 
91
94
  it 'Authorization header' do
92
- expect(Doorkeeper::AccessToken).to receive(:authenticate).with(token_string)
95
+ expect(Doorkeeper::AccessToken).to receive(:authenticate).with(token_string).and_return(token)
93
96
  request.env['HTTP_AUTHORIZATION'] = "Bearer #{token_string}"
94
97
  get :index
95
98
  end
@@ -101,7 +104,7 @@ describe 'Doorkeeper_for helper' do
101
104
  end
102
105
 
103
106
  it 'does not change Authorization header value' do
104
- expect(Doorkeeper::AccessToken).to receive(:authenticate).exactly(2).times
107
+ expect(Doorkeeper::AccessToken).to receive(:authenticate).exactly(2).times.and_return(token)
105
108
  request.env['HTTP_AUTHORIZATION'] = "Bearer #{token_string}"
106
109
  get :index
107
110
  controller.send(:remove_instance_variable, :@token)
@@ -172,6 +175,7 @@ describe 'Doorkeeper_for helper' do
172
175
 
173
176
  it 'allows if the token has particular scopes' do
174
177
  token = double(Doorkeeper::AccessToken, accessible?: true, scopes: %w(write public))
178
+ expect(token).to receive(:acceptable?).with(['write']).and_return(true)
175
179
  expect(Doorkeeper::AccessToken).to receive(:authenticate).with(token_string).and_return(token)
176
180
  get :index, access_token: token_string
177
181
  expect(response).to be_success
@@ -180,9 +184,10 @@ describe 'Doorkeeper_for helper' do
180
184
  it 'does not allow if the token does not include given scope' do
181
185
  token = double(Doorkeeper::AccessToken, accessible?: true, scopes: ['public'], revoked?: false, expired?: false)
182
186
  expect(Doorkeeper::AccessToken).to receive(:authenticate).with(token_string).and_return(token)
187
+ expect(token).to receive(:acceptable?).with(['write']).and_return(false)
183
188
  get :index, access_token: token_string
184
- expect(response.status).to eq 401
185
- expect(response.header['WWW-Authenticate']).to match(/^Bearer/)
189
+ expect(response.status).to eq 403
190
+ expect(response.header).to_not include('WWW-Authenticate')
186
191
  end
187
192
  end
188
193
 
@@ -302,6 +307,8 @@ describe 'Doorkeeper_for helper' do
302
307
  context 'with invalid token', token: :invalid do
303
308
  it 'does not allow access if passed block evaluates to false' do
304
309
  get :index, access_token: token_string
310
+ expect(response.status).to eq 401
311
+ expect(response.header['WWW-Authenticate']).to match(/^Bearer/)
305
312
  end
306
313
 
307
314
  it 'allows access if passed block evaluates to true' do
@@ -12,7 +12,7 @@ describe 'Revocable' do
12
12
  describe :revoke do
13
13
  it 'updates :revoked_at attribute with current time' do
14
14
  clock = double now: double
15
- expect(subject).to receive(:update_column).with(:revoked_at, clock.now)
15
+ expect(subject).to receive(:update_attribute).with(:revoked_at, clock.now)
16
16
  subject.revoke(clock)
17
17
  end
18
18
  end
@@ -1,5 +1,6 @@
1
1
  require 'spec_helper'
2
2
  require 'active_support/core_ext/module/delegation'
3
+ require 'active_support/core_ext/object/blank'
3
4
  require 'doorkeeper/oauth/scopes'
4
5
  require 'doorkeeper/models/scopes'
5
6
 
@@ -29,4 +30,14 @@ describe 'Doorkeeper::Models::Scopes' do
29
30
  expect(subject.scopes_string).to eq('public admin')
30
31
  end
31
32
  end
33
+
34
+ describe :includes_scope? do
35
+ it 'should return true if at least one scope is included' do
36
+ expect(subject.includes_scope?(['public', 'private'])).to be true
37
+ end
38
+
39
+ it 'should return false if no scopes are included' do
40
+ expect(subject.includes_scope?(['teacher', 'student'])).to be false
41
+ end
42
+ end
32
43
  end
@@ -32,6 +32,11 @@ module Doorkeeper::OAuth::Authorization
32
32
  uri = subject.uri_with_fragment 'http://example.com/', parameter: 'value'
33
33
  expect(uri).to eq('http://example.com/#parameter=value')
34
34
  end
35
+
36
+ it 'preserves original query parameters' do
37
+ uri = subject.uri_with_fragment 'http://example.com/?query1=value1', parameter: 'value'
38
+ expect(uri).to eq('http://example.com/?query1=value1#parameter=value')
39
+ end
35
40
  end
36
41
  end
37
42
  end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+ require 'active_model'
3
+ require 'doorkeeper'
4
+ require 'doorkeeper/oauth/forbidden_token_response'
5
+
6
+ module Doorkeeper::OAuth
7
+ describe ForbiddenTokenResponse do
8
+ describe '#name' do
9
+ it { expect(subject.name).to eq(:invalid_scope) }
10
+ end
11
+
12
+ describe '#status' do
13
+ it { expect(subject.status).to eq(:forbidden) }
14
+ end
15
+
16
+ describe :from_scopes do
17
+ it 'should have a list of acceptable scopes' do
18
+ response = ForbiddenTokenResponse.from_scopes(["public"])
19
+ expect(response.description).to include('public')
20
+ end
21
+ end
22
+ end
23
+ end
@@ -95,6 +95,36 @@ module Doorkeeper
95
95
  end
96
96
  end
97
97
 
98
+ describe '#acceptable?' do
99
+ context 'a token that is not accessible' do
100
+ let(:token) { FactoryGirl.create(:access_token, created_at: 6.hours.ago) }
101
+
102
+ it 'should return false' do
103
+ expect(token.acceptable?(nil)).to be false
104
+ end
105
+ end
106
+
107
+ context 'a token that has the incorrect scopes' do
108
+ let(:token) { FactoryGirl.create(:access_token) }
109
+
110
+ it 'should return false' do
111
+ expect(token.acceptable?(['public'])).to be false
112
+ end
113
+ end
114
+
115
+ context 'a token is acceptable with the correct scopes' do
116
+ let(:token) do
117
+ token = FactoryGirl.create(:access_token)
118
+ token[:scopes] = 'public'
119
+ token
120
+ end
121
+
122
+ it 'should return true' do
123
+ expect(token.acceptable?(['public'])).to be true
124
+ end
125
+ end
126
+ end
127
+
98
128
  describe '.revoke_all_for' do
99
129
  let(:resource_owner) { double(id: 100) }
100
130
  let(:application) { FactoryGirl.create :application }
@@ -47,7 +47,7 @@ feature 'Refresh Token Flow' do
47
47
  end
48
48
 
49
49
  scenario 'client request a token with expired access token' do
50
- @token.update_column :expires_in, -100
50
+ @token.update_attribute :expires_in, -100
51
51
  post refresh_token_endpoint_url(client: @client, refresh_token: @token.refresh_token)
52
52
  should_have_json 'refresh_token', Doorkeeper::AccessToken.last.refresh_token
53
53
  expect(@token.reload).to be_revoked
@@ -78,7 +78,7 @@ feature 'Refresh Token Flow' do
78
78
  end
79
79
 
80
80
  scenario 'client request a token after creating another token with the same user' do
81
- @token.update_column :expires_in, -100
81
+ @token.update_attribute :expires_in, -100
82
82
  post password_token_endpoint_url(client: @client, resource_owner: @resource_owner)
83
83
  post refresh_token_endpoint_url(client: @client, refresh_token: @token.refresh_token)
84
84
  should_have_json 'refresh_token', Doorkeeper::AccessToken.last.refresh_token
@@ -27,14 +27,14 @@ feature 'Private API' do
27
27
  end
28
28
 
29
29
  scenario 'client attempts to request protected resource with expired token' do
30
- @token.update_column :expires_in, -100 # expires token
30
+ @token.update_attribute :expires_in, -100 # expires token
31
31
  with_access_token_header @token.token
32
32
  visit '/full_protected_resources'
33
33
  response_status_should_be 401
34
34
  end
35
35
 
36
36
  scenario 'client requests protected resource with permanent token' do
37
- @token.update_column :expires_in, nil # never expires
37
+ @token.update_attribute :expires_in, nil # never expires
38
38
  with_access_token_header @token.token
39
39
  visit '/full_protected_resources'
40
40
  expect(page.body).to have_content('index')
@@ -42,15 +42,15 @@ feature 'Private API' do
42
42
 
43
43
  scenario 'access token with no scopes' do
44
44
  optional_scopes_exist :admin
45
- @token.update_column :scopes, nil
45
+ @token.update_attribute :scopes, nil
46
46
  with_access_token_header @token.token
47
47
  visit '/full_protected_resources/1.json'
48
- response_status_should_be 401
48
+ response_status_should_be 403
49
49
  end
50
50
 
51
51
  scenario 'access token with default scope' do
52
52
  default_scopes_exist :admin
53
- @token.update_column :scopes, 'admin'
53
+ @token.update_attribute :scopes, 'admin'
54
54
  with_access_token_header @token.token
55
55
  visit '/full_protected_resources/1.json'
56
56
  expect(page.body).to have_content('show')
@@ -4,7 +4,7 @@ shared_context 'valid token', token: :valid do
4
4
  end
5
5
 
6
6
  let :token do
7
- double(Doorkeeper::AccessToken, accessible?: true)
7
+ double(Doorkeeper::AccessToken, accessible?: true, includes_scope?: true, acceptable?: true)
8
8
  end
9
9
 
10
10
  before :each do
@@ -18,7 +18,7 @@ shared_context 'invalid token', token: :invalid do
18
18
  end
19
19
 
20
20
  let :token do
21
- double(Doorkeeper::AccessToken, accessible?: false, revoked?: false, expired?: false)
21
+ double(Doorkeeper::AccessToken, accessible?: false, revoked?: false, expired?: false, includes_scope?: false, acceptable?: false)
22
22
  end
23
23
 
24
24
  before :each do
@@ -41,7 +41,6 @@ describe RedirectUriValidator do
41
41
 
42
42
  it 'is invalid when the uri has a query parameter' do
43
43
  subject.redirect_uri = 'http://example.com/abcd?xyz=123'
44
- expect(subject).not_to be_valid
45
- expect(subject.errors[:redirect_uri].first).to eq('cannot contain a query parameter.')
44
+ expect(subject).to be_valid
46
45
  end
47
46
  end
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: 1.3.1
4
+ version: 1.4.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: 2014-07-06 00:00:00.000000000 Z
12
+ date: 2014-07-31 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: railties
@@ -151,6 +151,20 @@ dependencies:
151
151
  - - "~>"
152
152
  - !ruby/object:Gem::Version
153
153
  version: 3.0.1
154
+ - !ruby/object:Gem::Dependency
155
+ name: pry
156
+ requirement: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - "~>"
159
+ - !ruby/object:Gem::Version
160
+ version: 0.10.0
161
+ type: :development
162
+ prerelease: false
163
+ version_requirements: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - "~>"
166
+ - !ruby/object:Gem::Version
167
+ version: 0.10.0
154
168
  description: Doorkeeper is an OAuth 2 provider for Rails.
155
169
  email:
156
170
  - felipe@applicake.com
@@ -171,6 +185,7 @@ files:
171
185
  - app/assets/stylesheets/doorkeeper/admin/application.css
172
186
  - app/assets/stylesheets/doorkeeper/application.css
173
187
  - app/controllers/doorkeeper/application_controller.rb
188
+ - app/controllers/doorkeeper/application_metal_controller.rb
174
189
  - app/controllers/doorkeeper/applications_controller.rb
175
190
  - app/controllers/doorkeeper/authorizations_controller.rb
176
191
  - app/controllers/doorkeeper/authorized_applications_controller.rb
@@ -211,8 +226,6 @@ files:
211
226
  - lib/doorkeeper/models/mongo_mapper/access_grant.rb
212
227
  - lib/doorkeeper/models/mongo_mapper/access_token.rb
213
228
  - lib/doorkeeper/models/mongo_mapper/application.rb
214
- - lib/doorkeeper/models/mongo_mapper/revocable.rb
215
- - lib/doorkeeper/models/mongoid/revocable.rb
216
229
  - lib/doorkeeper/models/mongoid/scopes.rb
217
230
  - lib/doorkeeper/models/mongoid/version.rb
218
231
  - lib/doorkeeper/models/mongoid2/access_grant.rb
@@ -239,6 +252,7 @@ files:
239
252
  - lib/doorkeeper/oauth/code_response.rb
240
253
  - lib/doorkeeper/oauth/error.rb
241
254
  - lib/doorkeeper/oauth/error_response.rb
255
+ - lib/doorkeeper/oauth/forbidden_token_response.rb
242
256
  - lib/doorkeeper/oauth/helpers/scope_checker.rb
243
257
  - lib/doorkeeper/oauth/helpers/unique_token.rb
244
258
  - lib/doorkeeper/oauth/helpers/uri_checker.rb
@@ -347,6 +361,7 @@ files:
347
361
  - spec/lib/oauth/code_request_spec.rb
348
362
  - spec/lib/oauth/error_response_spec.rb
349
363
  - spec/lib/oauth/error_spec.rb
364
+ - spec/lib/oauth/forbidden_token_response_spec.rb
350
365
  - spec/lib/oauth/helpers/scope_checker_spec.rb
351
366
  - spec/lib/oauth/helpers/unique_token_spec.rb
352
367
  - spec/lib/oauth/helpers/uri_checker_spec.rb
@@ -1,15 +0,0 @@
1
- module Doorkeeper
2
- module Models
3
- module MongoMapper
4
- module Revocable
5
- def self.included(base)
6
- base.class_eval do
7
- def update_column(attr, val)
8
- update_attribute attr, val
9
- end
10
- end
11
- end
12
- end
13
- end
14
- end
15
- end
@@ -1,15 +0,0 @@
1
- module Doorkeeper
2
- module Models
3
- module Mongoid
4
- module Revocable
5
- def self.included(base)
6
- base.class_eval do
7
- def update_column(attr, val)
8
- update_attribute attr, val
9
- end
10
- end
11
- end
12
- end
13
- end
14
- end
15
- end