dreamwords-oauth2 0.8.1

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.
@@ -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