def generate_presigned_url(self, ClientMethod, Params=None, ExpiresIn=3600, HttpMethod=None): """Generate a presigned url given a client, its method, and arguments :type ClientMethod: string :param ClientMethod: The client method to presign for :type Params: dict :param Params: The parameters normally passed to ``ClientMethod``. :type ExpiresIn: int :param ExpiresIn: The number of seconds the presigned url is valid for. By default it expires in an hour (3600 seconds) :type HttpMethod: string :param HttpMethod: The http method to use on the generated url. By default, the http method is whatever is used in the method's model. :returns: The presigned url """ client_method = ClientMethod params = Params if params is None: params = {} expires_in = ExpiresIn http_method = HttpMethod context = {'is_presign_request': True} request_signer = self._request_signer serializer = self._serializer try: operation_name = self._PY_TO_OP_NAME[client_method] except KeyError: raise UnknownClientMethodError(method_name=client_method) operation_model = self.meta.service_model.operation_model(operation_name) params = self._emit_api_params(params, operation_model, context) # Create a request dict based on the params to serialize. request_dict = serializer.serialize_to_request(params, operation_model) # Switch out the http method if user specified it. if http_method is not None: request_dict['method'] = http_method # Prepare the request dict by including the client's endpoint url. prepare_request_dict(request_dict, endpoint_url=self.meta.endpoint_url, context=context) # Generate the presigned url. return request_signer.generate_presigned_url(request_dict=request_dict, expires_in=expires_in, operation_name=operation_name)
def generate_presigned_url(self, ClientMethod, Params=None, ExpiresIn=3600, HttpMethod=None): """Generate a presigned url given a client, its method, and arguments :type ClientMethod: string :param ClientMethod: The client method to presign for :type Params: dict :param Params: The parameters normally passed to ``ClientMethod``. :type ExpiresIn: int :param ExpiresIn: The number of seconds the presigned url is valid for. By default it expires in an hour (3600 seconds) :type HttpMethod: string :param HttpMethod: The http method to use on the generated url. By default, the http method is whatever is used in the method's model. :returns: The presigned url """ client_method = ClientMethod params = Params if params is None: params = {} expires_in = ExpiresIn http_method = HttpMethod context = { 'is_presign_request': True } request_signer = self._request_signer serializer = self._serializer try: operation_name = self._PY_TO_OP_NAME[client_method] except KeyError: raise UnknownClientMethodError(method_name=client_method) operation_model = self.meta.service_model.operation_model( operation_name) params = self._emit_api_params(params, operation_model, context) # Create a request dict based on the params to serialize. request_dict = serializer.serialize_to_request( params, operation_model) # Switch out the http method if user specified it. if http_method is not None: request_dict['method'] = http_method # Prepare the request dict by including the client's endpoint url. prepare_request_dict( request_dict, endpoint_url=self.meta.endpoint_url, context=context) # Generate the presigned url. return request_signer.generate_presigned_url( request_dict=request_dict, expires_in=expires_in, operation_name=operation_name)
def _convert_to_request_dict(self, api_params, operation_model, context=None): # Given the API params provided by the user and the operation_model # we can serialize the request to a request_dict. operation_name = operation_model.name # Emit an event that allows users to modify the parameters at the # beginning of the method. It allows handlers to modify existing # parameters or return a new set of parameters to use. responses = self.meta.events.emit( 'provide-client-params.{endpoint_prefix}.{operation_name}'.format( endpoint_prefix=self._service_model.endpoint_prefix, operation_name=operation_name), params=api_params, model=operation_model, context=context) api_params = first_non_none_response(responses, default=api_params) event_name = ( 'before-parameter-build.{endpoint_prefix}.{operation_name}') self.meta.events.emit(event_name.format( endpoint_prefix=self._service_model.endpoint_prefix, operation_name=operation_name), params=api_params, model=operation_model, context=context) request_dict = self._serializer.serialize_to_request( api_params, operation_model) prepare_request_dict(request_dict, endpoint_url=self._endpoint.host, user_agent=self._client_config.user_agent) return request_dict
def _convert_to_request_dict(self, api_params, operation_model): # Given the API params provided by the user and the operation_model # we can serialize the request to a request_dict. operation_name = operation_model.name # Emit an event that allows users to modify the parameters at the # beginning of the method. It allows handlers to modify existing # parameters or return a new set of parameters to use. responses = self.meta.events.emit( 'provide-client-params.{endpoint_prefix}.{operation_name}'.format( endpoint_prefix=self._service_model.endpoint_prefix, operation_name=operation_name), params=api_params, model=operation_model) api_params = first_non_none_response(responses, default=api_params) event_name = ( 'before-parameter-build.{endpoint_prefix}.{operation_name}') self.meta.events.emit( event_name.format( endpoint_prefix=self._service_model.endpoint_prefix, operation_name=operation_name), params=api_params, model=operation_model) request_dict = self._serializer.serialize_to_request( api_params, operation_model) prepare_request_dict(request_dict, endpoint_url=self._endpoint.host, user_agent=self._client_config.user_agent) self.meta.events.emit( 'before-call.{endpoint_prefix}.{operation_name}'.format( endpoint_prefix=self._service_model.endpoint_prefix, operation_name=operation_name), model=operation_model, params=request_dict, request_signer=self._request_signer ) return request_dict
def prepare_base_request_dict(self, request_dict, endpoint_url=None, user_agent=None): self.base_request_dict.update(request_dict) if user_agent is None: user_agent = self.user_agent if endpoint_url is None: endpoint_url = self.endpoint_url prepare_request_dict(self.base_request_dict, endpoint_url=endpoint_url, user_agent=user_agent)
def _convert_to_request_dict(self, api_params, operation_model, context=None): api_params = self._emit_api_params( api_params, operation_model, context) request_dict = self._serializer.serialize_to_request( api_params, operation_model) prepare_request_dict(request_dict, endpoint_url=self._endpoint.host, user_agent=self._client_config.user_agent, context=context) return request_dict
async def _convert_to_request_dict(self, api_params, operation_model, context=None): api_params = await self._emit_api_params( api_params, operation_model, context) request_dict = self._serializer.serialize_to_request( api_params, operation_model) if not self._client_config.inject_host_prefix: request_dict.pop('host_prefix', None) prepare_request_dict(request_dict, endpoint_url=self._endpoint.host, user_agent=self._client_config.user_agent, context=context) return request_dict
def _botocore_parser_integration_test(service: str, action: str, headers: dict = None, expected: dict = None, **kwargs): # Load the appropriate service service = load_service(service) # Use the serializer from botocore to serialize the request params serializer = create_serializer(service.protocol) operation_model = service.operation_model(action) serialized_request = serializer.serialize_to_request( kwargs, operation_model) prepare_request_dict(serialized_request, "") split_url = urlsplit(serialized_request.get("url")) path = split_url.path query_string = split_url.query body = serialized_request["body"] # use custom headers (if provided), or headers from serialized request as default headers = serialized_request.get("headers") if headers is None else headers if service.protocol in ["query", "ec2"]: # Serialize the body as query parameter body = urlencode(serialized_request["body"]) # Use our parser to parse the serialized body parser = create_parser(service) parsed_operation_model, parsed_request = parser.parse( HttpRequest( method=serialized_request.get("method") or "GET", path=unquote(path), query_string=to_str(query_string), headers=headers, body=body, raw_path=path, )) # Check if the determined operation_model is correct assert parsed_operation_model == operation_model # Check if the result is equal to the given "expected" dict or the kwargs (if "expected" has not been set) expected = expected or kwargs # The parser adds None for none-existing members on purpose. Remove those for the assert expected = { key: value for key, value in expected.items() if value is not None } parsed_request = { key: value for key, value in parsed_request.items() if value is not None } assert parsed_request == expected
def _convert_to_request_dict(self, api_params, operation_model, context=None): api_params = self._emit_api_params(api_params, operation_model, context) request_dict = self._serializer.serialize_to_request( api_params, operation_model) prepare_request_dict(request_dict, endpoint_url=self._endpoint.host, user_agent=self._client_config.user_agent, context=context) return request_dict
def generate_db_auth_token(self, DBHostname, Port, DBUsername, Region=None): """Generates an auth token used to connect to a db with IAM credentials. :type DBHostname: str :param DBHostname: The hostname of the database to connect to. :type Port: int :param Port: The port number the database is listening on. :type DBUsername: str :param DBUsername: The username to log in as. :type Region: str :param Region: The region the database is in. If None, the client region will be used. :return: A presigned url which can be used as an auth token. """ region = Region if region is None: region = self.meta.region_name params = { 'Action': 'connect', 'DBUser': DBUsername, } request_dict = { 'url_path': '/', 'query_string': '', 'headers': {}, 'body': params, 'method': 'GET' } # RDS requires that the scheme not be set when sent over. This can cause # issues when signing because the Python url parsing libraries follow # RFC 1808 closely, which states that a netloc must be introduced by `//`. # Otherwise the url is presumed to be relative, and thus the whole # netloc would be treated as a path component. To work around this we # introduce https here and remove it once we're done processing it. scheme = 'https://' endpoint_url = '%s%s:%s' % (scheme, DBHostname, Port) prepare_request_dict(request_dict, endpoint_url) presigned_url = self._request_signer.generate_presigned_url( operation_name='connect', request_dict=request_dict, region_name=region, expires_in=900, signing_name='rds-db') return presigned_url[len(scheme):]
def generate_db_auth_token(self, DBHostname, Port, DBUsername, Region=None): """Generates an auth token used to connect to a db with IAM credentials. :type DBHostname: str :param DBHostname: The hostname of the database to connect to. :type Port: int :param Port: The port number the database is listening on. :type DBUsername: str :param DBUsername: The username to log in as. :type Region: str :param Region: The region the database is in. If None, the client region will be used. :return: A presigned url which can be used as an auth token. """ region = Region if region is None: region = self.meta.region_name params = { 'Action': 'connect', 'DBUser': DBUsername, } request_dict = { 'url_path': '/', 'query_string': '', 'headers': {}, 'body': params, 'method': 'GET' } # RDS requires that the scheme not be set when sent over. This can cause # issues when signing because the Python url parsing libraries follow # RFC 1808 closely, which states that a netloc must be introduced by `//`. # Otherwise the url is presumed to be relative, and thus the whole # netloc would be treated as a path component. To work around this we # introduce https here and remove it once we're done processing it. scheme = 'https://' endpoint_url = '%s%s:%s' % (scheme, DBHostname, Port) prepare_request_dict(request_dict, endpoint_url) presigned_url = self._request_signer.generate_presigned_url( operation_name='connect', request_dict=request_dict, region_name=region, expires_in=900, signing_name='rds-db' ) return presigned_url[len(scheme):]
def test_recreate_request(self): client = Lambda().client() operation_model = client._service_model.operation_model('Invoke') self.result = operation_model payload = {"name": "bbbbaaaa"} request_dict= {'url_path': '/2015-03-31/functions/temp_lambda_HL58KB/invocations', 'query_string': {}, 'method': 'POST', 'headers': {}, 'body': json.dumps(payload)} endpoint_url = 'https://lambda.eu-west-1.amazonaws.com' user_agent='Boto3/1.12.5 Python/3.8.1 Darwin/18.7.0 Botocore/1.15.5' from botocore.awsrequest import prepare_request_dict prepare_request_dict(request_dict=request_dict,endpoint_url=endpoint_url,user_agent=user_agent) request = client._endpoint.create_request(request_dict, operation_model) headers = {'User-Agent': b'Boto3/1.12.5 Python/3.8.1 Darwin/18.7.0 Botocore/1.15.5', 'X-Amz-Date': b'20200224T010440Z', 'Authorization': b'AWS4-HMAC-SHA256 Credential=AKIAURGGJDT3TXD5DCXK/20200224/eu-west-1/lambda/aws4_request, SignedHeaders=host;x-amz-date, Signature=3ea5c19cc097466202e71c4e3b4e306327709442138bfd6443b27a25cfd89c91', 'Content-Length': '15'} self.result = requests.post(request.url,json=payload,headers=request.headers).text #self.result = request.url #http_session = URLLib3Session() #self.result = http_session.send(request).text #self.result = request.headers.items() return from botocore.endpoint import Endpoint endpoint = Endpoint() self.params = { 'url_path': '/2015-03-31/functions/temp_lambda_HL58KB/invocations', 'query_string': {}, 'method' : 'POST', 'headers' : {'User-Agent': 'Boto3/1.12.5 Python/3.8.1 Darwin/18.7.0 Botocore/1.15.5'}, 'body' : b'{"name": "123"}', 'url' : 'https://lambda.eu-west-1.amazonaws.com/2015-03-31/functions/temp_lambda_HL58KB/invocations', 'context' : {'client_region': 'eu-west-1', 'client_config': None, 'has_streaming_input': True, 'auth_type': None}} #< botocore.config.Config object at0x10f5802e0 > self.result =42
def _convert_to_request_dict(self, api_params, operation_model): # Given the API params provided by the user and the operation_model # we can serialize the request to a request_dict. operation_name = operation_model.name event_name = ( 'before-parameter-build.{endpoint_prefix}.{operation_name}') self.meta.events.emit( event_name.format( endpoint_prefix=self._service_model.endpoint_prefix, operation_name=operation_name), params=api_params, model=operation_model) request_dict = self._serializer.serialize_to_request( api_params, operation_model) prepare_request_dict(request_dict, endpoint_url=self._endpoint.host, user_agent=self._client_config.user_agent) self.meta.events.emit( 'before-call.{endpoint_prefix}.{operation_name}'.format( endpoint_prefix=self._service_model.endpoint_prefix, operation_name=operation_name), model=operation_model, params=request_dict, request_signer=self._request_signer ) return request_dict
def generate_presigned_post(self, Bucket, Key, Fields=None, Conditions=None, ExpiresIn=3600): """Builds the url and the form fields used for a presigned s3 post :type Bucket: string :param Bucket: The name of the bucket to presign the post to. Note that bucket related conditions should not be included in the ``conditions`` parameter. :type Key: string :param Key: Key name, optionally add ${filename} to the end to attach the submitted filename. Note that key related condtions and fields are filled out for you and should not be included in the ``fields`` or ``condtions`` parmater. :type Fields: dict :param Fields: A dictionary of prefilled form fields to build on top of. Elements that may be included are acl, Cache-Control, Content-Type, Content-Disposition, Content-Encoding, Expires, success_action_redirect, redirect, success_action_status, and x-amz-meta-. Note that if a particular element is included in the fields dictionary it will not be automatically added to the conditions list. You must specify a condition for the element as well. :type Conditions: list :param Conditions: A list of conditions to include in the policy. Each element can be either a list or a structure. For example: [ {"acl": "public-read"}, ["content-length-range", 2, 5], ["starts-with", "$success_action_redirect", ""] ] Conditions that are included may pertain to acl, content-length-range, Cache-Control, Content-Type, Content-Disposition, Content-Encoding, Expires, success_action_redirect, redirect, success_action_status, and/or x-amz-meta-. Note that if you include a condition, you must specify the a valid value in the fields dictionary as well. A value will not be added automatically to the fields dictionary based on the conditions. :type ExpiresIn: int :param ExpiresIn: The number of seconds the presigned post is valid for. :rtype: dict :returns: A dictionary with two elements: ``url`` and ``fields``. Url is the url to post to. Fields is a dictionary filled with the form fields and respective values to use when submitting the post. For example: {'url': 'https://mybucket.s3.amazonaws.com 'fields': {'acl': 'public-read', 'key': 'mykey', 'signature': 'mysignature', 'policy': 'mybase64 encoded policy'} } """ bucket = Bucket key = Key fields = Fields conditions = Conditions expires_in = ExpiresIn if fields is None: fields = {} if conditions is None: conditions = [] post_presigner = S3PostPresigner(self._request_signer) serializer = self._serializer # We choose the CreateBucket operation model because its url gets # serialized to what a presign post requires. operation_model = self.meta.service_model.operation_model('CreateBucket') # Create a request dict based on the params to serialize. request_dict = serializer.serialize_to_request({'Bucket': bucket}, operation_model) # Prepare the request dict by including the client's endpoint url. prepare_request_dict(request_dict, endpoint_url=self.meta.endpoint_url) # Append that the bucket name to the list of conditions. conditions.append({'bucket': bucket}) # If the key ends with filename, the only constraint that can be # imposed is if it starts with the specified prefix. if key.endswith('${filename}'): conditions.append(["starts-with", '$key', key[:-len('${filename}')]]) else: conditions.append({'key': key}) # Add the key to the fields. fields['key'] = key return post_presigner.generate_presigned_post(request_dict=request_dict, fields=fields, conditions=conditions, expires_in=expires_in)
def _assert_endpoints_equal(actual, expected, endpoint): if 'host' not in expected: return prepare_request_dict(actual, endpoint) actual_host = urlsplit(actual['url']).netloc assert_equal(actual_host, expected['host'], 'Host')
def generate_presigned_post(self, Bucket, Key, Fields=None, Conditions=None, ExpiresIn=3600): """Builds the url and the form fields used for a presigned s3 post :type Bucket: string :param Bucket: The name of the bucket to presign the post to. Note that bucket related conditions should not be included in the ``conditions`` parameter. :type Key: string :param Key: Key name, optionally add ${filename} to the end to attach the submitted filename. Note that key related condtions and fields are filled out for you and should not be included in the ``fields`` or ``condtions`` parmater. :type Fields: dict :param Fields: A dictionary of prefilled form fields to build on top of. Elements that may be included are acl, Cache-Control, Content-Type, Content-Disposition, Content-Encoding, Expires, success_action_redirect, redirect, success_action_status, and x-amz-meta-. Note that if a particular element is included in the fields dictionary it will not be automatically added to the conditions list. You must specify a condition for the element as well. :type Conditions: list :param Conditions: A list of conditions to include in the policy. Each element can be either a list or a structure. For example: [ {"acl": "public-read"}, ["content-length-range", 2, 5], ["starts-with", "$success_action_redirect", ""] ] Conditions that are included may pertain to acl, content-length-range, Cache-Control, Content-Type, Content-Disposition, Content-Encoding, Expires, success_action_redirect, redirect, success_action_status, and/or x-amz-meta-. Note that if you include a condition, you must specify the a valid value in the fields dictionary as well. A value will not be added automatically to the fields dictionary based on the conditions. :type ExpiresIn: int :param ExpiresIn: The number of seconds the presigned post is valid for. :rtype: dict :returns: A dictionary with two elements: ``url`` and ``fields``. Url is the url to post to. Fields is a dictionary filled with the form fields and respective values to use when submitting the post. For example: {'url': 'https://mybucket.s3.amazonaws.com 'fields': {'acl': 'public-read', 'key': 'mykey', 'signature': 'mysignature', 'policy': 'mybase64 encoded policy'} } """ bucket = Bucket key = Key fields = Fields conditions = Conditions expires_in = ExpiresIn if fields is None: fields = {} if conditions is None: conditions = [] post_presigner = S3PostPresigner(self._request_signer) serializer = self._serializer # We choose the CreateBucket operation model because its url gets # serialized to what a presign post requires. operation_model = self.meta.service_model.operation_model( 'CreateBucket') # Create a request dict based on the params to serialize. request_dict = serializer.serialize_to_request( {'Bucket': bucket}, operation_model) # Prepare the request dict by including the client's endpoint url. prepare_request_dict( request_dict, endpoint_url=self.meta.endpoint_url) # Append that the bucket name to the list of conditions. conditions.append({'bucket': bucket}) # If the key ends with filename, the only constraint that can be # imposed is if it starts with the specified prefix. if key.endswith('${filename}'): conditions.append(["starts-with", '$key', key[:-len('${filename}')]]) else: conditions.append({'key': key}) # Add the key to the fields. fields['key'] = key return post_presigner.generate_presigned_post( request_dict=request_dict, fields=fields, conditions=conditions, expires_in=expires_in)