rack-oauth2 1.12.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +3 -0
  3. data/.github/workflows/spec.yml +32 -0
  4. data/CHANGELOG.md +25 -0
  5. data/README.rdoc +1 -26
  6. data/VERSION +1 -1
  7. data/lib/rack/oauth2/access_token/authenticator.rb +1 -10
  8. data/lib/rack/oauth2/access_token/bearer.rb +1 -1
  9. data/lib/rack/oauth2/access_token/mtls.rb +2 -2
  10. data/lib/rack/oauth2/access_token.rb +4 -6
  11. data/lib/rack/oauth2/client.rb +97 -41
  12. data/lib/rack/oauth2/server/abstract/error.rb +2 -1
  13. data/lib/rack/oauth2/server/extension/pkce.rb +1 -1
  14. data/lib/rack/oauth2/server/rails/response_ext.rb +5 -5
  15. data/lib/rack/oauth2/server/resource/error.rb +4 -4
  16. data/lib/rack/oauth2/server/resource.rb +0 -1
  17. data/lib/rack/oauth2/server/token/error.rb +3 -1
  18. data/lib/rack/oauth2/server/token.rb +16 -5
  19. data/lib/rack/oauth2/urn.rb +3 -3
  20. data/lib/rack/oauth2/util.rb +6 -2
  21. data/lib/rack/oauth2.rb +11 -10
  22. data/rack-oauth2.gemspec +7 -5
  23. data/spec/helpers/webmock_helper.rb +8 -2
  24. data/spec/rack/oauth2/access_token/authenticator_spec.rb +2 -22
  25. data/spec/rack/oauth2/access_token/bearer_spec.rb +2 -2
  26. data/spec/rack/oauth2/access_token_spec.rb +0 -17
  27. data/spec/rack/oauth2/client_spec.rb +173 -75
  28. data/spec/rack/oauth2/oauth2_spec.rb +0 -43
  29. data/spec/rack/oauth2/server/authorize/error_spec.rb +6 -6
  30. data/spec/rack/oauth2/server/resource/bearer/error_spec.rb +2 -2
  31. data/spec/rack/oauth2/server/resource/bearer_spec.rb +9 -9
  32. data/spec/rack/oauth2/server/resource/error_spec.rb +21 -21
  33. data/spec/rack/oauth2/server/token/authorization_code_spec.rb +2 -2
  34. data/spec/rack/oauth2/server/token/client_credentials_spec.rb +32 -2
  35. data/spec/rack/oauth2/server/token/error_spec.rb +8 -8
  36. data/spec/rack/oauth2/server/token_spec.rb +72 -3
  37. data/spec/rack/oauth2/util_spec.rb +8 -3
  38. metadata +47 -51
  39. data/.travis.yml +0 -7
  40. data/lib/rack/oauth2/access_token/legacy.rb +0 -19
  41. data/lib/rack/oauth2/access_token/mac/sha256_hex_verifier.rb +0 -17
  42. data/lib/rack/oauth2/access_token/mac/signature.rb +0 -34
  43. data/lib/rack/oauth2/access_token/mac/verifier.rb +0 -44
  44. data/lib/rack/oauth2/access_token/mac.rb +0 -103
  45. data/lib/rack/oauth2/debugger/request_filter.rb +0 -30
  46. data/lib/rack/oauth2/debugger.rb +0 -3
  47. data/lib/rack/oauth2/server/resource/mac/error.rb +0 -24
  48. data/lib/rack/oauth2/server/resource/mac.rb +0 -36
  49. data/spec/mock_response/tokens/legacy.json +0 -5
  50. data/spec/mock_response/tokens/legacy.txt +0 -1
  51. data/spec/mock_response/tokens/legacy_without_expires_in.txt +0 -1
  52. data/spec/mock_response/tokens/mac.json +0 -8
  53. data/spec/rack/oauth2/access_token/legacy_spec.rb +0 -23
  54. data/spec/rack/oauth2/access_token/mac/sha256_hex_verifier_spec.rb +0 -28
  55. data/spec/rack/oauth2/access_token/mac/signature_spec.rb +0 -59
  56. data/spec/rack/oauth2/access_token/mac/verifier_spec.rb +0 -25
  57. data/spec/rack/oauth2/access_token/mac_spec.rb +0 -141
  58. data/spec/rack/oauth2/debugger/request_filter_spec.rb +0 -33
  59. data/spec/rack/oauth2/server/resource/mac/error_spec.rb +0 -52
  60. data/spec/rack/oauth2/server/resource/mac_spec.rb +0 -119
  61. /data/spec/mock_response/{blank → blank.txt} +0 -0
