oauth2 0.4.1 → 0.5.0

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.
@@ -1,19 +1,23 @@
1
- require 'spec_helper'
1
+ require 'helper'
2
2
 
3
3
  describe OAuth2::Client do
4
+ let!(:error_value) {'invalid_token'}
5
+ let!(:error_description_value) {'bad bad token'}
6
+
4
7
  subject do
5
- cli = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com')
6
- cli.connection.build do |b|
7
- b.adapter :test do |stub|
8
+ OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com') do |builder|
9
+ builder.adapter :test do |stub|
8
10
  stub.get('/success') {|env| [200, {'Content-Type' => 'text/awesome'}, 'yay']}
9
- stub.get('/unauthorized') {|env| [401, {'Content-Type' => 'text/plain'}, 'not authorized']}
10
- stub.get('/conflict') {|env| [409, {'Content-Type' => 'text/plain'}, 'not authorized']}
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']}
11
15
  stub.get('/redirect') {|env| [302, {'Content-Type' => 'text/plain', 'location' => '/success' }, '']}
16
+ stub.post('/redirect') {|env| [303, {'Content-Type' => 'text/plain', 'location' => '/reflect' }, '']}
12
17
  stub.get('/error') {|env| [500, {}, '']}
13
- stub.get('/json') {|env| [200, {'Content-Type' => 'application/json; charset=utf8'}, '{"abc":"def"}']}
18
+ stub.get('/empty_get') {|env| [204, {}, nil]}
14
19
  end
15
20
  end
16
- cli
17
21
  end
18
22
 
19
23
  describe '#initialize' do
@@ -34,122 +38,130 @@ describe OAuth2::Client do
34
38
  subject.connection.ssl.should == {}
35
39
  end
36
40
 
37
- it "should be able to pass parameters to the adapter, e.g. Faraday::Adapter::ActionDispatch" do
41
+ it "should be able to pass a block to configure the connection" do
38
42
  connection = stub('connection')
39
- Faraday::Connection.stub(:new => connection)
40
43
  session = stub('session', :to_ary => nil)
41
44
  builder = stub('builder')
42
45
  connection.stub(:build).and_yield(builder)
46
+ Faraday::Connection.stub(:new => connection)
43
47
 
44
- builder.should_receive(:adapter).with(:action_dispatch, session)
48
+ builder.should_receive(:adapter).with(:test)
45
49
 
46
- OAuth2::Client.new('abc', 'def', :adapter => [:action_dispatch, session])
50
+ OAuth2::Client.new('abc', 'def') do |builder|
51
+ builder.adapter :test
52
+ end.connection
47
53
  end
48
54
 
49
55
  it "defaults raise_errors to true" do
50
- subject.raise_errors.should be_true
56
+ subject.options[:raise_errors].should be_true
51
57
  end
52
58
 
53
59
  it "allows true/false for raise_errors option" do
54
60
  client = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :raise_errors => false)
55
- client.raise_errors.should be_false
61
+ client.options[:raise_errors].should be_false
56
62
  client = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :raise_errors => true)
57
- client.raise_errors.should be_true
63
+ client.options[:raise_errors].should be_true
58
64
  end
59
65
 
60
66
  it "allows get/post for access_token_method option" do
61
67
  client = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :access_token_method => :get)
62
- client.token_method.should == :get
68
+ client.options[:access_token_method].should == :get
63
69
  client = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :access_token_method => :post)
64
- client.token_method.should == :post
70
+ client.options[:access_token_method].should == :post
65
71
  end
66
72
  end
67
73
 
68
- %w(authorize access_token).each do |path_type|
69
- describe "##{path_type}_url" do
70
- it "should default to a path of /oauth/#{path_type}" do
71
- subject.send("#{path_type}_url").should == "https://api.example.com/oauth/#{path_type}"
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}"
72
78
  end
73
79
 
74
- it "should be settable via the :#{path_type}_path option" do
75
- subject.options[:"#{path_type}_path"] = '/oauth/custom'
76
- subject.send("#{path_type}_url").should == 'https://api.example.com/oauth/custom'
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'
77
83
  end
78
84
 
79
- it "should be settable via the :#{path_type}_url option" do
80
- subject.options[:"#{path_type}_url"] = 'https://abc.com/authorize'
81
- subject.send("#{path_type}_url").should == 'https://abc.com/authorize'
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'
82
88
  end
83
89
  end
84
90
  end
85
91
 
86
92
  describe "#request" do
87
- it "returns ResponseString on successful response" do
88
- response = subject.request(:get, '/success', {}, {})
89
- response.should == 'yay'
90
- response.status.should == 200
91
- response.headers.should == {'Content-Type' => 'text/awesome'}
93
+ it "works with a null response body" do
94
+ subject.request(:get, 'empty_get').body.should == ''
92
95
  end
93
96
 
94
- it "follows redirects properly" do
95
- response = subject.request(:get, '/redirect', {}, {})
96
- response.should == 'yay'
97
+ it "returns on a successful response" do
98
+ response = subject.request(:get, '/success')
99
+ response.body.should == 'yay'
97
100
  response.status.should == 200
98
101
  response.headers.should == {'Content-Type' => 'text/awesome'}
99
102
  end
100
103
 
101
- it "returns ResponseString on error if raise_errors is false" do
102
- subject.raise_errors = false
103
- response = subject.request(:get, '/unauthorized', {}, {})
104
-
105
- response.should == 'not authorized'
106
- response.status.should == 401
107
- response.headers.should == {'Content-Type' => 'text/plain'}
104
+ it "posts a body" do
105
+ response = subject.request(:post, '/reflect', :body => 'foo=bar')
106
+ response.body.should == 'foo=bar'
108
107
  end
