Google Cloud Services put Fails when Using Signed URL
<p>I am not able to PUT a file to google cloud services via a signed URL.  When I try to do a PUT from a JS Client, I get:</p>

<p>"SignatureDoesNotMatch...The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method."</p>

<p>When I try to post the file using CURL, I get the same error.</p>

<p>The curl command I use is: </p>

<pre><code>#!/bin/bash 
URL="https://storage.googleapis.com/..."
echo $URL
curl $URL -H "Content-Type: image/jpg" --upload-file b.jpg
</code></pre>

<p>I have configured the bucket I intend to post data to based on the documentation, I have generated a service account with the key, and this key is used to generate the signed url.  </p>

<p>The request I sign is of the form:</p>

<pre><code>PUT

image/jpg
1234567890
my-bucket/b.jpg
</code></pre>

<p>where the expiration and bucket names are set and computed.</p>

<p>I have the following Groovy code to generate signed urls:</p>

<pre><code> public String sign(PrivateKey key, String toSign) {
    Signature signer = Signature.getInstance("SHA256withRSA");
    signer.initSign(key);
    signer.update(toSign.getBytes("UTF-8"));
    byte[] rawSignature = signer.sign();
    String s = new String(Base64.encodeBase64(rawSignature), "UTF-8");

    return s;
}

public String signUrl(PrivateKey key, String clientId, String method, String md5, String contentType,
                             long expiration, String gcsPath) {

    String toSign = "${method}\n${md5}\n${contentType}\n${expiration}\n${gcsPath}";
    String signature = sign(key, toSign);
    String url = java.net.URLEncoder.encode(signature);
    return url;
}

public String generateSignedUrl(PrivateKey key, String clientId, String method, String md5, String contentType,
                                       long expiration, String gcsPath) {

    String canonicalizedResource = "/${gcsPath}";
    String signature = signUrl(key, clientId, method, md5, contentType, expiration, canonicalizedResource);
    String finalUrl = "https://storage.googleapis.com/${gcsPath}?GoogleAccessId=${clientId}&amp;Expires=${expiration}&amp;Signature=${signature}"

    finalUrl
}
</code></pre>

<p>This code is accompanied with the following passing unit test lifted straight out of the gsutils github project (<a href="https://github.com/GoogleCloudPlatform/gsutil/blob/master/gslib/tests/test_signurl.py" rel="nofollow">https://github.com/GoogleCloudPlatform/gsutil/blob/master/gslib/tests/test_signurl.py</a>):</p>

<pre><code>    @Test
void thatWeCanSignAPutUrlCorrectly() {
    String expected = """https://storage.googleapis.com/test/test.txt?GoogleAccessId=test@developer.gserviceaccount.com&amp;Expires=1391816302&amp;Signature=A6QbgTA8cXZCtjy2xCr401bdi0e7zChTBQ6BX61L7AfytTGEQDMD%2BbvOQKjX7%2FsEh77cmzcSxOEKqTLUDbbkPgPqW3j8sGPSRX9VM58bgj1vt9yU8cRKoegFHXAqsATx2G5rc%2FvEliFp9UWMfVj5TaukqlBAVuzZWlyx0aQa9tCKXRtC9YcxORxG41RfiowA2kd8XBTQt4M9XTzpVyr5rVMzfr2LvtGf9UAJvlt8p6T6nThl2vy9%2FwBoPcMFaOWQcGTagwjyKWDcI1vQPIFQLGftAcv3QnGZxZTtg8pZW%2FIxRJrBhfFfcAc62hDKyaU2YssSMy%2FjUJynWx3TIiJjhg%3D%3D""";

    long expiration = 1391816302;

    String signedUrl = gsUtils.generateSignedUrl(privateKey, "test@developer.gserviceaccount.com","PUT", "", "", expiration, "test/test.txt")

    assertEquals(expected, signedUrl);
}
</code></pre>

<p>Thank you for whatever insights you may be able to provide, I have been at this problem for a while.</p>