oauth2 0.3.0 → 0.4.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,22 +1,20 @@
1
- 0.0.10 - June 19, 2010
2
- ----------------------
3
- * Handle ActiveSupport JSON case where incompatible string does not raise an error. (via Flameeyes)
4
- * Depend on latest version of MultiJSON.
1
+ # CHANGELOG
5
2
 
6
- 0.0.9 - June 18, 2010
7
- ---------------------
8
- * Support a JSON token response with swappable JSON parser via MultiJSON.
9
- * Add support for "expires_in" parameter and relevant methods on AccessToken.
10
-
11
- 0.0.8 - April 27, 2010
12
- ----------------------
13
- * Change get_request_token to use POST to conform to OAuth 2.0 spec. (via jeremy)
14
-
15
- 0.0.7 - April 27, 2010
16
- ----------------------
17
- * Updating Faraday dependency for improved SSL support (via technoweenie)
18
-
19
- 0.0.6 - April 25, 2010
20
- ----------------------
21
- * Added ResponseString so as not to throw away response information when making requests.
22
- * Deprecated #access_token on WebServer strategy in favor of #get_access_token
3
+ * [0.4.0 - April 20, 2011](https://github.com/intridea/oauth2/compare/v0.3.0...v0.4.0)
4
+ * [0.3.0 - April 8, 2011](https://github.com/intridea/oauth2/compare/v0.2.0...v0.3.0)
5
+ * [0.2.0 - April 1, 2011](https://github.com/intridea/oauth2/compare/v0.1.1...v0.2.0)
6
+ * [0.1.1 - January 12, 2011](https://github.com/intridea/oauth2/compare/v0.1.0...v0.1.1)
7
+ * [0.1.0 - October 13, 2010](https://github.com/intridea/oauth2/compare/v0.0.13...v0.1.0)
8
+ * [0.0.13 - August 17, 2010](https://github.com/intridea/oauth2/compare/v0.0.12...v0.0.13)
9
+ * [0.0.12 - August 17, 2010](https://github.com/intridea/oauth2/compare/v0.0.11...v0.0.12)
10
+ * [0.0.11 - August 17, 2010](https://github.com/intridea/oauth2/compare/v0.0.10...v0.0.11)
11
+ * [0.0.10 - June 19, 2010](https://github.com/intridea/oauth2/compare/v0.0.9...v0.0.10)
12
+ * [0.0.9 - June 18, 2010](https://github.com/intridea/oauth2/compare/v0.0.8...v0.0.9)
13
+ * [0.0.8 - April 27, 2010](https://github.com/intridea/oauth2/compare/v0.0.7...v0.0.8)
14
+ * [0.0.7 - April 27, 2010](https://github.com/intridea/oauth2/compare/v0.0.6...v0.0.7)
15
+ * [0.0.6 - April 25, 2010](https://github.com/intridea/oauth2/compare/v0.0.5...v0.0.6)
16
+ * [0.0.5 - April 23, 2010](https://github.com/intridea/oauth2/compare/v0.0.4...v0.0.5)
17
+ * [0.0.4 - April 22, 2010](https://github.com/intridea/oauth2/compare/v0.0.3...v0.0.4)
18
+ * [0.0.3 - April 22, 2010](https://github.com/intridea/oauth2/compare/v0.0.2...v0.0.3)
19
+ * [0.0.2 - April 22, 2010](https://github.com/intridea/oauth2/compare/v0.0.1...v0.0.2)
20
+ * [0.0.1 - April 22, 2010](https://github.com/intridea/oauth2/compare/311d9f42e52b832119170d90e818f0f0b0078851...v0.0.1)
@@ -1,6 +1,7 @@
1
1
  module OAuth2
2
2
  class ErrorWithResponse < StandardError; attr_accessor :response end
3
3
  class AccessDenied < ErrorWithResponse; end
4
+ class Conflict < ErrorWithResponse; end
4
5
  class HTTPError < ErrorWithResponse; end
5
6
  end
6
7
 
@@ -9,4 +10,4 @@ require 'oauth2/strategy/base'
9
10
  require 'oauth2/strategy/web_server'
10
11
  require 'oauth2/strategy/password'
11
12
  require 'oauth2/access_token'
12
- require 'oauth2/response_object'
13
+ require 'oauth2/response_object'
@@ -27,7 +27,9 @@ module OAuth2
27
27
  end
28
28
 
29
29
  def request(verb, path, params={}, headers={})
30
- params = params.merge token_param => @token
30
+ if params.instance_of?(Hash)
31
+ params = params.merge token_param => @token
32
+ end
31
33
  headers = headers.merge 'Authorization' => "OAuth #{@token}"
32
34
  @client.request(verb, path, params, headers)
33
35
  end
@@ -2,7 +2,7 @@ require 'faraday'
2
2
 
3
3
  module OAuth2
4
4
  class Client
5
- attr_accessor :id, :secret, :site, :connection, :options, :raise_errors
5
+ attr_accessor :id, :secret, :site, :connection, :options, :raise_errors, :token_method
6
6
  attr_writer :json
7
7
 
8
8
  # Instantiate a new OAuth 2.0 client using the
@@ -15,6 +15,8 @@ module OAuth2
15
15
  # <tt>:authorize_path</tt> :: Specify the path to the authorization endpoint.
16
16
  # <tt>:authorize_url</tt> :: Specify a full URL of the authorization endpoint.
17
17
  # <tt>:access_token_path</tt> :: Specify the path to the access token endpoint.
18
+ # <tt>:access_token_method</tt> :: Specify the method to use for token endpoints, can be :get or :post
19
+ # (note: for Facebook this should be :get and for Google this should be :post)
18
20
  # <tt>:access_token_url</tt> :: Specify the full URL of the access token endpoint.
19
21
  # <tt>:parse_json</tt> :: If true, <tt>application/json</tt> responses will be automatically parsed.
20
22
  # <tt>:ssl</tt> :: Specify SSL options for the connection.
@@ -23,6 +25,7 @@ module OAuth2
23
25
  # <tt>:raise_errors</tt> :: Default true. When false it will then return the error status and response instead of raising an exception.
24
26
  def initialize(client_id, client_secret, opts={})
25
27
  self.options = opts.dup
28
+ self.token_method = self.options.delete(:access_token_method) || :get
26
29
  adapter = self.options.delete(:adapter)
27
30
  ssl_opts = self.options.delete(:ssl) || {}
28
31
  connection_opts = ssl_opts ? {:ssl => ssl_opts} : {}
@@ -52,7 +55,7 @@ module OAuth2
52
55
 
53
56
  # Makes a request relative to the specified site root.
54
57
  def request(verb, url, params={}, headers={})
55
- if verb == :get
58
+ if (verb == :get) || (verb == :delete)
56
59
  resp = connection.run_request(verb, url, nil, headers) do |req|
57
60
  req.params.update(params)
58
61
  end
@@ -64,10 +67,16 @@ module OAuth2
64
67
  case resp.status
65
68
  when 200...299
66
69
  return response_for(resp)
70
+ when 302
71
+ return request(verb, resp.headers['location'], params, headers)
67
72
  when 401
68
73
  e = OAuth2::AccessDenied.new("Received HTTP 401 during request.")
69
74
  e.response = resp
70
75
  raise e
76
+ when 409
77
+ e = OAuth2::Conflict.new("Received HTTP 409 during request.")
78
+ e.response = resp
79
+ raise e
71
80
  else
72
81
  e = OAuth2::HTTPError.new("Received HTTP #{resp.status} during request.")
73
82
  e.response = resp
@@ -51,7 +51,7 @@ module OAuth2
51
51
  include ResponseObject
52
52
 
53
53
  def initialize(response)
54
- super(response.body)
54
+ super(response.body.to_s)
55
55
  self.response = response
56
56
  end
57
57
  end
@@ -19,6 +19,15 @@ module OAuth2
19
19
  end
20
20
 
21
21
  def access_token_params(options={})
22
+ return default_params(options)
23
+ end
24
+
25
+ def refresh_token_params(options={})
26
+ return default_params(options)
27
+ end
28
+
29
+ private
30
+ def default_params(options={})
22
31
  {
23
32
  'client_id' => @client.id,
24
33
  'client_secret' => @client.secret
@@ -12,8 +12,30 @@ module OAuth2
12
12
  # in order to successfully verify your request for most OAuth 2.0
13
13
  # endpoints.
14
14
  def get_access_token(code, options={})
15
- response = @client.request(:get, @client.access_token_url, access_token_params(code, options))
15
+ response = @client.request(@client.token_method, @client.access_token_url, access_token_params(code, options))
16
+ parse_response(response)
17
+ end
18
+
19
+ def refresh_access_token(refresh_token, options={})
20
+ response = @client.request(@client.token_method, @client.access_token_url, refresh_token_params(refresh_token, options))
21
+ parse_response(response, refresh_token)
22
+ end
16
23
 
24
+ def access_token_params(code, options={}) #:nodoc:
25
+ super(options).merge({
26
+ 'grant_type' => 'authorization_code',
27
+ 'code' => code,
28
+ })
29
+ end
30
+
31
+ def refresh_token_params(refresh_token, options={}) #:nodoc:
32
+ super(options).merge({
33
+ 'grant_type' => 'refresh_token',
34
+ 'refresh_token' => refresh_token,
35
+ })
36
+ end
37
+
38
+ def parse_response(response, refresh_token = nil)
17
39
  if response.is_a? Hash
18
40
  params = response
19
41
  else
@@ -26,18 +48,11 @@ module OAuth2
26
48
  end
27
49
 
28
50
  access = params.delete('access_token')
29
- refresh = params.delete('refresh_token')
51
+ refresh = params.delete('refresh_token') || refresh_token
30
52
  # params['expires'] is only for Facebook
31
53
  expires_in = params.delete('expires_in') || params.delete('expires')
32
54
  OAuth2::AccessToken.new(@client, access, refresh, expires_in, params)
33
55
  end
34
-
35
- def access_token_params(code, options={}) #:nodoc:
36
- super(options).merge({
37
- 'grant_type' => 'authorization_code',
38
- 'code' => code,
39
- })
40
- end
41
56
  end
42
57
  end
43
58
  end
@@ -1,3 +1,3 @@
1
1
  module OAuth2
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -5,10 +5,11 @@ describe OAuth2::AccessToken do
5
5
  cli = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com')
6
6
  cli.connection.build do |b|
7
7
  b.adapter :test do |stub|
8
- stub.get('/client?oauth_token=monkey') {|env| [200, {}, 'get']}
9
- stub.post('/client') {|env| [200, {}, 'oauth_token=' << env[:body]['oauth_token']]}
10
- stub.put('/client') {|env| [200, {}, 'oauth_token=' << env[:body]['oauth_token']]}
11
- stub.delete('/client') {|env| [200, {}, 'oauth_token=' << env[:body]['oauth_token']]}
8
+ stub.get('/client?oauth_token=monkey') {|env| [200, {}, 'get']}
9
+ stub.post('/client') {|env| [200, {}, 'oauth_token=' << env[:body]['oauth_token']]}
10
+ stub.get('/empty_get?oauth_token=monkey') {|env| [204, {}, nil]}
11
+ stub.put('/client') {|env| [200, {}, 'oauth_token=' << env[:body]['oauth_token']]}
12
+ stub.delete('/client?oauth_token=monkey') {|env| [200, {}, 'delete']}
12
13
  end
13
14
  end
14
15
  cli
@@ -30,15 +31,21 @@ describe OAuth2::AccessToken do
30
31
  target.params['foo'].should == 'bar'
31
32
  end
32
33
 
33
- it "makes GET requests with access token" do
34
- subject.send(:get, 'client').should == 'get'
34
+ %w(get delete).each do |http_method|
35
+ it "makes #{http_method.upcase} requests with access token" do
36
+ subject.send(http_method.to_sym, 'client').should == http_method
37
+ end
35
38
  end
36
39
 
37
- %w(post put delete).each do |http_method|
40
+ %w(post put).each do |http_method|
38
41
  it "makes #{http_method.upcase} requests with access token" do
39
42
  subject.send(http_method.to_sym, 'client').should == 'oauth_token=monkey'
40
43
  end
41
44
  end
45
+
46
+ it "works with a null response body" do
47
+ subject.get('empty_get').should == ''
48
+ end
42
49
  end
43
50
 
44
51
  describe '#expires?' do
@@ -7,6 +7,8 @@ describe OAuth2::Client do
7
7
  b.adapter :test do |stub|
8
8
  stub.get('/success') {|env| [200, {'Content-Type' => 'text/awesome'}, 'yay']}
9
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('/redirect') {|env| [302, {'Content-Type' => 'text/plain', 'location' => '/success' }, '']}
10
12
  stub.get('/error') {|env| [500, {}, '']}
11
13
  stub.get('/json') {|env| [200, {'Content-Type' => 'application/json; charset=utf8'}, '{"abc":"def"}']}
12
14
  end
@@ -43,17 +45,24 @@ describe OAuth2::Client do
43
45
 
44
46
  OAuth2::Client.new('abc', 'def', :adapter => [:action_dispatch, session])
45
47
  end
46
-
48
+
47
49
  it "defaults raise_errors to true" do
48
50
  subject.raise_errors.should be_true
49
51
  end
50
-
52
+
51
53
  it "allows true/false for raise_errors option" do
52
54
  client = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :raise_errors => false)
53
55
  client.raise_errors.should be_false
54
56
  client = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :raise_errors => true)
55
57
  client.raise_errors.should be_true
56
58
  end
59
+
60
+ it "allows get/post for access_token_method option" do
61
+ client = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :access_token_method => :get)
62
+ client.token_method.should == :get
63
+ client = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :access_token_method => :post)
64
+ client.token_method.should == :post
65
+ end
57
66
  end
58
67
 
59
68
  %w(authorize access_token).each do |path_type|
@@ -82,6 +91,13 @@ describe OAuth2::Client do
82
91
  response.headers.should == {'Content-Type' => 'text/awesome'}
83
92
  end
84
93
 
94
+ it "follows redirects properly" do
95
+ response = subject.request(:get, '/redirect', {}, {})
96
+ response.should == 'yay'
97
+ response.status.should == 200
98
+ response.headers.should == {'Content-Type' => 'text/awesome'}
99
+ end
100
+
85
101
  it "returns ResponseString on error if raise_errors is false" do
86
102
  subject.raise_errors = false
87
103
  response = subject.request(:get, '/unauthorized', {}, {})
@@ -95,6 +111,10 @@ describe OAuth2::Client do
95
111
  lambda {subject.request(:get, '/unauthorized', {}, {})}.should raise_error(OAuth2::AccessDenied)
96
112
  end
97
113
 
114
+ it "raises OAuth2::Conflict on 409 response" do
115
+ lambda {subject.request(:get, '/conflict', {}, {})}.should raise_error(OAuth2::Conflict)
116
+ end
117
+
98
118
  it "raises OAuth2::HTTPError on error response" do
99
119
  lambda {subject.request(:get, '/error', {}, {})}.should raise_error(OAuth2::HTTPError)
100
120
  end
@@ -15,6 +15,32 @@ describe OAuth2::Strategy::WebServer do
15
15
  [200, {}, 'expires=600&access_token=salmon&refresh_token=trout&extra_param=steve']
16
16
  end
17
17
  end
18
+ stub.post('/oauth/access_token', { 'client_id' => 'abc', 'client_secret' => 'def', 'code' => 'sushi', 'grant_type' => 'authorization_code' }) do |env|
19
+ case @mode
20
+ when "formencoded"
21
+ [200, {}, 'expires_in=600&access_token=salmon&refresh_token=trout&extra_param=steve']
22
+ when "json"
23
+ [200, {}, '{"expires_in":600,"access_token":"salmon","refresh_token":"trout","extra_param":"steve"}']
24
+ when "from_facebook"
25
+ [200, {}, 'expires=600&access_token=salmon&refresh_token=trout&extra_param=steve']
26
+ end
27
+ end
28
+ stub.get('/oauth/access_token?client_id=abc&client_secret=def&grant_type=refresh_token&refresh_token=trout') do |env|
29
+ case @mode
30
+ when "formencoded"
31
+ [200, {}, 'expires_in=600&access_token=tuna']
32
+ when "json"
33
+ [200, {}, '{"expires_in":600,"access_token":"tuna"}']
34
+ end
35
+ end
36
+ stub.post('/oauth/access_token', { 'client_id' => 'abc', 'client_secret' => 'def', 'refresh_token' => 'trout', 'grant_type' => 'refresh_token' }) do |env|
37
+ case @mode
38
+ when "formencoded"
39
+ [200, {}, 'expires_in=600&access_token=tuna']
40
+ when "json"
41
+ [200, {}, '{"expires_in":600,"access_token":"tuna"}']
42
+ end
43
+ end
18
44
  end
19
45
  end
20
46
  cli
@@ -38,35 +64,73 @@ describe OAuth2::Strategy::WebServer do
38
64
 
39
65
  %w(json formencoded from_facebook).each do |mode|
40
66
  [false, true].each do |parse_json|
41
- describe "#get_access_token (#{mode}, parse_json=#{parse_json})" do
42
- before do
43
- @mode = mode
44
- client.json=parse_json
45
- @access = subject.get_access_token('sushi')
46
- end
67
+ [:get, :post].each do |verb|
68
+ describe "#get_access_token (#{mode}, token_method=#{verb} parse_json=#{parse_json})" do
69
+ before do
70
+ @mode = mode
71
+ client.json=parse_json
72
+ client.token_method=verb
73
+ @access = subject.get_access_token('sushi')
74
+ end
47
75
 
48
- it 'returns AccessToken with same Client' do
49
- @access.client.should == client
50
- end
76
+ it 'returns AccessToken with same Client' do
77
+ @access.client.should == client
78
+ end
51
79
 
52
- it 'returns AccessToken with #token' do
53
- @access.token.should == 'salmon'
54
- end
80
+ it 'returns AccessToken with #token' do
81
+ @access.token.should == 'salmon'
82
+ end
55
83
 
56
- it 'returns AccessToken with #refresh_token' do
57
- @access.refresh_token.should == 'trout'
58
- end
84
+ it 'returns AccessToken with #refresh_token' do
85
+ @access.refresh_token.should == 'trout'
86
+ end
59
87
 
60
- it 'returns AccessToken with #expires_in' do
61
- @access.expires_in.should == 600
62
- end
88
+ it 'returns AccessToken with #expires_in' do
89
+ @access.expires_in.should == 600
90
+ end
63
91
 
64
- it 'returns AccessToken with #expires_at' do
65
- @access.expires_at.should be_kind_of(Time)
92
+ it 'returns AccessToken with #expires_at' do
93
+ @access.expires_at.should be_kind_of(Time)
94
+ end
95
+
96
+ it 'returns AccessToken with params accessible via []' do
97
+ @access['extra_param'].should == 'steve'
98
+ end
66
99
  end
100
+ end
101
+ end
102
+ end
67
103
 
68
- it 'returns AccessToken with params accessible via []' do
69
- @access['extra_param'].should == 'steve'
104
+ %w(json formencoded).each do |mode|
105
+ [false, true].each do |parse_json|
106
+ [:get].each do |verb|
107
+ describe "#refresh_access_token (#{mode}, token_method=#{verb} parse_json=#{parse_json})" do
108
+ before do
109
+ @mode = mode
110
+ client.json=parse_json
111
+ client.token_method=verb
112
+ @access = subject.refresh_access_token('trout')
113
+ end
114
+
115
+ it 'returns AccessToken with same Client' do
116
+ @access.client.should == client
117
+ end
118
+
119
+ it 'returns AccessToken with #token' do
120
+ @access.token.should == 'tuna'
121
+ end
122
+
123
+ it 'returns AccessToken with #refresh_token' do
124
+ @access.refresh_token.should == 'trout'
125
+ end
126
+
127
+ it 'returns AccessToken with #expires_in' do
128
+ @access.expires_in.should == 600
129
+ end
130
+
131
+ it 'returns AccessToken with #expires_at' do
132
+ @access.expires_at.should be_kind_of(Time)
133
+ end
70
134
  end
71
135
  end
72
136
  end
@@ -1,3 +1,7 @@
1
+ require "rubygems"
2
+ require "bundler"
3
+ Bundler.setup
4
+
1
5
  require 'simplecov'
2
6
  SimpleCov.start
3
7
  require 'oauth2'
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: oauth2
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.3.0
5
+ version: 0.4.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Michael Bleigh
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-04-08 00:00:00 Z
13
+ date: 2011-04-20 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: faraday