oauth2 1.0.0 → 1.1.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.
- checksums.yaml +4 -4
- data/README.md +0 -1
- data/lib/oauth2/access_token.rb +7 -7
- data/lib/oauth2/client.rb +3 -3
- data/lib/oauth2/mac_token.rb +6 -8
- data/lib/oauth2/response.rb +22 -22
- data/lib/oauth2/strategy/assertion.rb +2 -2
- data/lib/oauth2/strategy/client_credentials.rb +2 -2
- data/lib/oauth2/version.rb +55 -11
- data/oauth2.gemspec +3 -6
- metadata +18 -29
- data/Rakefile +0 -39
- data/spec/helper.rb +0 -42
- data/spec/oauth2/access_token_spec.rb +0 -169
- data/spec/oauth2/client_spec.rb +0 -215
- data/spec/oauth2/mac_token_spec.rb +0 -119
- data/spec/oauth2/response_spec.rb +0 -91
- data/spec/oauth2/strategy/assertion_spec.rb +0 -56
- data/spec/oauth2/strategy/auth_code_spec.rb +0 -88
- data/spec/oauth2/strategy/base_spec.rb +0 -7
- data/spec/oauth2/strategy/client_credentials_spec.rb +0 -81
- data/spec/oauth2/strategy/implicit_spec.rb +0 -28
- data/spec/oauth2/strategy/password_spec.rb +0 -57
@@ -1,119 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
describe MACToken do
|
4
|
-
let(:token) { 'monkey' }
|
5
|
-
let(:client) do
|
6
|
-
Client.new('abc', 'def', :site => 'https://api.example.com') do |builder|
|
7
|
-
builder.request :url_encoded
|
8
|
-
builder.adapter :test do |stub|
|
9
|
-
VERBS.each do |verb|
|
10
|
-
stub.send(verb, '/token/header') { |env| [200, {}, env[:request_headers]['Authorization']] }
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
subject { MACToken.new(client, token, 'abc123') }
|
17
|
-
|
18
|
-
describe '#initialize' do
|
19
|
-
it 'assigns client and token' do
|
20
|
-
expect(subject.client).to eq(client)
|
21
|
-
expect(subject.token).to eq(token)
|
22
|
-
end
|
23
|
-
|
24
|
-
it 'assigns secret' do
|
25
|
-
expect(subject.secret).to eq('abc123')
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'defaults algorithm to hmac-sha-256' do
|
29
|
-
expect(subject.algorithm).to be_instance_of(OpenSSL::Digest::SHA256)
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'handles hmac-sha-256' do
|
33
|
-
mac = MACToken.new(client, token, 'abc123', :algorithm => 'hmac-sha-256')
|
34
|
-
expect(mac.algorithm).to be_instance_of(OpenSSL::Digest::SHA256)
|
35
|
-
end
|
36
|
-
|
37
|
-
it 'handles hmac-sha-1' do
|
38
|
-
mac = MACToken.new(client, token, 'abc123', :algorithm => 'hmac-sha-1')
|
39
|
-
expect(mac.algorithm).to be_instance_of(OpenSSL::Digest::SHA1)
|
40
|
-
end
|
41
|
-
|
42
|
-
it 'raises on improper algorithm' do
|
43
|
-
expect { MACToken.new(client, token, 'abc123', :algorithm => 'invalid-sha') }.to raise_error(ArgumentError)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
describe '#request' do
|
48
|
-
VERBS.each do |verb|
|
49
|
-
it "sends the token in the Authorization header for a #{verb.to_s.upcase} request" do
|
50
|
-
expect(subject.post('/token/header').body).to include("MAC id=\"#{token}\"")
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
describe '#header' do
|
56
|
-
it 'does not generate the same header twice' do
|
57
|
-
header = subject.header('get', 'https://www.example.com/hello')
|
58
|
-
duplicate_header = subject.header('get', 'https://www.example.com/hello')
|
59
|
-
|
60
|
-
expect(header).to_not eq(duplicate_header)
|
61
|
-
end
|
62
|
-
|
63
|
-
it 'generates the proper format' do
|
64
|
-
header = subject.header('get', 'https://www.example.com/hello?a=1')
|
65
|
-
expect(header).to match(/MAC id="#{token}", ts="[0-9]+", nonce="[^"]+", mac="[^"]+"/)
|
66
|
-
end
|
67
|
-
|
68
|
-
it 'passes ArgumentError with an invalid url' do
|
69
|
-
expect { subject.header('get', 'this-is-not-valid') }.to raise_error(ArgumentError)
|
70
|
-
end
|
71
|
-
|
72
|
-
it 'passes URI::InvalidURIError through' do
|
73
|
-
expect { subject.header('get', nil) }.to raise_error(URI::InvalidURIError)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
describe '#signature' do
|
78
|
-
it 'generates properly' do
|
79
|
-
signature = subject.signature(0, 'random-string', 'get', URI('https://www.google.com'))
|
80
|
-
expect(signature).to eq('rMDjVA3VJj3v1OmxM29QQljKia6msl5rjN83x3bZmi8=')
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
describe '#headers' do
|
85
|
-
it 'is an empty hash' do
|
86
|
-
expect(subject.headers).to eq({})
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
describe '.from_access_token' do
|
91
|
-
let(:access_token) do
|
92
|
-
AccessToken.new(
|
93
|
-
client, token,
|
94
|
-
:expires_at => 1,
|
95
|
-
:expires_in => 1,
|
96
|
-
:refresh_token => 'abc',
|
97
|
-
:random => 1
|
98
|
-
)
|
99
|
-
end
|
100
|
-
|
101
|
-
subject { MACToken.from_access_token(access_token, 'hello') }
|
102
|
-
|
103
|
-
it 'initializes client, token, and secret properly' do
|
104
|
-
expect(subject.client).to eq(client)
|
105
|
-
expect(subject.token).to eq(token)
|
106
|
-
expect(subject.secret).to eq('hello')
|
107
|
-
end
|
108
|
-
|
109
|
-
it 'initializes configuration options' do
|
110
|
-
expect(subject.expires_at).to eq(1)
|
111
|
-
expect(subject.expires_in).to eq(1)
|
112
|
-
expect(subject.refresh_token).to eq('abc')
|
113
|
-
end
|
114
|
-
|
115
|
-
it 'initializes params' do
|
116
|
-
expect(subject.params).to eq(:random => 1)
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
@@ -1,91 +0,0 @@
|
|
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
|
-
expect(subject.headers).to eq(headers)
|
15
|
-
expect(subject.status).to eq(status)
|
16
|
-
expect(subject.body).to eq(body)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
describe '.register_parser' do
|
21
|
-
let(:response) do
|
22
|
-
double('response', :headers => {'Content-Type' => 'application/foo-bar'},
|
23
|
-
:status => 200,
|
24
|
-
:body => 'baz')
|
25
|
-
end
|
26
|
-
before do
|
27
|
-
OAuth2::Response.register_parser(:foobar, 'application/foo-bar') do |body|
|
28
|
-
"foobar #{body}"
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'adds to the content types and parsers' do
|
33
|
-
expect(OAuth2::Response::PARSERS.keys).to include(:foobar)
|
34
|
-
expect(OAuth2::Response::CONTENT_TYPES.keys).to include('application/foo-bar')
|
35
|
-
end
|
36
|
-
|
37
|
-
it 'is able to parse that content type automatically' do
|
38
|
-
expect(OAuth2::Response.new(response).parsed).to eq('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
|
-
expect(subject.parsed.keys.size).to eq(2)
|
49
|
-
expect(subject.parsed['foo']).to eq('bar')
|
50
|
-
expect(subject.parsed['answer']).to eq('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
|
-
expect(subject.parsed.keys.size).to eq(2)
|
59
|
-
expect(subject.parsed['foo']).to eq('bar')
|
60
|
-
expect(subject.parsed['answer']).to eq(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
|
-
expect(MultiJson).not_to receive(:decode)
|
70
|
-
expect(MultiJson).not_to receive(:load)
|
71
|
-
expect(Rack::Utils).not_to receive(:parse_query)
|
72
|
-
|
73
|
-
subject = Response.new(response)
|
74
|
-
expect(subject.parsed).to be_nil
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
context 'xml parser registration' do
|
79
|
-
it 'tries to load multi_xml and use it' do
|
80
|
-
expect(OAuth2::Response::PARSERS[:xml]).not_to be_nil
|
81
|
-
end
|
82
|
-
|
83
|
-
it 'is able to parse xml' do
|
84
|
-
headers = {'Content-Type' => 'text/xml'}
|
85
|
-
body = '<?xml version="1.0" standalone="yes" ?><foo><bar>baz</bar></foo>'
|
86
|
-
|
87
|
-
response = double('response', :headers => headers, :body => body)
|
88
|
-
expect(OAuth2::Response.new(response).parsed).to eq('foo' => {'bar' => 'baz'})
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
@@ -1,56 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
describe OAuth2::Strategy::Assertion do
|
4
|
-
let(:client) do
|
5
|
-
cli = OAuth2::Client.new('abc', 'def', :site => 'http://api.example.com')
|
6
|
-
cli.connection.build do |b|
|
7
|
-
b.adapter :test do |stub|
|
8
|
-
stub.post('/oauth/token') do |env|
|
9
|
-
case @mode
|
10
|
-
when 'formencoded'
|
11
|
-
[200, {'Content-Type' => 'application/x-www-form-urlencoded'}, 'expires_in=600&access_token=salmon&refresh_token=trout']
|
12
|
-
when 'json'
|
13
|
-
[200, {'Content-Type' => 'application/json'}, '{"expires_in":600,"access_token":"salmon","refresh_token":"trout"}']
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
cli
|
19
|
-
end
|
20
|
-
|
21
|
-
let(:params) { {:hmac_secret => 'foo'} }
|
22
|
-
|
23
|
-
subject { client.assertion }
|
24
|
-
|
25
|
-
describe '#authorize_url' do
|
26
|
-
it 'raises NotImplementedError' do
|
27
|
-
expect { subject.authorize_url }.to raise_error(NotImplementedError)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
%w(json formencoded).each do |mode|
|
32
|
-
describe "#get_token (#{mode})" do
|
33
|
-
before do
|
34
|
-
@mode = mode
|
35
|
-
@access = subject.get_token(params)
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'returns AccessToken with same Client' do
|
39
|
-
expect(@access.client).to eq(client)
|
40
|
-
end
|
41
|
-
|
42
|
-
it 'returns AccessToken with #token' do
|
43
|
-
expect(@access.token).to eq('salmon')
|
44
|
-
end
|
45
|
-
|
46
|
-
it 'returns AccessToken with #expires_in' do
|
47
|
-
expect(@access.expires_in).to eq(600)
|
48
|
-
end
|
49
|
-
|
50
|
-
it 'returns AccessToken with #expires_at' do
|
51
|
-
expect(@access.expires_at).not_to be_nil
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
end
|
@@ -1,88 +0,0 @@
|
|
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 'includes the client_id' do
|
40
|
-
expect(subject.authorize_url).to include('client_id=abc')
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'includes the type' do
|
44
|
-
expect(subject.authorize_url).to include('response_type=code')
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'includes passed in options' do
|
48
|
-
cb = 'http://myserver.local/oauth/callback'
|
49
|
-
expect(subject.authorize_url(:redirect_uri => cb)).to 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 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
|
-
expect(@access.client).to eq(client)
|
64
|
-
end
|
65
|
-
|
66
|
-
it 'returns AccessToken with #token' do
|
67
|
-
expect(@access.token).to eq('salmon')
|
68
|
-
end
|
69
|
-
|
70
|
-
it 'returns AccessToken with #refresh_token' do
|
71
|
-
expect(@access.refresh_token).to eq('trout')
|
72
|
-
end
|
73
|
-
|
74
|
-
it 'returns AccessToken with #expires_in' do
|
75
|
-
expect(@access.expires_in).to eq(600)
|
76
|
-
end
|
77
|
-
|
78
|
-
it 'returns AccessToken with #expires_at' do
|
79
|
-
expect(@access.expires_at).to be_kind_of(Integer)
|
80
|
-
end
|
81
|
-
|
82
|
-
it 'returns AccessToken with params accessible via []' do
|
83
|
-
expect(@access['extra_param']).to eq('steve')
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
@@ -1,81 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
describe OAuth2::Strategy::ClientCredentials do
|
4
|
-
let(:kvform_token) { 'expires_in=600&access_token=salmon&refresh_token=trout' }
|
5
|
-
let(:json_token) { '{"expires_in":600,"access_token":"salmon","refresh_token":"trout"}' }
|
6
|
-
|
7
|
-
let(:client) do
|
8
|
-
OAuth2::Client.new('abc', 'def', :site => 'http://api.example.com') do |builder|
|
9
|
-
builder.adapter :test do |stub|
|
10
|
-
stub.post('/oauth/token', 'grant_type' => 'client_credentials') do |env|
|
11
|
-
client_id, client_secret = Base64.decode64(env[:request_headers]['Authorization'].split(' ', 2)[1]).split(':', 2)
|
12
|
-
client_id == 'abc' && client_secret == 'def' || fail(Faraday::Adapter::Test::Stubs::NotFound)
|
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
|
-
end
|
19
|
-
end
|
20
|
-
stub.post('/oauth/token', 'client_id' => 'abc', 'client_secret' => 'def', 'grant_type' => 'client_credentials') do |env|
|
21
|
-
case @mode
|
22
|
-
when 'formencoded'
|
23
|
-
[200, {'Content-Type' => 'application/x-www-form-urlencoded'}, kvform_token]
|
24
|
-
when 'json'
|
25
|
-
[200, {'Content-Type' => 'application/json'}, json_token]
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
subject { client.client_credentials }
|
33
|
-
|
34
|
-
describe '#authorize_url' do
|
35
|
-
it 'raises NotImplementedError' do
|
36
|
-
expect { subject.authorize_url }.to raise_error(NotImplementedError)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
describe '#authorization' do
|
41
|
-
it 'generates an Authorization header value for HTTP Basic Authentication' do
|
42
|
-
[
|
43
|
-
['abc', 'def', 'Basic YWJjOmRlZg=='],
|
44
|
-
['xxx', 'secret', 'Basic eHh4OnNlY3JldA==']
|
45
|
-
].each do |client_id, client_secret, expected|
|
46
|
-
expect(subject.authorization(client_id, client_secret)).to eq(expected)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
%w(json formencoded).each do |mode|
|
52
|
-
%w(default basic_auth request_body).each do |auth_scheme|
|
53
|
-
describe "#get_token (#{mode}) (#{auth_scheme})" do
|
54
|
-
before do
|
55
|
-
@mode = mode
|
56
|
-
@access = subject.get_token({}, auth_scheme == 'default' ? {} : {'auth_scheme' => auth_scheme})
|
57
|
-
end
|
58
|
-
|
59
|
-
it 'returns AccessToken with same Client' do
|
60
|
-
expect(@access.client).to eq(client)
|
61
|
-
end
|
62
|
-
|
63
|
-
it 'returns AccessToken with #token' do
|
64
|
-
expect(@access.token).to eq('salmon')
|
65
|
-
end
|
66
|
-
|
67
|
-
it 'returns AccessToken without #refresh_token' do
|
68
|
-
expect(@access.refresh_token).to be_nil
|
69
|
-
end
|
70
|
-
|
71
|
-
it 'returns AccessToken with #expires_in' do
|
72
|
-
expect(@access.expires_in).to eq(600)
|
73
|
-
end
|
74
|
-
|
75
|
-
it 'returns AccessToken with #expires_at' do
|
76
|
-
expect(@access.expires_at).not_to be_nil
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|