data/rack-oauth2.gemspec CHANGED
@@ -2,19 +2,20 @@ Gem::Specification.new do |s|
2
2
  s.name = 'rack-oauth2'
3
3
  s.version = File.read('VERSION')
4
4
  s.authors = ['nov matake']
5
- s.description = %q{OAuth 2.0 Server & Client Library. Both Bearer and MAC token type are supported.}
6
- s.summary = %q{OAuth 2.0 Server & Client Library - Both Bearer and MAC token type are supported}
5
+ s.description = %q{OAuth 2.0 Server & Client Library. Both Bearer token type are supported.}
6
+ s.summary = %q{OAuth 2.0 Server & Client Library - Both Bearer token type are supported}
7
7
  s.email = 'nov@matake.jp'
8
8
  s.extra_rdoc_files = ['LICENSE', 'README.rdoc']
9
9
  s.rdoc_options = ['--charset=UTF-8']
10
- s.homepage = 'http://github.com/nov/rack-oauth2'
10
+ s.homepage = 'https://github.com/nov/rack-oauth2'
11
11
  s.license = 'MIT'
12
12
  s.require_paths = ['lib']
13
13
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
14
14
  s.files = `git ls-files`.split("\n")
15
15
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
- s.add_runtime_dependency 'rack', '< 2.1'
17
- s.add_runtime_dependency 'httpclient'
16
+ s.add_runtime_dependency 'rack', '>= 2.1.0'
17
+ s.add_runtime_dependency 'faraday', '~> 2.0'
18
+ s.add_runtime_dependency 'faraday-follow_redirects'
18
19
  s.add_runtime_dependency 'activesupport'
19
20
  s.add_runtime_dependency 'attr_required'
20
21
  s.add_runtime_dependency 'json-jwt', '>= 1.11.0'
@@ -23,4 +24,5 @@ Gem::Specification.new do |s|
23
24
  s.add_development_dependency 'rspec'
24
25
  s.add_development_dependency 'rspec-its'
25
26
  s.add_development_dependency 'webmock'
27
+ s.add_development_dependency 'rexml'
26
28
  end
@@ -13,7 +13,7 @@ module WebMockHelper
13
13
 
14
14
  def request_for(method, options = {})
15
15
  request = {}
16
- params = options.try(:[], :params) || {}
16
+ params = options&.[](:params) || {}
17
17
  case method
18
18
  when :post, :put, :delete
19
19
  request[:body] = params
@@ -28,7 +28,13 @@ module WebMockHelper
28
28
 
29
29
  def response_for(response_file, options = {})
30
30
  response = {}
31
- response[:body] = File.new(File.join(File.dirname(__FILE__), '../mock_response', response_file))
31
+ format = options[:format] || :json
32
+ if format == :json
33
+ response[:headers] = {
34
+ 'Content-Type': 'application/json'
35
+ }
36
+ end
37
+ response[:body] = File.new(File.join(File.dirname(__FILE__), '../mock_response', "#{response_file}.#{format}"))
32
38
  if options[:status]
33
39
  response[:status] = options[:status]
34
40
  end
@@ -2,25 +2,16 @@ require 'spec_helper'
2
2
 
3
3
  describe Rack::OAuth2::AccessToken::Authenticator do
