Пример #1
0
 def add_auth(self, request):
     if self.credentials is None:
         raise NoCredentialsError
     logger.debug("Calculating signature using hmacv1 auth.")
     split = urlsplit(request.url)
     logger.debug('HTTP request method: %s', request.method)
     signature = self.get_signature(request.method, split, request.headers)
     request.headers['Authorization'] = (
         "AWS %s:%s" % (self.credentials.access_key, signature))
Пример #2
0
 def add_auth(self, request):
     if self.credentials is None:
         raise NoCredentialsError
     logger.debug("Calculating signature using hmacv1 auth.")
     split = urlsplit(request.url)
     logger.debug('HTTP request method: %s', request.method)
     signature = self.get_signature(request.method, split,
                                    request.headers)
     request.headers['Authorization'] = ("AWS %s:%s" % (self.credentials.access_key,
                                                        signature))
Пример #3
0
 def canonical_query_string(self, request):
     cqs = ''
     # The query string can come from two parts.  One is the
     # params attribute of the request.  The other is from the request
     # url (in which case we have to re-split the url into its components
     # and parse out the query string component).
     if request.params:
         return self._canonical_query_string_params(request.params)
     else:
         return self._canonical_query_string_url(urlsplit(request.url))
     return cqs
Пример #4
0
 def _modify_request_before_signing(self, request):
     # This is our chance to add additional query params we need
     # before we go about calculating the signature.
     request.headers = {}
     request.method = 'GET'
     # Note that we're not including X-Amz-Signature.
     # From the docs: "The Canonical Query String must include all the query
     # parameters from the preceding table except for X-Amz-Signature.
     auth_params = {
         'X-Amz-Algorithm': 'AWS4-HMAC-SHA256',
         'X-Amz-Credential': self.scope(request),
         'X-Amz-Date': self.timestamp,
         'X-Amz-Expires': self._expires,
         'X-Amz-SignedHeaders': 'host',
     }
     if self.credentials.token is not None:
         auth_params['X-Amz-Security-Token'] = self.credentials.token
     # Now parse the original query string to a dict, inject our new query
     # params, and serialize back to a query string.
     url_parts = urlsplit(request.url)
     # parse_qs makes each value a list, but in our case we know we won't
     # have repeated keys so we know we have single element lists which we
     # can convert back to scalar values.
     query_dict = dict([(k, v[0])
                        for k, v in parse_qs(url_parts.query).items()])
     # The spec is particular about this.  It *has* to be:
     # https://<endpoint>?<operation params>&<auth params>
     # You can't mix the two types of params together, i.e just keep doing
     # new_query_params.update(op_params)
     # new_query_params.update(auth_params)
     # percent_encode_sequence(new_query_params)
     operation_params = ''
     if request.data:
         # We also need to move the body params into the query string.
         # request.data will be populated, for example, with query services
         # which normally form encode the params into the body.
         # This means that request.data is a dict() of the operation params.
         query_dict.update(request.data)
         request.data = ''
     if query_dict:
         operation_params = percent_encode_sequence(query_dict) + '&'
     new_query_string = operation_params + \
             percent_encode_sequence(auth_params)
     # url_parts is a tuple (and therefore immutable) so we need to create
     # a new url_parts with the new query string.
     # <part>   - <index>
     # scheme   - 0
     # netloc   - 1
     # path     - 2
     # query    - 3  <-- we're replacing this.
     # fragment - 4
     p = url_parts
     new_url_parts = (p[0], p[1], p[2], new_query_string, p[4])
     request.url = urlunsplit(new_url_parts)
Пример #5
0
 def canonical_query_string(self, request):
     cqs = ''
     # The query string can come from two parts.  One is the
     # params attribute of the request.  The other is from the request
     # url (in which case we have to re-split the url into its components
     # and parse out the query string component).
     if request.params:
         return self._canonical_query_string_params(request.params)
     else:
         return self._canonical_query_string_url(urlsplit(request.url))
     return cqs
