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.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.gitignore +22 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +7 -0
- data/LICENSE +20 -0
- data/README.rdoc +78 -0
- data/Rakefile +25 -0
- data/VERSION +1 -0
- data/lib/rack/oauth2.rb +67 -0
- data/lib/rack/oauth2/access_token.rb +36 -0
- data/lib/rack/oauth2/access_token/authenticator.rb +24 -0
- data/lib/rack/oauth2/access_token/bearer.rb +11 -0
- data/lib/rack/oauth2/access_token/legacy.rb +23 -0
- data/lib/rack/oauth2/access_token/mac.rb +103 -0
- data/lib/rack/oauth2/access_token/mac/sha256_hex_verifier.rb +17 -0
- data/lib/rack/oauth2/access_token/mac/signature.rb +34 -0
- data/lib/rack/oauth2/access_token/mac/verifier.rb +44 -0
- data/lib/rack/oauth2/client.rb +139 -0
- data/lib/rack/oauth2/client/error.rb +14 -0
- data/lib/rack/oauth2/client/grant.rb +30 -0
- data/lib/rack/oauth2/client/grant/authorization_code.rb +12 -0
- data/lib/rack/oauth2/client/grant/client_credentials.rb +10 -0
- data/lib/rack/oauth2/client/grant/facebook_token.rb +12 -0
- data/lib/rack/oauth2/client/grant/password.rb +11 -0
- data/lib/rack/oauth2/client/grant/refresh_token.rb +11 -0
- data/lib/rack/oauth2/debugger.rb +3 -0
- data/lib/rack/oauth2/debugger/request_filter.rb +30 -0
- data/lib/rack/oauth2/server.rb +4 -0
- data/lib/rack/oauth2/server/abstract.rb +4 -0
- data/lib/rack/oauth2/server/abstract/error.rb +69 -0
- data/lib/rack/oauth2/server/abstract/handler.rb +20 -0
- data/lib/rack/oauth2/server/abstract/request.rb +29 -0
- data/lib/rack/oauth2/server/abstract/response.rb +15 -0
- data/lib/rack/oauth2/server/authorize.rb +117 -0
- data/lib/rack/oauth2/server/authorize/code.rb +39 -0
- data/lib/rack/oauth2/server/authorize/error.rb +71 -0
- data/lib/rack/oauth2/server/authorize/extension.rb +12 -0
- data/lib/rack/oauth2/server/authorize/extension/code_and_token.rb +39 -0
- data/lib/rack/oauth2/server/authorize/token.rb +43 -0
- data/lib/rack/oauth2/server/resource.rb +55 -0
- data/lib/rack/oauth2/server/resource/bearer.rb +47 -0
- data/lib/rack/oauth2/server/resource/bearer/error.rb +24 -0
- data/lib/rack/oauth2/server/resource/error.rb +81 -0
- data/lib/rack/oauth2/server/resource/mac.rb +36 -0
- data/lib/rack/oauth2/server/resource/mac/error.rb +24 -0
- data/lib/rack/oauth2/server/token.rb +87 -0
- data/lib/rack/oauth2/server/token/authorization_code.rb +28 -0
- data/lib/rack/oauth2/server/token/client_credentials.rb +23 -0
- data/lib/rack/oauth2/server/token/error.rb +54 -0
- data/lib/rack/oauth2/server/token/extension.rb +12 -0
- data/lib/rack/oauth2/server/token/extension/jwt.rb +37 -0
- data/lib/rack/oauth2/server/token/facebook_token.rb +27 -0
- data/lib/rack/oauth2/server/token/password.rb +27 -0
- data/lib/rack/oauth2/server/token/refresh_token.rb +26 -0
- data/lib/rack/oauth2/util.rb +58 -0
- data/rack-oauth2.gemspec +30 -0
- data/spec/helpers/time.rb +19 -0
- data/spec/helpers/webmock_helper.rb +41 -0
- data/spec/mock_response/blank +0 -0
- data/spec/mock_response/errors/invalid_request.json +4 -0
- data/spec/mock_response/resources/fake.txt +1 -0
- data/spec/mock_response/tokens/_Bearer.json +6 -0
- data/spec/mock_response/tokens/bearer.json +6 -0
- data/spec/mock_response/tokens/legacy.json +5 -0
- data/spec/mock_response/tokens/legacy.txt +1 -0
- data/spec/mock_response/tokens/legacy_without_expires_in.txt +1 -0
- data/spec/mock_response/tokens/mac.json +8 -0
- data/spec/mock_response/tokens/unknown.json +6 -0
- data/spec/rack/oauth2/access_token/authenticator_spec.rb +43 -0
- data/spec/rack/oauth2/access_token/bearer_spec.rb +18 -0
- data/spec/rack/oauth2/access_token/legacy_spec.rb +23 -0
- data/spec/rack/oauth2/access_token/mac/sha256_hex_verifier_spec.rb +28 -0
- data/spec/rack/oauth2/access_token/mac/signature_spec.rb +59 -0
- data/spec/rack/oauth2/access_token/mac/verifier_spec.rb +25 -0
- data/spec/rack/oauth2/access_token/mac_spec.rb +141 -0
- data/spec/rack/oauth2/access_token_spec.rb +69 -0
- data/spec/rack/oauth2/client/error_spec.rb +18 -0
- data/spec/rack/oauth2/client/grant/authorization_code_spec.rb +37 -0
- data/spec/rack/oauth2/client/grant/client_credentials_spec.rb +7 -0
- data/spec/rack/oauth2/client/grant/password_spec.rb +33 -0
- data/spec/rack/oauth2/client/grant/refresh_token_spec.rb +21 -0
- data/spec/rack/oauth2/client_spec.rb +287 -0
- data/spec/rack/oauth2/debugger/request_filter_spec.rb +33 -0
- data/spec/rack/oauth2/oauth2_spec.rb +74 -0
- data/spec/rack/oauth2/server/abstract/error_spec.rb +59 -0
- data/spec/rack/oauth2/server/authorize/code_spec.rb +57 -0
- data/spec/rack/oauth2/server/authorize/error_spec.rb +103 -0
- data/spec/rack/oauth2/server/authorize/extensions/code_and_token_spec.rb +60 -0
- data/spec/rack/oauth2/server/authorize/token_spec.rb +73 -0
- data/spec/rack/oauth2/server/authorize_spec.rb +214 -0
- data/spec/rack/oauth2/server/resource/bearer/error_spec.rb +52 -0
- data/spec/rack/oauth2/server/resource/bearer_spec.rb +123 -0
- data/spec/rack/oauth2/server/resource/error_spec.rb +147 -0
- data/spec/rack/oauth2/server/resource/mac/error_spec.rb +52 -0
- data/spec/rack/oauth2/server/resource/mac_spec.rb +119 -0
- data/spec/rack/oauth2/server/resource_spec.rb +23 -0
- data/spec/rack/oauth2/server/token/authorization_code_spec.rb +43 -0
- data/spec/rack/oauth2/server/token/client_credentials_spec.rb +23 -0
- data/spec/rack/oauth2/server/token/error_spec.rb +77 -0
- data/spec/rack/oauth2/server/token/password_spec.rb +37 -0
- data/spec/rack/oauth2/server/token/refresh_token_spec.rb +34 -0
- data/spec/rack/oauth2/server/token_spec.rb +134 -0
- data/spec/rack/oauth2/util_spec.rb +97 -0
- data/spec/spec_helper.rb +14 -0
- metadata +326 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Rack::OAuth2::AccessToken::MAC::Verifier do
|
4
|
+
let(:verifier) { Rack::OAuth2::AccessToken::MAC::Verifier.new(:algorithm => algorithm) }
|
5
|
+
subject { verifier }
|
6
|
+
|
7
|
+
context 'when "hmac-sha-1" is specified' do
|
8
|
+
let(:algorithm) { 'hmac-sha-1' }
|
9
|
+
its(:hash_generator) { should be_instance_of OpenSSL::Digest::SHA1 }
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'when "hmac-sha-256" is specified' do
|
13
|
+
let(:algorithm) { 'hmac-sha-256' }
|
14
|
+
its(:hash_generator) { should be_instance_of OpenSSL::Digest::SHA256 }
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'otherwise' do
|
18
|
+
let(:algorithm) { 'invalid' }
|
19
|
+
it do
|
20
|
+
expect { verifier.send(:hash_generator) }.to raise_error(StandardError, 'Unsupported Algorithm')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Rack::OAuth2::AccessToken::MAC do
|
4
|
+
let(:ts) { 1305820234 }
|
5
|
+
let :token do
|
6
|
+
Rack::OAuth2::AccessToken::MAC.new(
|
7
|
+
:access_token => 'access_token',
|
8
|
+
:mac_key => 'secret',
|
9
|
+
:mac_algorithm => 'hmac-sha-256',
|
10
|
+
:ts => ts
|
11
|
+
)
|
12
|
+
end
|
13
|
+
let :token_with_ext_verifier do
|
14
|
+
Rack::OAuth2::AccessToken::MAC.new(
|
15
|
+
:access_token => 'access_token',
|
16
|
+
:mac_key => 'secret',
|
17
|
+
:mac_algorithm => 'hmac-sha-256',
|
18
|
+
:ts => ts,
|
19
|
+
:ext_verifier => Rack::OAuth2::AccessToken::MAC::Sha256HexVerifier
|
20
|
+
)
|
21
|
+
end
|
22
|
+
let(:nonce) { '1000:51e74de734c05613f37520872e68db5f' }
|
23
|
+
let(:resource_endpoint) { 'https://server.example.com/resources/fake' }
|
24
|
+
subject { token }
|
25
|
+
|
26
|
+
its(:mac_key) { should == 'secret' }
|
27
|
+
its(:mac_algorithm) { should == 'hmac-sha-256' }
|
28
|
+
its(:token_response) do
|
29
|
+
should == {
|
30
|
+
:access_token => 'access_token',
|
31
|
+
:refresh_token => nil,
|
32
|
+
:token_type => :mac,
|
33
|
+
:expires_in => nil,
|
34
|
+
:scope => '',
|
35
|
+
:mac_key => 'secret',
|
36
|
+
:mac_algorithm => 'hmac-sha-256'
|
37
|
+
}
|
38
|
+
end
|
39
|
+
its(:generate_nonce) { should be_a String }
|
40
|
+
|
41
|
+
describe 'verify!' do
|
42
|
+
let(:request) { Rack::OAuth2::Server::Resource::MAC::Request.new(env) }
|
43
|
+
|
44
|
+
context 'when no ext_verifier is given' do
|
45
|
+
let(:env) do
|
46
|
+
Rack::MockRequest.env_for(
|
47
|
+
'/protected_resources',
|
48
|
+
'HTTP_AUTHORIZATION' => %{MAC id="access_token", nonce="#{nonce}", ts="#{ts}" mac="#{signature}"}
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'when signature is valid' do
|
53
|
+
let(:signature) { 'BgooS/voPOZWLwoVfx4+zbC3xAVKW3jtjhKYOfIGZOA=' }
|
54
|
+
it do
|
55
|
+
|
56
|
+
token.verify!(request.setup!).should == :verified
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'otherwise' do
|
61
|
+
let(:signature) { 'invalid' }
|
62
|
+
it do
|
63
|
+
expect { token.verify!(request.setup!) }.to raise_error(
|
64
|
+
Rack::OAuth2::Server::Resource::MAC::Unauthorized,
|
65
|
+
'invalid_token :: Signature Invalid'
|
66
|
+
)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'when ext_verifier is given' do
|
72
|
+
let(:env) do
|
73
|
+
Rack::MockRequest.env_for(
|
74
|
+
'/protected_resources',
|
75
|
+
:method => :POST,
|
76
|
+
:params => {
|
77
|
+
:key1 => 'value1'
|
78
|
+
},
|
79
|
+
'HTTP_AUTHORIZATION' => %{MAC id="access_token", nonce="#{nonce}", ts="#{ts}", mac="#{signature}", ext="#{ext}"}
|
80
|
+
)
|
81
|
+
end
|
82
|
+
let(:signature) { 'invalid' }
|
83
|
+
|
84
|
+
context 'when ext is invalid' do
|
85
|
+
let(:ext) { 'invalid' }
|
86
|
+
it do
|
87
|
+
expect { token_with_ext_verifier.verify!(request.setup!) }.to raise_error(
|
88
|
+
Rack::OAuth2::Server::Resource::MAC::Unauthorized,
|
89
|
+
'invalid_token :: Sha256HexVerifier Invalid'
|
90
|
+
)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'when ext is valid' do
|
95
|
+
let(:ext) { '4cfcd46c59f54b5ea6a5f9b05c28b52fef2864747194b5fdfc3d59c0057bf35a' }
|
96
|
+
|
97
|
+
context 'when signature is valid' do
|
98
|
+
let(:signature) { 'dZYR54n+Lym5qCRRmDqmRZ71rG+bkjSWmqrOv8OjYHk=' }
|
99
|
+
it do
|
100
|
+
Time.fix(Time.at(1302361200)) do
|
101
|
+
token_with_ext_verifier.verify!(request.setup!).should == :verified
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'otherwise' do
|
107
|
+
it do
|
108
|
+
expect { token.verify!(request.setup!) }.to raise_error(
|
109
|
+
Rack::OAuth2::Server::Resource::MAC::Unauthorized,
|
110
|
+
'invalid_token :: Signature Invalid'
|
111
|
+
)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe '.authenticate' do
|
119
|
+
let(:request) { HTTPClient.new.send(:create_request, :post, URI.parse(resource_endpoint), {}, {:hello => "world"}, {}) }
|
120
|
+
context 'when no ext_verifier is given' do
|
121
|
+
let(:signature) { 'pOBaL6HRawe4tUPmcU4vJEj1f2GJqrbQOlCcdAYgI/s=' }
|
122
|
+
|
123
|
+
it 'should set Authorization header' do
|
124
|
+
token.should_receive(:generate_nonce).and_return(nonce)
|
125
|
+
request.header.should_receive(:[]=).with('Authorization', "MAC id=\"access_token\", nonce=\"#{nonce}\", ts=\"#{ts.to_i}\", mac=\"#{signature}\"")
|
126
|
+
token.authenticate(request)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context 'when ext_verifier is given' do
|
131
|
+
let(:signature) { 'vgU0fj6rSpwUCAoCOrXlu8pZBR8a5Q5xIVlB4MCvJeM=' }
|
132
|
+
let(:ext) { '3d011e09502a84552a0f8ae112d024cc2c115597e3a577d5f49007902c221dc5' }
|
133
|
+
it 'should set Authorization header with ext_verifier' do
|
134
|
+
token_with_ext_verifier.should_receive(:generate_nonce).and_return(nonce)
|
135
|
+
request.header.should_receive(:[]=).with('Authorization', "MAC id=\"access_token\", nonce=\"#{nonce}\", ts=\"#{ts.to_i}\", mac=\"#{signature}\", ext=\"#{ext}\"")
|
136
|
+
token_with_ext_verifier.authenticate(request)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Rack::OAuth2::AccessToken do
|
4
|
+
let :token do
|
5
|
+
Rack::OAuth2::AccessToken::Bearer.new(
|
6
|
+
:access_token => 'access_token',
|
7
|
+
:refresh_token => 'refresh_token',
|
8
|
+
:expires_in => 3600,
|
9
|
+
:scope => [:scope1, :scope2]
|
10
|
+
)
|
11
|
+
end
|
12
|
+
subject { token }
|
13
|
+
|
14
|
+
its(:access_token) { should == 'access_token' }
|
15
|
+
its(:refresh_token) { should == 'refresh_token' }
|
16
|
+
its(:expires_in) { should == 3600 }
|
17
|
+
its(:scope) { should == [:scope1, :scope2] }
|
18
|
+
its(:token_response) do
|
19
|
+
should == {
|
20
|
+
:token_type => :bearer,
|
21
|
+
:access_token => 'access_token',
|
22
|
+
:refresh_token => 'refresh_token',
|
23
|
+
:expires_in => 3600,
|
24
|
+
:scope => 'scope1 scope2'
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'when access_token is missing' do
|
29
|
+
it do
|
30
|
+
expect do
|
31
|
+
Rack::OAuth2::AccessToken::Bearer.new(
|
32
|
+
:refresh_token => 'refresh_token',
|
33
|
+
:expires_in => 3600,
|
34
|
+
:scope => [:scope1, :scope2]
|
35
|
+
)
|
36
|
+
end.to raise_error AttrRequired::AttrMissing
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'otherwise' do
|
41
|
+
it do
|
42
|
+
expect do
|
43
|
+
Rack::OAuth2::AccessToken::Bearer.new(
|
44
|
+
:access_token => 'access_token'
|
45
|
+
)
|
46
|
+
end.not_to raise_error
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
let(:resource_endpoint) { 'https://server.example.com/resources/fake' }
|
51
|
+
[:get, :delete, :post, :put].each do |method|
|
52
|
+
describe method do
|
53
|
+
it 'should delegate to HTTPClient with Authenticator filter' do
|
54
|
+
token.httpclient.should_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
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
describe Rack::OAuth2::Client::Error do
|
4
|
+
let :error do
|
5
|
+
{
|
6
|
+
:error => :invalid_request,
|
7
|
+
:error_description => 'Include invalid parameters',
|
8
|
+
:error_uri => 'http://server.example.com/error/invalid_request'
|
9
|
+
}
|
10
|
+
end
|
11
|
+
subject do
|
12
|
+
Rack::OAuth2::Client::Error.new 400, error
|
13
|
+
end
|
14
|
+
|
15
|
+
its(:status) { should == 400 }
|
16
|
+
its(:message) { should == error[:error_description] }
|
17
|
+
its(:response) { should == error }
|
18
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
describe Rack::OAuth2::Client::Grant::AuthorizationCode do
|
4
|
+
let(:redirect_uri) { 'https://client.example.com/callback' }
|
5
|
+
let(:grant) { Rack::OAuth2::Client::Grant::AuthorizationCode }
|
6
|
+
|
7
|
+
context 'when code is given' do
|
8
|
+
let :attributes do
|
9
|
+
{:code => 'code'}
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'when redirect_uri is given' do
|
13
|
+
let :attributes do
|
14
|
+
{:code => 'code', :redirect_uri => redirect_uri}
|
15
|
+
end
|
16
|
+
subject { grant.new attributes }
|
17
|
+
its(:redirect_uri) { should == redirect_uri }
|
18
|
+
its(:as_json) do
|
19
|
+
should == {:grant_type => :authorization_code, :code => 'code', :redirect_uri => redirect_uri}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'otherwise' do
|
24
|
+
subject { grant.new attributes }
|
25
|
+
its(:redirect_uri) { should be_nil }
|
26
|
+
its(:as_json) do
|
27
|
+
should == {:grant_type => :authorization_code, :code => 'code', :redirect_uri => nil}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'otherwise' do
|
33
|
+
it do
|
34
|
+
expect { grant.new }.to raise_error AttrRequired::AttrMissing
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
describe Rack::OAuth2::Client::Grant::Password do
|
4
|
+
let(:grant) { Rack::OAuth2::Client::Grant::Password }
|
5
|
+
|
6
|
+
context 'when username is given' do
|
7
|
+
let :attributes do
|
8
|
+
{:username => 'username'}
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'when password is given' do
|
12
|
+
let :attributes do
|
13
|
+
{:username => 'username', :password => 'password'}
|
14
|
+
end
|
15
|
+
subject { grant.new attributes }
|
16
|
+
its(:as_json) do
|
17
|
+
should == {:grant_type => :password, :username => 'username', :password => 'password'}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'otherwise' do
|
22
|
+
it do
|
23
|
+
expect { grant.new attributes }.to raise_error AttrRequired::AttrMissing
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'otherwise' do
|
29
|
+
it do
|
30
|
+
expect { grant.new }.to raise_error AttrRequired::AttrMissing
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
describe Rack::OAuth2::Client::Grant::RefreshToken do
|
4
|
+
let(:grant) { Rack::OAuth2::Client::Grant::RefreshToken }
|
5
|
+
|
6
|
+
context 'when refresh_token is given' do
|
7
|
+
let :attributes do
|
8
|
+
{:refresh_token => 'refresh_token'}
|
9
|
+
end
|
10
|
+
subject { grant.new attributes }
|
11
|
+
its(:as_json) do
|
12
|
+
should == {:grant_type => :refresh_token, :refresh_token => 'refresh_token'}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'otherwise' do
|
17
|
+
it do
|
18
|
+
expect { grant.new }.to raise_error AttrRequired::AttrMissing
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,287 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
describe Rack::OAuth2::Client do
|
4
|
+
let :client do
|
5
|
+
Rack::OAuth2::Client.new(
|
6
|
+
:identifier => 'client_id',
|
7
|
+
:secret => 'client_secret',
|
8
|
+
:host => 'server.example.com',
|
9
|
+
:redirect_uri => 'https://client.example.com/callback'
|
10
|
+
)
|
11
|
+
end
|
12
|
+
subject { client }
|
13
|
+
|
14
|
+
its(:identifier) { should == 'client_id' }
|
15
|
+
its(:secret) { should == 'client_secret' }
|
16
|
+
its(:authorization_endpoint) { should == '/oauth2/authorize' }
|
17
|
+
its(:token_endpoint) { should == '/oauth2/token' }
|
18
|
+
|
19
|
+
context 'when identifier is missing' do
|
20
|
+
it do
|
21
|
+
expect { Rack::OAuth2::Client.new }.to raise_error AttrRequired::AttrMissing
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#authorization_uri' do
|
26
|
+
subject { client.authorization_uri }
|
27
|
+
it { should include 'https://server.example.com/oauth2/authorize' }
|
28
|
+
it { should include 'client_id=client_id' }
|
29
|
+
it { should include 'redirect_uri=https%3A%2F%2Fclient.example.com%2Fcallback' }
|
30
|
+
it { should include 'response_type=code' }
|
31
|
+
|
32
|
+
context 'when endpoints are absolute URIs' do
|
33
|
+
before do
|
34
|
+
client.authorization_endpoint = 'https://server2.example.com/oauth/authorize'
|
35
|
+
client.token_endpoint = 'https://server2.example.com/oauth/token'
|
36
|
+
end
|
37
|
+
it { should include 'https://server2.example.com/oauth/authorize' }
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'when scheme is specified' do
|
41
|
+
before { client.scheme = 'http' }
|
42
|
+
it { should include 'http://server.example.com/oauth2/authorize' }
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'when response_type is token' do
|
46
|
+
subject { client.authorization_uri(:response_type => :token) }
|
47
|
+
it { should include 'response_type=token' }
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'when response_type is an Array' do
|
51
|
+
subject { client.authorization_uri(:response_type => [:token, :code]) }
|
52
|
+
it { should include 'response_type=token+code' }
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'when scope is given' do
|
56
|
+
subject { client.authorization_uri(:scope => [:scope1, :scope2]) }
|
57
|
+
it { should include 'scope=scope1+scope2' }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#authorization_code=' do
|
62
|
+
before { client.authorization_code = 'code' }
|
63
|
+
subject { client.instance_variable_get('@grant') }
|
64
|
+
it { should be_instance_of Rack::OAuth2::Client::Grant::AuthorizationCode }
|
65
|
+
end
|
66
|
+
|
67
|
+
describe '#resource_owner_credentials=' do
|
68
|
+
before { client.resource_owner_credentials = 'username', 'password' }
|
69
|
+
subject { client.instance_variable_get('@grant') }
|
70
|
+
it { should be_instance_of Rack::OAuth2::Client::Grant::Password }
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '#refresh_token=' do
|
74
|
+
before { client.refresh_token = 'refresh_token' }
|
75
|
+
subject { client.instance_variable_get('@grant') }
|
76
|
+
it { should be_instance_of Rack::OAuth2::Client::Grant::RefreshToken }
|
77
|
+
end
|
78
|
+
|
79
|
+
describe '#access_token!' do
|
80
|
+
subject { client.access_token! }
|
81
|
+
|
82
|
+
describe 'client authentication method' do
|
83
|
+
before do
|
84
|
+
client.authorization_code = 'code'
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should be Basic auth as default' do
|
88
|
+
mock_response(
|
89
|
+
:post,
|
90
|
+
'https://server.example.com/oauth2/token',
|
91
|
+
'tokens/bearer.json',
|
92
|
+
:request_header => {
|
93
|
+
'Authorization' => 'Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ='
|
94
|
+
}
|
95
|
+
)
|
96
|
+
client.access_token!
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'when other auth method specified' do
|
100
|
+
it do
|
101
|
+
mock_response(
|
102
|
+
:post,
|
103
|
+
'https://server.example.com/oauth2/token',
|
104
|
+
'tokens/bearer.json',
|
105
|
+
:params => {
|
106
|
+
:client_id => 'client_id',
|
107
|
+
:client_secret => 'client_secret',
|
108
|
+
:code => 'code',
|
109
|
+
:grant_type => 'authorization_code',
|
110
|
+
:redirect_uri => 'https://client.example.com/callback'
|
111
|
+
}
|
112
|
+
)
|
113
|
+
client.access_token! :client_auth_body
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe 'scopes' do
|
119
|
+
context 'when scope option given' do
|
120
|
+
it 'should specify given scope' do
|
121
|
+
mock_response(
|
122
|
+
:post,
|
123
|
+
'https://server.example.com/oauth2/token',
|
124
|
+
'tokens/bearer.json',
|
125
|
+
:params => {
|
126
|
+
:grant_type => 'client_credentials',
|
127
|
+
:scope => 'a b'
|
128
|
+
}
|
129
|
+
)
|
130
|
+
client.access_token! :scope => [:a, :b]
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
context 'when bearer token is given' do
|
136
|
+
before do
|
137
|
+
client.authorization_code = 'code'
|
138
|
+
mock_response(
|
139
|
+
:post,
|
140
|
+
'https://server.example.com/oauth2/token',
|
141
|
+
'tokens/bearer.json'
|
142
|
+
)
|
143
|
+
end
|
144
|
+
it { should be_instance_of Rack::OAuth2::AccessToken::Bearer }
|
145
|
+
its(:token_type) { should == :bearer }
|
146
|
+
its(:access_token) { should == 'access_token' }
|
147
|
+
its(:refresh_token) { should == 'refresh_token' }
|
148
|
+
its(:expires_in) { should == 3600 }
|
149
|
+
|
150
|
+
context 'when token type is "Bearer", not "bearer"' do
|
151
|
+
before do
|
152
|
+
client.authorization_code = 'code'
|
153
|
+
mock_response(
|
154
|
+
:post,
|
155
|
+
'https://server.example.com/oauth2/token',
|
156
|
+
'tokens/_Bearer.json'
|
157
|
+
)
|
158
|
+
end
|
159
|
+
it { should be_instance_of Rack::OAuth2::AccessToken::Bearer }
|
160
|
+
its(:token_type) { should == :bearer }
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
context 'when mac token is given' do
|
165
|
+
before do
|
166
|
+
client.authorization_code = 'code'
|
167
|
+
mock_response(
|
168
|
+
:post,
|
169
|
+
'https://server.example.com/oauth2/token',
|
170
|
+
'tokens/mac.json'
|
171
|
+
)
|
172
|
+
end
|
173
|
+
it { should be_instance_of Rack::OAuth2::AccessToken::MAC }
|
174
|
+
its(:token_type) { should == :mac }
|
175
|
+
its(:access_token) { should == 'access_token' }
|
176
|
+
its(:refresh_token) { should == 'refresh_token' }
|
177
|
+
its(:expires_in) { should == 3600 }
|
178
|
+
end
|
179
|
+
|
180
|
+
context 'when no-type token is given (JSON)' do
|
181
|
+
before do
|
182
|
+
client.authorization_code = 'code'
|
183
|
+
mock_response(
|
184
|
+
:post,
|
185
|
+
'https://server.example.com/oauth2/token',
|
186
|
+
'tokens/legacy.json'
|
187
|
+
)
|
188
|
+
end
|
189
|
+
it { should be_instance_of Rack::OAuth2::AccessToken::Legacy }
|
190
|
+
its(:token_type) { should == :legacy }
|
191
|
+
its(:access_token) { should == 'access_token' }
|
192
|
+
its(:refresh_token) { should == 'refresh_token' }
|
193
|
+
its(:expires_in) { should == 3600 }
|
194
|
+
end
|
195
|
+
|
196
|
+
context 'when no-type token is given (key-value)' do
|
197
|
+
before do
|
198
|
+
mock_response(
|
199
|
+
:post,
|
200
|
+
'https://server.example.com/oauth2/token',
|
201
|
+
'tokens/legacy.txt'
|
202
|
+
)
|
203
|
+
end
|
204
|
+
it { should be_instance_of Rack::OAuth2::AccessToken::Legacy }
|
205
|
+
its(:token_type) { should == :legacy }
|
206
|
+
its(:access_token) { should == 'access_token' }
|
207
|
+
its(:expires_in) { should == 3600 }
|
208
|
+
|
209
|
+
context 'when expires_in is not given' do
|
210
|
+
before do
|
211
|
+
mock_response(
|
212
|
+
:post,
|
213
|
+
'https://server.example.com/oauth2/token',
|
214
|
+
'tokens/legacy_without_expires_in.txt'
|
215
|
+
)
|
216
|
+
end
|
217
|
+
its(:expires_in) { should be_nil }
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
context 'when unknown-type token is given' do
|
222
|
+
before do
|
223
|
+
client.authorization_code = 'code'
|
224
|
+
mock_response(
|
225
|
+
:post,
|
226
|
+
'https://server.example.com/oauth2/token',
|
227
|
+
'tokens/unknown.json'
|
228
|
+
)
|
229
|
+
end
|
230
|
+
it do
|
231
|
+
expect { client.access_token! }.to raise_error(StandardError, 'Unknown Token Type')
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
context 'when error response is given' do
|
236
|
+
before do
|
237
|
+
mock_response(
|
238
|
+
:post,
|
239
|
+
'https://server.example.com/oauth2/token',
|
240
|
+
'errors/invalid_request.json',
|
241
|
+
:status => 400
|
242
|
+
)
|
243
|
+
end
|
244
|
+
it do
|
245
|
+
expect { client.access_token! }.to raise_error Rack::OAuth2::Client::Error
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
context 'when no body given' do
|
250
|
+
context 'when error given' do
|
251
|
+
before do
|
252
|
+
mock_response(
|
253
|
+
:post,
|
254
|
+
'https://server.example.com/oauth2/token',
|
255
|
+
'blank',
|
256
|
+
:status => 400
|
257
|
+
)
|
258
|
+
end
|
259
|
+
it do
|
260
|
+
expect { client.access_token! }.to raise_error Rack::OAuth2::Client::Error
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
context 'when no host info' do
|
267
|
+
let :client do
|
268
|
+
Rack::OAuth2::Client.new(
|
269
|
+
:identifier => 'client_id',
|
270
|
+
:secret => 'client_secret',
|
271
|
+
:redirect_uri => 'https://client.example.com/callback'
|
272
|
+
)
|
273
|
+
end
|
274
|
+
|
275
|
+
describe '#authorization_uri' do
|
276
|
+
it do
|
277
|
+
expect { client.authorization_uri }.to raise_error 'No Host Info'
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
describe '#access_token!' do
|
282
|
+
it do
|
283
|
+
expect { client.access_token! }.to raise_error 'No Host Info'
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|