rack-oauth2-revibe 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.gitignore +22 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +3 -0
  6. data/Gemfile +7 -0
  7. data/LICENSE +20 -0
  8. data/README.rdoc +78 -0
  9. data/Rakefile +25 -0
  10. data/VERSION +1 -0
  11. data/lib/rack/oauth2.rb +67 -0
  12. data/lib/rack/oauth2/access_token.rb +36 -0
  13. data/lib/rack/oauth2/access_token/authenticator.rb +24 -0
  14. data/lib/rack/oauth2/access_token/bearer.rb +11 -0
  15. data/lib/rack/oauth2/access_token/legacy.rb +23 -0
  16. data/lib/rack/oauth2/access_token/mac.rb +103 -0
  17. data/lib/rack/oauth2/access_token/mac/sha256_hex_verifier.rb +17 -0
  18. data/lib/rack/oauth2/access_token/mac/signature.rb +34 -0
  19. data/lib/rack/oauth2/access_token/mac/verifier.rb +44 -0
  20. data/lib/rack/oauth2/client.rb +139 -0
  21. data/lib/rack/oauth2/client/error.rb +14 -0
  22. data/lib/rack/oauth2/client/grant.rb +30 -0
  23. data/lib/rack/oauth2/client/grant/authorization_code.rb +12 -0
  24. data/lib/rack/oauth2/client/grant/client_credentials.rb +10 -0
  25. data/lib/rack/oauth2/client/grant/facebook_token.rb +12 -0
  26. data/lib/rack/oauth2/client/grant/password.rb +11 -0
  27. data/lib/rack/oauth2/client/grant/refresh_token.rb +11 -0
  28. data/lib/rack/oauth2/debugger.rb +3 -0
  29. data/lib/rack/oauth2/debugger/request_filter.rb +30 -0
  30. data/lib/rack/oauth2/server.rb +4 -0
  31. data/lib/rack/oauth2/server/abstract.rb +4 -0
  32. data/lib/rack/oauth2/server/abstract/error.rb +69 -0
  33. data/lib/rack/oauth2/server/abstract/handler.rb +20 -0
  34. data/lib/rack/oauth2/server/abstract/request.rb +29 -0
  35. data/lib/rack/oauth2/server/abstract/response.rb +15 -0
  36. data/lib/rack/oauth2/server/authorize.rb +117 -0
  37. data/lib/rack/oauth2/server/authorize/code.rb +39 -0
  38. data/lib/rack/oauth2/server/authorize/error.rb +71 -0
  39. data/lib/rack/oauth2/server/authorize/extension.rb +12 -0
  40. data/lib/rack/oauth2/server/authorize/extension/code_and_token.rb +39 -0
  41. data/lib/rack/oauth2/server/authorize/token.rb +43 -0
  42. data/lib/rack/oauth2/server/resource.rb +55 -0
  43. data/lib/rack/oauth2/server/resource/bearer.rb +47 -0
  44. data/lib/rack/oauth2/server/resource/bearer/error.rb +24 -0
  45. data/lib/rack/oauth2/server/resource/error.rb +81 -0
  46. data/lib/rack/oauth2/server/resource/mac.rb +36 -0
  47. data/lib/rack/oauth2/server/resource/mac/error.rb +24 -0
  48. data/lib/rack/oauth2/server/token.rb +87 -0
  49. data/lib/rack/oauth2/server/token/authorization_code.rb +28 -0
  50. data/lib/rack/oauth2/server/token/client_credentials.rb +23 -0
  51. data/lib/rack/oauth2/server/token/error.rb +54 -0
  52. data/lib/rack/oauth2/server/token/extension.rb +12 -0
  53. data/lib/rack/oauth2/server/token/extension/jwt.rb +37 -0
  54. data/lib/rack/oauth2/server/token/facebook_token.rb +27 -0
  55. data/lib/rack/oauth2/server/token/password.rb +27 -0
  56. data/lib/rack/oauth2/server/token/refresh_token.rb +26 -0
  57. data/lib/rack/oauth2/util.rb +58 -0
  58. data/rack-oauth2.gemspec +30 -0
  59. data/spec/helpers/time.rb +19 -0
  60. data/spec/helpers/webmock_helper.rb +41 -0
  61. data/spec/mock_response/blank +0 -0
  62. data/spec/mock_response/errors/invalid_request.json +4 -0
  63. data/spec/mock_response/resources/fake.txt +1 -0
  64. data/spec/mock_response/tokens/_Bearer.json +6 -0
  65. data/spec/mock_response/tokens/bearer.json +6 -0
  66. data/spec/mock_response/tokens/legacy.json +5 -0
  67. data/spec/mock_response/tokens/legacy.txt +1 -0
  68. data/spec/mock_response/tokens/legacy_without_expires_in.txt +1 -0
  69. data/spec/mock_response/tokens/mac.json +8 -0
  70. data/spec/mock_response/tokens/unknown.json +6 -0
  71. data/spec/rack/oauth2/access_token/authenticator_spec.rb +43 -0
  72. data/spec/rack/oauth2/access_token/bearer_spec.rb +18 -0
  73. data/spec/rack/oauth2/access_token/legacy_spec.rb +23 -0
  74. data/spec/rack/oauth2/access_token/mac/sha256_hex_verifier_spec.rb +28 -0
  75. data/spec/rack/oauth2/access_token/mac/signature_spec.rb +59 -0
  76. data/spec/rack/oauth2/access_token/mac/verifier_spec.rb +25 -0
  77. data/spec/rack/oauth2/access_token/mac_spec.rb +141 -0
  78. data/spec/rack/oauth2/access_token_spec.rb +69 -0
  79. data/spec/rack/oauth2/client/error_spec.rb +18 -0
  80. data/spec/rack/oauth2/client/grant/authorization_code_spec.rb +37 -0
  81. data/spec/rack/oauth2/client/grant/client_credentials_spec.rb +7 -0
  82. data/spec/rack/oauth2/client/grant/password_spec.rb +33 -0
  83. data/spec/rack/oauth2/client/grant/refresh_token_spec.rb +21 -0
  84. data/spec/rack/oauth2/client_spec.rb +287 -0
  85. data/spec/rack/oauth2/debugger/request_filter_spec.rb +33 -0
  86. data/spec/rack/oauth2/oauth2_spec.rb +74 -0
  87. data/spec/rack/oauth2/server/abstract/error_spec.rb +59 -0
  88. data/spec/rack/oauth2/server/authorize/code_spec.rb +57 -0
  89. data/spec/rack/oauth2/server/authorize/error_spec.rb +103 -0
  90. data/spec/rack/oauth2/server/authorize/extensions/code_and_token_spec.rb +60 -0
  91. data/spec/rack/oauth2/server/authorize/token_spec.rb +73 -0
  92. data/spec/rack/oauth2/server/authorize_spec.rb +214 -0
  93. data/spec/rack/oauth2/server/resource/bearer/error_spec.rb +52 -0
  94. data/spec/rack/oauth2/server/resource/bearer_spec.rb +123 -0
  95. data/spec/rack/oauth2/server/resource/error_spec.rb +147 -0
  96. data/spec/rack/oauth2/server/resource/mac/error_spec.rb +52 -0
  97. data/spec/rack/oauth2/server/resource/mac_spec.rb +119 -0
  98. data/spec/rack/oauth2/server/resource_spec.rb +23 -0
  99. data/spec/rack/oauth2/server/token/authorization_code_spec.rb +43 -0
  100. data/spec/rack/oauth2/server/token/client_credentials_spec.rb +23 -0
  101. data/spec/rack/oauth2/server/token/error_spec.rb +77 -0
  102. data/spec/rack/oauth2/server/token/password_spec.rb +37 -0
  103. data/spec/rack/oauth2/server/token/refresh_token_spec.rb +34 -0
  104. data/spec/rack/oauth2/server/token_spec.rb +134 -0
  105. data/spec/rack/oauth2/util_spec.rb +97 -0
  106. data/spec/spec_helper.rb +14 -0
  107. metadata +326 -0
