Class: Aws::Sigv4::Signer
- Inherits:
-
Object
- Object
- Aws::Sigv4::Signer
- Defined in:
- lib/aws-sigv4/signer.rb
Overview
Utility class for creating AWS signature version 4 signature. This class provides two methods for generating signatures:
-
#sign_request - Computes a signature of the given request, returning the hash of headers that should be applied to the request.
-
#presign_url - Computes a presigned request with an expiration. By default, the body of this request is not signed and the request expires in 15 minutes.
## Configuration
To use the signer, you need to specify the service, region, and credentials. The service name is normally the endpoint prefix to an AWS service. For example:
ec2.us-west-1.amazonaws.com => ec2
The region is normally the second portion of the endpoint, following the service name.
ec2.us-west-1.amazonaws.com => us-west-1
It is important to have the correct service and region name, or the signature will be invalid.
## Credentials
The signer requires credentials. You can configure the signer with static credentials:
signer = Aws::Sigv4::Signer.new(
service: 's3',
region: 'us-east-1',
# static credentials
access_key_id: 'akid',
secret_access_key: 'secret'
)
You can also provide refreshing credentials via the ‘:credentials_provider`. If you are using the AWS SDK for Ruby, you can use any of the credential classes:
signer = Aws::Sigv4::Signer.new(
service: 's3',
region: 'us-east-1',
credentials_provider: Aws::InstanceProfileCredentials.new
)
Other AWS SDK for Ruby classes that can be provided via ‘:credentials_provider`:
-
‘Aws::Credentials`
-
‘Aws::SharedCredentials`
-
‘Aws::InstanceProfileCredentials`
-
‘Aws::AssumeRoleCredentials`
-
‘Aws::ECSCredentials`
A credential provider is any object that responds to ‘#credentials` returning another object that responds to `#access_key_id`, `#secret_access_key`, and `#session_token`.
Instance Attribute Summary collapse
-
#apply_checksum_header ⇒ Boolean
readonly
When ‘true` the `x-amz-content-sha256` header will be signed and returned in the signature headers.
-
#credentials_provider ⇒ #credentials
readonly
Returns an object that responds to ‘#credentials`, returning an object that responds to the following methods:.
- #region ⇒ String readonly
- #service ⇒ String readonly
-
#unsigned_headers ⇒ Set<String>
readonly
Returns a set of header names that should not be signed.
Class Method Summary collapse
- .uri_escape(string) ⇒ Object private
- .uri_escape_path(path) ⇒ Object private
Instance Method Summary collapse
-
#initialize(options = {}) ⇒ Signer
constructor
A new instance of Signer.
-
#presign_url(options) ⇒ HTTPS::URI, HTTP::URI
Signs a URL with query authentication.
-
#sign_request(request) ⇒ Signature
Computes a version 4 signature signature.
Constructor Details
#initialize(service: , region: , access_key_id: , secret_access_key: , session_token: nil, **options) ⇒ Signer #initialize(service: , region: , credentials: , **options) ⇒ Signer #initialize(service: , region: , credentials_provider: , **options) ⇒ Signer
Returns a new instance of Signer.
118 119 120 121 122 123 124 125 126 127 |
# File 'lib/aws-sigv4/signer.rb', line 118 def initialize( = {}) @service = extract_service() @region = extract_region() @credentials_provider = extract_credentials_provider() @unsigned_headers = Set.new((.fetch(:unsigned_headers, [])).map(&:downcase)) @unsigned_headers << 'authorization' [:uri_escape_path, :apply_checksum_header].each do |opt| instance_variable_set("@#{opt}", .key?(opt) ? !![:opt] : true) end end |
Instance Attribute Details
#apply_checksum_header ⇒ Boolean (readonly)
When ‘true` the `x-amz-content-sha256` header will be signed and returned in the signature headers.
152 153 154 |
# File 'lib/aws-sigv4/signer.rb', line 152 def apply_checksum_header @apply_checksum_header end |
#credentials_provider ⇒ #credentials (readonly)
Returns an object that responds to ‘#credentials`, returning an object that responds to the following methods:
-
‘#access_key_id` => String
-
‘#secret_access_key` => String
-
‘#session_token` => String, nil
-
‘#set?` => Boolean
144 145 146 |
# File 'lib/aws-sigv4/signer.rb', line 144 def credentials_provider @credentials_provider end |
#region ⇒ String (readonly)
133 134 135 |
# File 'lib/aws-sigv4/signer.rb', line 133 def region @region end |
#service ⇒ String (readonly)
130 131 132 |
# File 'lib/aws-sigv4/signer.rb', line 130 def service @service end |
#unsigned_headers ⇒ Set<String> (readonly)
Returns a set of header names that should not be signed. All header names have been downcased.
148 149 150 |
# File 'lib/aws-sigv4/signer.rb', line 148 def unsigned_headers @unsigned_headers end |
Class Method Details
.uri_escape(string) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
585 586 587 588 589 590 591 |
# File 'lib/aws-sigv4/signer.rb', line 585 def uri_escape(string) if string.nil? nil else CGI.escape(string.encode('UTF-8')).gsub('+', '%20').gsub('%7E', '~') end end |
.uri_escape_path(path) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
580 581 582 |
# File 'lib/aws-sigv4/signer.rb', line 580 def uri_escape_path(path) path.gsub(/[^\/]+/) { |part| uri_escape(part) } end |
Instance Method Details
#presign_url(options) ⇒ HTTPS::URI, HTTP::URI
Signs a URL with query authentication. Using query parameters to authenticate requests is useful when you want to express a request entirely in a URL. This method is also referred as presigning a URL.
See [Authenticating Requests: Using Query Parameters (AWS Signature Version 4)](docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html) for more information.
To generate a presigned URL, you must provide a HTTP URI and the http method.
url = signer.presigned_url(
http_method: 'GET',
url: 'https://my-bucket.s3-us-east-1.amazonaws.com/key',
expires_in: 60
)
By default, signatures are valid for 15 minutes. You can specify the number of seconds for the URL to expire in.
url = signer.presigned_url(
http_method: 'GET',
url: 'https://my-bucket.s3-us-east-1.amazonaws.com/key',
expires_in: 3600 # one hour
)
You can provide a hash of headers that you plan to send with the request. Every ‘X-Amz-*’ header you plan to send with the request must be provided, or the signature is invalid. Other headers are optional, but should be provided for security reasons.
url = signer.presigned_url(
http_method: 'PUT',
url: 'https://my-bucket.s3-us-east-1.amazonaws.com/key',
headers: {
'X-Amz-Meta-Custom' => 'metadata'
}
)
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 |
# File 'lib/aws-sigv4/signer.rb', line 313 def presign_url() creds = get_credentials http_method = extract_http_method() url = extract_url() headers = downcase_headers([:headers]) headers['host'] = host(url) datetime = headers['x-amz-date'] datetime ||= ([:time] || Time.now).utc.strftime("%Y%m%dT%H%M%SZ") date = datetime[0,8] content_sha256 = headers['x-amz-content-sha256'] content_sha256 ||= [:body_digest] content_sha256 ||= sha256_hexdigest([:body] || '') params = {} params['X-Amz-Algorithm'] = 'AWS4-HMAC-SHA256' params['X-Amz-Credential'] = credential(creds, date) params['X-Amz-Date'] = datetime params['X-Amz-Expires'] = extract_expires_in() params['X-Amz-SignedHeaders'] = signed_headers(headers) params['X-Amz-Security-Token'] = creds.session_token if creds.session_token params = params.map do |key, value| "#{uri_escape(key)}=#{uri_escape(value)}" end.join('&') if url.query url.query += '&' + params else url.query = params end creq = canonical_request(http_method, url, headers, content_sha256) sts = string_to_sign(datetime, creq) url.query += '&X-Amz-Signature=' + signature(creds.secret_access_key, date, sts) url end |
#sign_request(request) ⇒ Signature
Computes a version 4 signature signature. Returns the resultant signature as a hash of headers to apply to your HTTP request. The given request is not modified.
signature = signer.sign_request(
http_method: 'PUT',
url: 'https://domain.com',
headers: {
'Abc' => 'xyz',
},
body: 'body' # String or IO object
)
# Apply the following hash of headers to your HTTP request
signature.headers['Host']
signature.headers['X-Amz-Date']
signature.headers['X-Amz-Security-Token']
signature.headers['X-Amz-Content-Sha256']
signature.headers['Authorization']
In addition to computing the signature headers, the canonicalized request, string to sign and content sha256 checksum are also available. These values are useful for debugging signature errors returned by AWS.
signature.canonical_request #=> "..."
signature.string_to_sign #=> "..."
signature.content_sha256 #=> "..."
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
# File 'lib/aws-sigv4/signer.rb', line 201 def sign_request(request) creds = get_credentials http_method = extract_http_method(request) url = extract_url(request) headers = downcase_headers(request[:headers]) datetime = headers['x-amz-date'] datetime ||= Time.now.utc.strftime("%Y%m%dT%H%M%SZ") date = datetime[0,8] content_sha256 = headers['x-amz-content-sha256'] content_sha256 ||= sha256_hexdigest(request[:body] || '') sigv4_headers = {} sigv4_headers['host'] = host(url) sigv4_headers['x-amz-date'] = datetime sigv4_headers['x-amz-security-token'] = creds.session_token if creds.session_token sigv4_headers['x-amz-content-sha256'] ||= content_sha256 if @apply_checksum_header headers = headers.merge(sigv4_headers) # merge so we do not modify given headers hash # compute signature parts creq = canonical_request(http_method, url, headers, content_sha256) sts = string_to_sign(datetime, creq) sig = signature(creds.secret_access_key, date, sts) # apply signature sigv4_headers['authorization'] = [ "AWS4-HMAC-SHA256 Credential=#{credential(creds, date)}", "SignedHeaders=#{signed_headers(headers)}", "Signature=#{sig}", ].join(', ') # Returning the signature components. Signature.new( headers: sigv4_headers, string_to_sign: sts, canonical_request: creq, content_sha256: content_sha256 ) end |