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.
15 16 17 18 19 20 21 22 |
# File 'lib/ey-hmac/adapter.rb', line 15 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!
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/ey-hmac/adapter.rb', line 110 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 siganature #{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
103 104 105 106 107 |
# File 'lib/ey-hmac/adapter.rb', line 103 def authenticated?(={}, &block) authenticated!(&block) rescue Ey::Hmac::Error false end |
#authorization(key_id, key_secret) ⇒ String
Returns HMAC header value of #request.
42 43 44 |
# File 'lib/ey-hmac/adapter.rb', line 42 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.
87 88 89 |
# File 'lib/ey-hmac/adapter.rb', line 87 def raise NotImplementedError end |
#body ⇒ String, NilClass
68 69 70 |
# File 'lib/ey-hmac/adapter.rb', line 68 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’
28 29 30 |
# File 'lib/ey-hmac/adapter.rb', line 28 def canonicalize [method, content_type, content_digest, date, path].join("\n") end |
#content_digest ⇒ String
Digest of body. Default is MD5.
61 62 63 |
# File 'lib/ey-hmac/adapter.rb', line 61 def content_digest raise NotImplementedError end |
#content_type ⇒ String
Returns value of the Content-Type header in #request.
74 75 76 |
# File 'lib/ey-hmac/adapter.rb', line 74 def content_type raise NotImplementedError end |
#date ⇒ String
Returns value of the Date header in #request.
81 82 83 |
# File 'lib/ey-hmac/adapter.rb', line 81 def date raise NotImplementedError end |
#method ⇒ String
Returns upcased request verb. i.e. ‘GET’.
48 49 50 |
# File 'lib/ey-hmac/adapter.rb', line 48 def method raise NotImplementedError end |
#path ⇒ String
Returns request path. i.e. ‘/blogs/1’.
54 55 56 |
# File 'lib/ey-hmac/adapter.rb', line 54 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
133 134 135 136 137 138 139 140 141 |
# File 'lib/ey-hmac/adapter.rb', line 133 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’
95 96 97 |
# File 'lib/ey-hmac/adapter.rb', line 95 def sign!(key_id, key_secret) raise NotImplementedError end |
#signature(key_secret, digest = self.sign_with) ⇒ String
Returns HMAC signature of #request.
35 36 37 |
# File 'lib/ey-hmac/adapter.rb', line 35 def signature(key_secret, digest = self.sign_with) Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest.new(digest.to_s), key_secret, canonicalize)).strip end |