Предписанный URL-адрес AWS работает с библиотекой запросов Python, но не работает с cURL - PullRequest
0 голосов
/ 04 октября 2019

Недавно я начал использовать предварительно подписанные URL-адреса AWS для загрузки файлов на S3. Созданные предварительно подписанные URL-адреса отлично работают при использовании библиотеки Python Requests следующим образом:

Создание предварительно подписанного URL:

def create_presigned_post(bucket_name, object_name,
                          fields=None, conditions=None, expiration=3600):
    """Generate a presigned URL S3 POST request to upload a file

    :param bucket_name: string
    :param object_name: string
    :param fields: Dictionary of prefilled form fields
    :param conditions: List of conditions to include in the policy
    :param expiration: Time in seconds for the presigned URL to remain valid
    :return: Dictionary with the following keys:
        url: URL to post to
        fields: Dictionary of form fields and values to submit with the POST
    :return: None if error.
    """

    # Generate a presigned S3 POST URL
    s3_client = boto3.client('s3')
    try:
        response = s3_client.generate_presigned_post(bucket_name,
                                                     object_name,
                                                     Fields=fields,
                                                     Conditions=conditions,
                                                     ExpiresIn=expiration)
    except ClientError as e:
        logging.error(e)
        return None

    # The response contains the presigned URL and required fields
    return response

Выполнение запроса для получения предварительно назначенного URL


# Getting a presigned_url to upload the file into S3 Bucket.
        headers = {'Content-type': 'application/json', 'request': 'upload_url', 'target': FILENAME, 'x-api-key': API_KEY}

        r_upload = requests.post(url = API_ENDPOINT, headers = headers)

        url = json.loads(json.loads(r_upload.text)['body'])['url']
        fields_ = json.loads(json.loads(r_upload.text)['body'])['fields']
        fields = {
                "x-amz-algorithm": fields_["x-amz-algorithm"],
                "key": fields_["key"],
                "policy": fields_["policy"],
                "x-amz-signature": fields_["x-amz-signature"],
                "x-amz-date": fields_["x-amz-date"],
                "x-amz-credential": fields_["x-amz-credential"],
                "x-amz-security-token":  fields_["x-amz-security-token"]
        }

        fileobj = open(FILENAME, 'rb')
        http_response = requests.post(url, data=fields,files={'file': (FILENAME, fileobj)})

Действительный ответ

 "{\"url\": \"https://****.s3.amazonaws.com/\", 
   \"fields\": 
        {\"key\": \"******\", \"x-amz-algorithm\": \"*******\", \"x-amz-credential\": \"*******\", \"x-amz-date\": \"*********\", \"x-amz-security-token\": \"********", \"policy\": \"**********\", \"x-amz-signature\": \"*******\"}}

И, как вы можете видеть, я не даю AWSAccessKeyили любые учетные данные при загрузке файла с использованием сгенерированного предварительно подписанного URL-адреса, и это так логично, поскольку предварительно подписанный URL-адрес создается для внешних пользователей, которые не должны предоставлять учетные данные при использовании такого URL-адреса.

Однако и при попытке выполнить тот же вызов, сделанный библиотекой Python Requests, используя cURL, запрос завершается с ошибкой:

< HTTP/1.1 403 Forbidden
<Error><Code>AccessDenied</Code><Message>Access Denied</Message><Error>

Чтобы получить точный вызов запроса, сделанный requests.post,Я бегу:

req = http_response.request
command = "curl -X {method} -H {headers} -d '{data}' '{uri}'"
method = "PUT"
uri = req.url
data = req.body
headers = ['"{0}: {1}"'.format(k, v) for k, v in req.headers.items()]
headers = " -H ".join(headers)
print(command.format(method=method, headers=headers, data=data, uri=uri))

Что возвращает:

curl -v -X PUT -H "Connection: keep-alive" --upload-file xxxx.zip -H "Accept-Encoding: gzip, deflate" -H "Accept: */*" -H "User-Agent: python-requests/2.18.4" -H "Content-Length: xxxx" -H "Content-Type: multipart/form-data; boundary=8a9864bdxxxxx00100ba04cc055a" -d '--8a9864bd377041xxxxx04cc055a
Content-Disposition: form-data; name="x-amz-algorithm"
AWS4-HMAC-SHA256

--8a9864bd377041e0b00100ba04cc055a
Content-Disposition: form-data; name="key"
xxxxx.zip

--8a9864bd377041e0b00100ba04cc055a
Content-Disposition: form-data; name="x-amz-signature"
*****

--8a9864bd377041e0b00100ba04cc055a
Content-Disposition: form-data; name="x-amz-security-token"
*****

--8a9864bd377041e0b00100ba04cc055a
Content-Disposition: form-data; name="x-amz-date"
*****

--8a9864bd377041e0b00100ba04cc055a
Content-Disposition: form-data; name="policy"
*****

--8a9864bd377041e0b00100ba04cc055a
Content-Disposition: form-data; name="x-amz-credential"
xxxxx/xxxxx/xxxx/s3/aws4_request

' 'https://xxxxx.s3.amazonaws.com/'

Затем переформулируйте его:

$ curl -v -T file "https://****.s3.amazonaws.com/?key=************&x-amz-algorithm=***************&x-amz-credential=*************&x-amz-security-token=************&policy=**********&x-amz-signature=****************

После исследования я не нашел ничего похожего на эту проблему,но: https://aws.amazon.com/es/premiumsupport/knowledge-center/s3-access-denied-error/

Это все еще кажется мне не логичным, потому что яне предполагается вводить учетные данные при использовании предварительно подписанного URL-адреса.

Я не знаю, пропускаю ли я что-то из полного запроса, сделанного библиотекой Python Requests.

Любые идеи, пожалуйста!

С уважением,

Ршад

1 Ответ

0 голосов
/ 04 октября 2019

Эта простая команда curl должна работать:

При обычном предварительно назначенном URL-адресе это будет выглядеть следующим образом:

curl -v \
-F key=<filename> \
-F x-amz-algorithm=*** \
-F x-amz-credential=*** \
-F x-amz-date=*** \
-F x-amz-security-token=*** \
-F policy=*** \
-F x-amz-signature=*** \
-F file=@<filename> \
'https://<bucket>.s3.amazonaws.com/'

Поле -F позволяет вам указать дополнительные данные POST, которыедолжен быть загружен в S3 (то есть из данных полей, возвращенных с предварительно подписанными URL-адресами.

С уважением,

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...