class Aws::SNS::MessageVerifier
A utility class that can be used to verify the authenticity of messages sent by Amazon SNS
.
verifier = Aws::SNS::MessageVerifier.new # returns true/false verifier.authentic?(message_body) # raises a Aws::SNS::MessageVerifier::VerificationError on failure verifier.authenticate!(message_body)
You can re-use a single {MessageVerifier} instance to authenticate multiple SNS
messages.
Constants
- AWS_HOSTNAMES
@api private
- SIGNABLE_KEYS
@api private
Public Class Methods
new(http_options = {})
click to toggle source
@param [Hash] http_options Supported options to be passed to Net::HTTP. @option http_options [String] :http_proxy A proxy to send
requests through. Formatted like 'http://proxy.com:123'.
# File lib/aws-sdk-sns/message_verifier.rb, line 46 def initialize(http_options = {}) @cached_pems = {} @http_proxy = http_options[:http_proxy] end
Public Instance Methods
authentic?(message_body)
click to toggle source
@param [String<JSON>] message_body @return [Boolean] Returns `true` if the given message has been
successfully verified. Returns `false` otherwise.
# File lib/aws-sdk-sns/message_verifier.rb, line 54 def authentic?(message_body) authenticate!(message_body) rescue VerificationError false end
authenticate!(message_body)
click to toggle source
@param [String<JSON>] message_body @return [Boolean] Returns `true` when the given message has been
successfully verified.
@raise [VerificationError] Raised when the given message has failed
verification.
# File lib/aws-sdk-sns/message_verifier.rb, line 65 def authenticate!(message_body) msg = Json.load(message_body) msg = convert_lambda_msg(msg) if is_from_lambda(msg) if public_key(msg).verify(sha1, signature(msg), canonical_string(msg)) true else msg = 'the authenticity of the message cannot be verified' raise VerificationError, msg end end
Private Instance Methods
canonical_string(message)
click to toggle source
# File lib/aws-sdk-sns/message_verifier.rb, line 99 def canonical_string(message) parts = [] SIGNABLE_KEYS.each do |key| value = message[key] unless value.nil? or value.empty? parts << "#{key}\n#{value}\n" end end parts.join end
convert_lambda_msg(message)
click to toggle source
# File lib/aws-sdk-sns/message_verifier.rb, line 82 def convert_lambda_msg(message) cert_url = message.delete('SigningCertUrl') unsubscribe_url = message.delete('UnsubscribeUrl') message['SigningCertURL'] = cert_url message['UnsubscribeURL'] = unsubscribe_url message end
download_pem(uri)
click to toggle source
# File lib/aws-sdk-sns/message_verifier.rb, line 124 def download_pem(uri) verify_uri!(uri) https_get(uri) end
http_proxy_parts()
click to toggle source
# File lib/aws-sdk-sns/message_verifier.rb, line 178 def http_proxy_parts # empty string if not configured, URI parts return nil http_proxy = URI.parse(@http_proxy.to_s) [ http_proxy.host, http_proxy.port, (http_proxy.user && CGI.unescape(http_proxy.user)), (http_proxy.password && CGI.unescape(http_proxy.password)) ] end
https_get(uri, failed_attempts = 0)
click to toggle source
# File lib/aws-sdk-sns/message_verifier.rb, line 156 def https_get(uri, failed_attempts = 0) args = [] args << uri.host args << uri.port args += http_proxy_parts http = Net::HTTP.new(*args.compact) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_PEER http.start resp = http.request(Net::HTTP::Get.new(uri.request_uri)) http.finish if resp.code == '200' resp.body else raise VerificationError, resp.body end rescue => error failed_attempts += 1 retry if failed_attempts < 3 raise VerificationError, error.message end
is_from_lambda(message)
click to toggle source
# File lib/aws-sdk-sns/message_verifier.rb, line 78 def is_from_lambda(message) message.key? 'SigningCertUrl' end
pem(uri)
click to toggle source
# File lib/aws-sdk-sns/message_verifier.rb, line 116 def pem(uri) if @cached_pems[uri.to_s] @cached_pems[uri.to_s] else @cached_pems[uri.to_s] = download_pem(uri) end end
public_key(message)
click to toggle source
# File lib/aws-sdk-sns/message_verifier.rb, line 110 def public_key(message) x509_url = URI.parse(message['SigningCertURL']) x509 = OpenSSL::X509::Certificate.new(pem(x509_url)) OpenSSL::PKey::RSA.new(x509.public_key) end
sha1()
click to toggle source
# File lib/aws-sdk-sns/message_verifier.rb, line 91 def sha1 OpenSSL::Digest::SHA1.new end
signature(message)
click to toggle source
# File lib/aws-sdk-sns/message_verifier.rb, line 95 def signature(message) Base64.decode64(message['Signature']) end
verify_hosted_by_aws!(uri)
click to toggle source
# File lib/aws-sdk-sns/message_verifier.rb, line 142 def verify_hosted_by_aws!(uri) unless AWS_HOSTNAMES.any? { |pattern| pattern.match(uri.host) } msg = "signing cert is not hosted by AWS: #{uri}" raise VerificationError, msg end end
verify_https!(uri)
click to toggle source
# File lib/aws-sdk-sns/message_verifier.rb, line 135 def verify_https!(uri) unless uri.scheme == 'https' msg = "the SigningCertURL must be https, got: #{uri}" raise VerificationError, msg end end
verify_pem!(uri)
click to toggle source
# File lib/aws-sdk-sns/message_verifier.rb, line 149 def verify_pem!(uri) unless File.extname(uri.path) == '.pem' msg = "the SigningCertURL must link to a .pem file" raise VerificationError, msg end end
verify_uri!(uri)
click to toggle source
# File lib/aws-sdk-sns/message_verifier.rb, line 129 def verify_uri!(uri) verify_https!(uri) verify_hosted_by_aws!(uri) verify_pem!(uri) end