1

I have some CORS rules on my S3 bucket.

This is what it looks like:

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

When I am in my app, and I try to upload a file (aka...do a POST request) in my JS console, I get this error:

XMLHttpRequest cannot load https://myapp.s3.amazonaws.com/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://prod-myapp.herokuapp.com' is therefore not allowed access. The response had HTTP status code 403.

I attempted to do a POST from my CLI and I got this:

$ curl -v -H "Origin: http://prod-myapp.herokuapp.com" -X POST https://myapp.s3.amazonaws.com
* Rebuilt URL to: https://myapp.s3.amazonaws.com/
*   Trying XX.XXX.XX.153...
* Connected to myapp.s3.amazonaws.com (XX.XXX.XX.153) port 443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
* Server certificate: *.s3.amazonaws.com
* Server certificate: VeriSign Class 3 Secure Server CA - G3
* Server certificate: VeriSign Class 3 Public Primary Certification Authority - G5
> POST / HTTP/1.1
> Host: myapp.s3.amazonaws.com
> User-Agent: curl/7.43.0
> Accept: */*
> Origin: http://prod-myapp.herokuapp.com
> 
< HTTP/1.1 412 Precondition Failed
< x-amz-request-id: SOME_ID
< x-amz-id-2: SOME_ID_2
< Content-Type: application/xml
< Transfer-Encoding: chunked
< Date: Thu, 17 Sep 2015 04:43:28 GMT
< Server: AmazonS3
< 
<?xml version="1.0" encoding="UTF-8"?>
* Connection #0 to host myapp.s3.amazonaws.com left intact
<Error><Code>PreconditionFailed</Code><Message>At least one of the pre-conditions you specified did not hold</Message><Condition>Bucket POST must be of the enclosure-type multipart/form-data</Condition><RequestId>SOME_ID</RequestId><HostId>SOME_HOST_ID</HostId></Error>

I just added the CORS rule that applies to the domain I am trying from about 10 - 15 minutes ago. But I was under the impression that it should happen immediately.

Is there some remote cache that I need to bust to get my browser to work? I tried it both in normal mode and in Incognito Mode.

Also, based on the results from curl, it seems as if I am no longer getting an Access-Control-Allow-Origin header error, right? So, theoretically, it should be working in my browser.

Am I misreading what is happening at the command-line?

What else am I missing?

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
marcamillion
  • 32,933
  • 55
  • 189
  • 380
  • The fact that curl is not returning the CORS headers indicates that CORS is not set on AWS. Are you using CloudFront by any chance? –  Sep 26 '15 at 01:24
  • Network tab - > Disable cache on Chrome if you think that might be cache issue, incognito wont work – Vitaliy Terziev Feb 16 '16 at 13:56

3 Answers3

0

This is a slightly solution that what I have done. I set up the policy in S3 to allow put content to bucket by only the restrict domain as referer

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AddPerm",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::myapp/*",
            "Condition": {
                "StringLike": {
                    "aws:Referer": "http://prod-myapp.herokuapp.com/*"
                }
            }
        }
    ]
}

so you can test the PUT method by

curl -v -H "Referer: http://prod-myapp.herokuapp.com/index.php" -H "Content-Length: 0" -X PUT https://myapp.s3.amazonaws.com/testobject.jpg
0

The error message from curl says:

At least one of the pre-conditions you specified did not hold
Bucket POST must be of the enclosure-type multipart/form-data

You can make curl use the content-type "multipart/form-data" by using the -F option (e.g. "-F name=value"). You can use this multiple times to add all of the form parameters that you need. This page lists the parameters expected by S3:

http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html

Specifying "file" and "key" gets you to the point where it fails with an "Access Denied" error. I assume that you've set it to be private, so you probably need the "access-key-id" or similar to get beyond this point.

curl -v -H "Origin: http://prod-myapp.herokuapp.com" -X POST \
    https://myapp.s3.amazonaws.com -F key=wibble -F file=value

Also, based on the results from curl, it seems as if I am no longer getting an Access-Control-Allow-Origin header error, right? So, theoretically, it should be working in my browser.

It seems actually to make no difference whether you specify the -H origin option, so I'm not sure if your CORS setting is actually having any effect.

sheltond
  • 1,877
  • 11
  • 15
0

Check which requests you send to the server, before POST request can be sent OPTIONS request (chrome do it)

I got Precondition Failed error for CORS because only POST method was allowed, allowing OPTIONS method resolved this problem.

genichm
  • 525
  • 7
  • 18