Signed url for google bucket does not match signature
I'm having a hard time working with google repository.
So, I'm trying to make a signed URL , already has a Client ID (which is an email address) and a private key (as described here ), so:
STEP 1: build a string
function googleBuildConfigurationString($method, $expiration, $file, array $options = []) {
$allowedMethods = ['GET', 'HEAD', 'PUT', 'DELETE'];
// initialize
$method = strtoupper($method);
$contentType = $options['Content_Type'];
$contentMd5 = $options['Content_MD5'] ? base64_encode($options['Content_MD5']) : '';
$headers = $options['Canonicalized_Extension_Headers'] ? $options['Canonicalized_Extension_Headers'] . PHP_EOL : '';
$file = $file ? $file : $options['Canonicalized_Resource'];
// validate
if(array_search($method, $allowedMethods) === false) {
throw new RuntimeException("Method '{$method}' is not allowed");
}
if(!$expiration) {
throw new RuntimeException("An expiration date should be provided.");
}
return <<<TXT
{$method}
{$contentMd5}
{$contentType}
{$expiration}
{$headers}{$file}
TXT;
}
So far so good (I think) repeating the output, it looks like the examples, so now sign the line
STEP 2: Signing the string I originally used openssl_public_encrypt, after searching found that the google-api-php client has Google_Signer_P12 (which actually uses openssl_sign), so the method looks like this:
function googleSignString($certificatePath, $stringToSign) {
return (new Google_Signer_P12(
file_get_contents($certificatePath),
'notasecret'
))->sign($stringToSign);
}
And here I am not sure if this signing is correct, finally creating the final url
STEP 3: create the URL
function googleBuildSignedUrl($serviceEmail, $file, $expiration, $signature) {
return "http://storage.googleapis.com{$file}"
. "?GoogleAccessId={$serviceEmail}"
. "&Expires={$expiration}"
. "&Signature=" . urlencode($signature);
}
But the url will open in the browser:
<Error>
<Code>SignatureDoesNotMatch</Code>
<Message>
The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.
</Message>
<StringToSign>GET 1437470250 /example/video.mp4</StringToSign>
</Error>
I added a gist with the latest script which will be easier to read
So, any idea what I am doing wrong?
source to share
I found a solution, there was an error with the expiration date when I did:
$expiration = (new DateTime())->modify('+3h')->getTimestamp();
So, I changed h
to hours
, so now it works, for example:
$expiration = (new DateTime())->modify('+3hours')->getTimestamp();
But that didn't quite solve it, the actual missing part is that Google_Signer_P12::sign()
it requires it to be base64 encoded which is stated in the google docs:
Google Cloud Storage expects Base64 encoding in its APIs.
However, I (wrongly) though would Google_Signer_P12::sign()
have done it already, so after I realized it was necessary, I changed the sign method to:
function googleSignString($certificatePath, $stringToSign)
{
return base64_encode((new Google_Signer_P12(
file_get_contents($certificatePath),
'notasecret'
))->sign($stringToSign));
}
And now it works !!!
I've also updated the gist for anyone who wants to use it :)
source to share