Создание подписи Amazon S3 CORS с помощью Python

У меня чертовски много времени, чтобы заставить S3 принимать загрузки через запрос CORS POST, сгенерированный PhoneGap (Cordova) FileTransfer.upload(). Любые предложения относительно того, что я могу упустить, будут оценены. В настоящее время я получаю ответ 403 AccessDenied, используя приведенный ниже код. Я много раз просматривал это, сравнивая с документацией S3, и не могу понять проблему.

Вот код Python, который генерирует подпись:

# Create policy document for S3.
policy_obj = {"expiration": "2014-01-01T00:00:00Z",
  "conditions": [ 
    {"bucket": "<my.bucket.name>"}, 
    ["starts-with", "$key", "story_"],
    {"acl": "public-read"},
    ["eq", "$Content-Type", "audio/mp4"],
    ["content-length-range", str(0), str(2097152)]
  ]
}

policy = base64.b64encode(json.dumps(policy_obj))

# Create signature for S3
signature = base64.b64encode(
    hmac.new(
        key=app.config['AWS_SECRET_KEY'], 
        msg=policy, 
        digestmod=hashlib.sha1
    ).digest()
)

Подпись, созданная этим процессом, совпадает с подписью, созданной S3 Signature Tester (преобразование политики base64 в Hex а затем запустить это через Signature Tester с секретным ключом).

Результирующая политика и подпись передаются клиенту, а запрос к S3 создается с помощью этого вызова PhoneGap FileTransfer:

// Upload file to Amazon S3
// r is the response object generated by Python
var options = new FileUploadOptions();
options.chunkedMode = false;
options.mimeType="audio/mp4";
options.fileKey='file';
options.fileName='story_' + uniqueKey + '.m4a';
options.params={
    "key": "${filename}",
    "acl": "public-read",
    "AWSAccessKeyId": r.aws_access_key,
    "Policy": r.policy,
    "Signature": r.signature,
};

var ft = new FileTransfer();
ft.upload(path, "http://<my.bucket.name>.s3.amazonaws.com/", uploadSuccess, uploadFail, options);

Это конфигурация CORS (да, я планирую заблокировать ее, как только загрузка будет работать):

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

Это политика ведра:

{
    "Version": "2008-10-17",
    "Id": "Policy1356975063803",
    "Statement": [
        {
            "Sid": "Stmt1357234455973",
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<my.bucket.name>/*"
        },
        {
            "Sid": "Stmt1356975061658",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::293855469575:root"
            },
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::<my.bucket.name>"
        }
    ]
}

ОБНОВЛЕНИЕ:

Вот как выглядит сама политика после того, как Python преобразовал объект в JSON:

{
  "conditions": [
    {
      "bucket": "<my.bucket.name>"
    }, 
    [
      "starts-with", 
      "$key", 
      "story_"
    ], 
    {
      "acl": "public-read"
    }, 
    [
      "eq", 
      "$Content-Type", 
      "audio/mp4"
    ], 
    [
      "content-length-range", 
      "0", 
      "6291456"
    ]
  ], 
  "expiration": "2014-01-01T00:00:00Z"
}

person bjudson    schedule 04.01.2013    source источник
comment
Вот сценарий S3 для Django, не вижу существенной разницы между тем, что они делают, и тем, что делаю я (я безуспешно пробовал параметр indent=2): djangosnippets.org/snippets/2829   -  person bjudson    schedule 12.03.2013


Ответы (1)


Вы пытались удалить новые строки в своей политике?

Вот код Ruby для политики, любезно предоставленный s3_file_upload:

Base64.encode64(policy_data.to_json).gsub("\n", "")

Пожалуйста, дайте мне знать, если вам удалось заставить вашу загрузку работать, так как я пытаюсь сделать то же самое.

person Thomas O'Dell    schedule 10.02.2013
comment
Функция json.dumps(), которую я использую выше, по умолчанию генерирует политику без новой строки. Я также пробовал это с новыми строками (установив параметр indent=2), я пытался удалить пробелы с помощью strip() и просто пытался загрузить документ политики из текстового файла, а не генерировать json из объекта. Каждый раз получаю ответ 403. Если вам повезло, дайте мне знать... - person bjudson; 12.03.2013