oauth2 0.9.2 → 0.9.3
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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/CONTRIBUTING.md +6 -3
- data/README.md +2 -11
- data/Rakefile +21 -1
- data/lib/oauth2/access_token.rb +16 -15
- data/lib/oauth2/client.rb +13 -11
- data/lib/oauth2/response.rb +8 -12
- data/lib/oauth2/strategy/assertion.rb +6 -8
- data/lib/oauth2/strategy/auth_code.rb +3 -3
- data/lib/oauth2/strategy/client_credentials.rb +12 -4
- data/lib/oauth2/strategy/implicit.rb +3 -3
- data/lib/oauth2/strategy/password.rb +2 -2
- data/lib/oauth2/version.rb +4 -7
- data/oauth2.gemspec +8 -9
- data/spec/helper.rb +5 -1
- data/spec/oauth2/access_token_spec.rb +38 -38
- data/spec/oauth2/client_spec.rb +58 -59
- data/spec/oauth2/response_spec.rb +20 -20
- data/spec/oauth2/strategy/assertion_spec.rb +13 -14
- data/spec/oauth2/strategy/auth_code_spec.rb +22 -22
- data/spec/oauth2/strategy/base_spec.rb +2 -2
- data/spec/oauth2/strategy/client_credentials_spec.rb +28 -17
- data/spec/oauth2/strategy/implicit_spec.rb +8 -8
- data/spec/oauth2/strategy/password_spec.rb +13 -13
- metadata +52 -82
- metadata.gz.sig +0 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9924e71401dd6ab5d22d1472dbdc7505452938ef
|
4
|
+
data.tar.gz: 117bb2eb9de7facad9c2c090d492a350309d62e9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6a5bfc4ac23428a81c0c30418d8180cfebe7cef9fb0071fdfe94753acc34c6a54f4bb9733a36e6bbfddb360b3f33fbd7bec2513c94f590a20064348384195a75
|
7
|
+
data.tar.gz: f429aed04aedecaffea86c0e1690767994bb4af758ec6243177f426ac660cb36b506154ce89c7e291fd726a57c2555e7ff9528ff7500a53862cfe9f41c45451f
|
checksums.yaml.gz.sig
ADDED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/CONTRIBUTING.md
CHANGED
@@ -4,11 +4,14 @@
|
|
4
4
|
3. Add specs for your unimplemented feature or bug fix.
|
5
5
|
4. Run `bundle exec rake spec`. If your specs pass, return to step 3.
|
6
6
|
5. Implement your feature or bug fix.
|
7
|
-
6. Run `bundle exec rake
|
7
|
+
6. Run `bundle exec rake`. If your specs fail, return to step 5.
|
8
8
|
7. Run `open coverage/index.html`. If your changes are not completely covered
|
9
9
|
by your tests, return to step 3.
|
10
|
-
8. Add
|
11
|
-
9.
|
10
|
+
8. Add documentation for your feature or bug fix.
|
11
|
+
9. Run `bundle exec rake verify_measurements`. If your changes are not 100%
|
12
|
+
documented, go back to step 8.
|
13
|
+
10. Commit and push your changes.
|
14
|
+
11. [Submit a pull request.][pr]
|
12
15
|
|
13
16
|
[fork]: http://help.github.com/fork-a-repo/
|
14
17
|
[branch]: http://learn.github.com/p/branching.html
|
data/README.md
CHANGED
@@ -14,22 +14,12 @@
|
|
14
14
|
|
15
15
|
A Ruby wrapper for the OAuth 2.0 specification. This is a work in progress,
|
16
16
|
being built first to solve the pragmatic process of connecting to existing
|
17
|
-
OAuth 2.0 endpoints (
|
17
|
+
OAuth 2.0 endpoints (e.g. Facebook) with the goal of building it up to meet
|
18
18
|
the entire specification over time.
|
19
19
|
|
20
20
|
## Installation
|
21
21
|
gem install oauth2
|
22
22
|
|
23
|
-
To ensure the code you're installing hasn't been tampered with, it's
|
24
|
-
recommended that you verify the signature. To do this, you need to add my
|
25
|
-
public key as a trusted certificate (you only need to do this once):
|
26
|
-
|
27
|
-
gem cert --add <(curl -Ls https://raw.github.com/intridea/oauth2/master/certs/sferik.pem)
|
28
|
-
|
29
|
-
Then, install the gem with the high security trust policy:
|
30
|
-
|
31
|
-
gem install oauth2 -P HighSecurity
|
32
|
-
|
33
23
|
## Resources
|
34
24
|
* [View Source on GitHub][code]
|
35
25
|
* [Report Issues on GitHub][issues]
|
@@ -120,6 +110,7 @@ implementations:
|
|
120
110
|
* Ruby 1.9.2
|
121
111
|
* Ruby 1.9.3
|
122
112
|
* Ruby 2.0.0
|
113
|
+
* Ruby 2.1.0
|
123
114
|
* [JRuby][]
|
124
115
|
* [Rubinius][]
|
125
116
|
|
data/Rakefile
CHANGED
@@ -4,7 +4,6 @@ Bundler::GemHelper.install_tasks
|
|
4
4
|
require 'rspec/core/rake_task'
|
5
5
|
RSpec::Core::RakeTask.new(:spec)
|
6
6
|
|
7
|
-
task :default => :spec
|
8
7
|
task :test => :spec
|
9
8
|
|
10
9
|
namespace :doc do
|
@@ -17,3 +16,24 @@ namespace :doc do
|
|
17
16
|
rdoc.rdoc_files.include('README.md', 'LICENSE.md', 'lib/**/*.rb')
|
18
17
|
end
|
19
18
|
end
|
19
|
+
|
20
|
+
begin
|
21
|
+
require 'rubocop/rake_task'
|
22
|
+
Rubocop::RakeTask.new
|
23
|
+
rescue LoadError
|
24
|
+
task :rubocop do
|
25
|
+
$stderr.puts 'Rubocop is disabled'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
require 'yardstick/rake/measurement'
|
30
|
+
Yardstick::Rake::Measurement.new do |measurement|
|
31
|
+
measurement.output = 'measurement/report.txt'
|
32
|
+
end
|
33
|
+
|
34
|
+
require 'yardstick/rake/verify'
|
35
|
+
Yardstick::Rake::Verify.new do |verify|
|
36
|
+
verify.threshold = 58.9
|
37
|
+
end
|
38
|
+
|
39
|
+
task :default => [:spec, :rubocop, :verify_measurements]
|
data/lib/oauth2/access_token.rb
CHANGED
@@ -10,7 +10,7 @@ module OAuth2
|
|
10
10
|
# @param [Hash] a hash of AccessToken property values
|
11
11
|
# @return [AccessToken] the initalized AccessToken
|
12
12
|
def from_hash(client, hash)
|
13
|
-
|
13
|
+
new(client, hash.delete('access_token') || hash.delete(:access_token), hash)
|
14
14
|
end
|
15
15
|
|
16
16
|
# Initializes an AccessToken from a key/value application/x-www-form-urlencoded string
|
@@ -36,7 +36,7 @@ module OAuth2
|
|
36
36
|
# @option opts [String] :header_format ('Bearer %s') the string format to use for the Authorization header
|
37
37
|
# @option opts [String] :param_name ('access_token') the parameter name to use for transmission of the
|
38
38
|
# Access Token value in :body or :query transmission mode
|
39
|
-
def initialize(client, token, opts={})
|
39
|
+
def initialize(client, token, opts = {})
|
40
40
|
@client = client
|
41
41
|
@token = token.to_s
|
42
42
|
[:refresh_token, :expires_in, :expires_at].each do |arg|
|
@@ -77,8 +77,8 @@ module OAuth2
|
|
77
77
|
#
|
78
78
|
# @return [AccessToken] a new AccessToken
|
79
79
|
# @note options should be carried over to the new AccessToken
|
80
|
-
def refresh!(params={})
|
81
|
-
|
80
|
+
def refresh!(params = {})
|
81
|
+
fail('A refresh_token is not available') unless refresh_token
|
82
82
|
params.merge!(:client_id => @client.id,
|
83
83
|
:client_secret => @client.secret,
|
84
84
|
:grant_type => 'refresh_token',
|
@@ -93,7 +93,7 @@ module OAuth2
|
|
93
93
|
#
|
94
94
|
# @return [Hash] a hash of AccessToken property values
|
95
95
|
def to_hash
|
96
|
-
params.merge(
|
96
|
+
params.merge(:access_token => token, :refresh_token => refresh_token, :expires_at => expires_at)
|
97
97
|
end
|
98
98
|
|
99
99
|
# Make a request with the Access Token
|
@@ -102,53 +102,54 @@ module OAuth2
|
|
102
102
|
# @param [String] path the HTTP URL path of the request
|
103
103
|
# @param [Hash] opts the options to make the request with
|
104
104
|
# @see Client#request
|
105
|
-
def request(verb, path, opts={}, &block)
|
106
|
-
|
105
|
+
def request(verb, path, opts = {}, &block)
|
106
|
+
self.token = opts
|
107
107
|
@client.request(verb, path, opts, &block)
|
108
108
|
end
|
109
109
|
|
110
110
|
# Make a GET request with the Access Token
|
111
111
|
#
|
112
112
|
# @see AccessToken#request
|
113
|
-
def get(path, opts={}, &block)
|
113
|
+
def get(path, opts = {}, &block)
|
114
114
|
request(:get, path, opts, &block)
|
115
115
|
end
|
116
116
|
|
117
117
|
# Make a POST request with the Access Token
|
118
118
|
#
|
119
119
|
# @see AccessToken#request
|
120
|
-
def post(path, opts={}, &block)
|
120
|
+
def post(path, opts = {}, &block)
|
121
121
|
request(:post, path, opts, &block)
|
122
122
|
end
|
123
123
|
|
124
124
|
# Make a PUT request with the Access Token
|
125
125
|
#
|
126
126
|
# @see AccessToken#request
|
127
|
-
def put(path, opts={}, &block)
|
127
|
+
def put(path, opts = {}, &block)
|
128
128
|
request(:put, path, opts, &block)
|
129
129
|
end
|
130
130
|
|
131
131
|
# Make a PATCH request with the Access Token
|
132
132
|
#
|
133
133
|
# @see AccessToken#request
|
134
|
-
def patch(path, opts={}, &block)
|
134
|
+
def patch(path, opts = {}, &block)
|
135
135
|
request(:patch, path, opts, &block)
|
136
136
|
end
|
137
137
|
|
138
138
|
# Make a DELETE request with the Access Token
|
139
139
|
#
|
140
140
|
# @see AccessToken#request
|
141
|
-
def delete(path, opts={}, &block)
|
141
|
+
def delete(path, opts = {}, &block)
|
142
142
|
request(:delete, path, opts, &block)
|
143
143
|
end
|
144
144
|
|
145
145
|
# Get the headers hash (includes Authorization token)
|
146
146
|
def headers
|
147
|
-
{
|
147
|
+
{'Authorization' => options[:header_format] % token}
|
148
148
|
end
|
149
149
|
|
150
150
|
private
|
151
|
-
|
151
|
+
|
152
|
+
def token=(opts) # rubocop:disable MethodLength
|
152
153
|
case options[:mode]
|
153
154
|
when :header
|
154
155
|
opts[:headers] ||= {}
|
@@ -165,7 +166,7 @@ module OAuth2
|
|
165
166
|
end
|
166
167
|
# @todo support for multi-part (file uploads)
|
167
168
|
else
|
168
|
-
|
169
|
+
fail("invalid :mode option of #{options[:mode]}")
|
169
170
|
end
|
170
171
|
end
|
171
172
|
end
|
data/lib/oauth2/client.rb
CHANGED
@@ -23,7 +23,7 @@ module OAuth2
|
|
23
23
|
# @option opts [Boolean] :raise_errors (true) whether or not to raise an OAuth2::Error
|
24
24
|
# on responses with 400+ status codes
|
25
25
|
# @yield [builder] The Faraday connection builder
|
26
|
-
def initialize(client_id, client_secret, opts={}, &block)
|
26
|
+
def initialize(client_id, client_secret, opts = {}, &block)
|
27
27
|
_opts = opts.dup
|
28
28
|
@id = client_id
|
29
29
|
@secret = client_secret
|
@@ -61,14 +61,14 @@ module OAuth2
|
|
61
61
|
# The authorize endpoint URL of the OAuth2 provider
|
62
62
|
#
|
63
63
|
# @param [Hash] params additional query parameters
|
64
|
-
def authorize_url(params=nil)
|
64
|
+
def authorize_url(params = nil)
|
65
65
|
connection.build_url(options[:authorize_url], params).to_s
|
66
66
|
end
|
67
67
|
|
68
68
|
# The token endpoint URL of the OAuth2 provider
|
69
69
|
#
|
70
70
|
# @param [Hash] params additional query parameters
|
71
|
-
def token_url(params=nil)
|
71
|
+
def token_url(params = nil)
|
72
72
|
connection.build_url(options[:token_url], params).to_s
|
73
73
|
end
|
74
74
|
|
@@ -84,8 +84,8 @@ module OAuth2
|
|
84
84
|
# code response for this request. Will default to client option
|
85
85
|
# @option opts [Symbol] :parse @see Response::initialize
|
86
86
|
# @yield [req] The Faraday request
|
87
|
-
def request(verb, url, opts={})
|
88
|
-
url =
|
87
|
+
def request(verb, url, opts = {}) # rubocop:disable CyclomaticComplexity, MethodLength
|
88
|
+
url = connection.build_url(url, opts[:params]).to_s
|
89
89
|
|
90
90
|
response = connection.run_request(verb, url, opts[:body], opts[:headers]) do |req|
|
91
91
|
yield(req) if block_given?
|
@@ -106,12 +106,13 @@ module OAuth2
|
|
106
106
|
# on non-redirecting 3xx statuses, just return the response
|
107
107
|
response
|
108
108
|
when 400..599
|
109
|
-
|
110
|
-
|
111
|
-
response.error =
|
109
|
+
error = Error.new(response)
|
110
|
+
fail(error) if opts.fetch(:raise_errors, options[:raise_errors])
|
111
|
+
response.error = error
|
112
112
|
response
|
113
113
|
else
|
114
|
-
|
114
|
+
error = Error.new(response)
|
115
|
+
fail(error, "Unhandled status code value of #{response.status}")
|
115
116
|
end
|
116
117
|
end
|
117
118
|
|
@@ -121,7 +122,7 @@ module OAuth2
|
|
121
122
|
# @param [Hash] access token options, to pass to the AccessToken object
|
122
123
|
# @param [Class] class of access token for easier subclassing OAuth2::AccessToken
|
123
124
|
# @return [AccessToken] the initalized AccessToken
|
124
|
-
def get_token(params, access_token_opts={}, access_token_class = AccessToken)
|
125
|
+
def get_token(params, access_token_opts = {}, access_token_class = AccessToken)
|
125
126
|
opts = {:raise_errors => options[:raise_errors], :parse => params.delete(:parse)}
|
126
127
|
if options[:token_method] == :post
|
127
128
|
headers = params.delete(:headers)
|
@@ -132,7 +133,8 @@ module OAuth2
|
|
132
133
|
opts[:params] = params
|
133
134
|
end
|
134
135
|
response = request(options[:token_method], token_url, opts)
|
135
|
-
|
136
|
+
error = Error.new(response)
|
137
|
+
fail(error) if options[:raise_errors] && !(response.parsed.is_a?(Hash) && response.parsed['access_token'])
|
136
138
|
access_token_class.from_hash(self, response.parsed.merge(access_token_opts))
|
137
139
|
end
|
138
140
|
|
data/lib/oauth2/response.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'multi_json'
|
2
|
+
require 'multi_xml'
|
2
3
|
require 'rack'
|
3
4
|
|
4
5
|
module OAuth2
|
@@ -26,7 +27,7 @@ module OAuth2
|
|
26
27
|
# @param [Hash] opts options in which to initialize the instance
|
27
28
|
# @option opts [Symbol] :parse (:automatic) how to parse the response body. one of :query (for x-www-form-urlencoded),
|
28
29
|
# :json, or :automatic (determined by Content-Type response header)
|
29
|
-
def initialize(response, opts={})
|
30
|
+
def initialize(response, opts = {})
|
30
31
|
@response = response
|
31
32
|
@options = {:parse => :automatic}.merge(opts)
|
32
33
|
end
|
@@ -49,11 +50,9 @@ module OAuth2
|
|
49
50
|
# Procs that, when called, will parse a response body according
|
50
51
|
# to the specified format.
|
51
52
|
PARSERS = {
|
52
|
-
|
53
|
-
|
54
|
-
:
|
55
|
-
:query => lambda{ |body| Rack::Utils.parse_query(body) },
|
56
|
-
:text => lambda{ |body| body }
|
53
|
+
:json => lambda { |body| MultiJson.load(body) rescue body }, # rubocop:disable RescueModifier
|
54
|
+
:query => lambda { |body| Rack::Utils.parse_query(body) },
|
55
|
+
:text => lambda { |body| body }
|
57
56
|
}
|
58
57
|
|
59
58
|
# Content type assignments for various potential HTTP content types.
|
@@ -85,9 +84,6 @@ module OAuth2
|
|
85
84
|
end
|
86
85
|
end
|
87
86
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
MultiXml.parse(body) rescue body
|
92
|
-
end
|
93
|
-
rescue LoadError; end
|
87
|
+
OAuth2::Response.register_parser(:xml, ['text/xml', 'application/rss+xml', 'application/rdf+xml', 'application/atom+xml']) do |body|
|
88
|
+
MultiXml.parse(body) rescue body # rubocop:disable RescueModifier
|
89
|
+
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'httpauth'
|
2
1
|
require 'jwt'
|
3
2
|
|
4
3
|
module OAuth2
|
@@ -26,7 +25,7 @@ module OAuth2
|
|
26
25
|
#
|
27
26
|
# @raise [NotImplementedError]
|
28
27
|
def authorize_url
|
29
|
-
|
28
|
+
fail(NotImplementedError, 'The authorization endpoint is not used in this strategy')
|
30
29
|
end
|
31
30
|
|
32
31
|
# Retrieve an access token given the specified client.
|
@@ -43,15 +42,15 @@ module OAuth2
|
|
43
42
|
# params :exp, expired at, in seconds, like Time.now.utc.to_i + 3600
|
44
43
|
#
|
45
44
|
# @param [Hash] opts options
|
46
|
-
def get_token(params={}, opts={})
|
45
|
+
def get_token(params = {}, opts = {})
|
47
46
|
hash = build_request(params)
|
48
47
|
@client.get_token(hash, opts.merge('refresh_token' => nil))
|
49
48
|
end
|
50
49
|
|
51
50
|
def build_request(params)
|
52
51
|
assertion = build_assertion(params)
|
53
|
-
{:grant_type =>
|
54
|
-
:assertion_type =>
|
52
|
+
{:grant_type => 'assertion',
|
53
|
+
:assertion_type => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
|
55
54
|
:assertion => assertion,
|
56
55
|
:scope => params[:scope]
|
57
56
|
}.merge(client_params)
|
@@ -64,12 +63,11 @@ module OAuth2
|
|
64
63
|
:exp => params[:exp]
|
65
64
|
}
|
66
65
|
if params[:hmac_secret]
|
67
|
-
|
66
|
+
JWT.encode(claims, params[:hmac_secret], 'HS256')
|
68
67
|
elsif params[:private_key]
|
69
|
-
|
68
|
+
JWT.encode(claims, params[:private_key], 'RS256')
|
70
69
|
end
|
71
70
|
end
|
72
71
|
end
|
73
72
|
end
|
74
73
|
end
|
75
|
-
|
@@ -7,14 +7,14 @@ module OAuth2
|
|
7
7
|
# The required query parameters for the authorize URL
|
8
8
|
#
|
9
9
|
# @param [Hash] params additional query parameters
|
10
|
-
def authorize_params(params={})
|
10
|
+
def authorize_params(params = {})
|
11
11
|
params.merge('response_type' => 'code', 'client_id' => @client.id)
|
12
12
|
end
|
13
13
|
|
14
14
|
# The authorization URL endpoint of the provider
|
15
15
|
#
|
16
16
|
# @param [Hash] params additional query parameters for the URL
|
17
|
-
def authorize_url(params={})
|
17
|
+
def authorize_url(params = {})
|
18
18
|
@client.authorize_url(authorize_params.merge(params))
|
19
19
|
end
|
20
20
|
|
@@ -24,7 +24,7 @@ module OAuth2
|
|
24
24
|
# @param [Hash] params additional params
|
25
25
|
# @param [Hash] opts options
|
26
26
|
# @note that you must also provide a :redirect_uri with most OAuth 2.0 providers
|
27
|
-
def get_token(code, params={}, opts={})
|
27
|
+
def get_token(code, params = {}, opts = {})
|
28
28
|
params = {'grant_type' => 'authorization_code', 'code' => code}.merge(client_params).merge(params)
|
29
29
|
@client.get_token(params, opts)
|
30
30
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'base64'
|
2
2
|
|
3
3
|
module OAuth2
|
4
4
|
module Strategy
|
@@ -10,19 +10,27 @@ module OAuth2
|
|
10
10
|
#
|
11
11
|
# @raise [NotImplementedError]
|
12
12
|
def authorize_url
|
13
|
-
|
13
|
+
fail(NotImplementedError, 'The authorization endpoint is not used in this strategy')
|
14
14
|
end
|
15
15
|
|
16
16
|
# Retrieve an access token given the specified client.
|
17
17
|
#
|
18
18
|
# @param [Hash] params additional params
|
19
19
|
# @param [Hash] opts options
|
20
|
-
def get_token(params={}, opts={})
|
20
|
+
def get_token(params = {}, opts = {})
|
21
21
|
request_body = opts.delete('auth_scheme') == 'request_body'
|
22
22
|
params.merge!('grant_type' => 'client_credentials')
|
23
|
-
params.merge!(request_body ? client_params : {:headers => {'Authorization' =>
|
23
|
+
params.merge!(request_body ? client_params : {:headers => {'Authorization' => authorization(client_params['client_id'], client_params['client_secret'])}})
|
24
24
|
@client.get_token(params, opts.merge('refresh_token' => nil))
|
25
25
|
end
|
26
|
+
|
27
|
+
# Returns the Authorization header value for Basic Authentication
|
28
|
+
#
|
29
|
+
# @param [String] The client ID
|
30
|
+
# @param [String] the client secret
|
31
|
+
def authorization(client_id, client_secret)
|
32
|
+
'Basic ' + Base64.encode64(client_id + ':' + client_secret).gsub("\n", '')
|
33
|
+
end
|
26
34
|
end
|
27
35
|
end
|
28
36
|
end
|
@@ -7,14 +7,14 @@ module OAuth2
|
|
7
7
|
# The required query parameters for the authorize URL
|
8
8
|
#
|
9
9
|
# @param [Hash] params additional query parameters
|
10
|
-
def authorize_params(params={})
|
10
|
+
def authorize_params(params = {})
|
11
11
|
params.merge('response_type' => 'token', 'client_id' => @client.id)
|
12
12
|
end
|
13
13
|
|
14
14
|
# The authorization URL endpoint of the provider
|
15
15
|
#
|
16
16
|
# @param [Hash] params additional query parameters for the URL
|
17
|
-
def authorize_url(params={})
|
17
|
+
def authorize_url(params = {})
|
18
18
|
@client.authorize_url(authorize_params.merge(params))
|
19
19
|
end
|
20
20
|
|
@@ -22,7 +22,7 @@ module OAuth2
|
|
22
22
|
#
|
23
23
|
# @raise [NotImplementedError]
|
24
24
|
def get_token(*)
|
25
|
-
|
25
|
+
fail(NotImplementedError, 'The token is accessed differently in this strategy')
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|