Amazon S3 PHP SDK pre-signed requests - php

I am trying to generate a presigned request with the S3 PHP SDK like this:
$s3Client = Aws\S3\S3Client::factory([
'credentials' => new Aws\Common\Credentials\Credentials('my-access-code', 'xxx')
]);
$command = $s3Client->getCommand('GetObject', [
'Bucket' => 'my-bucket-name',
'Key' => 'awesome-cat-image.png',
]);
$signedUrl = $command->createPresignedUrl('+10 minutes');
But when I goto the URL I get an error saying:
<Error>
<Code>SignatureDoesNotMatch</Code>
<Message>
The request signature we calculated does not match the signature you provided. Check your key and signing method.
</Message>
<AWSAccessKeyId>xxx</AWSAccessKeyId>
<StringToSign>GET 1422564095 /my-bucket-name/awesome-cat-image.png</StringToSign>
<SignatureProvided>xxx</SignatureProvided>
<StringToSignBytes>
xxx
</StringToSignBytes>
<RequestId>xxx</RequestId>
<HostId>
xxx
</HostId>
</Error>
Accessing https://my-bucket-name.s3.amazonaws.com/awesome-cat-image.png works just fine with permissions set to allow non authenticated users.

$cmd = $s3Client->getCommand('GetObject', [
'Bucket' => 'my-bucket',
'Key' => 'testKey'
]);
$request = $s3Client->createPresignedRequest($cmd, '+20 minutes');
// Get the actual presigned-url
$presignedUrl = (string) $request->getUri();
You can find more details here http://docs.aws.amazon.com/aws-sdk-php/v3/guide/service/s3-presigned-url.html

Related

The provided token is malformed or otherwise invalid

