oauth2-aptible 0.9.4.aptible

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,205 @@
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 'assigns id and secret' do
25
+ expect(subject.id).to eq('abc')
26
+ expect(subject.secret).to eq('def')
27
+ end
28
+
29
+ it 'assigns site from the options hash' do
30
+ expect(subject.site).to eq('https://api.example.com')
31
+ end
32
+
33
+ it 'assigns Faraday::Connection#host' do
34
+ expect(subject.connection.host).to eq('api.example.com')
35
+ end
36
+
37
+ it 'leaves Faraday::Connection#ssl unset' do
38
+ expect(subject.connection.ssl).to be_empty
39
+ end
40
+
41
+ it 'is able to pass a block to configure the connection' do
42
+ connection = double('connection')
43
+ builder = double('builder')
44
+ allow(connection).to receive(:build).and_yield(builder)
45
+ allow(Faraday::Connection).to receive(:new).and_return(connection)
46
+
47
+ expect(builder).to receive(:adapter).with(:test)
48
+
49
+ OAuth2::Client.new('abc', 'def') do |client|
50
+ client.adapter :test
51
+ end.connection
52
+ end
53
+
54
+ it 'defaults raise_errors to true' do
55
+ expect(subject.options[:raise_errors]).to be true
56
+ end
57
+
58
+ it 'allows true/false for raise_errors option' do
59
+ client = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :raise_errors => false)
60
+ expect(client.options[:raise_errors]).to be false
61
+ client = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :raise_errors => true)
62
+ expect(client.options[:raise_errors]).to be true
63
+ end
64
+
65
+ it 'allows override of raise_errors option' do
66
+ client = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :raise_errors => true) do |builder|
67
+ builder.adapter :test do |stub|
68
+ stub.get('/notfound') { |env| [404, {}, nil] }
69
+ end
70
+ end
71
+ expect(client.options[:raise_errors]).to be true
72
+ expect { client.request(:get, '/notfound') }.to raise_error(OAuth2::Error)
73
+ response = client.request(:get, '/notfound', :raise_errors => false)
74
+ expect(response.status).to eq(404)
75
+ end
76
+
77
+ it 'allows get/post for access_token_method option' do
78
+ client = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :access_token_method => :get)
79
+ expect(client.options[:access_token_method]).to eq(:get)
80
+ client = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :access_token_method => :post)
81
+ expect(client.options[:access_token_method]).to eq(:post)
82
+ end
83
+
84
+ it 'does not mutate the opts hash argument' do
85
+ opts = {:site => 'http://example.com/'}
86
+ opts2 = opts.dup
87
+ OAuth2::Client.new 'abc', 'def', opts
88
+ expect(opts).to eq(opts2)
89
+ end
90
+ end
91
+
92
+ %w(authorize token).each do |url_type|
93
+ describe ":#{url_type}_url option" do
94
+ it "defaults to a path of /oauth/#{url_type}" do
95
+ expect(subject.send("#{url_type}_url")).to eq("https://api.example.com/oauth/#{url_type}")
96
+ end
97
+
98
+ it "is settable via the :#{url_type}_url option" do
99
+ subject.options[:"#{url_type}_url"] = '/oauth/custom'
100
+ expect(subject.send("#{url_type}_url")).to eq('https://api.example.com/oauth/custom')
101
+ end
102
+
103
+ it 'allows a different host than the site' do
104
+ subject.options[:"#{url_type}_url"] = 'https://api.foo.com/oauth/custom'
105
+ expect(subject.send("#{url_type}_url")).to eq('https://api.foo.com/oauth/custom')
106
+ end
107
+ end
108
+ end
109
+
110
+ describe '#request' do
111
+ it 'works with a null response body' do
112
+ expect(subject.request(:get, 'empty_get').body).to eq('')
113
+ end
114
+
115
+ it 'returns on a successful response' do
116
+ response = subject.request(:get, '/success')
117
+ expect(response.body).to eq('yay')
118
+ expect(response.status).to eq(200)
119
+ expect(response.headers).to eq('Content-Type' => 'text/awesome')
120
+ end
121
+
122
+ it 'posts a body' do
123
+ response = subject.request(:post, '/reflect', :body => 'foo=bar')
124
+ expect(response.body).to eq('foo=bar')
125
+ end
126
+
127
+ it 'follows redirects properly' do
128
+ response = subject.request(:get, '/redirect')
129
+ expect(response.body).to eq('yay')
130
+ expect(response.status).to eq(200)
131
+ expect(response.headers).to eq('Content-Type' => 'text/awesome')
132
+ end
133
+
134
+ it 'redirects using GET on a 303' do
135
+ response = subject.request(:post, '/redirect', :body => 'foo=bar')
136
+ expect(response.body).to be_empty
137
+ expect(response.status).to eq(200)
138
+ end
139
+
140
+ it 'obeys the :max_redirects option' do
141
+ max_redirects = subject.options[:max_redirects]
142
+ subject.options[:max_redirects] = 0
143
+ response = subject.request(:get, '/redirect')
144
+ expect(response.status).to eq(302)
145
+ subject.options[:max_redirects] = max_redirects
146
+ end
147
+
148
+ it 'returns if raise_errors is false' do
149
+ subject.options[:raise_errors] = false
150
+ response = subject.request(:get, '/unauthorized')
151
+
152
+ expect(response.status).to eq(401)
153
+ expect(response.headers).to eq('Content-Type' => 'application/json')
154
+ expect(response.error).not_to be_nil
155
+ end
156
+
157
+ %w(/unauthorized /conflict /error).each do |error_path|
158
+ it "raises OAuth2::Error on error response to path #{error_path}" do
159
+ expect { subject.request(:get, error_path) }.to raise_error(OAuth2::Error)
160
+ end
161
+ end
162
+
163
+ it 'parses OAuth2 standard error response' do
164
+ begin
165
+ subject.request(:get, '/unauthorized')
166
+ rescue StandardError => e
167
+ expect(e.code).to eq(error_value)
168
+ expect(e.description).to eq(error_description_value)
169
+ expect(e.to_s).to match(/#{error_value}/)
170
+ expect(e.to_s).to match(/#{error_description_value}/)
171
+ end
172
+ end
173
+
174
+ it 'provides the response in the Exception' do
175
+ begin
176
+ subject.request(:get, '/error')
177
+ rescue StandardError => e
178
+ expect(e.response).not_to be_nil
179
+ expect(e.to_s).to match(/unknown error/)
180
+ end
181
+ end
182
+ end
183
+
184
+ it 'instantiates an AuthCode strategy with this client' do
185
+ expect(subject.auth_code).to be_kind_of(OAuth2::Strategy::AuthCode)
186
+ end
187
+
188
+ it 'instantiates an Implicit strategy with this client' do
189
+ expect(subject.implicit).to be_kind_of(OAuth2::Strategy::Implicit)
190
+ end
191
+
192
+ context 'with SSL options' do
193
+ subject do
194
+ cli = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :ssl => {:ca_file => 'foo.pem'})
195
+ cli.connection.build do |b|
196
+ b.adapter :test
197
+ end
198
+ cli
199
+ end
200
+
201
+ it 'passes the SSL options along to Faraday::Connection#ssl' do
202
+ expect(subject.connection.ssl.fetch(:ca_file)).to eq('foo.pem')
203
+ end
204
+ end
205
+ end
@@ -0,0 +1,101 @@
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
+ expect(subject.headers).to eq(headers)
15
+ expect(subject.status).to eq(status)
16
+ expect(subject.body).to eq(body)
17
+ end
18
+ end
19
+
20
+ describe '.register_parser' do
21
+ let(:response) do
22
+ double('response', :headers => {'Content-Type' => 'application/foo-bar'},
23
+ :status => 200,
24
+ :body => 'baz')
25
+ end
26
+ before do
27
+ OAuth2::Response.register_parser(:foobar, 'application/foo-bar') do |body|
28
+ "foobar #{body}"
29
+ end
30
+ end
31
+
32
+ it 'adds to the content types and parsers' do
33
+ expect(OAuth2::Response::PARSERS.keys).to include(:foobar)
34
+ expect(OAuth2::Response::CONTENT_TYPES.keys).to include('application/foo-bar')
35
+ end
36
+
37
+ it 'is able to parse that content type automatically' do
38
+ expect(OAuth2::Response.new(response).parsed).to eq('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
+ expect(subject.parsed.keys.size).to eq(2)
49
+ expect(subject.parsed['foo']).to eq('bar')
50
+ expect(subject.parsed['answer']).to eq('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
+ expect(subject.parsed.keys.size).to eq(2)
59
+ expect(subject.parsed['foo']).to eq('bar')
60
+ expect(subject.parsed['answer']).to eq(42)
61
+ end
62
+
63
+ it 'parses alternative application/json extension bodies' do
64
+ headers = {'Content-Type' => 'application/hal+json'}
65
+ body = MultiJson.encode(:foo => 'bar', :answer => 42)
66
+ response = double('response', :headers => headers, :body => body)
67
+ subject = Response.new(response)
68
+ expect(subject.parsed.keys.size).to eq(2)
69
+ expect(subject.parsed['foo']).to eq('bar')
70
+ expect(subject.parsed['answer']).to eq(42)
71
+ end
72
+
73
+ it "doesn't try to parse other content-types" do
74
+ headers = {'Content-Type' => 'text/html'}
75
+ body = '<!DOCTYPE html><html><head></head><body></body></html>'
76
+
77
+ response = double('response', :headers => headers, :body => body)
78
+
79
+ expect(MultiJson).not_to receive(:decode)
80
+ expect(MultiJson).not_to receive(:load)
81
+ expect(Rack::Utils).not_to receive(:parse_query)
82
+
83
+ subject = Response.new(response)
84
+ expect(subject.parsed).to be_nil
85
+ end
86
+ end
87
+
88
+ context 'xml parser registration' do
89
+ it 'tries to load multi_xml and use it' do
90
+ expect(OAuth2::Response::PARSERS[:xml]).not_to be_nil
91
+ end
92
+
93
+ it 'is able to parse xml' do
94
+ headers = {'Content-Type' => 'text/xml'}
95
+ body = '<?xml version="1.0" standalone="yes" ?><foo><bar>baz</bar></foo>'
96
+
97
+ response = double('response', :headers => headers, :body => body)
98
+ expect(OAuth2::Response.new(response).parsed).to eq('foo' => {'bar' => 'baz'})
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,56 @@
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 'raises NotImplementedError' do
27
+ expect { subject.authorize_url }.to 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
+ expect(@access.client).to eq(client)
40
+ end
41
+
42
+ it 'returns AccessToken with #token' do
43
+ expect(@access.token).to eq('salmon')
44
+ end
45
+
46
+ it 'returns AccessToken with #expires_in' do
47
+ expect(@access.expires_in).to eq(600)
48
+ end
49
+
50
+ it 'returns AccessToken with #expires_at' do
51
+ expect(@access.expires_at).not_to be_nil
52
+ end
53
+ end
54
+ end
55
+
56
+ end
@@ -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 'includes the client_id' do
40
+ expect(subject.authorize_url).to include('client_id=abc')
41
+ end
42
+
43
+ it 'includes the type' do
44
+ expect(subject.authorize_url).to include('response_type=code')
45
+ end
46
+
47
+ it 'includes passed in options' do
48
+ cb = 'http://myserver.local/oauth/callback'
49
+ expect(subject.authorize_url(:redirect_uri => cb)).to 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 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
+ expect(@access.client).to eq(client)
64
+ end
65
+
66
+ it 'returns AccessToken with #token' do
67
+ expect(@access.token).to eq('salmon')
68
+ end
69
+
70
+ it 'returns AccessToken with #refresh_token' do
71
+ expect(@access.refresh_token).to eq('trout')
72
+ end
73
+
74
+ it 'returns AccessToken with #expires_in' do
75
+ expect(@access.expires_in).to eq(600)
76
+ end
77
+
78
+ it 'returns AccessToken with #expires_at' do
79
+ expect(@access.expires_at).to be_kind_of(Integer)
80
+ end
81
+
82
+ it 'returns AccessToken with params accessible via []' do
83
+ expect(@access['extra_param']).to eq('steve')
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end