AWS4 request signing with Ruby -


i have codebase work aws cloudfront in limited capacity , trying status of distribution invalidation through api endpoint documented here: http://docs.aws.amazon.com/cloudfront/latest/apireference/api_getinvalidation.html

this endpoint requires request headers signed using aws4 signature, i'm stuggling with. i've modeled of request signing code based on signing code in aws sdk ruby: https://github.com/aws/aws-sdk-ruby/blob/master/aws-sdk-core/lib/aws-sdk-core/signers/v4.rb

my code follows:

class cfagent    rfc8601basic = "%y%m%dt%h%m%sz"   cf_agent_access_key = "validaccesskey"   cf_agent_secret_access_key = "validsecret"    def self.cf_dist_invalidation_status     dist_id = "abc123"     invalidation_id = "xyz"     url = "https://cloudfront.amazonaws.com/2017-03-25/#{dist_id}/invalidation/#{invalidation_id}"      headers = {       "content-type" => "application/json; charset=utf8"     }     headers = sign("get", uri.parse(url), headers, "{}", cf_agent_access_key, cf_agent_secret_access_key, "us-east-1")     puts "signed headers:", headers      res = simplehttp.get(url, headers)     puts "status:", res.code     puts "body:", res.body   end    def self.sign(method, uri, headers, body, access_key, secret_key, region, service_name=nil)     method = method.upcase     service = service_name || uri.host.split(".", 2)[0]      date_header = headers["date"] || headers["date"] || headers["date"]     date = (date_header ? time.parse(date_header) : time.zone.now).utc.strftime(rfc8601basic)      body_digest = hexdigest(body)      headers['x-amz-date'] = date     headers['host'] = host(uri)     headers['x-amz-content-sha256'] ||= body_digest      headers['authorization'] = authorization(method, uri, headers, body_digest, date, access_key, secret_key, region, service)     headers   end    private    def self.host(uri)     if ((uri.scheme == 'http' && uri.port == 80) || (uri.scheme == 'https' && uri.port = 443))       uri.host     else       "#{uri.host}:#{uri.port}"     end   end    def self.authorization(method, uri, headers, body_digest, date, access_key, secret_key, region, service)     [       "aws4-hmac-sha256 credential=#{credential(access_key, date, region, service)}",       "signedheaders=#{signed_headers(headers)}",       "signature=#{signature(method, uri, headers, body_digest, date, access_key, secret_key, region, service)}"     ].join(', ')   end    def self.credential(access_key, date, region, service)     "#{access_key}/#{credential_string(date, region, service)}"   end    def self.signature(method, uri, headers, body_digest, date, access_key, secret_key, region, service)     k_date = hmac("aws4" + secret_key, date[0,8])     k_region = hmac(k_date, region)     k_service = hmac(k_region, service)     k_credentials = hmac(k_service, "aws4_request")     hexhmac(k_credentials, string_to_sign(method, uri, headers, body_digest, date, access_key, secret_key, region, service))   end    def self.string_to_sign(method, uri, headers, body_digest, date, access_key, secret_key, region, service)     [       'aws4-hmac-sha256',       date,       credential_string(date, region, service),       hexdigest(canonical_request(method, uri, headers, body_digest))     ].join("\n")   end    def self.credential_string(date, region, service)     [       date[0,8],       region,       service,       "aws4_request"     ].join("/")   end    def self.canonical_request(method, uri, headers, body_digest)     [       method,       pathname.new(uri.path).cleanpath.to_s,       uri.query,       canonical_headers(headers),       signed_headers(headers),       body_digest     ].join("\n")   end    def self.canonical_headers(headers)     c_headers = []     headers.each_pair |k,v|       k = k.downcase       c_headers << [k,v]     end     c_headers = c_headers.sort_by(&:first)     c_headers.map{|k,v| "#{k}:#{canonical_header_value(v.to_s)}" }.join("\n")   end    def self.canonical_header_value(value)     value.match(/^".*"$/) ? value : value.gsub(/\s+/, ' ').strip   end    def self.signed_headers(headers)     headers.keys.inject([]) |signed_headers, header_key|       header_key = header_key.downcase       signed_headers << header_key       signed_headers     end.sort.join(';')   end    def self.hexdigest(value)     digest::sha256.new.update(value).hexdigest   end    def self.hmac(key, value)     openssl::hmac.digest(openssl::digest.new('sha256'), key, value)   end    def self.hexhmac(key, value)     openssl::hmac.hexdigest(openssl::digest.new('sha256'), key, value)   end  end 

when call cfagent.cfinvalidation_status, receive 403 error "missinginvalidationtoken" code. "simplehttp" simple library wraps net/http make http/https requests (please assume works).

what missing?

thanks in advance.


Comments

Popular posts from this blog

node.js - Node js - Trying to send POST request, but it is not loading javascript content -

javascript - Replicate keyboard event with html button -

javascript - Web audio api 5.1 surround example not working in firefox -