Example #1
0
    def _modify_request_before_signing(self, request):
        # We automatically set this header, so if it's the auto-set value we
        # want to get rid of it since it doesn't make sense for presigned urls.
        content_type = request.headers.get('content-type')
        blacklisted_content_type = (
            'application/x-www-form-urlencoded; charset=utf-8'
        )
        if content_type == blacklisted_content_type:
            del request.headers['content-type']

        # 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.
        signed_headers = self.signed_headers(self.headers_to_sign(request))

        auth_params = {
            'X-Amz-Algorithm': 'AWS4-HMAC-SHA256',
            'X-Amz-Credential': self.scope(request),
            'X-Amz-Date': request.context['timestamp'],
            'X-Amz-Expires': self._expires,
            'X-Amz-SignedHeaders': signed_headers,
        }
        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, keep_blank_values=True).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. To
            # do this, we first have to convert it to a dict.
            query_dict.update(self._get_body_as_dict(request))
            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)
Example #2
0
    def _modify_request_before_signing(self, request):
        # We automatically set this header, so if it's the auto-set value we
        # want to get rid of it since it doesn't make sense for presigned urls.
        content_type = request.headers.get('content-type')
        blacklisted_content_type = (
            'application/x-www-form-urlencoded; charset=utf-8'
        )
        if content_type == blacklisted_content_type:
            del request.headers['content-type']

        # 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.
        signed_headers = self.signed_headers(self.headers_to_sign(request))

        auth_params = {
            'X-Amz-Algorithm': 'AWS4-HMAC-SHA256',
            'X-Amz-Credential': self.scope(request),
            'X-Amz-Date': request.context['timestamp'],
            'X-Amz-Expires': self._expires,
            'X-Amz-SignedHeaders': signed_headers,
        }
        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, keep_blank_values=True).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. To
            # do this, we first have to convert it to a dict.
            query_dict.update(self._get_body_as_dict(request))
            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)
Example #3
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': request.context['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)
Example #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)
Example #5
0
def _serialize_request_description(request_dict):
    if isinstance(request_dict.get('body'), dict):
        # urlencode the request body.
        encoded = percent_encode_sequence(request_dict['body']).encode('utf-8')
        request_dict['body'] = encoded
    if isinstance(request_dict.get('query_string'), dict):
        encoded = percent_encode_sequence(request_dict.pop('query_string'))
        if encoded:
            # 'requests' automatically handle this, but we in the
            # test runner we need to handle the case where the url_path
            # already has query params.
            if '?' not in request_dict['url_path']:
                request_dict['url_path'] += '?%s' % encoded
            else:
                request_dict['url_path'] += '&%s' % encoded
Example #6
0
def prepare_request_dict(request_dict, endpoint_url, user_agent=None):
    """
    This method prepares a request dict to be created into an
    AWSRequestObject. This prepares the request dict by adding the
    url and the user agent to the request dict.

    :type request_dict: dict
    :param request_dict:  The request dict (created from the
        ``serialize`` module).

    :type user_agent: string
    :param user_agent: The user agent to use for this request.

    :type endpoint_url: string
    :param endpoint_url: The full endpoint url, which contains at least
        the scheme, the hostname, and optionally any path components.
    """
    r = request_dict
    if user_agent is not None:
        headers = r['headers']
        headers['User-Agent'] = user_agent
    url = _urljoin(endpoint_url, r['url_path'])
    if r['query_string']:
        encoded_query_string = percent_encode_sequence(r['query_string'])
        if '?' not in url:
            url += '?%s' % encoded_query_string
        else:
            url += '&%s' % encoded_query_string
    r['url'] = url