4
4
  let(:resource_endpoint) { 'https://server.example.com/resources/fake' }
5
- let(:request) { HTTP::Message.new_request(:get, URI.parse(resource_endpoint)) }
5
+ let(:request) { Faraday::Request.new(:get, URI.parse(resource_endpoint)) }
6
6
  let(:authenticator) { Rack::OAuth2::AccessToken::Authenticator.new(token) }
7
7
 
8
8
  shared_examples_for :authenticator do
9
9
  it 'should let the token authenticate the request' do
10
10
  expect(token).to receive(:authenticate).with(request)
11
- authenticator.filter_request(request)
11
+ authenticator.authenticate(request)
12
12
  end
13
13
  end
14
14
 
15
- context 'when Legacy token is given' do
16
- let(:token) do
17
- Rack::OAuth2::AccessToken::Legacy.new(
18
- access_token: 'access_token'
19
- )
20
- end
21
- it_behaves_like :authenticator
22
- end
23
-
24
15
  context 'when Bearer token is given' do
25
16
  let(:token) do
26
17
  Rack::OAuth2::AccessToken::Bearer.new(
@@ -29,15 +20,4 @@ describe Rack::OAuth2::AccessToken::Authenticator do
29
20
  end
30
21
  it_behaves_like :authenticator
31
22
  end
32
-
33
- context 'when MAC token is given' do
34
- let(:token) do
35
- Rack::OAuth2::AccessToken::MAC.new(
36
- access_token: 'access_token',
37
- mac_key: 'secret',
38
- mac_algorithm: 'hmac-sha-256'
39
- )
40
- end
41
- it_behaves_like :authenticator
42
- end
43
23
  end
@@ -7,11 +7,11 @@ describe Rack::OAuth2::AccessToken::Bearer do
7
7
  )
8
8
  end
9
9
  let(:resource_endpoint) { 'https://server.example.com/resources/fake' }
10
- let(:request) { HTTPClient.new.send(:create_request, :post, URI.parse(resource_endpoint), {}, {hello: "world"}, {}) }
10
+ let(:request) { Faraday::Request.new(:post, URI.parse(resource_endpoint), '', {hello: "world"}, {}) }
11
11
 
12
12
  describe '.authenticate' do
13
13
  it 'should set Authorization header' do
14
- expect(request.header).to receive(:[]=).with('Authorization', 'Bearer access_token')
14
+ expect(request.headers).to receive(:[]=).with('Authorization', 'Bearer access_token')
15
15
  token.authenticate(request)
16
16
  end
17
17
  end
@@ -49,23 +49,6 @@ describe Rack::OAuth2::AccessToken do
49
49
 
50
50
  let(:resource_endpoint) { 'https://server.example.com/resources/fake' }
51
51
  [:get, :delete, :post, :put].each do |method|
52
- describe method do
53
- it 'should delegate to HTTPClient with Authenticator filter' do
54
- expect(token.httpclient).to receive(method).with(resource_endpoint)
55
- token.httpclient.request_filter.last.should be_a Rack::OAuth2::AccessToken::Authenticator
56
- token.send method, resource_endpoint
57
- end
58
- end
59
-
60
- context 'in debug mode' do
61
- it do
62
- Rack::OAuth2.debug do
63
- token.httpclient.request_filter[-2].should be_a Rack::OAuth2::AccessToken::Authenticator
64
- token.httpclient.request_filter.last.should be_a Rack::OAuth2::Debugger::RequestFilter
65
- end
66
- end
67
- end
68
-
69
52
  context 'when extension params given' do
70
53
  subject do
