rack-oauth2 0.7.0 → 0.8.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +9 -9
- data/VERSION +1 -1
- data/lib/rack/oauth2.rb +1 -1
- data/lib/rack/oauth2/access_token.rb +5 -17
- data/lib/rack/oauth2/access_token/authenticator.rb +24 -0
- data/lib/rack/oauth2/access_token/bearer.rb +2 -3
- data/lib/rack/oauth2/access_token/legacy.rb +2 -3
- data/lib/rack/oauth2/access_token/mac.rb +19 -45
- data/lib/rack/oauth2/client.rb +17 -4
- data/rack-oauth2.gemspec +2 -2
- data/spec/helpers/webmock_helper.rb +42 -0
- data/spec/{fake_response → mock_response}/errors/invalid_request.json +0 -0
- data/spec/{fake_response → mock_response}/resources/fake.txt +0 -0
- data/spec/{fake_response → mock_response}/tokens/bearer.json +0 -0
- data/spec/{fake_response → mock_response}/tokens/legacy.json +0 -0
- data/spec/{fake_response → mock_response}/tokens/legacy.txt +0 -0
- data/spec/{fake_response → mock_response}/tokens/legacy_without_expires_in.txt +0 -0
- data/spec/{fake_response → mock_response}/tokens/mac.json +0 -0
- data/spec/{fake_response → mock_response}/tokens/unknown.json +0 -0
- data/spec/rack/oauth2/access_token/authenticator_spec.rb +43 -0
- data/spec/rack/oauth2/access_token/bearer_spec.rb +5 -30
- data/spec/rack/oauth2/access_token/legacy_spec.rb +8 -33
- data/spec/rack/oauth2/access_token/mac_spec.rb +21 -65
- data/spec/rack/oauth2/access_token_spec.rb +13 -1
- data/spec/rack/oauth2/client_spec.rb +7 -7
- data/spec/spec_helper.rb +2 -15
- metadata +28 -23
data/Gemfile.lock
CHANGED
@@ -1,31 +1,28 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rack-oauth2 (0.
|
4
|
+
rack-oauth2 (0.8.0.alpha)
|
5
5
|
activesupport (>= 2.3)
|
6
6
|
attr_required (>= 0.0.3)
|
7
|
+
httpclient (>= 2.2.0.2)
|
7
8
|
i18n
|
8
9
|
json (>= 1.4.3)
|
9
10
|
rack (>= 1.1)
|
10
|
-
restclient_with_cert
|
11
11
|
|
12
12
|
GEM
|
13
13
|
remote: http://rubygems.org/
|
14
14
|
specs:
|
15
15
|
activesupport (3.0.7)
|
16
|
+
addressable (2.2.6)
|
16
17
|
attr_required (0.0.3)
|
18
|
+
crack (0.1.8)
|
17
19
|
diff-lcs (1.1.2)
|
18
|
-
|
20
|
+
httpclient (2.2.0.2)
|
19
21
|
i18n (0.5.0)
|
20
22
|
json (1.5.1)
|
21
|
-
mime-types (1.16)
|
22
23
|
rack (1.2.2)
|
23
24
|
rake (0.8.7)
|
24
25
|
rcov (0.9.9)
|
25
|
-
rest-client (1.6.1)
|
26
|
-
mime-types (>= 1.16)
|
27
|
-
restclient_with_cert (0.0.7)
|
28
|
-
rest-client (>= 1.6)
|
29
26
|
rspec (2.5.0)
|
30
27
|
rspec-core (~> 2.5.0)
|
31
28
|
rspec-expectations (~> 2.5.0)
|
@@ -34,13 +31,16 @@ GEM
|
|
34
31
|
rspec-expectations (2.5.0)
|
35
32
|
diff-lcs (~> 1.1.2)
|
36
33
|
rspec-mocks (2.5.0)
|
34
|
+
webmock (1.6.4)
|
35
|
+
addressable (> 2.2.5, ~> 2.2)
|
36
|
+
crack (>= 0.1.7)
|
37
37
|
|
38
38
|
PLATFORMS
|
39
39
|
ruby
|
40
40
|
|
41
41
|
DEPENDENCIES
|
42
|
-
fakeweb (>= 1.3)
|
43
42
|
rack-oauth2!
|
44
43
|
rake (>= 0.8)
|
45
44
|
rcov (>= 0.9)
|
46
45
|
rspec (<= 2.5, >= 2)
|
46
|
+
webmock (>= 1.6.2)
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.8.0.alpha
|
data/lib/rack/oauth2.rb
CHANGED
@@ -2,14 +2,17 @@ module Rack
|
|
2
2
|
module OAuth2
|
3
3
|
class AccessToken
|
4
4
|
include AttrRequired, AttrOptional
|
5
|
-
attr_required :access_token, :token_type
|
5
|
+
attr_required :access_token, :token_type, :client
|
6
6
|
attr_optional :refresh_token, :expires_in, :scope
|
7
|
+
delegate :get, :post, :put, :delete, :to => :client
|
7
8
|
|
8
9
|
def initialize(attributes = {})
|
9
10
|
(required_attributes + optional_attributes).each do |key|
|
10
11
|
self.send :"#{key}=", attributes[key]
|
11
12
|
end
|
12
13
|
@token_type = self.class.to_s.split('::').last.underscore.to_sym
|
14
|
+
@client = HTTPClient.new
|
15
|
+
@client.request_filter << Authenticator.new(self)
|
13
16
|
attr_missing!
|
14
17
|
end
|
15
18
|
|
@@ -22,26 +25,11 @@ module Rack
|
|
22
25
|
:scope => Array(scope).join(' ')
|
23
26
|
}
|
24
27
|
end
|
25
|
-
|
26
|
-
def get(url, headers = {}, &block)
|
27
|
-
RestClient.get url, authenticate(headers), &block
|
28
|
-
end
|
29
|
-
|
30
|
-
def post(url, payload, headers = {}, &block)
|
31
|
-
RestClient.post url, payload, authenticate(headers), &block
|
32
|
-
end
|
33
|
-
|
34
|
-
def put(url, payload, headers = {}, &block)
|
35
|
-
RestClient.put url, payload, authenticate(headers), &block
|
36
|
-
end
|
37
|
-
|
38
|
-
def delete(url, headers = {}, &block)
|
39
|
-
RestClient.delete url, authenticate(headers), &block
|
40
|
-
end
|
41
28
|
end
|
42
29
|
end
|
43
30
|
end
|
44
31
|
|
32
|
+
require 'rack/oauth2/access_token/authenticator'
|
45
33
|
require 'rack/oauth2/access_token/bearer'
|
46
34
|
require 'rack/oauth2/access_token/mac'
|
47
35
|
require 'rack/oauth2/access_token/legacy'
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Rack
|
2
|
+
module OAuth2
|
3
|
+
class AccessToken
|
4
|
+
class Authenticator
|
5
|
+
def initialize(token)
|
6
|
+
@token = token
|
7
|
+
end
|
8
|
+
|
9
|
+
# Callback called in HTTPClient (before sending a request)
|
10
|
+
# request:: HTTP::Message
|
11
|
+
def filter_request(request)
|
12
|
+
@token.authenticate(request)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Callback called in HTTPClient (after received a response)
|
16
|
+
# response:: HTTP::Message
|
17
|
+
# request:: HTTP::Message
|
18
|
+
def filter_response(response, request)
|
19
|
+
# nothing to do
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -2,9 +2,8 @@ module Rack
|
|
2
2
|
module OAuth2
|
3
3
|
class AccessToken
|
4
4
|
class Bearer < AccessToken
|
5
|
-
|
6
|
-
|
7
|
-
headers.merge(:AUTHORIZATION => "Bearer #{access_token}")
|
5
|
+
def authenticate(request)
|
6
|
+
request.header["Authorization"] = "Bearer #{access_token}"
|
8
7
|
end
|
9
8
|
end
|
10
9
|
end
|
@@ -11,9 +11,8 @@ module Rack
|
|
11
11
|
self.access_token
|
12
12
|
end
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
headers.merge(:AUTHORIZATION => "OAuth2 #{access_token}")
|
14
|
+
def authenticate(request)
|
15
|
+
request.header["Authorization"] = "OAuth2 #{access_token}"
|
17
16
|
end
|
18
17
|
end
|
19
18
|
end
|
@@ -20,13 +20,12 @@ module Rack
|
|
20
20
|
|
21
21
|
def verify!(request)
|
22
22
|
if request.body_hash.present?
|
23
|
-
|
23
|
+
BodyHash.new(
|
24
24
|
:raw_body => request.body.read,
|
25
25
|
:algorithm => self.mac_algorithm
|
26
|
-
)
|
27
|
-
_body_hash_.verify!(request.body_hash)
|
26
|
+
).verify!(request.body_hash)
|
28
27
|
end
|
29
|
-
|
28
|
+
Signature.new(
|
30
29
|
:secret => self.mac_key,
|
31
30
|
:algorithm => self.mac_algorithm,
|
32
31
|
:nonce => request.nonce,
|
@@ -36,60 +35,35 @@ module Rack
|
|
36
35
|
:port => request.port,
|
37
36
|
:body_hash => request.body_hash,
|
38
37
|
:ext => request.ext
|
39
|
-
)
|
40
|
-
_signature_.verify!(request.signature)
|
38
|
+
).verify!(request.signature)
|
41
39
|
rescue Verifier::VerificationFailed => e
|
42
40
|
request.invalid_token! e.message
|
43
41
|
end
|
44
42
|
|
45
|
-
def
|
46
|
-
_headers_ = authenticate(:get, url, headers)
|
47
|
-
RestClient.get url, _headers_, &block
|
48
|
-
end
|
49
|
-
|
50
|
-
def post(url, payload, headers = {}, &block)
|
51
|
-
_headers_ = authenticate(:post, url, headers, payload)
|
52
|
-
RestClient.post url, payload, _headers_, &block
|
53
|
-
end
|
54
|
-
|
55
|
-
def put(url, payload, headers = {}, &block)
|
56
|
-
_headers_ = authenticate(:put, url, headers, payload)
|
57
|
-
RestClient.put url, payload, _headers_, &block
|
58
|
-
end
|
59
|
-
|
60
|
-
def delete(url, headers = {}, &block)
|
61
|
-
_headers_ = authenticate(:delete, url, headers)
|
62
|
-
RestClient.delete url, _headers_, &block
|
63
|
-
end
|
64
|
-
|
65
|
-
private
|
66
|
-
|
67
|
-
def authenticate(method, url, headers = {}, payload = {})
|
68
|
-
_url_ = URI.parse(url)
|
43
|
+
def authenticate(request)
|
69
44
|
@nonce = generate_nonce
|
70
|
-
if
|
71
|
-
|
72
|
-
|
73
|
-
:raw_body => raw_body,
|
45
|
+
if request.contenttype == 'application/x-www-form-urlencoded'
|
46
|
+
@body_hash = BodyHash.new(
|
47
|
+
:raw_body => request.body,
|
74
48
|
:algorithm => self.mac_algorithm
|
75
|
-
)
|
76
|
-
@body_hash = _body_hash_.calculate
|
49
|
+
).calculate
|
77
50
|
end
|
78
|
-
|
51
|
+
@signature = Signature.new(
|
79
52
|
:secret => self.mac_key,
|
80
53
|
:algorithm => self.mac_algorithm,
|
81
54
|
:nonce => self.nonce,
|
82
|
-
:method =>
|
83
|
-
:request_uri =>
|
84
|
-
:host =>
|
85
|
-
:port =>
|
55
|
+
:method => request.header.request_method,
|
56
|
+
:request_uri => request.header.create_query_uri,
|
57
|
+
:host => request.header.request_uri.host,
|
58
|
+
:port => request.header.request_uri.port,
|
86
59
|
:body_hash => self.body_hash,
|
87
60
|
:ext => self.ext
|
88
|
-
)
|
89
|
-
|
90
|
-
headers.merge(:AUTHORIZATION => authorization_header)
|
61
|
+
).calculate
|
62
|
+
request.header['Authorization'] = authorization_header
|
91
63
|
end
|
92
64
|
|
65
|
+
private
|
66
|
+
|
93
67
|
def authorization_header
|
94
68
|
header = "MAC"
|
95
69
|
header << " id=\"#{access_token}\","
|
@@ -102,7 +76,7 @@ module Rack
|
|
102
76
|
def generate_nonce
|
103
77
|
[
|
104
78
|
(Time.now.utc - @issued_at).to_i,
|
105
|
-
ActiveSupport::SecureRandom.
|
79
|
+
ActiveSupport::SecureRandom.hex
|
106
80
|
].join(':')
|
107
81
|
end
|
108
82
|
end
|
data/lib/rack/oauth2/client.rb
CHANGED
@@ -51,7 +51,7 @@ module Rack
|
|
51
51
|
:client_secret => self.secret
|
52
52
|
)
|
53
53
|
handle_response do
|
54
|
-
|
54
|
+
HTTPClient.new.post absolute_uri_for(token_endpoint), Util.compact_hash(params)
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
@@ -67,6 +67,15 @@ module Rack
|
|
67
67
|
|
68
68
|
def handle_response
|
69
69
|
response = yield
|
70
|
+
case response.status
|
71
|
+
when 200..201
|
72
|
+
handle_success_response response
|
73
|
+
else
|
74
|
+
handle_error_response response
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def handle_success_response(response)
|
70
79
|
token_hash = JSON.parse(response.body).with_indifferent_access
|
71
80
|
case token_hash[:token_type]
|
72
81
|
when 'bearer'
|
@@ -81,9 +90,13 @@ module Rack
|
|
81
90
|
rescue JSON::ParserError
|
82
91
|
# NOTE: Facebook support (They don't use JSON as token response)
|
83
92
|
AccessToken::Legacy.new Rack::Utils.parse_nested_query(response.body).with_indifferent_access
|
84
|
-
|
85
|
-
|
86
|
-
|
93
|
+
end
|
94
|
+
|
95
|
+
def handle_error_response(response)
|
96
|
+
error = JSON.parse(response.body).with_indifferent_access
|
97
|
+
raise Error.new(response.status, error)
|
98
|
+
rescue JSON::ParserError
|
99
|
+
raise Error.new(response.status, :error => 'Unknown', :error_description => resonse.body)
|
87
100
|
end
|
88
101
|
end
|
89
102
|
end
|
data/rack-oauth2.gemspec
CHANGED
@@ -15,12 +15,12 @@ Gem::Specification.new do |s|
|
|
15
15
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
16
|
s.add_runtime_dependency "rack", ">= 1.1"
|
17
17
|
s.add_runtime_dependency "json", ">= 1.4.3"
|
18
|
-
s.add_runtime_dependency "
|
18
|
+
s.add_runtime_dependency "httpclient", ">= 2.2.0.2"
|
19
19
|
s.add_runtime_dependency "activesupport", ">= 2.3"
|
20
20
|
s.add_runtime_dependency "i18n"
|
21
21
|
s.add_runtime_dependency "attr_required", ">= 0.0.3"
|
22
22
|
s.add_development_dependency "rake", ">= 0.8"
|
23
23
|
s.add_development_dependency "rcov", ">= 0.9"
|
24
24
|
s.add_development_dependency "rspec", ">= 2", "<= 2.5"
|
25
|
-
s.add_development_dependency "
|
25
|
+
s.add_development_dependency "webmock", ">= 1.6.2"
|
26
26
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'webmock/rspec'
|
2
|
+
|
3
|
+
module WebMockHelper
|
4
|
+
def mock_response(method, endpoint, response_file, options = {})
|
5
|
+
stub_request(method, endpoint).with(
|
6
|
+
request_for(method, options)
|
7
|
+
).to_return(
|
8
|
+
response_for(response_file, options)
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def request_for(method, options = {})
|
15
|
+
request = {}
|
16
|
+
if options[:access_token]
|
17
|
+
options[:params] ||= {}
|
18
|
+
options[:params][:oauth_token] = options[:access_token].to_s
|
19
|
+
end
|
20
|
+
if options[:params]
|
21
|
+
case method
|
22
|
+
when :post, :put
|
23
|
+
request[:body] = options[:params]
|
24
|
+
else
|
25
|
+
request[:query] = options[:params]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
request
|
29
|
+
end
|
30
|
+
|
31
|
+
def response_for(response_file, options = {})
|
32
|
+
response = {}
|
33
|
+
response[:body] = File.new(File.join(File.dirname(__FILE__), '../mock_response', response_file))
|
34
|
+
if options[:status]
|
35
|
+
response[:status] = options[:status]
|
36
|
+
end
|
37
|
+
response
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
include WebMockHelper
|
42
|
+
WebMock.disable_net_connect!
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Rack::OAuth2::AccessToken::Authenticator do
|
4
|
+
let(:resource_endpoint) { 'https://server.example.com/resources/fake' }
|
5
|
+
let(:request) { HTTP::Message.new_request(:get, URI.parse(resource_endpoint)) }
|
6
|
+
let(:authenticator) { Rack::OAuth2::AccessToken::Authenticator.new(token) }
|
7
|
+
|
8
|
+
shared_examples_for :authenticator do
|
9
|
+
it 'should let the token authenticate the request' do
|
10
|
+
token.should_receive(:authenticate).with(request)
|
11
|
+
authenticator.filter_request(request)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'when Legacy token is given' do
|
16
|
+
let(:token) do
|
17
|
+
Rack::OAuth2::AccessToken::Legacy.new(
|
18
|
+
:access_token => 'access_token'
|
19
|
+
)
|
20
|
+
end
|
21
|
+
it_behaves_like :authenticator
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'when Bearer token is given' do
|
25
|
+
let(:token) do
|
26
|
+
Rack::OAuth2::AccessToken::Bearer.new(
|
27
|
+
:access_token => 'access_token'
|
28
|
+
)
|
29
|
+
end
|
30
|
+
it_behaves_like :authenticator
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'when MAC token is given' do
|
34
|
+
let(:token) do
|
35
|
+
Rack::OAuth2::AccessToken::MAC.new(
|
36
|
+
:access_token => 'access_token',
|
37
|
+
:mac_key => 'secret',
|
38
|
+
:mac_algorithm => 'hmac-sha-256'
|
39
|
+
)
|
40
|
+
end
|
41
|
+
it_behaves_like :authenticator
|
42
|
+
end
|
43
|
+
end
|
@@ -7,37 +7,12 @@ describe Rack::OAuth2::AccessToken::Bearer do
|
|
7
7
|
)
|
8
8
|
end
|
9
9
|
let(:resource_endpoint) { 'https://server.example.com/resources/fake' }
|
10
|
+
let(:request) { HTTPClient.new.send(:create_request, :post, URI.parse(resource_endpoint), {}, {:hello => "world"}, {}) }
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
describe method.to_s.upcase do
|
17
|
-
it 'should have Bearer Authorization header' do
|
18
|
-
RestClient.should_receive(method).with(
|
19
|
-
resource_endpoint,
|
20
|
-
:AUTHORIZATION => 'Bearer access_token'
|
21
|
-
)
|
22
|
-
token.send method, resource_endpoint
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
[:post, :put].each do |method|
|
28
|
-
before do
|
29
|
-
fake_response(method, resource_endpoint, 'resources/fake.txt')
|
30
|
-
end
|
31
|
-
|
32
|
-
describe method.to_s.upcase do
|
33
|
-
it 'should have Bearer Authorization header' do
|
34
|
-
RestClient.should_receive(method).with(
|
35
|
-
resource_endpoint,
|
36
|
-
{:key => :value},
|
37
|
-
{:AUTHORIZATION => 'Bearer access_token'}
|
38
|
-
)
|
39
|
-
token.send method, resource_endpoint, {:key => :value}
|
40
|
-
end
|
12
|
+
describe '.authenticate' do
|
13
|
+
it 'should set Authorization header' do
|
14
|
+
request.header.should_receive(:[]=).with('Authorization', 'Bearer access_token')
|
15
|
+
token.authenticate(request)
|
41
16
|
end
|
42
17
|
end
|
43
18
|
end
|
@@ -7,42 +7,17 @@ describe Rack::OAuth2::AccessToken::Legacy do
|
|
7
7
|
)
|
8
8
|
end
|
9
9
|
let(:resource_endpoint) { 'https://server.example.com/resources/fake' }
|
10
|
-
|
11
|
-
[:get, :delete].each do |method|
|
12
|
-
before do
|
13
|
-
fake_response(method, resource_endpoint, 'resources/fake.txt')
|
14
|
-
end
|
15
|
-
|
16
|
-
describe method.to_s.upcase do
|
17
|
-
it 'should have OAuth2 Authorization header' do
|
18
|
-
RestClient.should_receive(method).with(
|
19
|
-
resource_endpoint,
|
20
|
-
:AUTHORIZATION => 'OAuth2 access_token'
|
21
|
-
)
|
22
|
-
token.send method, resource_endpoint
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
[:post, :put].each do |method|
|
28
|
-
before do
|
29
|
-
fake_response(method, resource_endpoint, 'resources/fake.txt')
|
30
|
-
end
|
31
|
-
|
32
|
-
describe method.to_s.upcase do
|
33
|
-
it 'should have OAuth2 Authorization header' do
|
34
|
-
RestClient.should_receive(method).with(
|
35
|
-
resource_endpoint,
|
36
|
-
{:key => :value},
|
37
|
-
{:AUTHORIZATION => 'OAuth2 access_token'}
|
38
|
-
)
|
39
|
-
token.send method, resource_endpoint, {:key => :value}
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
10
|
+
let(:request) { HTTPClient.new.send(:create_request, :post, URI.parse(resource_endpoint), {}, {:hello => "world"}, {}) }
|
43
11
|
|
44
12
|
describe '#to_s' do
|
45
13
|
subject { token }
|
46
14
|
its(:to_s) { should == token.access_token }
|
47
15
|
end
|
16
|
+
|
17
|
+
describe '.authenticate' do
|
18
|
+
it 'should set Authorization header' do
|
19
|
+
request.header.should_receive(:[]=).with('Authorization', 'OAuth2 access_token')
|
20
|
+
token.authenticate(request)
|
21
|
+
end
|
22
|
+
end
|
48
23
|
end
|
@@ -5,9 +5,12 @@ describe Rack::OAuth2::AccessToken::MAC do
|
|
5
5
|
Rack::OAuth2::AccessToken::MAC.new(
|
6
6
|
:access_token => 'access_token',
|
7
7
|
:mac_key => 'secret',
|
8
|
-
:mac_algorithm => 'hmac-sha-256'
|
8
|
+
:mac_algorithm => 'hmac-sha-256',
|
9
|
+
:issued_at => issued_at
|
9
10
|
)
|
10
11
|
end
|
12
|
+
let(:issued_at) { 1305820455 }
|
13
|
+
let(:nonce) { '1000:51e74de734c05613f37520872e68db5f' }
|
11
14
|
let(:resource_endpoint) { 'https://server.example.com/resources/fake' }
|
12
15
|
subject { token }
|
13
16
|
|
@@ -26,63 +29,6 @@ describe Rack::OAuth2::AccessToken::MAC do
|
|
26
29
|
end
|
27
30
|
its(:generate_nonce) { should be_a String }
|
28
31
|
|
29
|
-
describe 'HTTP methods' do
|
30
|
-
before do
|
31
|
-
token.should_receive(:generate_nonce).and_return("51e74de734c05613f37520872e68db5f")
|
32
|
-
end
|
33
|
-
|
34
|
-
describe :GET do
|
35
|
-
let(:resource_endpoint) { 'https://server.example.com/resources/fake?key=value' }
|
36
|
-
it 'should have MAC Authorization header' do
|
37
|
-
Time.fix(Time.at(1302361200)) do
|
38
|
-
RestClient.should_receive(:get).with(
|
39
|
-
resource_endpoint,
|
40
|
-
:AUTHORIZATION => 'MAC id="access_token", nonce="51e74de734c05613f37520872e68db5f", mac="gMJ8AmvTGmfPFCJCf5DUwNTmT7ksw6GqyoGW2lUIUZ0="'
|
41
|
-
)
|
42
|
-
token.get resource_endpoint
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
describe :POST do
|
48
|
-
it 'should have MAC Authorization header' do
|
49
|
-
Time.fix(Time.at(1302361200)) do
|
50
|
-
RestClient.should_receive(:post).with(
|
51
|
-
resource_endpoint,
|
52
|
-
{:key => :value},
|
53
|
-
{:AUTHORIZATION => 'MAC id="access_token", nonce="51e74de734c05613f37520872e68db5f", bodyhash="Vj8DVxGNBe8UXWvd8pZswj6Gyo8vAT+RXlZa/fCfeiM=", mac="7OOseGqNi14lThhRnwhItACXACM4Qp5GleBEuizzUpw="'}
|
54
|
-
)
|
55
|
-
token.post resource_endpoint, :key => :value
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
describe :PUT do
|
61
|
-
it 'should have MAC Authorization header' do
|
62
|
-
Time.fix(Time.at(1302361200)) do
|
63
|
-
RestClient.should_receive(:put).with(
|
64
|
-
resource_endpoint,
|
65
|
-
{:key => :value},
|
66
|
-
{:AUTHORIZATION => 'MAC id="access_token", nonce="51e74de734c05613f37520872e68db5f", bodyhash="Vj8DVxGNBe8UXWvd8pZswj6Gyo8vAT+RXlZa/fCfeiM=", mac="lxTg/F29zkE7vBEbAK9VULRpM4IN5uShqHbj2k7e9lA="'}
|
67
|
-
)
|
68
|
-
token.put resource_endpoint, :key => :value
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
describe :DELETE do
|
74
|
-
it 'should have MAC Authorization header' do
|
75
|
-
Time.fix(Time.at(1302361200)) do
|
76
|
-
RestClient.should_receive(:delete).with(
|
77
|
-
resource_endpoint,
|
78
|
-
:AUTHORIZATION => 'MAC id="access_token", nonce="51e74de734c05613f37520872e68db5f", mac="JtOibEO1rBQNBGy6hUPT29L2cHSmLP09K+kUL4oEe/g="'
|
79
|
-
)
|
80
|
-
token.delete resource_endpoint
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
32
|
describe 'verify!' do
|
87
33
|
let(:request) { Rack::OAuth2::Server::Resource::MAC::Request.new(env) }
|
88
34
|
|
@@ -90,16 +36,14 @@ describe Rack::OAuth2::AccessToken::MAC do
|
|
90
36
|
let(:env) do
|
91
37
|
Rack::MockRequest.env_for(
|
92
38
|
'/protected_resources',
|
93
|
-
'HTTP_AUTHORIZATION' => %{MAC id="access_token", nonce="
|
39
|
+
'HTTP_AUTHORIZATION' => %{MAC id="access_token", nonce="#{nonce}", mac="#{signature}"}
|
94
40
|
)
|
95
41
|
end
|
96
42
|
|
97
43
|
context 'when signature is valid' do
|
98
|
-
let(:signature) { '
|
44
|
+
let(:signature) { 'nbQj0NdvSBKdwvw1yX6wpQ4EwrQKBg/r3lqwJGcthDU=' }
|
99
45
|
it do
|
100
|
-
|
101
|
-
token.verify!(request.setup!).should == :verified
|
102
|
-
end
|
46
|
+
token.verify!(request.setup!).should == :verified
|
103
47
|
end
|
104
48
|
end
|
105
49
|
|
@@ -122,7 +66,7 @@ describe Rack::OAuth2::AccessToken::MAC do
|
|
122
66
|
:params => {
|
123
67
|
:key1 => 'value1'
|
124
68
|
},
|
125
|
-
'HTTP_AUTHORIZATION' => %{MAC id="access_token", nonce="
|
69
|
+
'HTTP_AUTHORIZATION' => %{MAC id="access_token", nonce="#{nonce}", bodyhash="#{body_hash}", mac="#{signature}"}
|
126
70
|
)
|
127
71
|
end
|
128
72
|
let(:signature) { 'invalid' }
|
@@ -141,7 +85,7 @@ describe Rack::OAuth2::AccessToken::MAC do
|
|
141
85
|
let(:body_hash) { 'TPzUbFn1S16mpfmwXCi1L+8oZHRxlLX9/D1ZwAV781o=' }
|
142
86
|
|
143
87
|
context 'when signature is valid' do
|
144
|
-
let(:signature) { '
|
88
|
+
let(:signature) { 'ebFlQPMO3WzEZ3ncuIFnVK7IsVt+JEorQEEMJTiz/t8=' }
|
145
89
|
it do
|
146
90
|
Time.fix(Time.at(1302361200)) do
|
147
91
|
token.verify!(request.setup!).should == :verified
|
@@ -160,4 +104,16 @@ describe Rack::OAuth2::AccessToken::MAC do
|
|
160
104
|
end
|
161
105
|
end
|
162
106
|
end
|
107
|
+
|
108
|
+
describe '.authenticate' do
|
109
|
+
let(:request) { HTTPClient.new.send(:create_request, :post, URI.parse(resource_endpoint), {}, {:hello => "world"}, {}) }
|
110
|
+
let(:body_hash) { 'PQEeCVAqhFUqD4rhEtAkzCwRVZfjpXfV9JAHkCwiHcU=' }
|
111
|
+
let(:signature) { 'aL2Oh8gWrCAtJ/Xu6XMtJb6ZsYQT+GxQTs/TgJDQ7ZY=' }
|
112
|
+
|
113
|
+
it 'should set Authorization header' do
|
114
|
+
token.should_receive(:generate_nonce).and_return(nonce)
|
115
|
+
request.header.should_receive(:[]=).with('Authorization', "MAC id=\"access_token\", nonce=\"#{nonce}\", bodyhash=\"#{body_hash}\", mac=\"#{signature}\"")
|
116
|
+
token.authenticate(request)
|
117
|
+
end
|
118
|
+
end
|
163
119
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Rack::OAuth2::AccessToken do
|
4
|
-
|
4
|
+
let :token do
|
5
5
|
Rack::OAuth2::AccessToken::Bearer.new(
|
6
6
|
:access_token => 'access_token',
|
7
7
|
:refresh_token => 'refresh_token',
|
@@ -9,6 +9,7 @@ describe Rack::OAuth2::AccessToken do
|
|
9
9
|
:scope => [:scope1, :scope2]
|
10
10
|
)
|
11
11
|
end
|
12
|
+
subject { token }
|
12
13
|
|
13
14
|
its(:access_token) { should == 'access_token' }
|
14
15
|
its(:refresh_token) { should == 'refresh_token' }
|
@@ -45,4 +46,15 @@ describe Rack::OAuth2::AccessToken do
|
|
45
46
|
end.should_not raise_error
|
46
47
|
end
|
47
48
|
end
|
49
|
+
|
50
|
+
let(:resource_endpoint) { 'https://server.example.com/resources/fake' }
|
51
|
+
[:get, :delete, :post, :put].each do |method|
|
52
|
+
describe method do
|
53
|
+
it 'should delegate to HTTPClient with Authenticator filter' do
|
54
|
+
token.client.should_receive(method).with(resource_endpoint)
|
55
|
+
token.client.request_filter.last.should be_a Rack::OAuth2::AccessToken::Authenticator
|
56
|
+
token.send method, resource_endpoint
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
48
60
|
end
|
@@ -77,7 +77,7 @@ describe Rack::OAuth2::Client do
|
|
77
77
|
context 'when bearer token is given' do
|
78
78
|
before do
|
79
79
|
client.authorization_code = 'code'
|
80
|
-
|
80
|
+
mock_response(
|
81
81
|
:post,
|
82
82
|
'https://server.example.com/oauth2/token',
|
83
83
|
'tokens/bearer.json'
|
@@ -93,7 +93,7 @@ describe Rack::OAuth2::Client do
|
|
93
93
|
context 'when mac token is given' do
|
94
94
|
before do
|
95
95
|
client.authorization_code = 'code'
|
96
|
-
|
96
|
+
mock_response(
|
97
97
|
:post,
|
98
98
|
'https://server.example.com/oauth2/token',
|
99
99
|
'tokens/mac.json'
|
@@ -109,7 +109,7 @@ describe Rack::OAuth2::Client do
|
|
109
109
|
context 'when no-type token is given (JSON)' do
|
110
110
|
before do
|
111
111
|
client.authorization_code = 'code'
|
112
|
-
|
112
|
+
mock_response(
|
113
113
|
:post,
|
114
114
|
'https://server.example.com/oauth2/token',
|
115
115
|
'tokens/legacy.json'
|
@@ -124,7 +124,7 @@ describe Rack::OAuth2::Client do
|
|
124
124
|
|
125
125
|
context 'when no-type token is given (key-value)' do
|
126
126
|
before do
|
127
|
-
|
127
|
+
mock_response(
|
128
128
|
:post,
|
129
129
|
'https://server.example.com/oauth2/token',
|
130
130
|
'tokens/legacy.txt'
|
@@ -137,7 +137,7 @@ describe Rack::OAuth2::Client do
|
|
137
137
|
|
138
138
|
context 'when expires_in is not given' do
|
139
139
|
before do
|
140
|
-
|
140
|
+
mock_response(
|
141
141
|
:post,
|
142
142
|
'https://server.example.com/oauth2/token',
|
143
143
|
'tokens/legacy_without_expires_in.txt'
|
@@ -150,7 +150,7 @@ describe Rack::OAuth2::Client do
|
|
150
150
|
context 'when unknown-type token is given' do
|
151
151
|
before do
|
152
152
|
client.authorization_code = 'code'
|
153
|
-
|
153
|
+
mock_response(
|
154
154
|
:post,
|
155
155
|
'https://server.example.com/oauth2/token',
|
156
156
|
'tokens/unknown.json'
|
@@ -163,7 +163,7 @@ describe Rack::OAuth2::Client do
|
|
163
163
|
|
164
164
|
context 'when error response is given' do
|
165
165
|
before do
|
166
|
-
|
166
|
+
mock_response(
|
167
167
|
:post,
|
168
168
|
'https://server.example.com/oauth2/token',
|
169
169
|
'errors/invalid_request.json',
|
data/spec/spec_helper.rb
CHANGED
@@ -1,23 +1,10 @@
|
|
1
|
-
require 'rack/oauth2'
|
2
1
|
require 'rspec'
|
3
|
-
require '
|
2
|
+
require 'rack/oauth2'
|
4
3
|
require 'helpers/time'
|
4
|
+
require 'helpers/webmock_helper'
|
5
5
|
|
6
6
|
def simple_app
|
7
7
|
lambda do |env|
|
8
8
|
[ 200, {'Content-Type' => 'text/plain'}, ["HELLO"] ]
|
9
9
|
end
|
10
10
|
end
|
11
|
-
|
12
|
-
def fake_response(method, endpoint, file_path, options = {})
|
13
|
-
FakeWeb.register_uri(
|
14
|
-
method,
|
15
|
-
endpoint,
|
16
|
-
options.merge(
|
17
|
-
:body => File.read(
|
18
|
-
File.join(File.dirname(__FILE__), 'fake_response', file_path)
|
19
|
-
)
|
20
|
-
)
|
21
|
-
)
|
22
|
-
end
|
23
|
-
FakeWeb.allow_net_connect = false
|
metadata
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-oauth2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
version: 0.
|
4
|
+
prerelease: 6
|
5
|
+
version: 0.8.0.alpha
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- nov matake
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-05-
|
13
|
+
date: 2011-05-19 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rack
|
@@ -35,14 +35,14 @@ dependencies:
|
|
35
35
|
type: :runtime
|
36
36
|
version_requirements: *id002
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
|
-
name:
|
38
|
+
name: httpclient
|
39
39
|
prerelease: false
|
40
40
|
requirement: &id003 !ruby/object:Gem::Requirement
|
41
41
|
none: false
|
42
42
|
requirements:
|
43
43
|
- - ">="
|
44
44
|
- !ruby/object:Gem::Version
|
45
|
-
version:
|
45
|
+
version: 2.2.0.2
|
46
46
|
type: :runtime
|
47
47
|
version_requirements: *id003
|
48
48
|
- !ruby/object:Gem::Dependency
|
@@ -115,14 +115,14 @@ dependencies:
|
|
115
115
|
type: :development
|
116
116
|
version_requirements: *id009
|
117
117
|
- !ruby/object:Gem::Dependency
|
118
|
-
name:
|
118
|
+
name: webmock
|
119
119
|
prerelease: false
|
120
120
|
requirement: &id010 !ruby/object:Gem::Requirement
|
121
121
|
none: false
|
122
122
|
requirements:
|
123
123
|
- - ">="
|
124
124
|
- !ruby/object:Gem::Version
|
125
|
-
version:
|
125
|
+
version: 1.6.2
|
126
126
|
type: :development
|
127
127
|
version_requirements: *id010
|
128
128
|
description: OAuth 2.0 Server & Client Library. Both Bearer and MAC token type are supported.
|
@@ -146,6 +146,7 @@ files:
|
|
146
146
|
- VERSION
|
147
147
|
- lib/rack/oauth2.rb
|
148
148
|
- lib/rack/oauth2/access_token.rb
|
149
|
+
- lib/rack/oauth2/access_token/authenticator.rb
|
149
150
|
- lib/rack/oauth2/access_token/bearer.rb
|
150
151
|
- lib/rack/oauth2/access_token/legacy.rb
|
151
152
|
- lib/rack/oauth2/access_token/mac.rb
|
@@ -183,15 +184,17 @@ files:
|
|
183
184
|
- lib/rack/oauth2/server/token/refresh_token.rb
|
184
185
|
- lib/rack/oauth2/util.rb
|
185
186
|
- rack-oauth2.gemspec
|
186
|
-
- spec/fake_response/errors/invalid_request.json
|
187
|
-
- spec/fake_response/resources/fake.txt
|
188
|
-
- spec/fake_response/tokens/bearer.json
|
189
|
-
- spec/fake_response/tokens/legacy.json
|
190
|
-
- spec/fake_response/tokens/legacy.txt
|
191
|
-
- spec/fake_response/tokens/legacy_without_expires_in.txt
|
192
|
-
- spec/fake_response/tokens/mac.json
|
193
|
-
- spec/fake_response/tokens/unknown.json
|
194
187
|
- spec/helpers/time.rb
|
188
|
+
- spec/helpers/webmock_helper.rb
|
189
|
+
- spec/mock_response/errors/invalid_request.json
|
190
|
+
- spec/mock_response/resources/fake.txt
|
191
|
+
- spec/mock_response/tokens/bearer.json
|
192
|
+
- spec/mock_response/tokens/legacy.json
|
193
|
+
- spec/mock_response/tokens/legacy.txt
|
194
|
+
- spec/mock_response/tokens/legacy_without_expires_in.txt
|
195
|
+
- spec/mock_response/tokens/mac.json
|
196
|
+
- spec/mock_response/tokens/unknown.json
|
197
|
+
- spec/rack/oauth2/access_token/authenticator_spec.rb
|
195
198
|
- spec/rack/oauth2/access_token/bearer_spec.rb
|
196
199
|
- spec/rack/oauth2/access_token/legacy_spec.rb
|
197
200
|
- spec/rack/oauth2/access_token/mac/body_hash_spec.rb
|
@@ -248,15 +251,17 @@ signing_key:
|
|
248
251
|
specification_version: 3
|
249
252
|
summary: OAuth 2.0 Server & Client Library - Both Bearer and MAC token type are supported
|
250
253
|
test_files:
|
251
|
-
- spec/fake_response/errors/invalid_request.json
|
252
|
-
- spec/fake_response/resources/fake.txt
|
253
|
-
- spec/fake_response/tokens/bearer.json
|
254
|
-
- spec/fake_response/tokens/legacy.json
|
255
|
-
- spec/fake_response/tokens/legacy.txt
|
256
|
-
- spec/fake_response/tokens/legacy_without_expires_in.txt
|
257
|
-
- spec/fake_response/tokens/mac.json
|
258
|
-
- spec/fake_response/tokens/unknown.json
|
259
254
|
- spec/helpers/time.rb
|
255
|
+
- spec/helpers/webmock_helper.rb
|
256
|
+
- spec/mock_response/errors/invalid_request.json
|
257
|
+
- spec/mock_response/resources/fake.txt
|
258
|
+
- spec/mock_response/tokens/bearer.json
|
259
|
+
- spec/mock_response/tokens/legacy.json
|
260
|
+
- spec/mock_response/tokens/legacy.txt
|
261
|
+
- spec/mock_response/tokens/legacy_without_expires_in.txt
|
262
|
+
- spec/mock_response/tokens/mac.json
|
263
|
+
- spec/mock_response/tokens/unknown.json
|
264
|
+
- spec/rack/oauth2/access_token/authenticator_spec.rb
|
260
265
|
- spec/rack/oauth2/access_token/bearer_spec.rb
|
261
266
|
- spec/rack/oauth2/access_token/legacy_spec.rb
|
262
267
|
- spec/rack/oauth2/access_token/mac/body_hash_spec.rb
|