oauth2 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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