71
54
  Rack::OAuth2::AccessToken::Bearer.new(
@@ -1,12 +1,15 @@
1
1
  require 'spec_helper.rb'
2
2
 
3
3
  describe Rack::OAuth2::Client do
4
+ let(:client_id) { 'client_id' }
5
+ let(:client_secret) { 'client_secret' }
4
6
  let :client do
5
7
  Rack::OAuth2::Client.new(
6
- identifier: 'client_id',
7
- secret: 'client_secret',
8
+ identifier: client_id,
9
+ secret: client_secret,
8
10
  host: 'server.example.com',
9
- redirect_uri: 'https://client.example.com/callback'
11
+ redirect_uri: 'https://client.example.com/callback',
12
+ revocation_endpoint: '/oauth2/revoke'
10
13
  )
11
14
  end
12
15
  subject { client }
@@ -15,6 +18,7 @@ describe Rack::OAuth2::Client do
15
18
  its(:secret) { should == 'client_secret' }
16
19
  its(:authorization_endpoint) { should == '/oauth2/authorize' }
17
20
  its(:token_endpoint) { should == '/oauth2/token' }
21
+ its(:revocation_endpoint) { should == '/oauth2/revoke' }
18
22
 
19
23
  context 'when identifier is missing' do
20
24
  it do
@@ -89,7 +93,7 @@ describe Rack::OAuth2::Client do
89
93
  mock_response(
90
94
  :post,
91
95
  'https://server.example.com/oauth2/token',
92
- 'tokens/bearer.json',
96
+ 'tokens/bearer',
93
97
  request_header: {
94
98
  'Authorization' => 'Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ='
95
99
  }
@@ -97,13 +101,49 @@ describe Rack::OAuth2::Client do
97
101
  client.access_token!
98
102
  end
99
103
 
104
+ context 'when Basic auth method is used' do
105
+ context 'when client_id is a url' do
106
+ let(:client_id) { 'https://client.example.com'}
107
+
108
+ it 'should be encoded in "application/x-www-form-urlencoded"' do
109
+ mock_response(
110
+ :post,
111
+ 'https://server.example.com/oauth2/token',
112
+ 'tokens/bearer',
113
+ request_header: {
114
+ 'Authorization' => 'Basic aHR0cHMlM0ElMkYlMkZjbGllbnQuZXhhbXBsZS5jb206Y2xpZW50X3NlY3JldA=='
115
+ }
116
+ )
117
+ client.access_token!
118
+ end
119
+ end
120
+ end
121
+
122
+ context 'when basic_without_www_form_urlencode method is used' do
123
+ context 'when client_id is a url' do
124
+ let(:client_id) { 'https://client.example.com'}
125
+
126
+ it 'should be encoded in "application/x-www-form-urlencoded"' do
127
+ mock_response(
128
+ :post,
129
+ 'https://server.example.com/oauth2/token',
130
+ 'tokens/bearer',
131
+ request_header: {
132
+ 'Authorization' => 'Basic aHR0cHM6Ly9jbGllbnQuZXhhbXBsZS5jb206Y2xpZW50X3NlY3JldA=='
133
+ }
134
+ )
135
+ client.access_token! :basic_without_www_form_urlencode
136
+ end
137
+ end
138
+ end
139
+
100
140
  context 'when jwt_bearer auth method specified' do
101
141
  context 'when client_secret is given' do
102
142
  it 'should be JWT bearer client assertion w/ auto-generated HS256-signed JWT assertion' do
103
143
  mock_response(
104
144
  :post,
105
145
  'https://server.example.com/oauth2/token',
106
- 'tokens/bearer.json',
146
+ 'tokens/bearer',
107
147
  params: {
108
148
  client_assertion: /^eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9\..+/, # NOTE: HS256
109
149
  client_assertion_type: Rack::OAuth2::URN::ClientAssertionType::JWT_BEARER,
@@ -131,7 +171,7 @@ describe Rack::OAuth2::Client do
131
171
  mock_response(
132
172
  :post,
133
173
  'https://server.example.com/oauth2/token',
134
- 'tokens/bearer.json',
174
+ 'tokens/bearer',
135
175
  params: {
136
176
  client_assertion: /^eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9\..+/, # NOTE: RS256
137
177
  client_assertion_type: Rack::OAuth2::URN::ClientAssertionType::JWT_BEARER,
@@ -148,7 +188,7 @@ describe Rack::OAuth2::Client do
148
188
  let :client do
149
189
  Rack::OAuth2::Client.new(
150
190
  identifier: 'client_id',
151
- private_key: OpenSSL::PKey::EC.new('prime256v1').generate_key,
191
+ private_key: OpenSSL::PKey::EC.generate('prime256v1'),
152
192
  host: 'server.example.com',
153
193
  redirect_uri: 'https://client.example.com/callback'
154
194
  )
@@ -158,7 +198,7 @@ describe Rack::OAuth2::Client do
158
198
  mock_response(
159
199
  :post,
160
200
  'https://server.example.com/oauth2/token',
161
- 'tokens/bearer.json',
201
+ 'tokens/bearer',
162
202
  params: {
163
203
  client_assertion: /^eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9\..+/, # NOTE: ES256
164
204
  client_assertion_type: Rack::OAuth2::URN::ClientAssertionType::JWT_BEARER,
@@ -185,7 +225,7 @@ describe Rack::OAuth2::Client do
185
225
  mock_response(
186
226
  :post,
187
227
  'https://server.example.com/oauth2/token',
188
- 'tokens/bearer.json',
228
+ 'tokens/bearer',
189
229
  params: {
190
230
  client_assertion: 'any.jwt.assertion',
191
231
  client_assertion_type: Rack::OAuth2::URN::ClientAssertionType::JWT_BEARER,
@@ -204,7 +244,7 @@ describe Rack::OAuth2::Client do
204
244
  mock_response(
205
245
  :post,
206
246
  'https://server.example.com/oauth2/token',
207
- 'tokens/bearer.json',
247
+ 'tokens/bearer',
208
248
  params: {
209
249
  client_id: 'client_id',
210
250
  client_secret: 'client_secret',
@@ -222,7 +262,7 @@ describe Rack::OAuth2::Client do
222
262
  mock_response(
223
263
  :post,
224
264
  'https://server.example.com/oauth2/token',
225
- 'tokens/bearer.json',
265
+ 'tokens/bearer',
226
266
  params: {
227
267
  client_id: 'client_id',
228
268
  client_secret: 'client_secret',
@@ -242,7 +282,7 @@ describe Rack::OAuth2::Client do
242
282
  mock_response(
243
283
  :post,
244
284
  'https://server.example.com/oauth2/token',
245
- 'tokens/bearer.json',
285
+ 'tokens/bearer',
246
286
  params: {
247
287
  grant_type: 'client_credentials',
248
288
  scope: 'a b'
@@ -258,7 +298,7 @@ describe Rack::OAuth2::Client do
258
298
  mock_response(
259
299
  :post,
260
300
  'https://server.example.com/oauth2/token',
261
- 'tokens/bearer.json',
301
+ 'tokens/bearer',
262
302
  params: {
263
303
  grant_type: 'client_credentials',
264
304
  resource: 'something'
@@ -269,13 +309,30 @@ describe Rack::OAuth2::Client do
269
309
  end
270
310
  end
271
311
 
312
+ context 'local_http_config handling' do
313
+ it do
314
+ mock_response(
315
+ :post,
316
+ 'https://server.example.com/oauth2/token',
317
+ 'tokens/bearer',
318
+ request_header: {
319
+ 'Authorization' => 'Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=',
320
+ 'X-Foo' => 'bar'
321
+ }
322
+ )
323
+ client.access_token! do |request|
324
+ request.headers['X-Foo'] = 'bar'
325
+ end
326
+ end
327
+ end
328
+
272
329
  context 'when bearer token is given' do
273
330
  before do
274
331
  client.authorization_code = 'code'
275
332
  mock_response(
276
333
  :post,
277
334
  'https://server.example.com/oauth2/token',
278
- 'tokens/bearer.json'
335
+ 'tokens/bearer'
279
336
  )
280
337
  end
281
338
  it { should be_instance_of Rack::OAuth2::AccessToken::Bearer }
@@ -290,7 +347,7 @@ describe Rack::OAuth2::Client do
290
347
  mock_response(
291
348
  :post,
292
349
  'https://server.example.com/oauth2/token',
293
- 'tokens/_Bearer.json'
350
+ 'tokens/_Bearer'
294
351
  )
295
352
  end
296
353
  it { should be_instance_of Rack::OAuth2::AccessToken::Bearer }
@@ -298,112 +355,146 @@ describe Rack::OAuth2::Client do
298
355
  end
299
356
  end
300
357
 
301
- context 'when mac token is given' do
358
+ context 'when unknown-type token is given' do
302
359
  before do
303
360
  client.authorization_code = 'code'
304
361
  mock_response(
305
362
  :post,
306
363
  'https://server.example.com/oauth2/token',
307
- 'tokens/mac.json'
364
+ 'tokens/unknown'
308
365
  )
309
366
  end
310
- it { should be_instance_of Rack::OAuth2::AccessToken::MAC }
311
- its(:token_type) { should == :mac }
312
- its(:access_token) { should == 'access_token' }
313
- its(:refresh_token) { should == 'refresh_token' }
314
- its(:expires_in) { should == 3600 }
367
+ it do
368
+ expect { client.access_token! }.to raise_error(StandardError, 'Unknown Token Type')
369
+ end
315
370
  end
316
371
 
317
- context 'when no-type token is given (JSON)' do
372
+ context 'when error response is given' do
318
373
  before do
319
- client.authorization_code = 'code'
320
374
  mock_response(
321
375
  :post,
322
376
  'https://server.example.com/oauth2/token',
323
- 'tokens/legacy.json'
377
+ 'errors/invalid_request',
378
+ status: 400
324
379
  )
325
380
  end
326
- it { should be_instance_of Rack::OAuth2::AccessToken::Legacy }
327
- its(:token_type) { should == :legacy }
328
- its(:access_token) { should == 'access_token' }
329
- its(:refresh_token) { should == 'refresh_token' }
330
- its(:expires_in) { should == 3600 }
381
+ it do
382
+ expect { client.access_token! }.to raise_error Rack::OAuth2::Client::Error
383
+ end
384
+ end
331
385
 
332
- context 'when token_type is forced' do
386
+ context 'when no body given' do
387
+ context 'when error given' do
333
388
  before do
334
- client.force_token_type! :bearer
389
+ mock_response(
390
+ :post,
391
+ 'https://server.example.com/oauth2/token',
392
+ 'blank',
393
+ format: 'txt',
394
+ status: 400
395
+ )
396
+ end
397
+ it do
398
+ expect { client.access_token! }.to raise_error Rack::OAuth2::Client::Error
335
399
  end
336
- it { should be_instance_of Rack::OAuth2::AccessToken::Bearer }
337
- its(:token_type) { should == :bearer }
338
400
  end
339
401
  end
402
+ end
340
403
 
341
- context 'when no-type token is given (key-value)' do
342
- before do
404
+ describe '#revoke!' do
405
+ context 'local_http_config handling' do
406
+ it do
343
407
  mock_response(
344
408
  :post,
345
- 'https://server.example.com/oauth2/token',
346
- 'tokens/legacy.txt'
409
+ 'https://server.example.com/oauth2/revoke',
410
+ 'blank',
411
+ format: 'txt',
412
+ status: 200,
413
+ body: {
414
+ token: 'access_token',
415
+ token_type_hint: 'access_token'
416
+ },
417
+ request_header: {
418
+ 'Authorization' => 'Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=',
419
+ 'X-Foo' => 'bar'
420
+ }
347
421
  )
348
- end
349
- it { should be_instance_of Rack::OAuth2::AccessToken::Legacy }
350
- its(:token_type) { should == :legacy }
351
- its(:access_token) { should == 'access_token' }
352
- its(:expires_in) { should == 3600 }
353
-
354
- context 'when expires_in is not given' do
355
- before do
356
- mock_response(
357
- :post,
358
- 'https://server.example.com/oauth2/token',
359
- 'tokens/legacy_without_expires_in.txt'
360
- )
422
+ client.revoke!(access_token: 'access_token') do |request|
423
+ request.headers['X-Foo'] = 'bar'
361
424
  end
362
- its(:expires_in) { should be_nil }
363
425
  end
364
426
  end
365
427
 
366
- context 'when unknown-type token is given' do
428
+ context 'when access_token given' do
367
429
  before do
368
- client.authorization_code = 'code'
369
430
  mock_response(
370
431
  :post,
371
- 'https://server.example.com/oauth2/token',
372
- 'tokens/unknown.json'
432
+ 'https://server.example.com/oauth2/revoke',
433
+ 'blank',
434
+ format: 'txt',
435
+ status: 200,
436
+ body: {
437
+ token: 'access_token',
438
+ token_type_hint: 'access_token'
439
+ }
373
440
  )
374
441
  end
375
442
  it do
376
- expect { client.access_token! }.to raise_error(StandardError, 'Unknown Token Type')
443
+ client.revoke!(access_token: 'access_token').should == :success
377
444
  end
378
445
  end
379
446
 
380
- context 'when error response is given' do
447
+ context 'when refresh_token given' do
381
448
  before do
382
449
  mock_response(
383
450
  :post,
384
- 'https://server.example.com/oauth2/token',
385
- 'errors/invalid_request.json',
451
+ 'https://server.example.com/oauth2/revoke',
452
+ 'blank',
453
+ format: 'txt',
454
+ status: 200,
455
+ body: {
456
+ token: 'refresh_token',
457
+ token_type_hint: 'refresh_token'
458
+ }
459
+ )
460
+ end
461
+
462
+ context 'as argument' do
463
+ it do
464
+ client.revoke!(refresh_token: 'refresh_token').should == :success
465
+ end
466
+ end
467
+
468
+ context 'as grant' do
469
+ it do
470
+ client.refresh_token = 'refresh_token'
471
+ client.revoke!
472
+ end
473
+ end
474
+ end
475
+
476
+ context 'when error response given' do
477
+ before do
478
+ mock_response(
479
+ :post,
480
+ 'https://server.example.com/oauth2/revoke',
481
+ 'errors/invalid_request',
386
482
  status: 400
387
483
  )
388
484
  end
485
+
389
486
  it do
390
- expect { client.access_token! }.to raise_error Rack::OAuth2::Client::Error
487
+ expect do
488
+ client.revoke! access_token: 'access_token'
489
+ end.to raise_error Rack::OAuth2::Client::Error
391
490
  end
392
491
  end
393
492
 
394
- context 'when no body given' do
395
- context 'when error given' do
396
- before do
397
- mock_response(
398
- :post,
399
- 'https://server.example.com/oauth2/token',
400
- 'blank',
401
- status: 400
402
- )
403
- end
404
- it do
405
- expect { client.access_token! }.to raise_error Rack::OAuth2::Client::Error
406
- end
493
+ context 'when no token given' do
494
+ it do
495
+ expect do
496
+ client.revoke!
497
+ end.to raise_error ArgumentError
407
498
  end
408
499
  end
409
500
  end
@@ -413,7 +504,8 @@ describe Rack::OAuth2::Client do
413
504
  Rack::OAuth2::Client.new(
414
505
  identifier: 'client_id',
415
506
  secret: 'client_secret',
416
- redirect_uri: 'https://client.example.com/callback'
507
+ redirect_uri: 'https://client.example.com/callback',
508
+ revocation_endpoint: '/oauth2/revoke'
417
509
  )
418
510
  end
419
511
 
@@ -428,5 +520,11 @@ describe Rack::OAuth2::Client do
428
520
  expect { client.access_token! }.to raise_error 'No Host Info'
429
521
  end
430
522
  end
523
+
524
+ describe '#revoke!' do
525
+ it do
526
+ expect { client.revoke! access_token: 'access_token' }.to raise_error 'No Host Info'
527
+ end
528
+ end
431
529
  end
432
530
  end
@@ -28,47 +28,4 @@ describe Rack::OAuth2 do
28
28
  Rack::OAuth2.debugging?.should == true
29
29
  end
30
30
  end
31
-
32
- describe '.http_config' do
33
- context 'when request_filter added' do
34
- context 'when "debug!" is called' do
35
- after { Rack::OAuth2.reset_http_config! }
36
-
37
- it 'should put Debugger::RequestFilter at last' do
38
- Rack::OAuth2.debug!
39
- Rack::OAuth2.http_config do |config|
40
- config.request_filter << Proc.new {}
41
- end
42
- Rack::OAuth2.http_client.request_filter.last.should be_instance_of Rack::OAuth2::Debugger::RequestFilter
43
- end
44
-
45
- it 'should reset_http_config' do
46
- Rack::OAuth2.debug!
47
- Rack::OAuth2.http_config do |config|
48
- config.request_filter << Proc.new {}
49
- end
50
- size = Rack::OAuth2.http_client.request_filter.size
51
- Rack::OAuth2.reset_http_config!
52
- Rack::OAuth2.http_client.request_filter.size.should == size - 1
53
- end
54
-
55
- end
56
- end
57
- end
58
-
59
- describe ".http_client" do
60
- context "when local_http_config is used" do
61
- it "should correctly set request_filter" do
62
- clnt1 = Rack::OAuth2.http_client
63
- clnt2 = Rack::OAuth2.http_client("my client") do |config|
64
- config.request_filter << Proc.new {}
65
- end
66
- clnt3 = Rack::OAuth2.http_client
67
-
68
- clnt1.request_filter.size.should == clnt3.request_filter.size
69
- clnt1.request_filter.size.should == clnt2.request_filter.size - 1
70
-
71
- end
72
- end
73
- end
74
31
  end
@@ -23,27 +23,27 @@ describe Rack::OAuth2::Server::Authorize::BadRequest do
23
23
  context 'when protocol_params_location = :query' do
24
24
  before { error.protocol_params_location = :query }
25
25
  it 'should redirect with error in query' do
26
- state, header, response = error.finish
26
+ state, headers, response = error.finish
27
27
  state.should == 302
28
- header["Location"].should == "#{redirect_uri}?error=invalid_request"
28
+ headers["Location"].should == "#{redirect_uri}?error=invalid_request"
29
29
  end
30
30
  end
31
31
 
32
32
  context 'when protocol_params_location = :fragment' do
33
33
  before { error.protocol_params_location = :fragment }
34
34
  it 'should redirect with error in fragment' do
35
- state, header, response = error.finish
35
+ state, headers, response = error.finish
36
36
  state.should == 302
37
- header["Location"].should == "#{redirect_uri}#error=invalid_request"
37
+ headers["Location"].should == "#{redirect_uri}#error=invalid_request"
38
38
  end
39
39
  end
40
40
 
41
41
  context 'otherwise' do
42
42
  before { error.protocol_params_location = :other }
43
43
  it 'should redirect without error' do
44
- state, header, response = error.finish
44
+ state, headers, response = error.finish
45
45
  state.should == 302
46
- header["Location"].should == redirect_uri
46
+ headers["Location"].should == redirect_uri
47
47
  end
48
48
  end
49
49
  end
@@ -12,8 +12,8 @@ describe Rack::OAuth2::Server::Resource::Bearer::Unauthorized do
12
12
 
13
13
  describe '#finish' do
14
14
  it 'should use Bearer scheme' do
15
- status, header, response = error.finish
16
- header['WWW-Authenticate'].should include 'Bearer'
15
+ status, headers, response = error.finish
16
+ headers['WWW-Authenticate'].should include 'Bearer'
17
17
  end
18
18
  end
19
19
  end