Repository URL to install this package:
|
Version:
0.10 ▾
|
"""
Provides AWS4SigningKey class for generating Amazon Web Services
authentication version 4 signing keys.
"""
# Licensed under the MIT License:
# http://opensource.org/licenses/MIT
from __future__ import unicode_literals
import hmac
import hashlib
from warnings import warn
from datetime import datetime
from .six import text_type
class AWS4SigningKey:
"""
AWS signing key. Used to sign AWS authentication strings.
The secret key is stored in the instance after instantiation, this can be
changed via the store_secret_key argument, see below for details.
Methods:
generate_key() -- Generate AWS4 Signing Key string
sign_sha256() -- Generate SHA256 HMAC signature, encoding message to bytes
first if required
Attributes:
region -- AWS region the key is scoped for
service -- AWS service the key is scoped for
date -- Date the key is scoped for
scope -- The AWS scope string for this key, calculated from the above
attributes
key -- The signing key string itself
amz_date -- Deprecated name for 'date'. Use the 'date' attribute instead.
amz_date will be removed in a future version.
"""
def __init__(self, secret_key, region, service, date=None,
store_secret_key=True):
"""
>>> AWS4SigningKey(secret_key, region, service[, date]
... [, store_secret_key])
secret_key -- This is your AWS secret access key
region -- The region you're connecting to, as per list at
http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region
e.g. us-east-1. For services which don't require a
region (e.g. IAM), use us-east-1.
service -- The name of the service you're connecting to, as per
endpoints at:
http://docs.aws.amazon.com/general/latest/gr/rande.html
e.g. elasticbeanstalk
date -- 8-digit date of the form YYYYMMDD. Key is only valid for
requests with a Date or X-Amz-Date header matching this
date. If date is not supplied the current date is
used.
store_secret_key
-- Whether the secret key is stored in the instance. By
default this is True, meaning the key is stored in
the secret_key property and is available to any
code the instance is passed to. Having the secret
key retained makes it easier to regenerate the key
if a scope parameter changes (usually the date).
This is used by the AWS4Auth class to perform its
automatic key updates when a request date/scope date
mismatch is encountered.
If you are passing instances to untrusted code you can
set this to False. This will cause the secret key to be
discarded as soon as the signing key has been generated.
Note though that you will need to manually regenerate
keys when needed (or if you use the regenerate_key()
method on an AWS4Auth instance you will need to pass it
the secret key).
All arguments should be supplied as strings.
"""
self.region = region
self.service = service
self.date = date or datetime.utcnow().strftime('%Y%m%d')
self.scope = '{}/{}/{}/aws4_request'.format(
self.date,
self.region,
self.service)
self.store_secret_key = store_secret_key
self.secret_key = secret_key if self.store_secret_key else None
self.key = self.generate_key(secret_key, self.region,
self.service, self.date)
@classmethod
def generate_key(cls, secret_key, region, service, date,
intermediates=False):
"""
Generate the signing key string as bytes.
If intermediate is set to True, returns a 4-tuple containing the key
and the intermediate keys:
( signing_key, date_key, region_key, service_key )
The intermediate keys can be used for testing against examples from
Amazon.
"""
init_key = ('AWS4' + secret_key).encode('utf-8')
date_key = cls.sign_sha256(init_key, date)
region_key = cls.sign_sha256(date_key, region)
service_key = cls.sign_sha256(region_key, service)
key = cls.sign_sha256(service_key, 'aws4_request')
if intermediates:
return (key, date_key, region_key, service_key)
else:
return key
@staticmethod
def sign_sha256(key, msg):
"""
Generate an SHA256 HMAC, encoding msg to UTF-8 if not
already encoded.
key -- signing key. bytes.
msg -- message to sign. unicode or bytes.
"""
if isinstance(msg, text_type):
msg = msg.encode('utf-8')
return hmac.new(key, msg, hashlib.sha256).digest()
@property
def amz_date(self):
msg = ("This attribute has been renamed to 'date'. 'amz_date' is "
"deprecated and will be removed in a future version.")
warn(msg, DeprecationWarning)
return self.date