oauth2-aptible 0.9.4.aptible

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,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