class AWS::Core::Signers::S3

@api private

Constants

QUERY_PARAMS
SUB_RESOURCES

Attributes

credentials[R]

@return [CredentialProviders::Provider]

Public Class Methods

new(credentials) click to toggle source

@param [CredentialProviders::Provider] credentials

# File lib/aws/core/signers/s3.rb, line 34
def initialize credentials
  @credentials = credentials
end

Private Class Methods

canonicalized_headers(req) click to toggle source

CanonicalizedAmzHeaders

See the developer guide for more information on how this element is generated.

# File lib/aws/core/signers/s3.rb, line 99
def canonicalized_headers req
  x_amz = req.headers.select{|k, v| k.to_s =~ /^x-amz-/i }
  x_amz = x_amz.collect{|k, v| [k.downcase, v] }
  x_amz = x_amz.sort_by{|k, v| k }
  x_amz = x_amz.collect{|k, v| "#{k}:#{v.to_s.strip}" }.join("\n")
  x_amz == '' ? nil : x_amz
end
canonicalized_resource(req) click to toggle source

From the S3 developer guide

CanonicalizedResource =
  [ "/" ` Bucket ] `
  <HTTP-Request-URI, protocol name up to the querystring> +
  [ sub-resource, if present. e.g. "?acl", "?location",
  "?logging", or "?torrent"];

@api private

# File lib/aws/core/signers/s3.rb, line 116
def canonicalized_resource req

  parts = []

  # virtual hosted-style requests require the hostname to appear
  # in the canonicalized resource prefixed by a forward slash.
  if
    AWS::S3::Client.dns_compatible_bucket_name?(req.bucket) and
    !req.path_style?
  then
    parts << "/#{req.bucket}"
  end

  # all requests require the portion of the un-decoded uri up to
  # but not including the query string
  parts << req.path

  # lastly any sub resource querystring params need to be appened
  # in lexigraphical ordered joined by '&' and prefixed by '?'
  params =
    sub_resource_params(req) +
    query_parameters_for_signature(req)

  unless params.empty?
    parts << '?'
    parts << params.sort.collect{|p| p.to_s }.join('&')
  end

  parts.join
end
query_parameters_for_signature(req) click to toggle source
# File lib/aws/core/signers/s3.rb, line 151
def query_parameters_for_signature req
  req.params.select { |p| QUERY_PARAMS.include?(p.name) }
end
signing_string_date(req) click to toggle source
# File lib/aws/core/signers/s3.rb, line 84
def signing_string_date req
  # if a date is provided via x-amz-date then we should omit the
  # Date header from the signing string (should appear as a blank line)
  if req.headers.detect{|k,v| k.to_s =~ /^x-amz-date$/i }
    ''
  else
    req.headers['date'] ||= Time.now.httpdate
  end
end
string_to_sign(req) click to toggle source

From the S3 developer guide:

StringToSign =
  HTTP-Verb ` "\n" `
  content-md5 ` "\n" `
  content-type ` "\n" `
  date ` "\n" `
  CanonicalizedAmzHeaders + CanonicalizedResource;
# File lib/aws/core/signers/s3.rb, line 74
def string_to_sign req
  [
    req.http_method,
    req.headers.values_at('content-md5', 'content-type').join("\n"),
    signing_string_date(req),
    canonicalized_headers(req),
    canonicalized_resource(req),
  ].flatten.compact.join("\n")
end
sub_resource_params(req) click to toggle source
# File lib/aws/core/signers/s3.rb, line 147
def sub_resource_params req
  req.params.select{|p| SUB_RESOURCES.include?(p.name) }
end

Public Instance Methods

sign_request(req) click to toggle source

@param [Http::Request] req @return [Http::Request]

# File lib/aws/core/signers/s3.rb, line 43
def sign_request req
  if token = credentials.session_token
    req.headers["x-amz-security-token"] = token
  end
  req.headers["authorization"] = authorization(req)
end

Private Instance Methods

authorization(req) click to toggle source
# File lib/aws/core/signers/s3.rb, line 52
def authorization req
  "AWS #{credentials.access_key_id}:#{signature(req)}"
end
signature(req) click to toggle source
# File lib/aws/core/signers/s3.rb, line 56
def signature req
  secret = credentials.secret_access_key
  signature = self.class.string_to_sign(req)
  signature = Base.sign(credentials.secret_access_key, signature, 'sha1')
  URI.escape(signature)
end