Class: Ey::Hmac::Adapter Abstract
- Inherits:
-
Object
- Object
- Ey::Hmac::Adapter
- Defined in:
- lib/ey-hmac/adapter.rb
Overview
override methods #method, #path, #body, #content_type and #content_digest
This class is responsible for forming the canonical string to used to sign requests
Defined Under Namespace
Constant Summary collapse
- AUTHORIZATION_REGEXP =
/\w+ ([^:]+):(.+)$/
Instance Attribute Summary collapse
-
#accept_digests ⇒ Object
readonly
Returns the value of attribute accept_digests.
-
#authorization_header ⇒ Object
readonly
Returns the value of attribute authorization_header.
-
#options ⇒ Object
readonly
Returns the value of attribute options.
-
#request ⇒ Object
readonly
Returns the value of attribute request.
-
#service ⇒ Object
readonly
Returns the value of attribute service.
-
#sign_with ⇒ Object
readonly
Returns the value of attribute sign_with.
Instance Method Summary collapse
- #authenticated!(&block) ⇒ Object (also: #authenticate!)
-
#authenticated?(options = {}) {|key_id| ... } ⇒ Boolean
Check #authorization_signature against calculated #signature.
-
#authorization(key_id, key_secret) ⇒ String
HMAC header value of #request.
-
#authorization_signature ⇒ String
abstract
Value of the #authorization_header.
- #body ⇒ String, NilClass abstract
-
#canonicalize ⇒ String
In order for the server to correctly authorize the request, the client and server MUST AGREE on this format.
-
#content_digest ⇒ String
abstract
Digest of body.
-
#content_type ⇒ String
abstract
Value of the Content-Type header in #request.
-
#date ⇒ String
abstract
Value of the Date header in #request.
-
#initialize(request, options = {}) ⇒ Adapter
constructor
A new instance of Adapter.
-
#method ⇒ String
abstract
Upcased request verb.
-
#path ⇒ String
abstract
Request path.
-
#secure_compare(a, b) ⇒ Object
Constant time string comparison.
-
#sign!(key_id, key_secret) ⇒ String
abstract
Add #signature header to request.
-
#signature(key_secret, digest = self.sign_with) ⇒ String
HMAC signature of #request.
Constructor Details
#initialize(request, options = {}) ⇒ Adapter
Returns a new instance of Adapter.
17 18 19 20 21 22 23 24 |
# File 'lib/ey-hmac/adapter.rb', line 17 def initialize(request, ={}) @request, @options = request, @authorization_header = [:authorization_header] || 'Authorization' @service = [:service] || 'EyHmac' @sign_with = [:sign_with] || :sha256 @accept_digests = Array([:accept_digests] || :sha256) end |
Instance Attribute Details
#accept_digests ⇒ Object (readonly)
Returns the value of attribute accept_digests.
9 10 11 |
# File 'lib/ey-hmac/adapter.rb', line 9 def accept_digests @accept_digests end |
#authorization_header ⇒ Object (readonly)
Returns the value of attribute authorization_header.
9 10 11 |
# File 'lib/ey-hmac/adapter.rb', line 9 def @authorization_header end |
#options ⇒ Object (readonly)
Returns the value of attribute options.
9 10 11 |
# File 'lib/ey-hmac/adapter.rb', line 9 def @options end |
#request ⇒ Object (readonly)
Returns the value of attribute request.
9 10 11 |
# File 'lib/ey-hmac/adapter.rb', line 9 def request @request end |
#service ⇒ Object (readonly)
Returns the value of attribute service.
9 10 11 |
# File 'lib/ey-hmac/adapter.rb', line 9 def service @service end |
#sign_with ⇒ Object (readonly)
Returns the value of attribute sign_with.
9 10 11 |
# File 'lib/ey-hmac/adapter.rb', line 9 def sign_with @sign_with end |
Instance Method Details
#authenticated!(&block) ⇒ Object Also known as: authenticate!
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/ey-hmac/adapter.rb', line 112 def authenticated!(&block) unless = AUTHORIZATION_REGEXP.match() raise(Ey::Hmac::MissingAuthorization, "Failed to parse authorization_signature #{}") end key_id = [1] signature_value = [2] unless key_secret = block.call(key_id) raise(Ey::Hmac::MissingSecret, "Failed to find secret matching #{key_id.inspect}") end calculated_signatures = self.accept_digests.map { |ad| signature(key_secret, ad) } unless calculated_signatures.any? { |cs| secure_compare(signature_value, cs) } raise(Ey::Hmac::SignatureMismatch, "Calculated signature #{signature_value} does not match #{calculated_signatures.inspect} using #{canonicalize.inspect}") end true end |
#authenticated?(options = {}) {|key_id| ... } ⇒ Boolean
Check #authorization_signature against calculated #signature
105 106 107 108 109 |
# File 'lib/ey-hmac/adapter.rb', line 105 def authenticated?(={}, &block) authenticated!(&block) rescue Ey::Hmac::Error false end |
#authorization(key_id, key_secret) ⇒ String
Returns HMAC header value of #request.
44 45 46 |
# File 'lib/ey-hmac/adapter.rb', line 44 def (key_id, key_secret) "#{service} #{key_id}:#{signature(key_secret, sign_with)}" end |
#authorization_signature ⇒ String
used when verifying a signed request
Returns value of the #authorization_header.
89 90 91 |
# File 'lib/ey-hmac/adapter.rb', line 89 def raise NotImplementedError end |
#body ⇒ String, NilClass
70 71 72 |
# File 'lib/ey-hmac/adapter.rb', line 70 def body raise NotImplementedError end |
#canonicalize ⇒ String
In order for the server to correctly authorize the request, the client and server MUST AGREE on this format
default canonical string formation is ‘#method\n#content_type\n#content_digest\n#date\n#path’
30 31 32 |
# File 'lib/ey-hmac/adapter.rb', line 30 def canonicalize [method, content_type, content_digest, date, path].join("\n") end |
#content_digest ⇒ String
Digest of body. Default is MD5.
63 64 65 |
# File 'lib/ey-hmac/adapter.rb', line 63 def content_digest raise NotImplementedError end |
#content_type ⇒ String
Returns value of the Content-Type header in #request.
76 77 78 |
# File 'lib/ey-hmac/adapter.rb', line 76 def content_type raise NotImplementedError end |
#date ⇒ String
Returns value of the Date header in #request.
83 84 85 |
# File 'lib/ey-hmac/adapter.rb', line 83 def date raise NotImplementedError end |
#method ⇒ String
Returns upcased request verb. i.e. ‘GET’.
50 51 52 |
# File 'lib/ey-hmac/adapter.rb', line 50 def method raise NotImplementedError end |
#path ⇒ String
Returns request path. i.e. ‘/blogs/1’.
56 57 58 |
# File 'lib/ey-hmac/adapter.rb', line 56 def path raise NotImplementedError end |
#secure_compare(a, b) ⇒ Object
Constant time string comparison. pulled from github.com/rack/rack/blob/master/lib/rack/utils.rb#L399
135 136 137 138 139 140 141 142 143 |
# File 'lib/ey-hmac/adapter.rb', line 135 def secure_compare(a, b) return false unless a.bytesize == b.bytesize l = a.unpack("C*") r, i = 0, -1 b.each_byte { |v| r |= v ^ l[i+=1] } r == 0 end |
#sign!(key_id, key_secret) ⇒ String
Add #signature header to request. Typically this is ‘Authorization’ or ‘WWW-Authorization’
97 98 99 |
# File 'lib/ey-hmac/adapter.rb', line 97 def sign!(key_id, key_secret) raise NotImplementedError end |
#signature(key_secret, digest = self.sign_with) ⇒ String
Returns HMAC signature of #request.
37 38 39 |
# File 'lib/ey-hmac/adapter.rb', line 37 def signature(key_secret, digest = self.sign_with) Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest.new(digest.to_s), key_secret, canonicalize)).strip end |