Пример #6
0
 def _modify_request_before_signing(self, request):
     # This is our chance to add additional query params we need
     # before we go about calculating the signature.
     request.headers = {}
     request.method = 'GET'
     # Note that we're not including X-Amz-Signature.
     # From the docs: "The Canonical Query String must include all the query
     # parameters from the preceding table except for X-Amz-Signature.
     auth_params = {
         'X-Amz-Algorithm': 'AWS4-HMAC-SHA256',
         'X-Amz-Credential': self.scope(request),
         'X-Amz-Date': self.timestamp,
         'X-Amz-Expires': self._expires,
         'X-Amz-SignedHeaders': 'host',
     }
     if self.credentials.token is not None:
         auth_params['X-Amz-Security-Token'] = self.credentials.token
     # Now parse the original query string to a dict, inject our new query
     # params, and serialize back to a query string.
     url_parts = urlsplit(request.url)
     # parse_qs makes each value a list, but in our case we know we won't
     # have repeated keys so we know we have single element lists which we
     # can convert back to scalar values.
     query_dict = dict([(k, v[0]) for k, v in parse_qs(url_parts.query).items()])
     # The spec is particular about this.  It *has* to be:
     # https://<endpoint>?<operation params>&<auth params>
     # You can't mix the two types of params together, i.e just keep doing
     # new_query_params.update(op_params)
     # new_query_params.update(auth_params)
     # percent_encode_sequence(new_query_params)
     operation_params = ''
     if request.data:
         # We also need to move the body params into the query string.
         # request.data will be populated, for example, with query services
         # which normally form encode the params into the body.
         # This means that request.data is a dict() of the operation params.
         query_dict.update(request.data)
         request.data = ''
     if query_dict:
         operation_params = percent_encode_sequence(query_dict) + '&'
     new_query_string = operation_params + \
             percent_encode_sequence(auth_params)
     # url_parts is a tuple (and therefore immutable) so we need to create
     # a new url_parts with the new query string.
     # <part>   - <index>
     # scheme   - 0
     # netloc   - 1
     # path     - 2
     # query    - 3  <-- we're replacing this.
     # fragment - 4
     p = url_parts
     new_url_parts = (p[0], p[1], p[2], new_query_string, p[4])
     request.url = urlunsplit(new_url_parts)
Пример #7
0
 def headers_to_sign(self, request):
     """
     Select the headers from the request that need to be included
     in the StringToSign.
     """
     header_map = HTTPHeaders()
     split = urlsplit(request.url)
     for name, value in request.headers.items():
         lname = name.lower()
         header_map[lname] = value
     if 'host' not in header_map:
         header_map['host'] = split.netloc
     return header_map
Пример #8
0
 def headers_to_sign(self, request):
     """
     Select the headers from the request that need to be included
     in the StringToSign.
     """
     header_map = HTTPHeaders()
     split = urlsplit(request.url)
     for name, value in request.headers.items():
         lname = name.lower()
         header_map[lname] = value
     if 'host' not in header_map:
         header_map['host'] = split.netloc
     return header_map
Пример #9
0
 def canonical_request(self, request):
     cr = [request.method.upper()]
     path = self._normalize_url_path(urlsplit(request.url).path)
     cr.append(path)
     cr.append(self.canonical_query_string(request))
     headers_to_sign = self.headers_to_sign(request)
     cr.append(self.canonical_headers(headers_to_sign) + '\n')
     cr.append(self.signed_headers(headers_to_sign))
     if 'X-Amz-Content-SHA256' in request.headers:
         body_checksum = request.headers['X-Amz-Content-SHA256']
     else:
         body_checksum = self.payload(request)
     cr.append(body_checksum)
     return '\n'.join(cr)
Пример #10
0
 def canonical_request(self, request):
     cr = [request.method.upper()]
     path = self._normalize_url_path(urlsplit(request.url).path)
     cr.append(path)
     cr.append(self.canonical_query_string(request))
     headers_to_sign = self.headers_to_sign(request)
     cr.append(self.canonical_headers(headers_to_sign) + '\n')
     cr.append(self.signed_headers(headers_to_sign))
     if 'X-Amz-Content-SHA256' in request.headers:
         body_checksum = request.headers['X-Amz-Content-SHA256']
     else:
         body_checksum = self.payload(request)
     cr.append(body_checksum)
     return '\n'.join(cr)
Пример #11
0
 def calc_signature(self, request, params):
     logger.debug("Calculating signature using v2 auth.")
     split = urlsplit(request.url)
     path = split.path
     if len(path) == 0:
         path = '/'
     string_to_sign = '%s\n%s\n%s\n' % (request.method, split.netloc, path)
     lhmac = hmac.new(self.credentials.secret_key.encode('utf-8'),
                      digestmod=sha256)
     pairs = []
     for key in sorted(params):
         value = six.text_type(params[key])
         pairs.append(
             quote(key.encode('utf-8'), safe='') + '=' +
             quote(value.encode('utf-8'), safe='-_~'))
     qs = '&'.join(pairs)
     string_to_sign += qs
     logger.debug('String to sign: %s', string_to_sign)
     lhmac.update(string_to_sign.encode('utf-8'))
     b64 = base64.b64encode(lhmac.digest()).strip().decode('utf-8')
     return (qs, b64)