latestAll S3 bucket file is displayed, but when I upload file then error is generate.
I have ARN and instance profile.
use Aws\Credentials\CredentialProvider;
use Aws\Credentials\InstanceProfileProvider;
use Aws\Credentials\AssumeRoleCredentialProvider;
use Aws\S3\S3Client;
use Aws\Sts\StsClient;
$profile = new InstanceProfileProvider();
$ARN = ""; // MY ARN
$sessionName = "s3-access-example";
$assumeRoleCredentials = new AssumeRoleCredentialProvider([
'client' => new StsClient([
'region' => "ap-east-1",
'version' => "latest",
'credentials' => $profile
]),
'assume_role_params' => [
'RoleArn' => $ARN,
'RoleSessionName' => $sessionName,
],
]);
$provider = CredentialProvider::memoize($assumeRoleCredentials);
$this->s3hd = S3Client::factory([
'credentials' => $provider,
'version' => "latest",
'region' => "ap-east-1"
]);
public function upload($name, $file, $type, $Bucket = false)
{
if (! $Bucket) {
$Bucket = $this->bucket;
}
$result = $this->s3hd->putObject([
'Bucket' => $Bucket,
'Key' => $name,
'SourceFile' => $file,
'ContentType' => $type,
'ACL' => 'public-read'
]);
$this->s3hd->waitUntil('ObjectExists', [
'Bucket' => $Bucket,
'Key' => $name
]);
return $result;
}
Message: Error executing "PutObject" on error file url here; AWS HTTP error: Client error: PUT error file url here resulted in a 400 Bad Request` response: InvalidTokenThe provided token is malformed or other (truncated...) InvalidToken (client): The provided token is malformed or otherwise invalid. - InvalidTokenThe provided token is malformed or otherwise invalid.
In my case. I was trying through CLI.
I configured AWS cli by running
aws configure
Inside ~/.aws/credentials, look for session_token. If you have the session_token. Then update it.
Otherwise remove session_token and try again.
And Voila It worked!
You're getting this error because Hong Kong (ap-east-1) is not enabled by default. You need to enable it in the AWS console if you have the correct permissions, then try again.
See the AWS Docs for instructions on how to do that.
I am using s3cmd and based on the above answer I was able to solve by deleting the .s3cmd file and reconfiguring (s3cmd --configure), which cleared the access_token:
diff .s3cfg previous_s3cmd
< access_token =
---
> access_token = vkp1Jf\etc...
Also increased the chunk sizes:
< recv_chunk = 65536
---
> recv_chunk = 4096
< send_chunk = 65536
---
> send_chunk = 4096
And I guess I had previously opted for https requests, as opposed to the (current) default:
< use_https = True
---
> use_https = False
Success
Success. Your access key and secret key worked fine :-)
Now verifying that encryption works...
Success. Encryption and decryption worked fine :-)

Uploading file to S3 using presigned URL in PHP

I am developing a Web Application using PHP. In my application, I need to upload the file to the AWS S3 bucket using Presigned URL. Now, I can read the private file from the S3 bucket using pre-signed like this.
$s3Client = new S3Client([
'version' => 'latest',
'region' => env('AWS_REGION', ''),
'credentials' => [
'key' => env('AWS_IAM_KEY', ''),
'secret' => env('AWS_IAM_SECRET', '')
]
]);
//GetObject
$cmd = $s3Client->getCommand('GetObject', [
'Bucket' => env('AWS_BUCKET',''),
'Key' => 'this-is-uploaded-using-presigned-url.png'
]);
$request = $s3Client->createPresignedRequest($cmd, '+20 minutes');
//This is for reading the image. It is working.
$presignedUrl = (string) $request->getUri();
When I access the $presignedUrl from the browser, I can get the file from the s3. It is working. But now, I am uploading a file to S3. Not reading the file from s3. Normally, I can upload the file to the S3 like this.
$client->putObject(array(
'Bucket' => $bucket,
'Key' => 'data.txt',
'Body' => 'Hello!'
));
The above code is not using the pre-signed URL. But I need to upload the file using a pre-signed URL. How, can I upload the file using a pre-signed URL. For example, what I am thinking is something like this.
$client->putObject(array(
'presigned-url' => 'url'
'Bucket' => $bucket,
'Key' => 'data.txt',
'Body' => 'Hello!'
));
How can I upload?
It seems reasonable that you can create a pre-signed PutPobject command by running:
$cmd = $s3Client->getCommand('PutObject', [
'Bucket' => $bucket,
'Key' => $key
]);
$request = $s3Client->createPresignedRequest($cmd, '+20 minutes')->withMethod('PUT');
Then you might want to perform the PUT call from PHP using:
file_put_contents(
$request->getUri(),
'Hello!',
stream_context_create(['http' => [ 'method' => 'PUT' ]])
);
If you want to create a URL that a browser can submit, then you need to have the browser send the file as a form POST. This AWS documentation explains how to create a pre-signed POST request with the fields that you then need to put into an HTML form and display to the user: https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/s3-presigned-post.html
Also, this answer might be useful: https://stackoverflow.com/a/59644117/53538

AWS S3 authorization mechanism - Signature 4

I'm currently struggling with getting a S3 download link working. I've been using this code as reference but when I try to open the file, I get the error:
The authorization mechanism you have provided is not supported. Please
use AWS4-HMAC-SHA256.
I tried a few other scripts floating around, but all ended with some other error message.
Is there an easy way to migrate the script I'm using to make it work with Signature v4?
UPDATE: as suggested by hjpotter92, I used the AWS-SDK and came up with this working code:
$client = S3Client::factory([
'version' => 'latest',
'region' => 'eu-central-1',
'signature' => 'v4',
'credentials' => [
'key' => '12345',
'secret' => 'ABCDE'
]
]);
$cmd = $client->getCommand('GetObject', [
'Bucket' => '###name###',
'Key' => $fileName
]);
$request = $client->createPresignedRequest($cmd, '+2 minutes');
$presignedUrl = (string) $request->getUri();
return $presignedUrl;

Create AWS S3 presigned URL with MD5 hash using PHP SDK

I've been unable to construct an S3 presigned URL containing a MD5 hash. Here is the code I'm using:
$s3 = new Aws\S3\S3Client( ... );
$md5Hash = "YmEwMWVmNzE5MjI3YzdjNmI0ZjYzNGMxZWI1MmY1Y2U=";
$cmd = $s3->getCommand('PutObject', [
'Bucket' => $bucket,
'Key' => $key,
'Content-MD5' => $md5Hash,
'ContentType' => $contentType,
'Body' => ''
]);
$request = $s3->createPresignedRequest($cmd, '+5 minutes');
$presignedUrl = (string)$request->getUri();
The resulting presignedURL looks something like:
http://s3-external-1.amazonaws.com/{bucket}/{key}?X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWC7FFD2T3NCEUNQ%2F20170503%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20170503T215723Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3000&X-Amz-Signature=ca61d80dcfee351e7ee8440a47c5007f1bc905ddc8229077abddab9c39412dc7
When I add the Content-MD5 hash to my PUT request, I get back an error indicating the MD5 header wasn't signed:
AccessDenied - There were headers present in the request which were not signed
HeadersNotSigned - content-md5
Any help appreciated!

Trying to register an amazon s3 presigned url and getting an error

The question it self explanatory, when trying to create a presigned url I get the following error:
Error retrieving credentials from the instance profile metadata server. (cURL error 28: Connection timed out after 1001 milliseconds (see http://curl.haxx.se/libcurl/c/libcurl-errors.html))
I have used the code from here exactly https://docs.aws.amazon.com/aws-sdk-php/v3/guide/service/s3-presigned-url.html
My code is below:
$s3Client = new S3Client([
'region' => 'eu-west-1',
'version' => '2006-03-01',
]);
$cmd = $s3Client->getCommand('GetObject', [
'Bucket' => 'my-bucket-name',
'Key' => 'AKIAJNCZ5***********'
]);
$request = $s3Client->createPresignedRequest($cmd, '+20 minutes');
// Get the actual presigned-url
$presignedUrl = (string) $request->getUri();
print_r($presignedUrl);
Any reason why this is happening?
EDIT::
Ok so this fixed my problem, but it wasnt not actually even in the docs:
$s3Client = new S3Client([
'region' => 'eu-west-1',
'version' => '2006-03-01',
'credentials' => ['key' => 'AKIAJNCZ5MY*******8','secret'=>'NgeFc+2/Q2cUAmL/+lP2gp***********8']
]);
Adding the credentials assoc array :)
However I am now unsure how to use this presigned url to download one of my files aha, so if anyone knows and doesnt mind putting me in the right direction :)
'Key' in the getCommand array is the name/path to the file you want to generate a pre-signed URL for, not your AWS key :)
$cmd = $s3Client->getCommand('GetObject', [
'Bucket' => 'my-bucket-name',
'Key' => 'path/to/file.txt', // or just file.txt if it's in the root of the bucket
]);

Categories