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