rack-oauth2-revibe 1.0.7

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.
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,17 @@
1
+ module Rack
2
+ module OAuth2
3
+ class AccessToken
4
+ class MAC
5
+ class Sha256HexVerifier < Verifier
6
+ attr_optional :raw_body
7
+
8
+ def calculate
9
+ return nil unless raw_body.present?
10
+
11
+ OpenSSL::Digest::SHA256.new.digest(raw_body).unpack('H*').first
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,34 @@
1
+ module Rack
2
+ module OAuth2
3
+ class AccessToken
4
+ class MAC
5
+ class Signature < Verifier
6
+ attr_required :secret, :ts, :nonce, :method, :request_uri, :host, :port
7
+ attr_optional :ext, :query
8
+
9
+ def calculate
10
+ Rack::OAuth2::Util.base64_encode OpenSSL::HMAC.digest(
11
+ hash_generator,
12
+ secret,
13
+ normalized_request_string
14
+ )
15
+ end
16
+
17
+ def normalized_request_string
18
+ [
19
+ ts.to_i,
20
+ nonce,
21
+ method.to_s.upcase,
22
+ request_uri,
23
+ host,
24
+ port,
25
+ ext || '',
26
+ nil
27
+ ].join("\n")
28
+ end
29
+
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,44 @@
1
+ module Rack
2
+ module OAuth2
3
+ class AccessToken
4
+ class MAC
5
+ class Verifier
6
+ include AttrRequired, AttrOptional
7
+ attr_required :algorithm
8
+
9
+ class VerificationFailed < StandardError; end
10
+
11
+ def initialize(attributes = {})
12
+ (required_attributes + optional_attributes).each do |key|
13
+ self.send :"#{key}=", attributes[key]
14
+ end
15
+ attr_missing!
16
+ rescue AttrRequired::AttrMissing => e
17
+ raise VerificationFailed.new("#{self.class.name.demodulize} Invalid: #{e.message}")
18
+ end
19
+
20
+ def verify!(expected)
21
+ if expected == self.calculate
22
+ :verified
23
+ else
24
+ raise VerificationFailed.new("#{self.class.name.demodulize} Invalid")
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def hash_generator
31
+ case algorithm.to_s
32
+ when 'hmac-sha-1'
33
+ OpenSSL::Digest::SHA1.new
34
+ when 'hmac-sha-256'
35
+ OpenSSL::Digest::SHA256.new
36
+ else
37
+ raise 'Unsupported Algorithm'
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,139 @@
1
+ module Rack
2
+ module OAuth2
3
+ class Client
4
+ include AttrRequired, AttrOptional
5
+ attr_required :identifier
6
+ attr_optional :secret, :redirect_uri, :scheme, :host, :port, :authorization_endpoint, :token_endpoint
7
+
8
+ def initialize(attributes = {})
9
+ (required_attributes + optional_attributes).each do |key|
10
+ self.send :"#{key}=", attributes[key]
11
+ end
12
+ @grant = Grant::ClientCredentials.new
13
+ @authorization_endpoint ||= '/oauth2/authorize'
14
+ @token_endpoint ||= '/oauth2/token'
15
+ attr_missing!
16
+ end
17
+
18
+ def authorization_uri(params = {})
19
+ params[:response_type] ||= :code
20
+ params[:response_type] = Array(params[:response_type]).join(' ')
21
+ params[:scope] = Array(params[:scope]).join(' ')
22
+ Util.redirect_uri absolute_uri_for(authorization_endpoint), :query, params.merge(
23
+ :client_id => self.identifier,
24
+ :redirect_uri => self.redirect_uri
25
+ )
26
+ end
27
+
28
+ def authorization_code=(code)
29
+ @grant = Grant::AuthorizationCode.new(
30
+ :code => code,
31
+ :redirect_uri => self.redirect_uri
32
+ )
33
+ end
34
+
35
+ def resource_owner_credentials=(credentials)
36
+ @grant = Grant::Password.new(
37
+ :username => credentials.first,
38
+ :password => credentials.last
39
+ )
40
+ end
41
+
42
+ def facebook_token=(token)
43
+ @grant = Grant::FacebookToken.new(
44
+ :facebook_token => token
45
+ )
46
+ end
47
+
48
+ def refresh_token=(token)
49
+ @grant = Grant::RefreshToken.new(
50
+ :refresh_token => token
51
+ )
52
+ end
53
+
54
+ def access_token!(*args)
55
+ headers, params = {}, @grant.as_json
56
+
57
+ # NOTE:
58
+ # Using Array#estract_options! for backward compatibility.
59
+ # Until v1.0.5, the first argument was 'client_auth_method' in scalar.
60
+ options = args.extract_options!
61
+ client_auth_method = args.first || options[:client_auth_method] || :basic
62
+
63
+ params[:scope] = Array(options[:scope]).join(' ') if options[:scope].present?
64
+
65
+ if secret && client_auth_method == :basic
66
+ cred = ["#{identifier}:#{secret}"].pack('m').tr("\n", '')
67
+ headers.merge!(
68
+ 'Authorization' => "Basic #{cred}"
69
+ )
70
+ else
71
+ params.merge!(
72
+ :client_id => identifier,
73
+ :client_secret => secret
74
+ )
75
+ end
76
+ handle_response do
77
+ Rack::OAuth2.http_client.post(
78
+ absolute_uri_for(token_endpoint),
79
+ Util.compact_hash(params),
80
+ headers
81
+ )
82
+ end
83
+ end
84
+
85
+ private
86
+
87
+ def absolute_uri_for(endpoint)
88
+ _endpoint_ = Util.parse_uri endpoint
89
+ _endpoint_.scheme ||= self.scheme || 'https'
90
+ _endpoint_.host ||= self.host
91
+ _endpoint_.port ||= self.port
92
+ raise 'No Host Info' unless _endpoint_.host
93
+ _endpoint_.to_s
94
+ end
95
+
96
+ def handle_response
97
+ response = yield
98
+ case response.status
99
+ when 200..201
100
+ handle_success_response response
101
+ else
102
+ handle_error_response response
103
+ end
104
+ end
105
+
106
+ def handle_success_response(response)
107
+ token_hash = parse_json response.body
108
+ case token_hash[:token_type].try(:downcase)
109
+ when 'bearer'
110
+ AccessToken::Bearer.new(token_hash)
111
+ when 'mac'
112
+ AccessToken::MAC.new(token_hash)
113
+ when nil
114
+ AccessToken::Legacy.new(token_hash)
115
+ else
116
+ raise 'Unknown Token Type'
117
+ end
118
+ rescue MultiJson::DecodeError
119
+ # NOTE: Facebook support (They don't use JSON as token response)
120
+ AccessToken::Legacy.new Rack::Utils.parse_nested_query(response.body).with_indifferent_access
121
+ end
122
+
123
+ def handle_error_response(response)
124
+ error = parse_json response.body
125
+ raise Error.new(response.status, error)
126
+ rescue MultiJson::DecodeError
127
+ raise Error.new(response.status, :error => 'Unknown', :error_description => response.body)
128
+ end
129
+
130
+ def parse_json(raw_json)
131
+ # MultiJson.parse('') returns nil when using MultiJson::Adapters::JsonGem
132
+ MultiJson.load(raw_json).try(:with_indifferent_access) || {}
133
+ end
134
+ end
135
+ end
136
+ end
137
+
138
+ require 'rack/oauth2/client/error'
139
+ require 'rack/oauth2/client/grant'
@@ -0,0 +1,14 @@
1
+ module Rack
2
+ module OAuth2
3
+ class Client
4
+ class Error < StandardError
5
+ attr_accessor :status, :response
6
+ def initialize(status, response)
7
+ @status = status
8
+ @response = response
9
+ super response[:error_description]
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,30 @@
1
+ module Rack
2
+ module OAuth2
3
+ class Client
4
+ class Grant
5
+ include AttrRequired, AttrOptional
6
+
7
+ def initialize(attributes = {})
8
+ (required_attributes + optional_attributes).each do |key|
9
+ self.send "#{key}=", attributes[key]
10
+ end
11
+ attr_missing!
12
+ end
13
+
14
+ def as_json(options = {})
15
+ (required_attributes + optional_attributes).inject({
16
+ :grant_type => self.class.name.demodulize.underscore.to_sym
17
+ }) do |hash, key|
18
+ hash.merge! key => self.send(key)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ require 'rack/oauth2/client/grant/authorization_code'
27
+ require 'rack/oauth2/client/grant/password'
28
+ require 'rack/oauth2/client/grant/facebook_token'
29
+ require 'rack/oauth2/client/grant/client_credentials'
30
+ require 'rack/oauth2/client/grant/refresh_token'
@@ -0,0 +1,12 @@
1
+ module Rack
2
+ module OAuth2
3
+ class Client
4
+ class Grant
5
+ class AuthorizationCode < Grant
6
+ attr_required :code
7
+ attr_optional :redirect_uri
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ module Rack
2
+ module OAuth2
3
+ class Client
4
+ class Grant
5
+ class ClientCredentials < Grant
6
+ end
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ module Rack
2
+ module OAuth2
3
+ class Client
4
+ class Grant
5
+ class FacebookToken < Grant
6
+ attr_required :facebook_token
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
12
+
@@ -0,0 +1,11 @@
1
+ module Rack
2
+ module OAuth2
3
+ class Client
4
+ class Grant
5
+ class Password < Grant
6
+ attr_required :username, :password
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Rack
2
+ module OAuth2
3
+ class Client
4
+ class Grant
5
+ class RefreshToken < Grant
6
+ attr_required :refresh_token
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ Dir[File.dirname(__FILE__) + '/debugger/*.rb'].each do |file|
2
+ require file
3
+ end
@@ -0,0 +1,30 @@
1
+ module Rack
2
+ module OAuth2
3
+ module Debugger
4
+ class RequestFilter
5
+ # Callback called in HTTPClient (before sending a request)
6
+ # request:: HTTP::Message
7
+ def filter_request(request)
8
+ started = "======= [Rack::OAuth2] HTTP REQUEST STARTED ======="
9
+ log started, request.dump
10
+ end
11
+
12
+ # Callback called in HTTPClient (after received a response)
13
+ # request:: HTTP::Message
14
+ # response:: HTTP::Message
15
+ def filter_response(request, response)
16
+ finished = "======= [Rack::OAuth2] HTTP REQUEST FINISHED ======="
17
+ log '-' * 50, response.dump, finished
18
+ end
19
+
20
+ private
21
+
22
+ def log(*outputs)
23
+ outputs.each do |output|
24
+ OAuth2.logger.info output
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,4 @@
1
+ require 'rack/oauth2/server/abstract'
2
+ require 'rack/oauth2/server/authorize'
3
+ require 'rack/oauth2/server/token'
4
+ require 'rack/oauth2/server/resource'
@@ -0,0 +1,4 @@
1
+ require 'rack/oauth2/server/abstract/handler'
2
+ require 'rack/oauth2/server/abstract/request'
3
+ require 'rack/oauth2/server/abstract/response'
4
+ require 'rack/oauth2/server/abstract/error'
@@ -0,0 +1,69 @@
1
+ module Rack
2
+ module OAuth2
3
+ module Server
4
+ module Abstract
5
+ class Error < StandardError
6
+ attr_accessor :status, :error, :description, :uri, :realm
7
+
8
+ def initialize(status, error, description = nil, options = {})
9
+ @status = status
10
+ @error = error
11
+ @description = description
12
+ @uri = options[:uri]
13
+ @realm = options[:realm]
14
+ super [error, description].compact.join(' :: ')
15
+ end
16
+
17
+ def protocol_params
18
+ {
19
+ :error => error,
20
+ :error_description => description,
21
+ :error_uri => uri
22
+ }
23
+ end
24
+
25
+ def finish
26
+ response = Rack::Response.new
27
+ response.status = status
28
+ yield response if block_given?
29
+ unless response.redirect?
30
+ response.header['Content-Type'] = 'application/json'
31
+ response.write MultiJson.dump(Util.compact_hash(protocol_params))
32
+ end
33
+ response.finish
34
+ end
35
+ end
36
+
37
+ class BadRequest < Error
38
+ def initialize(error = :bad_request, description = nil, options = {})
39
+ super 400, error, description, options
40
+ end
41
+ end
42
+
43
+ class Unauthorized < Error
44
+ def initialize(error = :unauthorized, description = nil, options = {})
45
+ super 401, error, description, options
46
+ end
47
+ end
48
+
49
+ class Forbidden < Error
50
+ def initialize(error = :forbidden, description = nil, options = {})
51
+ super 403, error, description, options
52
+ end
53
+ end
54
+
55
+ class ServerError < Error
56
+ def initialize(error = :forbidden, description = nil, options = {})
57
+ super 500, error, description, options
58
+ end
59
+ end
60
+
61
+ class TemporarilyUnavailable < Error
62
+ def initialize(error = :forbidden, description = nil, options = {})
63
+ super 503, error, description, options
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end