109
108
 
110
- it "raises OAuth2::AccessDenied on 401 response" do
111
- lambda {subject.request(:get, '/unauthorized', {}, {})}.should raise_error(OAuth2::AccessDenied)
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'}
112
114
  end
113
115
 
114
- it "raises OAuth2::Conflict on 409 response" do
115
- lambda {subject.request(:get, '/conflict', {}, {})}.should raise_error(OAuth2::Conflict)
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
116
120
  end
117
121
 
118
- it "raises OAuth2::HTTPError on error response" do
119
- lambda {subject.request(:get, '/error', {}, {})}.should raise_error(OAuth2::HTTPError)
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
120
128
  end
121
- end
122
129
 
123
- it '#web_server should instantiate a WebServer strategy with this client' do
124
- subject.web_server.should be_kind_of(OAuth2::Strategy::WebServer)
125
- end
130
+ it "returns if raise_errors is false" do
131
+ subject.options[:raise_errors] = false
132
+ response = subject.request(:get, '/unauthorized')
126
133
 
127
- context 'with JSON parsing' do
128
- before do
129
- subject.json = true
134
+ response.status.should == 401
135
+ response.headers.should == {'Content-Type' => 'application/json'}
136
+ response.error.should_not be_nil
130
137
  end
131
138
 
132
- describe '#request' do
133
- it 'should return a response hash' do
134
- response = subject.request(:get, '/json')
135
- puts response.inspect
136
- response.should be_kind_of(OAuth2::ResponseHash)
137
- response['abc'].should == 'def'
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)
138
142
  end
143
+ end
139
144
 
140
- it 'should only try to decode application/json' do
141
- subject.request(:get, '/success').should == 'yay'
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
142
151
  end
143
152
  end
144
153
 
145
- it 'should set json? based on the :parse_json option' do
146
- OAuth2::Client.new('abc', 'def', :site => 'http://example.com', :parse_json => true).should be_json
147
- OAuth2::Client.new('abc', 'def', :site => 'http://example.com', :parse_json => false).should_not be_json
154
+ it "provides the response in the Exception" do
155
+ begin
156
+ subject.request(:get, '/error')
157
+ rescue Exception => e
158
+ e.response.should_not be_nil
159
+ end
148
160
  end
161
+ end
149
162
 
150
- after do
151
- subject.json = false
152
- end
163
+ it '#auth_code should instantiate a AuthCode strategy with this client' do
164
+ subject.auth_code.should be_kind_of(OAuth2::Strategy::AuthCode)
153
165
  end
154
166
 
155
167
  context 'with SSL options' do
@@ -0,0 +1,90 @@
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
+ Rack::Utils.should_not_receive(:parse_query)
71
+
72
+ subject = Response.new(response)
73
+ subject.parsed.should be_nil
74
+ end
75
+ end
76
+
77
+ context 'xml parser registration' do
78
+ it 'should try to load multi_xml and use it' do
79
+ OAuth2::Response::PARSERS[:xml].should_not be_nil
80
+ end
81
+
82
+ it 'should be able to parse xml' do
83
+ headers = {'Content-Type' => 'text/xml'}
84
+ body = '<?xml version="1.0" standalone="yes" ?><foo><bar>baz</bar></foo>'
85
+
86
+ response = double('response', :headers => headers, :body => body)
87
+ OAuth2::Response.new(response).parsed.should == {"foo" => {"bar" => "baz"}}
88
+ end
89
+ end
90
+ 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 '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
@@ -1,4 +1,4 @@
1
- require 'spec_helper'
1
+ require 'helper'
2
2
 
3
3
  describe OAuth2::Strategy::Base do
4
4
  it 'should initialize with a Client' do
@@ -1,16 +1,16 @@
1
- require 'spec_helper'
1
+ require 'helper'
2
2
 
3
3
  describe OAuth2::Strategy::Password do
4
4
  let(:client) do
5
5
  cli = OAuth2::Client.new('abc', 'def', :site => 'http://api.example.com')
6
6
  cli.connection.build do |b|
7
7
  b.adapter :test do |stub|
8
- stub.post('/oauth/access_token') do |env|
8
+ stub.post('/oauth/token') do |env|
9
9
  case @mode
10
10
  when "formencoded"
11
- [200, {}, 'expires_in=600&access_token=salmon&refresh_token=trout']
11
+ [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, 'expires_in=600&access_token=salmon&refresh_token=trout']
12
12
  when "json"
13
- [200, {}, '{"expires_in":600,"access_token":"salmon","refresh_token":"trout"}']
13
+ [200, {'Content-Type' => 'application/json'}, '{"expires_in":600,"access_token":"salmon","refresh_token":"trout"}']
14
14
  end
15
15
  end
16
16
  end
@@ -26,10 +26,10 @@ describe OAuth2::Strategy::Password do
26
26
  end
27
27
 
28
28
  %w(json formencoded).each do |mode|
29
- describe "#get_access_token (#{mode})" do
29
+ describe "#get_token (#{mode})" do
30
30
  before do
31
31
  @mode = mode
32
- @access = subject.get_access_token('username', 'password')
32
+ @access = subject.get_token('username', 'password')
33
33
  end
34
34
 
35
35
  it 'returns AccessToken with same Client' do
@@ -49,7 +49,7 @@ describe OAuth2::Strategy::Password do
49
49
  end
50
50
 
51
51
  it 'returns AccessToken with #expires_at' do
52
- @access.expires_at.should be_kind_of(Time)
52
+ @access.expires_at.should_not be_nil
53
53
  end
54
54
  end
55
55
  end