dreamwords-oauth2 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,187 @@
1
+ require 'helper'
2
+
3
+ describe OAuth2::Client do
4
+ let!(:error_value) {'invalid_token'}
5
+ let!(:error_description_value) {'bad bad token'}
6
+
7
+ subject do
8
+ OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com') do |builder|
9
+ builder.adapter :test do |stub|
10
+ stub.get('/success') {|env| [200, {'Content-Type' => 'text/awesome'}, 'yay']}
11
+ stub.get('/reflect') {|env| [200, {}, env[:body]]}
12
+ stub.post('/reflect') {|env| [200, {}, env[:body]]}
13
+ stub.get('/unauthorized') {|env| [401, {'Content-Type' => 'application/json'}, MultiJson.encode(:error => error_value, :error_description => error_description_value)]}
14
+ stub.get('/conflict') {|env| [409, {'Content-Type' => 'text/plain'}, 'not authorized']}
15
+ stub.get('/redirect') {|env| [302, {'Content-Type' => 'text/plain', 'location' => '/success' }, '']}
16
+ stub.post('/redirect') {|env| [303, {'Content-Type' => 'text/plain', 'location' => '/reflect' }, '']}
17
+ stub.get('/error') {|env| [500, {'Content-Type' => 'text/plain'}, 'unknown error']}
18
+ stub.get('/empty_get') {|env| [204, {}, nil]}
19
+ end
20
+ end
21
+ end
22
+
23
+ describe '#initialize' do
24
+ it 'should assign id and secret' do
25
+ subject.id.should == 'abc'
26
+ subject.secret.should == 'def'
27
+ end
28
+
29
+ it 'should assign site from the options hash' do
30
+ subject.site.should == 'https://api.example.com'
31
+ end
32
+
33
+ it 'should assign Faraday::Connection#host' do
34
+ subject.connection.host.should == 'api.example.com'
35
+ end
36
+
37
+ it 'should leave Faraday::Connection#ssl unset' do
38
+ subject.connection.ssl.should == {}
39
+ end
40
+
41
+ it "should be able to pass a block to configure the connection" do
42
+ connection = stub('connection')
43
+ session = stub('session', :to_ary => nil)
44
+ builder = stub('builder')
45
+ connection.stub(:build).and_yield(builder)
46
+ Faraday::Connection.stub(:new => connection)
47
+
48
+ builder.should_receive(:adapter).with(:test)
49
+
50
+ OAuth2::Client.new('abc', 'def') do |builder|
51
+ builder.adapter :test
52
+ end.connection
53
+ end
54
+
55
+ it "defaults raise_errors to true" do
56
+ subject.options[:raise_errors].should be_true
57
+ end
58
+
59
+ it "allows true/false for raise_errors option" do
60
+ client = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :raise_errors => false)
61
+ client.options[:raise_errors].should be_false
62
+ client = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :raise_errors => true)
63
+ client.options[:raise_errors].should be_true
64
+ end
65
+
66
+ it "allows get/post for access_token_method option" do
67
+ client = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :access_token_method => :get)
68
+ client.options[:access_token_method].should == :get
69
+ client = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :access_token_method => :post)
70
+ client.options[:access_token_method].should == :post
71
+ end
72
+ end
73
+
74
+ %w(authorize token).each do |url_type|
75
+ describe ":#{url_type}_url option" do
76
+ it "should default to a path of /oauth/#{url_type}" do
77
+ subject.send("#{url_type}_url").should == "https://api.example.com/oauth/#{url_type}"
78
+ end
79
+
80
+ it "should be settable via the :#{url_type}_url option" do
81
+ subject.options[:"#{url_type}_url"] = '/oauth/custom'
82
+ subject.send("#{url_type}_url").should == 'https://api.example.com/oauth/custom'
83
+ end
84
+
85
+ it "allows a different host than the site" do
86
+ subject.options[:"#{url_type}_url"] = 'https://api.foo.com/oauth/custom'
87
+ subject.send("#{url_type}_url").should == 'https://api.foo.com/oauth/custom'
88
+ end
89
+ end
90
+ end
91
+
92
+ describe "#request" do
93
+ it "works with a null response body" do
94
+ subject.request(:get, 'empty_get').body.should == ''
95
+ end
96
+
97
+ it "returns on a successful response" do
98
+ response = subject.request(:get, '/success')
99
+ response.body.should == 'yay'
100
+ response.status.should == 200
101
+ response.headers.should == {'Content-Type' => 'text/awesome'}
102
+ end
103
+
104
+ it "posts a body" do
105
+ response = subject.request(:post, '/reflect', :body => 'foo=bar')
106
+ response.body.should == 'foo=bar'
107
+ end
108
+
109
+ it "follows redirects properly" do
110
+ response = subject.request(:get, '/redirect')
111
+ response.body.should == 'yay'
112
+ response.status.should == 200
113
+ response.headers.should == {'Content-Type' => 'text/awesome'}
114
+ end
115
+
116
+ it "redirects using GET on a 303" do
117
+ response = subject.request(:post, '/redirect', :body => 'foo=bar')
118
+ response.body.should be_empty
119
+ response.status.should == 200
120
+ end
121
+
122
+ it "obeys the :max_redirects option" do
123
+ max_redirects = subject.options[:max_redirects]
124
+ subject.options[:max_redirects] = 0
125
+ response = subject.request(:get, '/redirect')
126
+ response.status.should == 302
127
+ subject.options[:max_redirects] = max_redirects
128
+ end
129
+
130
+ it "returns if raise_errors is false" do
131
+ subject.options[:raise_errors] = false
132
+ response = subject.request(:get, '/unauthorized')
133
+
134
+ response.status.should == 401
135
+ response.headers.should == {'Content-Type' => 'application/json'}
136
+ response.error.should_not be_nil
137
+ end
138
+
139
+ %w(/unauthorized /conflict /error).each do |error_path|
140
+ it "raises OAuth2::Error on error response to path #{error_path}" do
141
+ lambda {subject.request(:get, error_path)}.should raise_error(OAuth2::Error)
142
+ end
143
+ end
144
+
145
+ it 'parses OAuth2 standard error response' do
146
+ begin
147
+ subject.request(:get, '/unauthorized')
148
+ rescue Exception => e
149
+ e.code.should == error_value
150
+ e.description.should == error_description_value
151
+ e.to_s.should match(/#{error_value}/)
152
+ e.to_s.should match(/#{error_description_value}/)
153
+ end
154
+ end
155
+
156
+ it "provides the response in the Exception" do
157
+ begin
158
+ subject.request(:get, '/error')
159
+ rescue Exception => e
160
+ e.response.should_not be_nil
161
+ e.to_s.should match(/unknown error/)
162
+ end
163
+ end
164
+ end
165
+
166
+ it '#auth_code should instantiate a AuthCode strategy with this client' do
167
+ subject.auth_code.should be_kind_of(OAuth2::Strategy::AuthCode)
168
+ end
169
+
170
+ it '#implicit should instantiate a Implicit strategy with this client' do
171
+ subject.implicit.should be_kind_of(OAuth2::Strategy::Implicit)
172
+ end
173
+
174
+ context 'with SSL options' do
175
+ subject do
176
+ cli = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :ssl => {:ca_file => 'foo.pem'})
177
+ cli.connection.build do |b|
178
+ b.adapter :test
179
+ end
180
+ cli
181
+ end
182
+
183
+ it 'should pass the SSL options along to Faraday::Connection#ssl' do
184
+ subject.connection.ssl.should == {:ca_file => 'foo.pem'}
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,91 @@
1
+ require 'helper'
2
+
3
+ describe OAuth2::Response do
4
+ describe '#initialize' do
5
+ let(:status) {200}
6
+ let(:headers) {{'foo' => 'bar'}}
7
+ let(:body) {'foo'}
8
+
9
+ it 'returns the status, headers and body' do
10
+ response = double('response', :headers => headers,
11
+ :status => status,
12
+ :body => body)
13
+ subject = Response.new(response)
14
+ subject.headers.should == headers
15
+ subject.status.should == status
16
+ subject.body.should == body
17
+ end
18
+ end
19
+
20
+ describe '.register_parser' do
21
+ let(:response) {
22
+ double('response', :headers => {'Content-Type' => 'application/foo-bar'},
23
+ :status => 200,
24
+ :body => 'baz')
25
+ }
26
+ before do
27
+ OAuth2::Response.register_parser(:foobar, 'application/foo-bar') do |body|
28
+ "foobar #{body}"
29
+ end
30
+ end
31
+
32
+ it 'should add to the content types and parsers' do
33
+ OAuth2::Response::PARSERS.keys.should be_include(:foobar)
34
+ OAuth2::Response::CONTENT_TYPES.keys.should be_include('application/foo-bar')
35
+ end
36
+
37
+ it 'should be able to parse that content type automatically' do
38
+ OAuth2::Response.new(response).parsed.should == 'foobar baz'
39
+ end
40
+ end
41
+
42
+ describe '#parsed' do
43
+ it "parses application/x-www-form-urlencoded body" do
44
+ headers = {'Content-Type' => 'application/x-www-form-urlencoded'}
45
+ body = 'foo=bar&answer=42'
46
+ response = double('response', :headers => headers, :body => body)
47
+ subject = Response.new(response)
48
+ subject.parsed.keys.size.should == 2
49
+ subject.parsed['foo'].should == 'bar'
50
+ subject.parsed['answer'].should == '42'
51
+ end
52
+
53
+ it "parses application/json body" do
54
+ headers = {'Content-Type' => 'application/json'}
55
+ body = MultiJson.encode(:foo => 'bar', :answer => 42)
56
+ response = double('response', :headers => headers, :body => body)
57
+ subject = Response.new(response)
58
+ subject.parsed.keys.size.should == 2
59
+ subject.parsed['foo'].should == 'bar'
60
+ subject.parsed['answer'].should == 42
61
+ end
62
+
63
+ it "doesn't try to parse other content-types" do
64
+ headers = {'Content-Type' => 'text/html'}
65
+ body = '<!DOCTYPE html><html><head></head><body></body></html>'
66
+
67
+ response = double('response', :headers => headers, :body => body)
68
+
69
+ MultiJson.should_not_receive(:decode)
70
+ MultiJson.should_not_receive(:load)
71
+ Rack::Utils.should_not_receive(:parse_query)
72
+
73
+ subject = Response.new(response)
74
+ subject.parsed.should be_nil
75
+ end
76
+ end
77
+
78
+ context 'xml parser registration' do
79
+ it 'should try to load multi_xml and use it' do
80
+ OAuth2::Response::PARSERS[:xml].should_not be_nil
81
+ end
82
+
83
+ it 'should be able to parse xml' do
84
+ headers = {'Content-Type' => 'text/xml'}
85
+ body = '<?xml version="1.0" standalone="yes" ?><foo><bar>baz</bar></foo>'
86
+
87
+ response = double('response', :headers => headers, :body => body)
88
+ OAuth2::Response.new(response).parsed.should == {"foo" => {"bar" => "baz"}}
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,57 @@
1
+ require 'helper'
2
+
3
+ describe OAuth2::Strategy::Assertion do
4
+ let(:client) do
5
+ cli = OAuth2::Client.new('abc', 'def', :site => 'http://api.example.com')
6
+ cli.connection.build do |b|
7
+ b.adapter :test do |stub|
8
+ stub.post('/oauth/token') do |env|
9
+ case @mode
10
+ when "formencoded"
11
+ [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, 'expires_in=600&access_token=salmon&refresh_token=trout']
12
+ when "json"
13
+ [200, {'Content-Type' => 'application/json'}, '{"expires_in":600,"access_token":"salmon","refresh_token":"trout"}']
14
+ end
15
+ end
16
+ end
17
+ end
18
+ cli
19
+ end
20
+
21
+ let(:params) { {:hmac_secret => 'foo'}}
22
+
23
+ subject {client.assertion}
24
+
25
+ describe "#authorize_url" do
26
+ it "should raise NotImplementedError" do
27
+ lambda {subject.authorize_url}.should raise_error(NotImplementedError)
28
+ end
29
+ end
30
+
31
+ %w(json formencoded).each do |mode|
32
+ describe "#get_token (#{mode})" do
33
+ before do
34
+ @mode = mode
35
+ @access = subject.get_token(params)
36
+ end
37
+
38
+ it 'returns AccessToken with same Client' do
39
+ @access.client.should == client
40
+ end
41
+
42
+ it 'returns AccessToken with #token' do
43
+ @access.token.should == 'salmon'
44
+ end
45
+
46
+ it 'returns AccessToken with #expires_in' do
47
+ @access.expires_in.should == 600
48
+ end
49
+
50
+ it 'returns AccessToken with #expires_at' do
51
+ @access.expires_at.should_not be_nil
52
+ end
53
+ end
54
+ end
55
+
56
+ end
57
+
@@ -0,0 +1,88 @@
1
+ require 'helper'
2
+
3
+ describe OAuth2::Strategy::AuthCode do
4
+ let(:code) {'sushi'}
5
+ let(:kvform_token) {'expires_in=600&access_token=salmon&refresh_token=trout&extra_param=steve'}
6
+ let(:facebook_token) {kvform_token.gsub('_in', '')}
7
+ let(:json_token) {MultiJson.encode(:expires_in => 600, :access_token => 'salmon', :refresh_token => 'trout', :extra_param => 'steve')}
8
+
9
+ let(:client) do
10
+ OAuth2::Client.new('abc', 'def', :site => 'http://api.example.com') do |builder|
11
+ builder.adapter :test do |stub|
12
+ stub.get("/oauth/token?client_id=abc&client_secret=def&code=#{code}&grant_type=authorization_code") do |env|
13
+ case @mode
14
+ when "formencoded"
15
+ [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, kvform_token]
16
+ when "json"
17
+ [200, {'Content-Type' => 'application/json'}, json_token]
18
+ when "from_facebook"
19
+ [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, facebook_token]
20
+ end
21
+ end
22
+ stub.post('/oauth/token', {'client_id' => 'abc', 'client_secret' => 'def', 'code' => 'sushi', 'grant_type' => 'authorization_code'}) do |env|
23
+ case @mode
24
+ when "formencoded"
25
+ [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, kvform_token]
26
+ when "json"
27
+ [200, {'Content-Type' => 'application/json'}, json_token]
28
+ when "from_facebook"
29
+ [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, facebook_token]
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ subject {client.auth_code}
37
+
38
+ describe '#authorize_url' do
39
+ it 'should include the client_id' do
40
+ subject.authorize_url.should be_include('client_id=abc')
41
+ end
42
+
43
+ it 'should include the type' do
44
+ subject.authorize_url.should be_include('response_type=code')
45
+ end
46
+
47
+ it 'should include passed in options' do
48
+ cb = 'http://myserver.local/oauth/callback'
49
+ subject.authorize_url(:redirect_uri => cb).should be_include("redirect_uri=#{Rack::Utils.escape(cb)}")
50
+ end
51
+ end
52
+
53
+ %w(json formencoded from_facebook).each do |mode|
54
+ [:get, :post].each do |verb|
55
+ describe "#get_token (#{mode}, access_token_method=#{verb}" do
56
+ before :each do
57
+ @mode = mode
58
+ client.options[:token_method] = verb
59
+ @access = subject.get_token(code)
60
+ end
61
+
62
+ it 'returns AccessToken with same Client' do
63
+ @access.client.should == client
64
+ end
65
+
66
+ it 'returns AccessToken with #token' do
67
+ @access.token.should == 'salmon'
68
+ end
69
+
70
+ it 'returns AccessToken with #refresh_token' do
71
+ @access.refresh_token.should == 'trout'
72
+ end
73
+
74
+ it 'returns AccessToken with #expires_in' do
75
+ @access.expires_in.should == 600
76
+ end
77
+
78
+ it 'returns AccessToken with #expires_at' do
79
+ @access.expires_at.should be_kind_of(Integer)
80
+ end
81
+
82
+ it 'returns AccessToken with params accessible via []' do
83
+ @access['extra_param'].should == 'steve'
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ describe OAuth2::Strategy::Base do
4
+ it 'should initialize with a Client' do
5
+ lambda{OAuth2::Strategy::Base.new(OAuth2::Client.new('abc', 'def'))}.should_not raise_error
6
+ end
7
+ end
@@ -0,0 +1,70 @@
1
+ require 'helper'
2
+
3
+ describe OAuth2::Strategy::ClientCredentials do
4
+ let(:kvform_token) { 'expires_in=600&access_token=salmon&refresh_token=trout' }
5
+ let(:json_token) { '{"expires_in":600,"access_token":"salmon","refresh_token":"trout"}' }
6
+
7
+ let(:client) do
8
+ OAuth2::Client.new('abc', 'def', :site => 'http://api.example.com') do |builder|
9
+ builder.adapter :test do |stub|
10
+ stub.post('/oauth/token', {'grant_type' => 'client_credentials'}) do |env|
11
+ client_id, client_secret = HTTPAuth::Basic.unpack_authorization(env[:request_headers]['Authorization'])
12
+ client_id == 'abc' && client_secret == 'def' or raise Faraday::Adapter::Test::Stubs::NotFound.new
13
+ case @mode
14
+ when "formencoded"
15
+ [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, kvform_token]
16
+ when "json"
17
+ [200, {'Content-Type' => 'application/json'}, json_token]
18
+ end
19
+ end
20
+ stub.post('/oauth/token', {'client_id' => 'abc', 'client_secret' => 'def', 'grant_type' => 'client_credentials'}) do |env|
21
+ case @mode
22
+ when "formencoded"
23
+ [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, kvform_token]
24
+ when "json"
25
+ [200, {'Content-Type' => 'application/json'}, json_token]
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ subject {client.client_credentials}
33
+
34
+ describe "#authorize_url" do
35
+ it "should raise NotImplementedError" do
36
+ lambda {subject.authorize_url}.should raise_error(NotImplementedError)
37
+ end
38
+ end
39
+
40
+ %w(json formencoded).each do |mode|
41
+ %w(default basic_auth request_body).each do |auth_scheme|
42
+ describe "#get_token (#{mode}) (#{auth_scheme})" do
43
+ before do
44
+ @mode = mode
45
+ @access = subject.get_token({}, auth_scheme == 'default' ? {} : {'auth_scheme' => auth_scheme})
46
+ end
47
+
48
+ it 'returns AccessToken with same Client' do
49
+ @access.client.should == client
50
+ end
51
+
52
+ it 'returns AccessToken with #token' do
53
+ @access.token.should == 'salmon'
54
+ end
55
+
56
+ it 'returns AccessToken without #refresh_token' do
57
+ @access.refresh_token.should be_nil
58
+ end
59
+
60
+ it 'returns AccessToken with #expires_in' do
61
+ @access.expires_in.should == 600
62
+ end
63
+
64
+ it 'returns AccessToken with #expires_at' do
65
+ @access.expires_at.should_not be_nil
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end