lib/ey-hmac/adapter.rb in ey-hmac-2.1.0 vs lib/ey-hmac/adapter.rb in ey-hmac-2.2.0

- old
+ new

@@ -35,11 +35,13 @@ # @param [String] key_secret private HMAC key # @param [String] signature digest hash function. Defaults to #sign_with # @return [String] HMAC signature of {#request} def signature(key_secret, digest = self.sign_with) - Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest.new(digest.to_s), key_secret, canonicalize)).strip + Base64.strict_encode64( + OpenSSL::HMAC.digest( + OpenSSL::Digest.new(digest.to_s), key_secret, canonicalize)).strip end # @param [String] key_id public HMAC key # @param [String] key_secret private HMAC key # @return [String] HMAC header value of {#request} @@ -110,45 +112,64 @@ false end # @see Ey::Hmac#authenticate! def authenticated!(&block) - unless authorization_match = AUTHORIZATION_REGEXP.match(authorization_signature) - raise(Ey::Hmac::MissingAuthorization, "Failed to parse authorization_signature #{authorization_signature}") - end + key_id, signature_value = check_signature! + key_secret = block.call(key_id) - key_id = authorization_match[1] - signature_value = authorization_match[2] - - unless key_secret = block.call(key_id) - raise(Ey::Hmac::MissingSecret, "Failed to find secret matching #{key_id.inspect}") + unless key_secret + raise Ey::Hmac::MissingSecret, + "Failed to find secret matching #{key_id.inspect}" end - unless @ttl.nil? - expiry = Time.parse(date).to_i + @ttl - current_time = Time.now.to_i - unless expiry > current_time - raise(Ey::Hmac::ExpiredHmac, "Signature has expired passed #{expiry}. Current time is #{current_time}") - end - end + check_ttl! - calculated_signatures = self.accept_digests.map { |ad| signature(key_secret, ad) } + calculated_signatures = accept_digests.map { |ad| signature(key_secret, ad) } + matching_signature = calculated_signatures.any? { |cs| secure_compare(signature_value, cs) } - 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}") + unless matching_signature + raise Ey::Hmac::SignatureMismatch, + "Calculated signature #{signature_value} does not match #{calculated_signatures.inspect} using #{canonicalize.inspect}" end + true end alias authenticate! authenticated! + protected + # Constant time string comparison. # pulled from https://github.com/rack/rack/blob/master/lib/rack/utils.rb#L399 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 + + def check_ttl! + if @ttl && date + expiry = Time.parse(date).to_i + @ttl + current_time = Time.now.to_i + + unless expiry > current_time + raise Ey::Hmac::ExpiredHmac, + "Signature has expired passed #{expiry}. Current time is #{current_time}" + end + end + end + + def check_signature! + authorization_match = AUTHORIZATION_REGEXP.match(authorization_signature) + + unless authorization_match + raise Ey::Hmac::MissingAuthorization, + "Failed to parse authorization_signature #{authorization_signature}" + end + + [authorization_match[1], authorization_match[2]] end end