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.
- data/.autotest +1 -0
- data/.gitignore +4 -1
- data/.travis.yml +1 -3
- data/Gemfile +1 -1
- data/README.md +62 -57
- data/Rakefile +3 -1
- data/lib/oauth2.rb +3 -9
- data/lib/oauth2/access_token.rb +122 -24
- data/lib/oauth2/client.rb +115 -74
- data/lib/oauth2/error.rb +17 -0
- data/lib/oauth2/response.rb +90 -0
- data/lib/oauth2/strategy/auth_code.rb +32 -0
- data/lib/oauth2/strategy/base.rb +7 -29
- data/lib/oauth2/strategy/password.rb +16 -27
- data/lib/oauth2/version.rb +1 -1
- data/oauth2.gemspec +23 -21
- data/spec/helper.rb +13 -0
- data/spec/oauth2/access_token_spec.rb +99 -45
- data/spec/oauth2/client_spec.rb +81 -69
- data/spec/oauth2/response_spec.rb +90 -0
- data/spec/oauth2/strategy/auth_code_spec.rb +88 -0
- data/spec/oauth2/strategy/base_spec.rb +1 -1
- data/spec/oauth2/strategy/password_spec.rb +7 -7
- metadata +114 -90
- data/CHANGELOG.md +0 -21
- data/lib/oauth2/response_object.rb +0 -58
- data/lib/oauth2/strategy/web_server.rb +0 -58
- data/spec/oauth2/strategy/web_server_spec.rb +0 -138
- data/spec/spec_helper.rb +0 -11
data/.autotest
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'autotest/bundler'
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -8,7 +8,7 @@ Installation
|
|
8
8
|
|
9
9
|
Continuous Integration
|
10
10
|
----------------------
|
11
|
-
[](http://travis-ci.org/intridea/oauth2)
|
12
12
|
|
13
13
|
Resources
|
14
14
|
---------
|
@@ -16,67 +16,48 @@ Resources
|
|
16
16
|
* Report Issues on GitHub (https://github.com/intridea/oauth2/issues)
|
17
17
|
* Read More at the Wiki (https://wiki.github.com/intridea/oauth2)
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
Below is a fully functional example of a Sinatra application that would authenticate to Facebook utilizing the OAuth 2.0 web server flow.
|
19
|
+
Generic Client Example
|
20
|
+
----------------------
|
22
21
|
|
23
|
-
require 'rubygems'
|
24
|
-
require 'sinatra'
|
25
22
|
require 'oauth2'
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
get
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
end
|
51
|
-
|
52
|
-
That's all there is to it! You can use the access token like you would with the
|
53
|
-
OAuth gem, calling HTTP verbs on it etc. You can view more examples on the [OAuth2
|
54
|
-
Wiki](http://wiki.github.com/intridea/oauth2/examples).
|
55
|
-
|
56
|
-
JSON Parsing
|
57
|
-
------------
|
58
|
-
Because JSON has become the standard format of the OAuth 2.0 specification,
|
59
|
-
the <tt>oauth2</tt> gem contains a mode that will perform automatic parsing
|
60
|
-
of JSON response bodies, returning a hash instead of a string. To enable this
|
61
|
-
mode, simply add the <tt>:parse_json</tt> option to your client initialization:
|
23
|
+
client = OAuth2::Client.new('client_id', 'client_secret', :site => 'https://example.org')
|
24
|
+
|
25
|
+
client.auth_code.authorize_url(:redirect_uri => 'http://localhost:8080/oauth2/callback')
|
26
|
+
# => "https://example.org/oauth/authorization?response_type=code&client_id=client_id&redirect_uri=http://localhost:8080/oauth2/callback"
|
27
|
+
|
28
|
+
token = client.auth_code.get_token('authorization_code_value', :redirect_uri => 'http://localhost:8080/oauth2/callback')
|
29
|
+
response = token.get('/api/resource', :params => { 'query_foo' => 'bar' })
|
30
|
+
response.class.name
|
31
|
+
# => OAuth2::Response
|
32
|
+
|
33
|
+
OAuth2::Response
|
34
|
+
----------------
|
35
|
+
The AccessToken methods #get, #post, #put and #delete and the generic #request will return an instance of the #OAuth2::Response class.
|
36
|
+
This instance contains a #parsed method that will parse the response body and return a Hash if the Content-Type is application/x-www-form-urlencoded or if the body is a JSON object. It will return an Array if the body is a JSON array. Otherwise, it will return the original body string.
|
37
|
+
|
38
|
+
The original response body, headers, and status can be accessed via their respective methods.
|
39
|
+
|
40
|
+
OAuth2::AccessToken
|
41
|
+
-------------------
|
42
|
+
If you have an existing Access Token for a user, you can initialize an instance using various class methods including the standard new, from_hash (if you have a hash of the values), or from_kvform (if you have an application/x-www-form-urlencoded encoded string of the values).
|
43
|
+
|
44
|
+
OAuth2::Error
|
45
|
+
-------------
|
46
|
+
On 400+ status code responses, an OAuth2::Error will be raised. If it is a standard OAuth2 error response, the body will be parsed and #code and #description will contain the values provided from the error and error_description parameters. The #response property of OAuth2::Error will always contain the OAuth2::Response instance.
|
62
47
|
|
63
|
-
|
64
|
-
'app_id',
|
65
|
-
'app_secret',
|
66
|
-
:site => 'https://example.com',
|
67
|
-
:parse_json => true,
|
68
|
-
)
|
69
|
-
|
70
|
-
# Obtain an access token using the client
|
71
|
-
token.get('/some/url.json') #=> {"some" => "hash"}
|
48
|
+
If you do not want an error to be raised, you may use :raise_errors => false option on initialization of the client. In this case the OAuth2::Response instance will be returned as usual and on 400+ status code responses, the Response instance will contain the OAuth2::Error instance.
|
72
49
|
|
73
|
-
|
74
|
-
|
75
|
-
|
50
|
+
Authorization Grants
|
51
|
+
--------------------
|
52
|
+
Currently the Authorization Code and Resource Owner Password Credentials authentication grant types have helper strategy classes that simplify client use. They are available via the #auth_code and #password methods respectively.
|
76
53
|
|
77
|
-
|
54
|
+
auth_url = client.auth_code.authorization_url(:redirect_uri => 'http://localhost:8080/oauth/callback')
|
55
|
+
token = client.auth_code.get_token('code_value', :redirect_uri => 'http://localhost:8080/oauth/callback')
|
56
|
+
|
57
|
+
token = client.password.get_token('username', 'password')
|
58
|
+
|
59
|
+
You can always use the #request method on the OAuth2::Client instance to make requests for tokens for any Authentication grant type.
|
78
60
|
|
79
|
-
It will then return the error status and response instead of raising an exception.
|
80
61
|
|
81
62
|
Note on Patches/Pull Requests
|
82
63
|
-----------------------------
|
@@ -87,7 +68,31 @@ Note on Patches/Pull Requests
|
|
87
68
|
5. Add specs for your feature or bug fix.
|
88
69
|
6. Run <tt>bundle exec rake spec</tt>. If your changes are not 100% covered, go back to step 5.
|
89
70
|
7. Commit and push your changes.
|
90
|
-
8. Submit a pull request. Please do not include changes to the [gemspec](https://github.com/intridea/oauth2/blob/master/oauth2.gemspec), [version](https://github.com/intridea/oauth2/blob/master/lib/oauth2/version.rb), or [changelog](https://github.com/intridea/oauth2/
|
71
|
+
8. Submit a pull request. Please do not include changes to the [gemspec](https://github.com/intridea/oauth2/blob/master/oauth2.gemspec), [version](https://github.com/intridea/oauth2/blob/master/lib/oauth2/version.rb), or [changelog](https://github.com/intridea/oauth2/wiki/Changelg) . (If you want to create your own version for some reason, please do so in a separate commit.)
|
72
|
+
|
73
|
+
Supported Rubies
|
74
|
+
----------------
|
75
|
+
This library aims to support and is [tested
|
76
|
+
against](http://travis-ci.org/intridea/oauth2) the following Ruby
|
77
|
+
implementations:
|
78
|
+
|
79
|
+
* Ruby 1.8.7
|
80
|
+
* Ruby 1.9.2
|
81
|
+
* Ruby Enterprise Edition 1.8.7
|
82
|
+
|
83
|
+
If something doesn't work on one of these interpreters, it should be considered
|
84
|
+
a bug.
|
85
|
+
|
86
|
+
This library may inadvertently work (or seem to work) on other Ruby
|
87
|
+
implementations, however support will only be provided for the versions listed
|
88
|
+
above.
|
89
|
+
|
90
|
+
If you would like this library to support another Ruby version, you may
|
91
|
+
volunteer to be a maintainer. Being a maintainer entails making sure all tests
|
92
|
+
run and pass on that implementation. When something breaks on your
|
93
|
+
implementation, you will be personally responsible for providing patches in a
|
94
|
+
timely fashion. If critical issues for a particular implementation exist at the
|
95
|
+
time of a major release, support for that Ruby version may be dropped.
|
91
96
|
|
92
97
|
Copyright
|
93
98
|
---------
|
data/Rakefile
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
|
1
3
|
require 'bundler'
|
2
4
|
Bundler::GemHelper.install_tasks
|
3
5
|
|
@@ -7,7 +9,7 @@ RSpec::Core::RakeTask.new(:spec)
|
|
7
9
|
task :default => :spec
|
8
10
|
task :test => :spec
|
9
11
|
|
10
|
-
require '
|
12
|
+
require 'rdoc/task'
|
11
13
|
Rake::RDocTask.new do |rdoc|
|
12
14
|
rdoc.rdoc_dir = 'rdoc'
|
13
15
|
rdoc.title = "oauth2 #{OAuth2::VERSION}"
|
data/lib/oauth2.rb
CHANGED
@@ -1,13 +1,7 @@
|
|
1
|
-
|
2
|
-
class ErrorWithResponse < StandardError; attr_accessor :response end
|
3
|
-
class AccessDenied < ErrorWithResponse; end
|
4
|
-
class Conflict < ErrorWithResponse; end
|
5
|
-
class HTTPError < ErrorWithResponse; end
|
6
|
-
end
|
7
|
-
|
1
|
+
require 'oauth2/error'
|
8
2
|
require 'oauth2/client'
|
9
3
|
require 'oauth2/strategy/base'
|
10
|
-
require 'oauth2/strategy/
|
4
|
+
require 'oauth2/strategy/auth_code'
|
11
5
|
require 'oauth2/strategy/password'
|
12
6
|
require 'oauth2/access_token'
|
13
|
-
require 'oauth2/
|
7
|
+
require 'oauth2/response'
|
data/lib/oauth2/access_token.rb
CHANGED
@@ -1,53 +1,151 @@
|
|
1
1
|
module OAuth2
|
2
2
|
class AccessToken
|
3
3
|
attr_reader :client, :token, :refresh_token, :expires_in, :expires_at, :params
|
4
|
-
attr_accessor :
|
4
|
+
attr_accessor :options
|
5
5
|
|
6
|
-
|
6
|
+
class << self
|
7
|
+
# Initializes an AccessToken from a Hash
|
8
|
+
#
|
9
|
+
# @param [Client] the OAuth2::Client instance
|
10
|
+
# @param [Hash] a hash of AccessToken property values
|
11
|
+
# @return [AccessToken] the initalized AccessToken
|
12
|
+
def from_hash(client, hash)
|
13
|
+
self.new(client, hash.delete('access_token') || hash.delete(:access_token), hash)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Initializes an AccessToken from a key/value application/x-www-form-urlencoded string
|
17
|
+
#
|
18
|
+
# @param [Client] client the OAuth2::Client instance
|
19
|
+
# @param [String] kvform the application/x-www-form-urlencoded string
|
20
|
+
# @return [AccessToken] the initalized AccessToken
|
21
|
+
def from_kvform(client, kvform)
|
22
|
+
from_hash(client, Rack::Utils.parse_query(kvform))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Initalize an AccessToken
|
27
|
+
#
|
28
|
+
# @param [Client] client the OAuth2::Client instance
|
29
|
+
# @param [String] token the Access Token value
|
30
|
+
# @param [Hash] opts the options to create the Access Token with
|
31
|
+
# @option opts [String] :refresh_token (nil) the refresh_token value
|
32
|
+
# @option opts [FixNum, String] :expires_in (nil) the number of seconds in which the AccessToken will expire
|
33
|
+
# @option opts [FixNum, String] :expires_at (nil) the epoch time in seconds in which AccessToken will expire
|
34
|
+
# @option opts [Symbol] :mode (:header) the transmission mode of the Access Token parameter value
|
35
|
+
# one of :header, :body or :query
|
36
|
+
# @option opts [String] :header_format ('Bearer %s') the string format to use for the Authorization header
|
37
|
+
# @option opts [String] :param_name ('bearer_token') the parameter name to use for transmission of the
|
38
|
+
# Access Token value in :body or :query transmission mode
|
39
|
+
def initialize(client, token, opts={})
|
7
40
|
@client = client
|
8
41
|
@token = token.to_s
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
@
|
13
|
-
@
|
42
|
+
[:refresh_token, :expires_in, :expires_at].each do |arg|
|
43
|
+
instance_variable_set("@#{arg}", opts.delete(arg) || opts.delete(arg.to_s))
|
44
|
+
end
|
45
|
+
@expires_in ||= opts.delete('expires')
|
46
|
+
@expires_in &&= @expires_in.to_i
|
47
|
+
@expires_at ||= Time.now.to_i + @expires_in if @expires_in
|
48
|
+
@options = {:mode => opts.delete(:mode) || :header,
|
49
|
+
:header_format => opts.delete(:header_format) || 'Bearer %s',
|
50
|
+
:param_name => opts.delete(:param_name) || 'bearer_token'}
|
51
|
+
@params = opts
|
14
52
|
end
|
15
53
|
|
54
|
+
# Indexer to additional params present in token response
|
55
|
+
#
|
56
|
+
# @param [String] key entry key to Hash
|
16
57
|
def [](key)
|
17
58
|
@params[key]
|
18
59
|
end
|
19
60
|
|
20
|
-
#
|
61
|
+
# Whether or not the token expires
|
62
|
+
#
|
63
|
+
# @return [Boolean]
|
21
64
|
def expires?
|
22
|
-
!!@
|
65
|
+
!!@expires_at
|
23
66
|
end
|
24
67
|
|
68
|
+
# Whether or not the token is expired
|
69
|
+
#
|
70
|
+
# @return [Boolean]
|
25
71
|
def expired?
|
26
|
-
expires? && expires_at < Time.now
|
72
|
+
expires? && (expires_at < Time.now.to_i)
|
27
73
|
end
|
28
74
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
75
|
+
# Refreshes the current Access Token
|
76
|
+
#
|
77
|
+
# @return [AccessToken] a new AccessToken
|
78
|
+
# @note options should be carried over to the new AccessToken
|
79
|
+
def refresh!(params={})
|
80
|
+
raise "A refresh_token is not available" unless refresh_token
|
81
|
+
params.merge!(:client_id => @client.id,
|
82
|
+
:client_secret => @client.secret,
|
83
|
+
:grant_type => 'refresh_token',
|
84
|
+
:refresh_token => refresh_token)
|
85
|
+
new_token = @client.get_token(params)
|
86
|
+
new_token.options = options
|
87
|
+
new_token
|
88
|
+
end
|
89
|
+
|
90
|
+
# Make a request with the Access Token
|
91
|
+
#
|
92
|
+
# @param [Symbol] verb the HTTP request method
|
93
|
+
# @param [String] path the HTTP URL path of the request
|
94
|
+
# @param [Hash] opts the options to make the request with
|
95
|
+
# @see Client#request
|
96
|
+
def request(verb, path, opts={}, &block)
|
97
|
+
set_token(opts)
|
98
|
+
@client.request(verb, path, opts, &block)
|
35
99
|
end
|
36
100
|
|
37
|
-
|
38
|
-
|
101
|
+
# Make a GET request with the Access Token
|
102
|
+
#
|
103
|
+
# @see AccessToken#request
|
104
|
+
def get(path, opts={}, &block)
|
105
|
+
request(:get, path, opts, &block)
|
39
106
|
end
|
40
107
|
|
41
|
-
|
42
|
-
|
108
|
+
# Make a POST request with the Access Token
|
109
|
+
#
|
110
|
+
# @see AccessToken#request
|
111
|
+
def post(path, opts={}, &block)
|
112
|
+
request(:post, path, opts, &block)
|
43
113
|
end
|
44
114
|
|
45
|
-
|
46
|
-
|
115
|
+
# Make a PUT request with the Access Token
|
116
|
+
#
|
117
|
+
# @see AccessToken#request
|
118
|
+
def put(path, opts={}, &block)
|
119
|
+
request(:put, path, opts, &block)
|
47
120
|
end
|
48
121
|
|
49
|
-
|
50
|
-
|
122
|
+
# Make a DELETE request with the Access Token
|
123
|
+
#
|
124
|
+
# @see AccessToken#request
|
125
|
+
def delete(path, opts={}, &block)
|
126
|
+
request(:delete, path, opts, &block)
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
def set_token(opts)
|
131
|
+
case options[:mode]
|
132
|
+
when :header
|
133
|
+
opts[:headers] ||= {}
|
134
|
+
opts[:headers]['Authorization'] = options[:header_format] % token
|
135
|
+
when :query
|
136
|
+
opts[:params] ||= {}
|
137
|
+
opts[:params][options[:param_name]] = token
|
138
|
+
when :body
|
139
|
+
opts[:body] ||= {}
|
140
|
+
if opts[:body].is_a?(Hash)
|
141
|
+
opts[:body][options[:param_name]] = token
|
142
|
+
else
|
143
|
+
opts[:body] << "&#{options[:param_name]}=#{token}"
|
144
|
+
end
|
145
|
+
# @todo support for multi-part (file uploads)
|
146
|
+
else
|
147
|
+
raise "invalid :mode option of #{options[:mode]}"
|
148
|
+
end
|
51
149
|
end
|
52
150
|
end
|
53
151
|
end
|
data/lib/oauth2/client.rb
CHANGED
@@ -1,105 +1,146 @@
|
|
1
1
|
require 'faraday'
|
2
2
|
|
3
3
|
module OAuth2
|
4
|
+
# The OAuth2::Client class
|
4
5
|
class Client
|
5
|
-
|
6
|
-
|
6
|
+
attr_reader :id, :secret
|
7
|
+
attr_accessor :site, :connection, :options
|
7
8
|
|
8
9
|
# Instantiate a new OAuth 2.0 client using the
|
9
|
-
#
|
10
|
+
# Client ID and Client Secret registered to your
|
10
11
|
# application.
|
11
12
|
#
|
12
|
-
#
|
13
|
+
# @param [String] client_id the client_id value
|
14
|
+
# @param [String] client_secret the client_secret value
|
15
|
+
# @param [Hash] opts the options to create the client with
|
16
|
+
# @option opts [String] :site the OAuth2 provider site host
|
17
|
+
# @option opts [String] :authorize_url ('/oauth/authorize') absolute or relative URL path to the Authorization endpoint
|
18
|
+
# @option opts [String] :token_url ('/oauth/token') absolute or relative URL path to the Token endpoint
|
19
|
+
# @option opts [Symbol] :token_method (:post) HTTP method to use to request token (:get or :post)
|
20
|
+
# @option opts [Hash] :connection_opts ({}) Hash of connection options to pass to initialize Faraday with
|
21
|
+
# @option opts [FixNum] :max_redirects (5) maximum number of redirects to follow
|
22
|
+
# @option opts [Boolean] :raise_errors (true) whether or not to raise an OAuth2::Error
|
23
|
+
# on responses with 400+ status codes
|
24
|
+
# @yield [builder] The Faraday connection builder
|
25
|
+
def initialize(client_id, client_secret, opts={}, &block)
|
26
|
+
@id = client_id
|
27
|
+
@secret = client_secret
|
28
|
+
@site = opts.delete(:site)
|
29
|
+
ssl = opts.delete(:ssl)
|
30
|
+
@options = {:authorize_url => '/oauth/authorize',
|
31
|
+
:token_url => '/oauth/token',
|
32
|
+
:token_method => :post,
|
33
|
+
:connection_opts => {},
|
34
|
+
:connection_build => block,
|
35
|
+
:max_redirects => 5,
|
36
|
+
:raise_errors => true}.merge(opts)
|
37
|
+
@options[:connection_opts][:ssl] = ssl if ssl
|
38
|
+
end
|
39
|
+
|
40
|
+
# Set the site host
|
13
41
|
#
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
# (note: for Facebook this should be :get and for Google this should be :post)
|
20
|
-
# <tt>:access_token_url</tt> :: Specify the full URL of the access token endpoint.
|
21
|
-
# <tt>:parse_json</tt> :: If true, <tt>application/json</tt> responses will be automatically parsed.
|
22
|
-
# <tt>:ssl</tt> :: Specify SSL options for the connection.
|
23
|
-
# <tt>:adapter</tt> :: The name of the Faraday::Adapter::* class to use, e.g. :net_http. To pass arguments
|
24
|
-
# to the adapter pass an array here, e.g. [:action_dispatch, my_test_session]
|
25
|
-
# <tt>:raise_errors</tt> :: Default true. When false it will then return the error status and response instead of raising an exception.
|
26
|
-
def initialize(client_id, client_secret, opts={})
|
27
|
-
self.options = opts.dup
|
28
|
-
self.token_method = self.options.delete(:access_token_method) || :post
|
29
|
-
adapter = self.options.delete(:adapter)
|
30
|
-
ssl_opts = self.options.delete(:ssl) || {}
|
31
|
-
connection_opts = ssl_opts ? {:ssl => ssl_opts} : {}
|
32
|
-
self.id = client_id
|
33
|
-
self.secret = client_secret
|
34
|
-
self.site = self.options.delete(:site) if self.options[:site]
|
35
|
-
self.connection = Faraday::Connection.new(site, connection_opts)
|
36
|
-
self.json = self.options.delete(:parse_json)
|
37
|
-
self.raise_errors = !(self.options.delete(:raise_errors) == false)
|
42
|
+
# @param [String] the OAuth2 provider site host
|
43
|
+
def site=(value)
|
44
|
+
@connection = nil
|
45
|
+
@site = value
|
46
|
+
end
|
38
47
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
48
|
+
# The Faraday connection object
|
49
|
+
def connection
|
50
|
+
@connection ||= begin
|
51
|
+
conn = Faraday.new(site, options[:connection_opts])
|
52
|
+
conn.build do |b|
|
53
|
+
options[:connection_build].call(b)
|
54
|
+
end if options[:connection_build]
|
55
|
+
conn
|
43
56
|
end
|
44
57
|
end
|
45
58
|
|
59
|
+
# The authorize endpoint URL of the OAuth2 provider
|
60
|
+
#
|
61
|
+
# @param [Hash] params additional query parameters
|
46
62
|
def authorize_url(params=nil)
|
47
|
-
|
48
|
-
connection.build_url(path, params).to_s
|
63
|
+
connection.build_url(options[:authorize_url], params).to_s
|
49
64
|
end
|
50
65
|
|
51
|
-
|
52
|
-
|
53
|
-
|
66
|
+
# The token endpoint URL of the OAuth2 provider
|
67
|
+
#
|
68
|
+
# @param [Hash] params additional query parameters
|
69
|
+
def token_url(params=nil)
|
70
|
+
connection.build_url(options[:token_url], params).to_s
|
54
71
|
end
|
55
72
|
|
56
73
|
# Makes a request relative to the specified site root.
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
74
|
+
#
|
75
|
+
# @param [Symbol] verb one of :get, :post, :put, :delete
|
76
|
+
# @param [String] url URL path of request
|
77
|
+
# @param [Hash] opts the options to make the request with
|
78
|
+
# @option opts [Hash] :params additional query parameters for the URL of the request
|
79
|
+
# @option opts [Hash, String] :body the body of the request
|
80
|
+
# @option opts [Hash] :headers http request headers
|
81
|
+
# @option opts [Boolean] :raise_errors whether or not to raise an OAuth2::Error on 400+ status
|
82
|
+
# code response for this request. Will default to client option
|
83
|
+
# @option opts [Symbol] :parse @see Response::initialize
|
84
|
+
# @yield [req] The Faraday request
|
85
|
+
def request(verb, url, opts={})
|
86
|
+
url = self.connection.build_url(url, opts[:params]).to_s
|
87
|
+
|
88
|
+
response = connection.run_request(verb, url, opts[:body], opts[:headers]) do |req|
|
89
|
+
yield(req) if block_given?
|
64
90
|
end
|
91
|
+
response = Response.new(response, :parse => opts[:parse])
|
65
92
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
when 409
|
77
|
-
e = OAuth2::Conflict.new("Received HTTP 409 during request.")
|
78
|
-
e.response = resp
|
79
|
-
raise e
|
80
|
-
else
|
81
|
-
e = OAuth2::HTTPError.new("Received HTTP #{resp.status} during request.")
|
82
|
-
e.response = resp
|
83
|
-
raise e
|
93
|
+
case response.status
|
94
|
+
when 200..299
|
95
|
+
response
|
96
|
+
when 300..399
|
97
|
+
opts[:redirect_count] ||= 0
|
98
|
+
opts[:redirect_count] += 1
|
99
|
+
return response if opts[:redirect_count] > options[:max_redirects]
|
100
|
+
if response.status == 303
|
101
|
+
verb = :get
|
102
|
+
opts.delete(:body)
|
84
103
|
end
|
104
|
+
request(verb, response.headers['location'], opts)
|
105
|
+
when 400..599
|
106
|
+
e = Error.new(response)
|
107
|
+
raise e if opts[:raise_errors] || options[:raise_errors]
|
108
|
+
response.error = e
|
109
|
+
response
|
85
110
|
else
|
86
|
-
|
111
|
+
raise Error.new(response), "Unhandled status code value of #{response.status}"
|
87
112
|
end
|
88
113
|
end
|
89
114
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
return ResponseObject.from(resp)
|
115
|
+
# Initializes an AccessToken by making a request to the token endpoint
|
116
|
+
#
|
117
|
+
# @param [Hash] params a Hash of params for the token endpoint
|
118
|
+
# @return [AccessToken] the initalized AccessToken
|
119
|
+
def get_token(params)
|
120
|
+
opts = {:raise_errors => true, :parse => params.delete(:parse)}
|
121
|
+
if options[:token_method] == :post
|
122
|
+
opts[:body] = params
|
123
|
+
opts[:headers] = {'Content-Type' => 'application/x-www-form-urlencoded'}
|
100
124
|
else
|
101
|
-
|
125
|
+
opts[:params] = params
|
102
126
|
end
|
127
|
+
response = request(options[:token_method], token_url, opts)
|
128
|
+
raise Error.new(response) unless response.parsed.is_a?(Hash) && response.parsed['access_token']
|
129
|
+
AccessToken.from_hash(self, response.parsed)
|
130
|
+
end
|
131
|
+
|
132
|
+
# The Authorization Code strategy
|
133
|
+
#
|
134
|
+
# @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-4.1
|
135
|
+
def auth_code
|
136
|
+
@auth_code ||= OAuth2::Strategy::AuthCode.new(self)
|
137
|
+
end
|
138
|
+
|
139
|
+
# The Resource Owner Password Credentials strategy
|
140
|
+
#
|
141
|
+
# @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-4.3
|
142
|
+
def password
|
143
|
+
@password ||= OAuth2::Strategy::Password.new(self)
|
103
144
|
end
|
104
145
|
end
|
105
146
|
end
|