Пример #12
0
 def calc_signature(self, request, params):
     logger.debug("Calculating signature using v2 auth.")
     split = urlsplit(request.url)
     path = split.path
     if len(path) == 0:
         path = '/'
     string_to_sign = '%s\n%s\n%s\n' % (request.method,
                                        split.netloc,
                                        path)
     lhmac = hmac.new(self.credentials.secret_key.encode('utf-8'),
                      digestmod=sha256)
     pairs = []
     for key in sorted(params):
         value = six.text_type(params[key])
         pairs.append(quote(key.encode('utf-8'), safe='') + '=' +
                      quote(value.encode('utf-8'), safe='-_~'))
     qs = '&'.join(pairs)
     string_to_sign += qs
     logger.debug('String to sign: %s', string_to_sign)
     lhmac.update(string_to_sign.encode('utf-8'))
     b64 = base64.b64encode(lhmac.digest()).strip().decode('utf-8')
     return (qs, b64)
Пример #13
0
def fix_s3_host(event_name, endpoint, request, auth, **kwargs):
    """
    This handler looks at S3 requests just before they are signed.
    If there is a bucket name on the path (true for everything except
    ListAllBuckets) it checks to see if that bucket name conforms to
    the DNS naming conventions.  If it does, it alters the request to
    use ``virtual hosting`` style addressing rather than ``path-style``
    addressing.  This allows us to avoid 301 redirects for all
    bucket names that can be CNAME'd.
    """
    parts = urlsplit(request.url)
    auth.auth_path = parts.path
    path_parts = parts.path.split('/')
    if isinstance(auth, botocore_eb.auth.SigV4Auth):
        return
    if len(path_parts) > 1:
        bucket_name = path_parts[1]
        logger.debug('Checking for DNS compatible bucket for: %s', request.url)
        if check_dns_name(bucket_name) and _allowed_region(
                endpoint.region_name):
            # If the operation is on a bucket, the auth_path must be
            # terminated with a '/' character.
            if len(path_parts) == 2:
                if auth.auth_path[-1] != '/':
                    auth.auth_path += '/'
            path_parts.remove(bucket_name)
            global_endpoint = 's3.amazonaws.com'
            host = bucket_name + '.' + global_endpoint
            new_tuple = (parts.scheme, host, '/'.join(path_parts), parts.query,
                         '')
            new_uri = urlunsplit(new_tuple)
            request.url = new_uri
            logger.debug('URI updated to: %s', new_uri)
        else:
            logger.debug('Not changing URI, bucket is not DNS compatible: %s',
                         bucket_name)
def fix_s3_host(event_name, endpoint, request, auth, **kwargs):
    """
    This handler looks at S3 requests just before they are signed.
    If there is a bucket name on the path (true for everything except
    ListAllBuckets) it checks to see if that bucket name conforms to
    the DNS naming conventions.  If it does, it alters the request to
    use ``virtual hosting`` style addressing rather than ``path-style``
    addressing.  This allows us to avoid 301 redirects for all
    bucket names that can be CNAME'd.
    """
    parts = urlsplit(request.url)
    auth.auth_path = parts.path
    path_parts = parts.path.split('/')
    if isinstance(auth, botocore_eb.auth.SigV4Auth):
        return
    if len(path_parts) > 1:
        bucket_name = path_parts[1]
        logger.debug('Checking for DNS compatible bucket for: %s',
                     request.url)
        if check_dns_name(bucket_name) and _allowed_region(endpoint.region_name):
            # If the operation is on a bucket, the auth_path must be
            # terminated with a '/' character.
            if len(path_parts) == 2:
                if auth.auth_path[-1] != '/':
                    auth.auth_path += '/'
            path_parts.remove(bucket_name)
            global_endpoint = 's3.amazonaws.com'
            host = bucket_name + '.' + global_endpoint
            new_tuple = (parts.scheme, host, '/'.join(path_parts),
                         parts.query, '')
            new_uri = urlunsplit(new_tuple)
            request.url = new_uri
            logger.debug('URI updated to: %s', new_uri)
        else:
            logger.debug('Not changing URI, bucket is not DNS compatible: %s',
                         bucket_name)