Example #7
0
    def _inject_signature(self, request, signature):
        query_dict = {}
        query_dict['AWSAccessKeyId'] = self.credentials.access_key
        query_dict['Signature'] = signature

        for header_key in request.headers:
            lk = header_key.lower()
            # For query string requests, Expires is used instead of the
            # Date header.
            if header_key == 'Date':
                query_dict['Expires'] = request.headers['Date']
            # We only want to include relevant headers in the query string.
            # These can be anything that starts with x-amz, is Content-MD5,
            # or is Content-Type.
            elif lk.startswith('x-amz-') or lk in ['content-md5',
                                                   'content-type']:
                query_dict[lk] = request.headers[lk]
        # Combine all of the identified headers into an encoded
        # query string
        new_query_string = percent_encode_sequence(query_dict)

        # Create a new url with the presigned url.
        p = urlsplit(request.url)
        if p[3]:
            # If there was a pre-existing query string, we should
            # add that back before injecting the new query string.
            new_query_string ='%s&%s' % (p[3], new_query_string)
        new_url_parts = (p[0], p[1], p[2], new_query_string, p[4])
        request.url = urlunsplit(new_url_parts)
    def _inject_signature(self, request, signature):
        query_dict = {}
        query_dict['AWSAccessKeyId'] = self.credentials.access_key
        query_dict['Signature'] = signature

        for header_key in request.headers:
            lk = header_key.lower()
            # For query string requests, Expires is used instead of the
            # Date header.
            if header_key == 'Date':
                query_dict['Expires'] = request.headers['Date']
            # We only want to include relevant headers in the query string.
            # These can be anything that starts with x-amz, is Content-MD5,
            # or is Content-Type.
            elif lk.startswith('x-amz-') or lk in [
                    'content-md5', 'content-type'
            ]:
                query_dict[lk] = request.headers[lk]
        # Combine all of the identified headers into an encoded
        # query string
        new_query_string = percent_encode_sequence(query_dict)

        # Create a new url with the presigned url.
        p = urlsplit(request.url)
        if p[3]:
            # If there was a pre-existing query string, we should
            # add that back before injecting the new query string.
            new_query_string = '%s&%s' % (p[3], new_query_string)
        new_url_parts = (p[0], p[1], p[2], new_query_string, p[4])
        request.url = urlunsplit(new_url_parts)
Example #9
0
def prepare_request_dict(request_dict, endpoint_url, user_agent=None):
    """
    This method prepares a request dict to be created into an
    AWSRequestObject. This prepares the request dict by adding the
    url and the user agent to the request dict.

    :type request_dict: dict
    :param request_dict:  The request dict (created from the
        ``serialize`` module).

    :type user_agent: string
    :param user_agent: The user agent to use for this request.

    :type endpoint_url: string
    :param endpoint_url: The full endpoint url, which contains at least
        the scheme, the hostname, and optionally any path components.
    """
    r = request_dict
    if user_agent is not None:
        headers = r['headers']
        headers['User-Agent'] = user_agent
    url = _urljoin(endpoint_url, r['url_path'])
    if r['query_string']:
        encoded_query_string = percent_encode_sequence(r['query_string'])
        if '?' not in url:
            url += '?%s' % encoded_query_string
        else:
            url += '&%s' % encoded_query_string
    r['url'] = url
Example #10
0
    def create_request_object(self, request_dict, user_agent, endpoint_url):
        """

        :type request_dict: dict
        :param request_dict:  The request dict (created from the ``serialize``
            module).

        :type user_agent: string
        :param user_agent: The user agent to use for this request.

        :type endpoint_url: string
        :param endpoint_url: The full endpoint url, which contains at least
            the scheme, the hostname, and optionally any path components.

        :rtype: ``botocore.awsrequest.AWSRequest``
        :return: An AWSRequest object based on the request_dict.

        """
        r = request_dict
        headers = r['headers']
        headers['User-Agent'] = user_agent
        url = self._urljoin(endpoint_url, r['url_path'])
        if r['query_string']:
            encoded_query_string = percent_encode_sequence(r['query_string'])
            if '?' not in url:
                url += '?%s' % encoded_query_string
            else:
                url += '&%s' % encoded_query_string
        request = AWSRequest(method=r['method'], url=url,
                             data=r['body'],
                             headers=headers)
        return request
Example #11
0
    def create_request_object(self, request_dict, user_agent, endpoint_url):
        """

        :type request_dict: dict
        :param request_dict:  The request dict (created from the ``serialize``
            module).

        :type user_agent: string
        :param user_agent: The user agent to use for this request.

        :type endpoint_url: string
        :param endpoint_url: The full endpoint url, which contains at least
            the scheme, the hostname, and optionally any path components.

        :rtype: ``botocore.awsrequest.AWSRequest``
        :return: An AWSRequest object based on the request_dict.

        """
        r = request_dict
        headers = r['headers']
        headers['User-Agent'] = user_agent
        url = self._urljoin(endpoint_url, r['url_path'])
        if r['query_string']:
            encoded_query_string = percent_encode_sequence(r['query_string'])
            if '?' not in url:
                url += '?%s' % encoded_query_string
            else:
                url += '&%s' % encoded_query_string
        request = AWSRequest(method=r['method'],
                             url=url,
                             data=r['body'],
                             headers=headers)
        return request
Example #12
0
 def _create_request_object(self, request_dict):
     r = request_dict
     user_agent = self._user_agent
     headers = r['headers']
     headers['User-Agent'] = user_agent
     url = urljoin(self.host, r['url_path'])
     if r['query_string']:
         encoded_query_string = percent_encode_sequence(r['query_string'])
         if '?' not in url:
             url += '?%s' % encoded_query_string
         else:
             url += '&%s' % encoded_query_string
     request = AWSRequest(method=r['method'], url=url,
                          data=r['body'],
                          headers=headers)
     return request
