def generate_presigned_url_for_uploading_part( bucket, key, credentials, uploadId, partNumber, region, expires ): """ Generate presigned url for uploading object part given uploadId and part number Args: bucket(str): bucket key(str): key credentials(dict): dictionary of aws credentials uploadId(str): uploadID of the multipart upload partNumber(int): part number region(str): bucket region expires(int): expiration time Returns: presigned_url(str) """ url = "https://{}.s3.amazonaws.com/{}".format(bucket, key) additional_signed_qs = {"partNumber": str(partNumber), "uploadId": uploadId} try: return generate_aws_presigned_url( url, "PUT", credentials, "s3", region, expires, additional_signed_qs ) except Exception as e: raise InternalError( "Can not generate presigned url for part number {} of key {}. Detail {}".format( partNumber, key, e ) )
def test_generate_presigned_url_escaped(): cred = { "aws_access_key_id": "AKIDEXAMPLE", "aws_secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY", } url = "https://s3.amazonaws.com/dummy/P0001_T1/[test]; .tar.gz" date = datetime.date(1999, 2, 19) with mock_datetime(date, datetime): presigned_url = generate_aws_presigned_url( url, "GET", cred, "s3", "us-east-1", 86400, { "user-id": "value2", "username": "******" }, ) expected = ( "https://{}".format( quote("s3.amazonaws.com/dummy/P0001_T1/[test]; .tar.gz")) + "?X-Amz-Algorithm=AWS4-HMAC-SHA256" "&X-Amz-Credential=AKIDEXAMPLE%2F19990219%2Fus-east-1%2Fs3%2Faws4_request" "&X-Amz-Date=19990219T000000Z" "&X-Amz-Expires=86400" "&X-Amz-SignedHeaders=host" "&user-id=value2" "&username=value1%20%28value3%29%40gmail.com" "&X-Amz-Signature=b4ac7428943c9801746b6d00112d3ae76739d79ee3e8e73070110979ddab4a1d" ) assert presigned_url == expected
def get_signed_url( self, action, expires_in, public_data=False, force_signed_url=True, **kwargs ): aws_creds = get_value( config, "AWS_CREDENTIALS", InternalError("credentials not configured") ) s3_buckets = get_value( config, "S3_BUCKETS", InternalError("buckets not configured") ) bucket_name = self.bucket_name() bucket = s3_buckets.get(bucket_name) if bucket and bucket.get("endpoint_url"): http_url = bucket["endpoint_url"].strip("/") + "/{}/{}".format( self.parsed_url.netloc, self.parsed_url.path.strip("/") ) else: http_url = "https://{}.s3.amazonaws.com/{}".format( self.parsed_url.netloc, self.parsed_url.path.strip("/") ) credential = S3IndexedFileLocation.get_credential_to_access_bucket( bucket_name, aws_creds, expires_in ) # if it's public and we don't need to force the signed url, just return the raw # s3 url aws_access_key_id = get_value( credential, "aws_access_key_id", InternalError("aws configuration not found"), ) # `aws_access_key_id == "*"` is a special case to support public buckets # where we do *not* want to try signing at all. the other case is that the # data is public and user requested to not sign the url if aws_access_key_id == "*" or (public_data and not force_signed_url): return http_url region = self.get_bucket_region() if not region and not bucket.get("endpoint_url"): region = flask.current_app.boto.get_bucket_region( self.parsed_url.netloc, credential ) user_info = _get_user_info() url = generate_aws_presigned_url( http_url, ACTION_DICT["s3"][action], credential, "s3", region, expires_in, user_info, ) return url
def test_generate_presigned_url(): cred = { "aws_access_key_id": "AKIDEXAMPLE", "aws_secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY", "aws_session_token": "FQoDYXdzEPv//////////wEaDD/RcZIzhOP3tz1Ut7N W7jud8VV53T59A2TNO2ZXkt", } url = "https://s3.amazonaws.com/cdis-presigned-url-test/testdata" date = datetime.date(2018, 2, 19) with mock_datetime(date, datetime): presigned_url = generate_aws_presigned_url( url, "GET", cred, "s3", "us-east-1", 86400, { "user-id": "value2", "username": "******" }, ) print(presigned_url) expected = ( "{}?X-Amz-Algorithm=AWS4-HMAC-SHA256" "&X-Amz-Credential=AKIDEXAMPLE%2F20180219%2Fus-east-1%2Fs3%2Faws4_request" "&X-Amz-Date=20180219T000000Z" "&X-Amz-Expires=86400" "&X-Amz-Security-Token={}" "&X-Amz-SignedHeaders=host" "&user-id=value2" "&username=value1%40gmail.com" "&X-Amz-Signature=e63e7c291b2c89abf7a94ca1ed7438862feaadffc47a0c925723798ffb5a9bea" .format(url, quote(cred.get("aws_session_token"), safe=""))) assert presigned_url == expected
def get_signed_url(self, action, expires_in, public_data=False): aws_creds = get_value( flask.current_app.config, "AWS_CREDENTIALS", InternalError("credentials not configured"), ) http_url = "https://{}.s3.amazonaws.com/{}".format( self.parsed_url.netloc, self.parsed_url.path.strip("/")) config = self.get_credential_to_access_bucket(aws_creds, expires_in) aws_access_key_id = get_value( config, "aws_access_key_id", InternalError("aws configuration not found")) if aws_access_key_id == "*": return http_url region = flask.current_app.boto.get_bucket_region( self.parsed_url.netloc, config) user_info = {} if not public_data: user_info = S3IndexedFileLocation.get_user_info() url = generate_aws_presigned_url( http_url, ACTION_DICT["s3"][action], config, "s3", region, expires_in, user_info, ) return url