@@ -0,0 +1,52 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe Rack::OAuth2::Server::Resource::MAC::Unauthorized do
4
+ let(:error) { Rack::OAuth2::Server::Resource::MAC::Unauthorized.new(:invalid_token) }
5
+
6
+ it { should be_a Rack::OAuth2::Server::Resource::Unauthorized }
7
+
8
+ describe '#scheme' do
9
+ subject { error }
10
+ its(:scheme) { should == :MAC }
11
+ end
12
+
13
+ describe '#finish' do
14
+ it 'should use MAC scheme' do
15
+ status, header, response = error.finish
16
+ header['WWW-Authenticate'].should =~ /^MAC /
17
+ end
18
+ end
19
+ end
20
+
21
+ describe Rack::OAuth2::Server::Resource::MAC::ErrorMethods do
22
+ let(:unauthorized) { Rack::OAuth2::Server::Resource::MAC::Unauthorized }
23
+ let(:redirect_uri) { 'http://client.example.com/callback' }
24
+ let(:default_description) { Rack::OAuth2::Server::Resource::ErrorMethods::DEFAULT_DESCRIPTION }
25
+ let(:env) { Rack::MockRequest.env_for("/authorize?client_id=client_id") }
26
+ let(:request) { Rack::OAuth2::Server::Resource::MAC::Request.new env }
27
+
28
+ describe 'unauthorized!' do
29
+ it do
30
+ expect { request.unauthorized! :invalid_client }.to raise_error unauthorized
31
+ end
32
+ end
33
+
34
+ Rack::OAuth2::Server::Resource::Bearer::ErrorMethods::DEFAULT_DESCRIPTION.keys.each do |error_code|
35
+ method = "#{error_code}!"
36
+ case error_code
37
+ when :invalid_request
38
+ # ignore
39
+ when :insufficient_scope
40
+ # ignore
41
+ else
42
+ describe method do
43
+ it "should raise Rack::OAuth2::Server::Resource::Bearer::Unauthorized with error = :#{error_code}" do
44
+ expect { request.send method }.to raise_error(unauthorized) { |error|
45
+ error.error.should == error_code
46
+ error.description.should == default_description[error_code]
47
+ }
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,119 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe Rack::OAuth2::Server::Resource::MAC do
4
+ let(:app) do
5
+ Rack::OAuth2::Server::Resource::MAC.new(simple_app) do |request|
6
+ case request.access_token
7
+ when 'valid_token'
8
+ token = mac_token
9
+ token.verify!(request)
10
+ token
11
+ when 'insufficient_scope_token'
12
+ request.insufficient_scope!
13
+ else
14
+ request.invalid_token!
15
+ end
16
+ end
17
+ end
18
+ let(:mac_token) do
19
+ Rack::OAuth2::AccessToken::MAC.new(
20
+ :access_token => 'valid_token',
21
+ :mac_key => 'secret',
22
+ :mac_algorithm => 'hmac-sha-256',
23
+ :ts => 1305820230 # fix verification time
24
+ )
25
+ end
26
+ let(:access_token) { env[Rack::OAuth2::Server::Resource::ACCESS_TOKEN] }
27
+ let(:request) { app.call(env) }
28
+ subject { app.call(env) }
29
+
30
+ shared_examples_for :non_mac_request do
31
+ it 'should skip OAuth 2.0 authentication' do
32
+ status, header, response = request
33
+ status.should == 200
34
+ access_token.should be_nil
35
+ end
36
+ end
37
+ shared_examples_for :authenticated_mac_request do
38
+ it 'should be authenticated' do
39
+ status, header, response = request
40
+ status.should == 200
41
+ access_token.should == mac_token
42
+ end
43
+ end
44
+ shared_examples_for :unauthorized_mac_request do
45
+ it 'should be unauthorized' do
46
+ status, header, response = request
47
+ status.should == 401
48
+ header['WWW-Authenticate'].should include 'MAC'
49
+ access_token.should be_nil
50
+ end
51
+ end
52
+ shared_examples_for :bad_mac_request do
53
+ it 'should be unauthorized' do
54
+ status, header, response = request
55
+ status.should == 400
56
+ access_token.should be_nil
57
+ end
58
+ end
59
+
60
+ context 'when no access token is given' do
61
+ let(:env) { Rack::MockRequest.env_for('/protected_resource') }
62
+ it 'should skip OAuth 2.0 authentication' do
63
+ status, header, response = request
64
+ status.should == 200
65
+ access_token.should be_nil
66
+ end
67
+ end
68
+
69
+ context 'when valid_token is given' do
70
+ context 'when other required params are missing' do
71
+ let(:env) { Rack::MockRequest.env_for('/protected_resource', 'HTTP_AUTHORIZATION' => 'MAC id="valid_token"') }
72
+ it_behaves_like :unauthorized_mac_request
73
+ end
74
+
75
+ context 'when other required params are invalid' do
76
+ let(:env) { Rack::MockRequest.env_for('/protected_resource', 'HTTP_AUTHORIZATION' => 'MAC id="valid_token", nonce="51e74de734c05613f37520872e68db5f", ts="1305820234", mac="invalid""') }
77
+ it_behaves_like :unauthorized_mac_request
78
+ end
79
+
80
+ context 'when all required params are valid' do
81
+ let(:env) { Rack::MockRequest.env_for('/protected_resource', 'HTTP_AUTHORIZATION' => 'MAC id="valid_token", nonce="51e74de734c05613f37520872e68db5f", ts="1305820234", mac="26JP6MMZyAHLHeMU8+m+NbVJgZbikp5SlT86/a62pwg="') }
82
+ it_behaves_like :authenticated_mac_request
83
+ end
84
+
85
+ context 'when all required params are valid and ts is expired' do
86
+ let(:env) { Rack::MockRequest.env_for('/protected_resource', 'HTTP_AUTHORIZATION' => 'MAC id="valid_token", nonce="51e74de734c05613f37520872e68db5f", ts="1305819234", mac="nuo4765MZrVL/qMsAtuTczhqZAE5y02ChaLCyOiVU68="') }
87
+ it_behaves_like :unauthorized_mac_request
88
+ end
89
+ end
90
+
91
+ context 'when invalid_token is given' do
92
+ let(:env) { Rack::MockRequest.env_for('/protected_resource', 'HTTP_AUTHORIZATION' => 'MAC id="invalid_token"') }
93
+ it_behaves_like :unauthorized_mac_request
94
+
95
+ describe 'realm' do
96
+ let(:env) { Rack::MockRequest.env_for('/protected_resource', 'HTTP_AUTHORIZATION' => 'MAC id="invalid_token"') }
97
+
98
+ context 'when specified' do
99
+ let(:realm) { 'server.example.com' }
100
+ let(:app) do
101
+ Rack::OAuth2::Server::Resource::MAC.new(simple_app, realm) do |request|
102
+ request.unauthorized!
103
+ end
104
+ end
105
+ it 'should use specified realm' do
106
+ status, header, response = request
107
+ header['WWW-Authenticate'].should include "MAC realm=\"#{realm}\""
108
+ end
109
+ end
110
+
111
+ context 'otherwize' do
112
+ it 'should use default realm' do
113
+ status, header, response = request
114
+ header['WWW-Authenticate'].should include "MAC realm=\"#{Rack::OAuth2::Server::Resource::DEFAULT_REALM}\""
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe Rack::OAuth2::Server::Resource do
4
+ subject { Rack::OAuth2::Server::Resource.new(simple_app, 'realm') }
5
+ its(:realm) { should == 'realm' }
6
+ end
7
+
8
+ describe Rack::OAuth2::Server::Resource::Request do
9
+ let(:env) { Rack::MockRequest.env_for('/protected_resource') }
10
+ let(:request) { Rack::OAuth2::Server::Resource::Request.new(env) }
11
+
12
+ describe '#setup!' do
13
+ it do
14
+ expect { request.setup! }.to raise_error(RuntimeError, 'Define me!')
15
+ end
16
+ end
17
+
18
+ describe '#oauth2?' do
19
+ it do
20
+ expect { request.oauth2? }.to raise_error(RuntimeError, 'Define me!')
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe Rack::OAuth2::Server::Token::AuthorizationCode do
4
+ let(:request) { Rack::MockRequest.new app }
5
+ let(:app) do
6
+ Rack::OAuth2::Server::Token.new do |request, response|
7
+ response.access_token = Rack::OAuth2::AccessToken::Bearer.new(:access_token => 'access_token')
8
+ end
9
+ end
10
+ let(:params) do
11
+ {
12
+ :grant_type => 'authorization_code',
13
+ :client_id => 'client_id',
14
+ :code => 'authorization_code',
15
+ :redirect_uri => 'http://client.example.com/callback'
16
+ }
17
+ end
18
+ let(:response) { request.post('/', :params => params) }
19
+ subject { response }
20
+
21
+ its(:status) { should == 200 }
22
+ its(:content_type) { should == 'application/json' }
23
+ its(:body) { should include '"access_token":"access_token"' }
24
+ its(:body) { should include '"token_type":"bearer"' }
25
+
26
+ it 'should prevent to be cached' do
27
+ response.header['Cache-Control'].should == 'no-store'
28
+ response.header['Pragma'].should == 'no-cache'
29
+ end
30
+
31
+ [:code].each do |required|
32
+ context "when #{required} is missing" do
33
+ before do
34
+ params.delete_if do |key, value|
35
+ key == required
36
+ end
37
+ end
38
+ its(:status) { should == 400 }
39
+ its(:content_type) { should == 'application/json' }
40
+ its(:body) { should include '"error":"invalid_request"' }
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe Rack::OAuth2::Server::Token::ClientCredentials do
4
+ let(:request) { Rack::MockRequest.new app }
5
+ let(:app) do
6
+ Rack::OAuth2::Server::Token.new do |request, response|
7
+ response.access_token = Rack::OAuth2::AccessToken::Bearer.new(:access_token => 'access_token')
8
+ end
9
+ end
10
+ let(:params) do
11
+ {
12
+ :grant_type => 'client_credentials',
13
+ :client_id => 'client_id',
14
+ :client_secret => 'client_secret'
15
+ }
16
+ end
17
+ subject { request.post('/', :params => params) }
18
+
19
+ its(:status) { should == 200 }
20
+ its(:content_type) { should == 'application/json' }
21
+ its(:body) { should include '"access_token":"access_token"' }
22
+ its(:body) { should include '"token_type":"bearer"' }
23
+ end
@@ -0,0 +1,77 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe Rack::OAuth2::Server::Token::BadRequest do
4
+ let(:error) { Rack::OAuth2::Server::Token::BadRequest.new(:invalid_request) }
5
+
6
+ it { should be_a Rack::OAuth2::Server::Abstract::BadRequest }
7
+
8
+ describe '#finish' do
9
+ it 'should respond in JSON' do
10
+ status, header, response = error.finish
11
+ status.should == 400
12
+ header['Content-Type'].should == 'application/json'
13
+ response.body.should == ['{"error":"invalid_request"}']
14
+ end
15
+ end
16
+ end
17
+
18
+ describe Rack::OAuth2::Server::Token::Unauthorized do
19
+ let(:error) { Rack::OAuth2::Server::Token::Unauthorized.new(:invalid_request) }
20
+
21
+ it { should be_a Rack::OAuth2::Server::Abstract::Unauthorized }
22
+
23
+ describe '#finish' do
24
+ it 'should respond in JSON' do
25
+ status, header, response = error.finish
26
+ status.should == 401
27
+ header['Content-Type'].should == 'application/json'
28
+ header['WWW-Authenticate'].should == 'Basic realm="OAuth2 Token Endpoint"'
29
+ response.body.should == ['{"error":"invalid_request"}']
30
+ end
31
+ end
32
+ end
33
+
34
+ describe Rack::OAuth2::Server::Token::ErrorMethods do
35
+ let(:bad_request) { Rack::OAuth2::Server::Token::BadRequest }
36
+ let(:unauthorized) { Rack::OAuth2::Server::Token::Unauthorized }
37
+ let(:redirect_uri) { 'http://client.example.com/callback' }
38
+ let(:default_description) { Rack::OAuth2::Server::Token::ErrorMethods::DEFAULT_DESCRIPTION }
39
+ let(:env) { Rack::MockRequest.env_for("/authorize?client_id=client_id") }
40
+ let(:request) { Rack::OAuth2::Server::Token::Request.new env }
41
+
42
+ describe 'bad_request!' do
43
+ it do
44
+ expect { request.bad_request! :invalid_request }.to raise_error bad_request
45
+ end
46
+ end
47
+
48
+ describe 'unauthorized!' do
49
+ it do
50
+ expect { request.unauthorized! :invalid_client }.to raise_error unauthorized
51
+ end
52
+ end
53
+
54
+ Rack::OAuth2::Server::Token::ErrorMethods::DEFAULT_DESCRIPTION.keys.each do |error_code|
55
+ method = "#{error_code}!"
56
+ case error_code
57
+ when :invalid_client
58
+ describe method do
59
+ it "should raise Rack::OAuth2::Server::Token::Unauthorized with error = :#{error_code}" do
60
+ expect { request.send method }.to raise_error(unauthorized) { |error|
61
+ error.error.should == error_code
62
+ error.description.should == default_description[error_code]
63
+ }
64
+ end
65
+ end
66
+ else
67
+ describe method do
68
+ it "should raise Rack::OAuth2::Server::Token::BadRequest with error = :#{error_code}" do
69
+ expect { request.send method }.to raise_error(bad_request) { |error|
70
+ error.error.should == error_code
71
+ error.description.should == default_description[error_code]
72
+ }
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe Rack::OAuth2::Server::Token::Password do
4
+ let(:request) { Rack::MockRequest.new app }
5
+ let(:app) do
6
+ Rack::OAuth2::Server::Token.new do |request, response|
7
+ response.access_token = Rack::OAuth2::AccessToken::Bearer.new(:access_token => 'access_token')
8
+ end
9
+ end
10
+ let(:params) do
11
+ {
12
+ :grant_type => 'password',
13
+ :client_id => 'client_id',
14
+ :username => 'nov',
15
+ :password => 'secret'
16
+ }
17
+ end
18
+ subject { request.post('/', :params => params) }
19
+
20
+ its(:status) { should == 200 }
21
+ its(:content_type) { should == 'application/json' }
22
+ its(:body) { should include '"access_token":"access_token"' }
23
+ its(:body) { should include '"token_type":"bearer"' }
24
+
25
+ [:username, :password].each do |required|
26
+ context "when #{required} is missing" do
27
+ before do
28
+ params.delete_if do |key, value|
29
+ key == required
30
+ end
31
+ end
32
+ its(:status) { should == 400 }
33
+ its(:content_type) { should == 'application/json' }
34
+ its(:body) { should include '"error":"invalid_request"' }
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe Rack::OAuth2::Server::Token::RefreshToken do
4
+ let(:request) { Rack::MockRequest.new app }
5
+ let(:app) do
6
+ Rack::OAuth2::Server::Token.new do |request, response|
7
+ response.access_token = Rack::OAuth2::AccessToken::Bearer.new(:access_token => 'access_token')
8
+ end
9
+ end
10
+ let(:params) do
11
+ {
12
+ :grant_type => "refresh_token",
13
+ :client_id => "client_id",
14
+ :refresh_token => "refresh_token"
15
+ }
16
+ end
17
+ subject { request.post('/', :params => params) }
18
+
19
+ its(:status) { should == 200 }
20
+ its(:content_type) { should == 'application/json' }
21
+ its(:body) { should include '"access_token":"access_token"' }
22
+ its(:body) { should include '"token_type":"bearer"' }
23
+
24
+ context 'when refresh_token is missing' do
25
+ before do
26
+ params.delete_if do |key, value|
27
+ key == :refresh_token
28
+ end
29
+ end
30
+ its(:status) { should == 400 }
31
+ its(:content_type) { should == 'application/json' }
32
+ its(:body) { should include '"error":"invalid_request"' }
33
+ end
34
+ end
@@ -0,0 +1,134 @@
1
+ require 'spec_helper.rb'
2
+ require 'base64'
3
+
4
+ describe Rack::OAuth2::Server::Token do
5
+ let(:request) { Rack::MockRequest.new app }
6
+ let(:app) do
7
+ Rack::OAuth2::Server::Token.new do |request, response|
8
+ response.access_token = Rack::OAuth2::AccessToken::Bearer.new(:access_token => 'access_token')
9
+ end
10
+ end
11
+ let(:params) do
12
+ {
13
+ :grant_type => 'authorization_code',
14
+ :client_id => 'client_id',
15
+ :code => 'authorization_code',
16
+ :redirect_uri => 'http://client.example.com/callback'
17
+ }
18
+ end
19
+ subject { request.post('/token', :params => params) }
20
+
21
+ context 'when multiple client credentials are given' do
22
+ context 'when different credentials are given' do
23
+ let(:env) do
24
+ Rack::MockRequest.env_for(
25
+ '/token',
26
+ 'HTTP_AUTHORIZATION' => "Basic #{Base64.encode64('client_id2:client_secret')}",
27
+ :params => params
28
+ )
29
+ end
30
+ it 'should fail with unsupported_grant_type' do
31
+ status, header, response = app.call(env)
32
+ status.should == 400
33
+ response.body.first.should include '"error":"invalid_request"'
34
+ end
35
+ end
36
+
37
+ context 'when same credentials are given' do
38
+ let(:env) do
39
+ Rack::MockRequest.env_for(
40
+ '/token',
41
+ 'HTTP_AUTHORIZATION' => "Basic #{Base64.encode64('client_id:client_secret')}",
42
+ :params => params
43
+ )
44
+ end
45
+ it 'should ignore duplicates' do
46
+ status, header, response = app.call(env)
47
+ status.should == 200
48
+ end
49
+ end
50
+ end
51
+
52
+ context 'when unsupported grant_type is given' do
53
+ before do
54
+ params.merge!(:grant_type => 'unknown')
55
+ end
56
+ its(:status) { should == 400 }
57
+ its(:content_type) { should == 'application/json' }
58
+ its(:body) { should include '"error":"unsupported_grant_type"' }
59
+ end
60
+
61
+ [:client_id, :grant_type].each do |required|
62
+ context "when #{required} is missing" do
63
+ before do
64
+ params.delete_if do |key, value|
65
+ key == required
66
+ end
67
+ end
68
+ its(:status) { should == 400 }
69
+ its(:content_type) { should == 'application/json' }
70
+ its(:body) { should include '"error":"invalid_request"' }
71
+ end
72
+ end
73
+
74
+ Rack::OAuth2::Server::Token::ErrorMethods::DEFAULT_DESCRIPTION.each do |error, default_message|
75
+ status = if error == :invalid_client
76
+ 401
77
+ else
78
+ 400
79
+ end
80
+ context "when #{error}" do
81
+ let(:app) do
82
+ Rack::OAuth2::Server::Token.new do |request, response|
83
+ request.send "#{error}!"
84
+ end
85
+ end
86
+ its(:status) { should == status }
87
+ its(:content_type) { should == 'application/json' }
88
+ its(:body) { should include "\"error\":\"#{error}\"" }
89
+ its(:body) { should include "\"error_description\":\"#{default_message}\"" }
90
+ end
91
+ end
92
+
93
+ context 'when responding' do
94
+ context 'when access_token is missing' do
95
+ let(:app) do
96
+ Rack::OAuth2::Server::Token.new
97
+ end
98
+ it do
99
+ expect { request.post('/', :params => params) }.to raise_error AttrRequired::AttrMissing
100
+ end
101
+ end
102
+ end
103
+
104
+ describe 'extensibility' do
105
+ before do
106
+ require 'rack/oauth2/server/token/extension/jwt'
107
+ end
108
+
109
+ subject { app }
110
+ let(:env) do
111
+ Rack::MockRequest.env_for(
112
+ '/token',
113
+ :params => params
114
+ )
115
+ end
116
+ let(:request) { Rack::OAuth2::Server::Token::Request.new env }
117
+ its(:extensions) { should == [Rack::OAuth2::Server::Token::Extension::JWT] }
118
+
119
+ describe 'JWT assertion' do
120
+ let(:params) do
121
+ {
122
+ :grant_type => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
123
+ :assertion => 'header.payload.signature'
124
+ }
125
+ end
126
+
127
+ it do
128
+ app.send(
129
+ :grant_type_for, request
130
+ ).should == Rack::OAuth2::Server::Token::Extension::JWT
131
+ end
132
+ end
133
+ end
134
+ end