Class: Aws::Signature::V4::Signature

Inherits:
Object
  • Object
show all
Defined in:
lib/aws/signature/v4.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(region, key_id, secret_key, algorithm: 'AWS4-HMAC-SHA256', content_type: 'application/x-amz-json-1.0', content_type_sign_header: 'application/x-amz-json-1.0,application/x-www-form-urlencoded', t: nil) ⇒ Signature

Returns a new instance of Signature.

Parameters:

  • region (String)

    AWS region

  • key_id (String)

    AWS user key id

  • secret_key (String)

    AWS user secret key



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/aws/signature/v4.rb', line 20

def initialize (region, key_id, secret_key, algorithm: 'AWS4-HMAC-SHA256', content_type: 'application/x-amz-json-1.0', content_type_sign_header: 'application/x-amz-json-1.0,application/x-www-form-urlencoded', t: nil)
  # calculate date and time
  @t = t || Time.now.utc
  @date = @t.strftime('%Y%m%d')
  @time = @t.strftime('%Y%m%dT%H%M%SZ')
  # mandatory fields
  @region = region
  @key_id = key_id
  @secret_key = secret_key
  # optional fields
  @algorithm = algorithm
  # content type used as signing header for generating token
  @content_type_sign_header = content_type_sign_header
  # final content type sent with service request
  @content_type = content_type
end

Instance Attribute Details

#headersObject

Your code goes here…



15
16
17
# File 'lib/aws/signature/v4.rb', line 15

def headers
  @headers
end

#signatureObject

Your code goes here…



15
16
17
# File 'lib/aws/signature/v4.rb', line 15

def signature
  @signature
end

Instance Method Details

#generate_signature(service_name, amz_target, http_method, payload, host, uri) ⇒ String

Public - generates AWS authentication signature key v4 to use with low level API calls (not using AWS SDKs) This also sets ‘Authorization’ header in the current instance See docs.aws.amazon.com/general/latest/gr/signing_aws_api_requests.html for reference

Parameters:

  • service_name (String)

    AWS service name e.g. dynamodb

  • amz_target (String)

    AWS service target operation

  • http_method (String)

    HTTP method e.g. POST

  • payload (String)

    HTTP body content

  • host (String)

    HTTP host url

  • uri (String)

    HTTP path after host

Returns:

  • (String)

    signature string that can be used in Authentication header to allow access to AWS services using APIs



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/aws/signature/v4.rb', line 47

def generate_signature (service_name, amz_target, http_method, payload, host, uri)
  # remove protocol (http://, https://) from host
  host = host.sub(/^https?\:\/\/(www.)?/,'')
  # construct headers
  # ordering of header values is important, so we reconstruct rather than add new fields
  @headers = {
      'Content-Type': @content_type_sign_header,
      'Host': host,
      'X-Amz-Date': @time,
      'X-Amz-Target': amz_target
  }
  # calculate credential scope
  credential_scope = "#{@date}/#{@region}/#{service_name}/aws4_request"

  hashed_payload = Digest::hexencode(Digest::SHA256.digest(payload.to_json)).downcase

  # CanonicalHeaders
  canonical_headers = @headers.keys.map {|k,v| k.downcase }.join(';')
  canonical_headers_entry = @headers.map {|k,v| k.to_s.downcase + ':' + v.to_s }.join("\n")

  # Task 1: Create a Canonical Request For Signature Version 4
  # http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
  canonical_request =
      "#{http_method}\n"\
      "#{uri}\n"\
      "\n"\
      "#{canonical_headers_entry}\n"\
      "\n"\
      "#{canonical_headers}\n"\
      "#{hashed_payload}"

  hashed_canonical_request = Digest::hexencode(Digest::SHA256.digest(canonical_request)).downcase

  # Task 2: Create a String to Sign for Signature Version 4
  # http://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html
  string_to_sign =
      "#{@algorithm}\n"\
      "#{@time}\n"\
      "#{credential_scope}\n"\
      "#{hashed_canonical_request}"

  # Task 3: Calculate the AWS Signature Version 4
  # http://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html
  signingKey = get_signature_key (service_name)

  # Task 4: Add the Signing Information to the Request
  # http://docs.aws.amazon.com/general/latest/gr/sigv4-add-signature-to-request.html
  @signature = Digest::hexencode(OpenSSL::HMAC.digest( OpenSSL::Digest.new('SHA256'),signingKey, string_to_sign))
  # generate authorization header and update it in headers
  generate_authorization_header(service_name, amz_target, http_method, payload, host, uri)
  @signature
end

#get_signature_key(service_name) ⇒ Object



100
101
102
103
104
105
106
# File 'lib/aws/signature/v4.rb', line 100

def get_signature_key (service_name)
  kDate    = OpenSSL::HMAC.digest('sha256', "AWS4" + @secret_key, @date)
  kRegion  = OpenSSL::HMAC.digest('sha256', kDate, @region)
  kService = OpenSSL::HMAC.digest('sha256', kRegion, service_name)
  kSigning = OpenSSL::HMAC.digest('sha256', kService, "aws4_request")
  kSigning
end