rack-oauth2-revibe 1.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.gitignore +22 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +3 -0
  6. data/Gemfile +7 -0
  7. data/LICENSE +20 -0
  8. data/README.rdoc +78 -0
  9. data/Rakefile +25 -0
  10. data/VERSION +1 -0
  11. data/lib/rack/oauth2.rb +67 -0
  12. data/lib/rack/oauth2/access_token.rb +36 -0
  13. data/lib/rack/oauth2/access_token/authenticator.rb +24 -0
  14. data/lib/rack/oauth2/access_token/bearer.rb +11 -0
  15. data/lib/rack/oauth2/access_token/legacy.rb +23 -0
  16. data/lib/rack/oauth2/access_token/mac.rb +103 -0
  17. data/lib/rack/oauth2/access_token/mac/sha256_hex_verifier.rb +17 -0
  18. data/lib/rack/oauth2/access_token/mac/signature.rb +34 -0
  19. data/lib/rack/oauth2/access_token/mac/verifier.rb +44 -0
  20. data/lib/rack/oauth2/client.rb +139 -0
  21. data/lib/rack/oauth2/client/error.rb +14 -0
  22. data/lib/rack/oauth2/client/grant.rb +30 -0
  23. data/lib/rack/oauth2/client/grant/authorization_code.rb +12 -0
  24. data/lib/rack/oauth2/client/grant/client_credentials.rb +10 -0
  25. data/lib/rack/oauth2/client/grant/facebook_token.rb +12 -0
  26. data/lib/rack/oauth2/client/grant/password.rb +11 -0
  27. data/lib/rack/oauth2/client/grant/refresh_token.rb +11 -0
  28. data/lib/rack/oauth2/debugger.rb +3 -0
  29. data/lib/rack/oauth2/debugger/request_filter.rb +30 -0
  30. data/lib/rack/oauth2/server.rb +4 -0
  31. data/lib/rack/oauth2/server/abstract.rb +4 -0
  32. data/lib/rack/oauth2/server/abstract/error.rb +69 -0
  33. data/lib/rack/oauth2/server/abstract/handler.rb +20 -0
  34. data/lib/rack/oauth2/server/abstract/request.rb +29 -0
  35. data/lib/rack/oauth2/server/abstract/response.rb +15 -0
  36. data/lib/rack/oauth2/server/authorize.rb +117 -0
  37. data/lib/rack/oauth2/server/authorize/code.rb +39 -0
  38. data/lib/rack/oauth2/server/authorize/error.rb +71 -0
  39. data/lib/rack/oauth2/server/authorize/extension.rb +12 -0
  40. data/lib/rack/oauth2/server/authorize/extension/code_and_token.rb +39 -0
  41. data/lib/rack/oauth2/server/authorize/token.rb +43 -0
  42. data/lib/rack/oauth2/server/resource.rb +55 -0
  43. data/lib/rack/oauth2/server/resource/bearer.rb +47 -0
  44. data/lib/rack/oauth2/server/resource/bearer/error.rb +24 -0
  45. data/lib/rack/oauth2/server/resource/error.rb +81 -0
  46. data/lib/rack/oauth2/server/resource/mac.rb +36 -0
  47. data/lib/rack/oauth2/server/resource/mac/error.rb +24 -0
  48. data/lib/rack/oauth2/server/token.rb +87 -0
  49. data/lib/rack/oauth2/server/token/authorization_code.rb +28 -0
  50. data/lib/rack/oauth2/server/token/client_credentials.rb +23 -0
  51. data/lib/rack/oauth2/server/token/error.rb +54 -0
  52. data/lib/rack/oauth2/server/token/extension.rb +12 -0
  53. data/lib/rack/oauth2/server/token/extension/jwt.rb +37 -0
  54. data/lib/rack/oauth2/server/token/facebook_token.rb +27 -0
  55. data/lib/rack/oauth2/server/token/password.rb +27 -0
  56. data/lib/rack/oauth2/server/token/refresh_token.rb +26 -0
  57. data/lib/rack/oauth2/util.rb +58 -0
  58. data/rack-oauth2.gemspec +30 -0
  59. data/spec/helpers/time.rb +19 -0
  60. data/spec/helpers/webmock_helper.rb +41 -0
  61. data/spec/mock_response/blank +0 -0
  62. data/spec/mock_response/errors/invalid_request.json +4 -0
  63. data/spec/mock_response/resources/fake.txt +1 -0
  64. data/spec/mock_response/tokens/_Bearer.json +6 -0
  65. data/spec/mock_response/tokens/bearer.json +6 -0
  66. data/spec/mock_response/tokens/legacy.json +5 -0
  67. data/spec/mock_response/tokens/legacy.txt +1 -0
  68. data/spec/mock_response/tokens/legacy_without_expires_in.txt +1 -0
  69. data/spec/mock_response/tokens/mac.json +8 -0
  70. data/spec/mock_response/tokens/unknown.json +6 -0
  71. data/spec/rack/oauth2/access_token/authenticator_spec.rb +43 -0
  72. data/spec/rack/oauth2/access_token/bearer_spec.rb +18 -0
  73. data/spec/rack/oauth2/access_token/legacy_spec.rb +23 -0
  74. data/spec/rack/oauth2/access_token/mac/sha256_hex_verifier_spec.rb +28 -0
  75. data/spec/rack/oauth2/access_token/mac/signature_spec.rb +59 -0
  76. data/spec/rack/oauth2/access_token/mac/verifier_spec.rb +25 -0
  77. data/spec/rack/oauth2/access_token/mac_spec.rb +141 -0
  78. data/spec/rack/oauth2/access_token_spec.rb +69 -0
  79. data/spec/rack/oauth2/client/error_spec.rb +18 -0
  80. data/spec/rack/oauth2/client/grant/authorization_code_spec.rb +37 -0
  81. data/spec/rack/oauth2/client/grant/client_credentials_spec.rb +7 -0
  82. data/spec/rack/oauth2/client/grant/password_spec.rb +33 -0
  83. data/spec/rack/oauth2/client/grant/refresh_token_spec.rb +21 -0
  84. data/spec/rack/oauth2/client_spec.rb +287 -0
  85. data/spec/rack/oauth2/debugger/request_filter_spec.rb +33 -0
  86. data/spec/rack/oauth2/oauth2_spec.rb +74 -0
  87. data/spec/rack/oauth2/server/abstract/error_spec.rb +59 -0
  88. data/spec/rack/oauth2/server/authorize/code_spec.rb +57 -0
  89. data/spec/rack/oauth2/server/authorize/error_spec.rb +103 -0
  90. data/spec/rack/oauth2/server/authorize/extensions/code_and_token_spec.rb +60 -0
  91. data/spec/rack/oauth2/server/authorize/token_spec.rb +73 -0
  92. data/spec/rack/oauth2/server/authorize_spec.rb +214 -0
  93. data/spec/rack/oauth2/server/resource/bearer/error_spec.rb +52 -0
  94. data/spec/rack/oauth2/server/resource/bearer_spec.rb +123 -0
  95. data/spec/rack/oauth2/server/resource/error_spec.rb +147 -0
  96. data/spec/rack/oauth2/server/resource/mac/error_spec.rb +52 -0
  97. data/spec/rack/oauth2/server/resource/mac_spec.rb +119 -0
  98. data/spec/rack/oauth2/server/resource_spec.rb +23 -0
  99. data/spec/rack/oauth2/server/token/authorization_code_spec.rb +43 -0
  100. data/spec/rack/oauth2/server/token/client_credentials_spec.rb +23 -0
  101. data/spec/rack/oauth2/server/token/error_spec.rb +77 -0
  102. data/spec/rack/oauth2/server/token/password_spec.rb +37 -0
  103. data/spec/rack/oauth2/server/token/refresh_token_spec.rb +34 -0
  104. data/spec/rack/oauth2/server/token_spec.rb +134 -0
  105. data/spec/rack/oauth2/util_spec.rb +97 -0
  106. data/spec/spec_helper.rb +14 -0
  107. metadata +326 -0
