我有一个代码库,我们在有限的容量中使用AWS CloudFront,并试图通过此处记录的API端点获取分发失效的状态:http://docs.aws.amazon.com/cloudfront/latest/APIReference/API_GetInvalidation.html
此端点要求使用我正在处理的AWS4签名对请求标头进行签名。我根据AWS SDK for Ruby中的签名代码对我的大部分请求签名代码进行了建模:https://github.com/aws/aws-sdk-ruby/blob/master/aws-sdk-core/lib/aws-sdk-core/signers/v4.rb
我的代码如下:
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 do |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([]) do |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
当我调用CFAgent.cfinvalidation_status时,我收到403错误,其中包含&#34; MissingInvalidationToken&#34;码。 &#34; SimpleHTTP&#34;是一个简单的库,它包装Net / HTTP以发出HTTP / HTTPS请求(请假设这有效)。
我错过了什么?
提前致谢。