Example #13
0
 def _create_request_object(self, request_dict):
     r = request_dict
     user_agent = self._user_agent
     headers = r['headers']
     headers['User-Agent'] = user_agent
     url = urljoin(self.host, r['url_path'])
     if r['query_string']:
         encoded_query_string = percent_encode_sequence(r['query_string'])
         if '?' not in url:
             url += '?%s' % encoded_query_string
         else:
             url += '&%s' % encoded_query_string
     request = AWSRequest(method=r['method'],
                          url=url,
                          data=r['body'],
                          headers=headers)
     return request
    def _modify_request_before_signing(self, request):
        super()._modify_request_before_signing(request)

        # We automatically set this header, so if it's the auto-set value we
        # want to get rid of it since it doesn't make sense for presigned urls.
        content_type = request.headers.get('content-type')
        if content_type == 'application/x-www-form-urlencoded; charset=utf-8':
            del request.headers['content-type']

        # 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, keep_blank_values=True).items()])
        if request.params:
            query_dict.update(request.params)
            request.params = {}
        # 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)
        if request.data:
            # We also need to move the body params into the query string. To
            # do this, we first have to convert it to a dict.
            query_dict.update(_get_body_as_dict(request))
            request.data = ''
        new_query_string = percent_encode_sequence(query_dict)
        # 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)
Example #15
0
 def test_percent_encode_list_values_of_string(self):
     self.assertEqual(
         percent_encode_sequence(
             OrderedDict([('k1', ['a', 'list']),
                          ('k2', ['another', 'list'])])),
         'k1=a&k1=list&k2=another&k2=list')
Example #16
0
 def _serialize_to_header_value(self, tags):
     return percent_encode_sequence([(tag['Key'], tag['Value'])
                                     for tag in tags])
Example #17
0
 def test_percent_encode_dict_string_string(self):
     self.assertEqual(
         percent_encode_sequence(OrderedDict([('k1', 'v1'), ('k2', 'v2')])),
                                 'k1=v1&k2=v2')
Example #18
0
 def test_percent_encode_single_list_of_values(self):
     self.assertEqual(percent_encode_sequence({'k1': ['a', 'b', 'c']}),
                      'k1=a&k1=b&k1=c')
Example #19
0
 def test_percent_encode_string_string_tuples(self):
     self.assertEqual(percent_encode_sequence([('k1', 'v1'), ('k2', 'v2')]),
                      'k1=v1&k2=v2')
Example #20
0
 def test_percent_encode_dict_single_pair(self):
     self.assertEqual(percent_encode_sequence({'k1': 'v1'}), 'k1=v1')
Example #21
0
 def test_percent_encode_empty(self):
     self.assertEqual(percent_encode_sequence({}), '')
Example #22
0
 def test_percent_encode_special_chars(self):
     self.assertEqual(
         percent_encode_sequence({'k1': 'with spaces++/'}),
         'k1=with%20spaces%2B%2B%2F')
Example #23
0
 def test_percent_encode_special_chars(self):
     self.assertEqual(percent_encode_sequence({'k1': 'with spaces++/'}),
                      'k1=with%20spaces%2B%2B%2F')
Example #24
0
 def test_percent_encode_empty(self):
     self.assertEqual(percent_encode_sequence({}), '')
Example #25
0
 def test_percent_encode_string_string_tuples(self):
     self.assertEqual(percent_encode_sequence([('k1', 'v1'), ('k2', 'v2')]),
                      'k1=v1&k2=v2')
Example #26
0
 def test_percent_encode_dict_single_pair(self):
     self.assertEqual(percent_encode_sequence({'k1': 'v1'}), 'k1=v1')
Example #27
0
 def test_percent_encode_dict_string_string(self):
     self.assertEqual(
         percent_encode_sequence(OrderedDict([('k1', 'v1'), ('k2', 'v2')])),
         'k1=v1&k2=v2')
Example #28
0
 def test_percent_encode_single_list_of_values(self):
     self.assertEqual(percent_encode_sequence({'k1': ['a', 'b', 'c']}),
                      'k1=a&k1=b&k1=c')
Example #29
0
 def test_percent_encode_list_values_of_string(self):
     self.assertEqual(
         percent_encode_sequence(
             OrderedDict([('k1', ['a', 'list']), ('k2', ['another',
                                                         'list'])])),
         'k1=a&k1=list&k2=another&k2=list')