@@ -0,0 +1,27 @@
1
+ module Rack
2
+ module OAuth2
3
+ module Server
4
+ class Token
5
+ class FacebookToken < Abstract::Handler
6
+ def call(env)
7
+ @request = Request.new(env)
8
+ @response = Response.new(request)
9
+ super
10
+ end
11
+
12
+ class Request < Token::Request
13
+ attr_required :facebook_token
14
+
15
+ def initialize(env)
16
+ super
17
+ @grant_type = :facebook_token
18
+ @facebook_token = params['facebook_token']
19
+ attr_missing!
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+
@@ -0,0 +1,27 @@
1
+ module Rack
2
+ module OAuth2
3
+ module Server
4
+ class Token
5
+ class Password < Abstract::Handler
6
+ def call(env)
7
+ @request = Request.new(env)
8
+ @response = Response.new(request)
9
+ super
10
+ end
11
+
12
+ class Request < Token::Request
13
+ attr_required :username, :password
14
+
15
+ def initialize(env)
16
+ super
17
+ @grant_type = :password
18
+ @username = params['username']
19
+ @password = params['password']
20
+ attr_missing!
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,26 @@
1
+ module Rack
2
+ module OAuth2
3
+ module Server
4
+ class Token
5
+ class RefreshToken < Abstract::Handler
6
+ def call(env)
7
+ @request = Request.new(env)
8
+ @response = Response.new(request)
9
+ super
10
+ end
11
+
12
+ class Request < Token::Request
13
+ attr_required :refresh_token
14
+
15
+ def initialize(env)
16
+ super
17
+ @grant_type = :refresh_token
18
+ @refresh_token = params['refresh_token']
19
+ attr_missing!
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,58 @@
1
+ require 'base64'
2
+
3
+ module Rack
4
+ module OAuth2
5
+ module Util
6
+ class << self
7
+ def rfc3986_encode(text)
8
+ URI.encode(text, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
9
+ end
10
+
11
+ def base64_encode(text)
12
+ Base64.encode64(text).gsub(/\n/, '')
13
+ end
14
+
15
+ def compact_hash(hash)
16
+ hash.reject do |key, value|
17
+ value.blank?
18
+ end
19
+ end
20
+
21
+ def parse_uri(uri)
22
+ case uri
23
+ when URI::Generic
24
+ uri
25
+ when String
26
+ URI.parse(uri)
27
+ else
28
+ raise "Invalid format of URI is given."
29
+ end
30
+ end
31
+
32
+ def redirect_uri(base_uri, location, params)
33
+ redirect_uri = parse_uri base_uri
34
+ case location
35
+ when :query
36
+ redirect_uri.query = [redirect_uri.query, Util.compact_hash(params).to_query].compact.join('&')
37
+ when :fragment
38
+ redirect_uri.fragment = Util.compact_hash(params).to_query
39
+ end
40
+ redirect_uri.to_s
41
+ end
42
+
43
+ def uri_match?(base, given)
44
+ base = parse_uri(base)
45
+ given = parse_uri(given)
46
+ base.path = '/' if base.path.blank?
47
+ given.path = '/' if given.path.blank?
48
+ [:scheme, :host, :port].all? do |key|
49
+ base.send(key) == given.send(key)
50
+ end && /^#{base.path}/ =~ given.path
51
+ rescue
52
+ false
53
+ end
54
+
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,30 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "rack-oauth2-revibe"
3
+ s.version = File.read("VERSION")
4
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.3.6") if s.respond_to? :required_rubygems_version=
5
+ s.authors = ["nov matake"]
6
+ s.description = %q{OAuth 2.0 Server & Client Library. Both Bearer and MAC token type are supported.}
7
+ s.summary = %q{OAuth 2.0 Server & Client Library - Both Bearer and MAC token type are supported}
8
+ s.email = "nov@matake.jp"
9
+ s.extra_rdoc_files = ["LICENSE", "README.rdoc"]
10
+ s.rdoc_options = ["--charset=UTF-8"]
11
+ s.homepage = "http://github.com/nov/rack-oauth2"
12
+ s.license = 'MIT'
13
+ s.require_paths = ["lib"]
14
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.add_runtime_dependency "rack", ">= 1.1"
18
+ s.add_runtime_dependency "multi_json", ">= 1.3.6"
19
+ s.add_runtime_dependency "httpclient", ">= 2.2.0.2"
20
+ s.add_runtime_dependency "activesupport", ">= 2.3"
21
+ s.add_runtime_dependency "attr_required", ">= 0.0.5"
22
+ s.add_development_dependency "rake", ">= 0.8"
23
+ if RUBY_VERSION >= '1.9'
24
+ s.add_development_dependency "cover_me", ">= 1.2.0"
25
+ else
26
+ s.add_development_dependency "rcov", ">= 0.9"
27
+ end
28
+ s.add_development_dependency "rspec", ">= 2"
29
+ s.add_development_dependency "webmock", ">= 1.6.2"
30
+ end
@@ -0,0 +1,19 @@
1
+ class Time
2
+ class << self
3
+ def now_with_fixed_time
4
+ if @fixed_time
5
+ @fixed_time.dup
6
+ else
7
+ now_without_fixed_time
8
+ end
9
+ end
10
+ alias_method_chain :now, :fixed_time
11
+
12
+ def fix(time = Time.now)
13
+ @fixed_time = time
14
+ yield
15
+ ensure
16
+ @fixed_time = nil
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,41 @@
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[:params]
17
+ case method
18
+ when :post, :put
19
+ request[:body] = options[:params]
20
+ else
21
+ request[:query] = options[:params]
22
+ end
23
+ end
24
+ if options[:request_header]
25
+ request[:headers] = options[:request_header]
26
+ end
27
+ request
28
+ end
29
+
30
+ def response_for(response_file, options = {})
31
+ response = {}
32
+ response[:body] = File.new(File.join(File.dirname(__FILE__), '../mock_response', response_file))
33
+ if options[:status]
34
+ response[:status] = options[:status]
35
+ end
36
+ response
37
+ end
38
+ end
39
+
40
+ include WebMockHelper
41
+ WebMock.disable_net_connect!
File without changes
@@ -0,0 +1,4 @@
1
+ {
2
+ "error":"invalid_request",
3
+ "error_description":"error description"
4
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "access_token":"access_token",
3
+ "refresh_token":"refresh_token",
4
+ "token_type":"Bearer",
5
+ "expires_in":3600
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "access_token":"access_token",
3
+ "refresh_token":"refresh_token",
4
+ "token_type":"bearer",
5
+ "expires_in":3600
6
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "access_token":"access_token",
3
+ "refresh_token":"refresh_token",
4
+ "expires_in":3600
5
+ }
@@ -0,0 +1 @@
1
+ access_token=access_token&expires=3600
@@ -0,0 +1 @@
1
+ access_token=access_token
@@ -0,0 +1,8 @@
1
+ {
2
+ "token_type":"mac",
3
+ "mac_algorithm":"hmac-sha-256",
4
+ "expires_in":3600,
5
+ "mac_key":"secret",
6
+ "refresh_token":"refresh_token",
7
+ "access_token":"access_token"
8
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "access_token":"access_token",
3
+ "refresh_token":"refresh_token",
4
+ "token_type":"unknown",
5
+ "expires_in":3600
6
+ }
@@ -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
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rack::OAuth2::AccessToken::Bearer do
4
+ let :token do
5
+ Rack::OAuth2::AccessToken::Bearer.new(
6
+ :access_token => 'access_token'
7
+ )
8
+ end
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"}, {}) }
11
+
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)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rack::OAuth2::AccessToken::Legacy do
4
+ let :token do
5
+ Rack::OAuth2::AccessToken::Legacy.new(
6
+ :access_token => 'access_token'
7
+ )
8
+ end
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"}, {}) }
11
+
12
+ describe '#to_s' do
13
+ subject { token }
14
+ its(:to_s) { should == token.access_token }
15
+ end
16
+
17
+ describe '.authenticate' do
18
+ it 'should set Authorization header' do
19
+ request.header.should_receive(:[]=).with('Authorization', 'OAuth access_token')
20
+ token.authenticate(request)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rack::OAuth2::AccessToken::MAC::Sha256HexVerifier do
4
+
5
+ # From the example of webtopay wallet API spec
6
+ # ref) https://www.webtopay.com/wallet/#authentication
7
+ context 'when example from webtopay wallet API' do
8
+ subject do
9
+ Rack::OAuth2::AccessToken::MAC::Sha256HexVerifier.new(
10
+ :algorithm => 'hmac-sha-256',
11
+ :raw_body => 'grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA&redirect_uri=http%3A%2F%2Flocalhost%2Fabc'
12
+ )
13
+ end
14
+ its(:calculate) { should == '21fb73c40b589622d0c78e9cd8900f89d9472aa724d0e5c3eca9ac1cd9d2a6d5' }
15
+ end
16
+
17
+
18
+ context 'when raw_body is empty' do
19
+ subject do
20
+ Rack::OAuth2::AccessToken::MAC::Sha256HexVerifier.new(
21
+ :algorithm => 'hmac-sha-256',
22
+ :raw_body => ''
23
+ )
24
+ end
25
+ its(:calculate) { should be_nil }
26
+ end
27
+
28
+ end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rack::OAuth2::AccessToken::MAC::Signature do
4
+ # From the example of Webtopay wallet API
5
+ # ref) https://www.webtopay.com/wallet/
6
+ context 'when ext is not given' do
7
+ subject do
8
+ Rack::OAuth2::AccessToken::MAC::Signature.new(
9
+ :secret => 'IrdTc8uQodU7PRpLzzLTW6wqZAO6tAMU',
10
+ :algorithm => 'hmac-sha-256',
11
+ :nonce => 'dj83hs9s',
12
+ :ts => 1336363200,
13
+ :method => 'GET',
14
+ :request_uri => '/wallet/rest/api/v1/payment/123',
15
+ :host => 'www.webtopay.com',
16
+ :port => 443
17
+ )
18
+ end
19
+ its(:calculate) { should == 'OZE9fTk2qiRtL1jb01L8lRxC66PTiAGhMDEmboeVeLs=' }
20
+ end
21
+
22
+ # From the example of MAC spec section 1.1
23
+ # ref) http://tools.ietf.org/pdf/draft-ietf-oauth-v2-http-mac-01.pdf
24
+ context 'when ext is not given' do
25
+ subject do
26
+ Rack::OAuth2::AccessToken::MAC::Signature.new(
27
+ :secret => '489dks293j39',
28
+ :algorithm => 'hmac-sha-1',
29
+ :nonce => 'dj83hs9s',
30
+ :ts => 1336363200,
31
+ :method => 'GET',
32
+ :request_uri => '/resource/1?b=1&a=2',
33
+ :host => 'example.com',
34
+ :port => 80
35
+ )
36
+ end
37
+ its(:calculate) { should == '6T3zZzy2Emppni6bzL7kdRxUWL4=' }
38
+ end
39
+
40
+ # From the example of MAC spec section 3.2
41
+ # ref) http://tools.ietf.org/pdf/draft-ietf-oauth-v2-http-mac-01.pdf
42
+ context 'otherwise' do
43
+ subject do
44
+ Rack::OAuth2::AccessToken::MAC::Signature.new(
45
+ :secret => '489dks293j39',
46
+ :algorithm => 'hmac-sha-1',
47
+ :nonce => '7d8f3e4a',
48
+ :ts => 264095,
49
+ :method => 'POST',
50
+ :request_uri => '/request?b5=%3D%253D&a3=a&c%40=&a2=r%20b&c2&a3=2+q',
51
+ :host => 'example.com',
52
+ :port => 80,
53
+ :ext => 'a,b,c'
54
+ )
55
+ end
56
+ its(:calculate) { should == '+txL5oOFHGYjrfdNYH5VEzROaBY=' }
57
+ end
58
+
59
+ end