Note that there are some explanatory texts on larger screens.

plurals
  1. POGAE Application needing to create Expiring Signed URL's to Google Cloud Storage
    text
    copied!<p>I was successfully able to create a stand-alone Java Application that creates Expiring Signed URL's to assets sitting in Google Cloud Storage. However, I have been unsuccessful in figuring out how to create Expiring Signed URL's to these same assets through AppEngine.</p> <p>How can I create a Expiring Signed URL to Google Cloud Storage Assets that I can return to client applications?</p> <p>Here is my Java Application that works:</p> <pre><code>import java.io.FileInputStream; import java.io.IOException; import java.net.URLEncoder; import java.security.KeyStore; import java.security.PrivateKey; import java.security.Signature; import java.security.UnrecoverableKeyException; import java.util.Calendar; import org.apache.commons.codec.binary.Base64; public class GCSSignedURL { public static void main(String[] args) throws Exception { final String googleAccessId = "XXXXXXXXXXXX@developer.gserviceaccount.com"; final String keyFile = "D:\\XXXXXXXXXXXXXXXXXXXXXXXXXXXXX-privatekey.p12"; final String keyPassword = "notasecret"; Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.MINUTE, 30); String httpVerb = "GET"; String contentMD5 = ""; String contentType = ""; long expiration = calendar.getTimeInMillis(); String canonicalizedExtensionHeaders = ""; String canonicalizedResource = "/myproj/foo.txt"; String stringToSign = httpVerb + "\n" + contentMD5 + "\n" + contentType + "\n" + expiration + "\n" + canonicalizedExtensionHeaders + canonicalizedResource; PrivateKey pkcsKey = loadKeyFromPkcs12(keyFile, keyPassword.toCharArray()); String signature = signData(pkcsKey, stringToSign); String baseURL = "https://storage.cloud.google.com/myproj/foo.txt"; String urlEncodedSignature = URLEncoder.encode(signature, "UTF-8"); String url = baseURL + "?GoogleAccessId=" + googleAccessId + "&amp;Expires=" + expiration + "&amp;Signature=" + urlEncodedSignature; System.out.println(url); } private static PrivateKey loadKeyFromPkcs12(String filename, char[] password) throws Exception { FileInputStream fis = new FileInputStream(filename); KeyStore ks = KeyStore.getInstance("PKCS12"); try { ks.load(fis, password); } catch (IOException e) { if (e.getCause() != null &amp;&amp; e.getCause() instanceof UnrecoverableKeyException) { System.err.println("Incorrect password"); } throw e; } return (PrivateKey) ks.getKey("privatekey", password); } private static String signData(PrivateKey key, String data) throws Exception { Signature signer = Signature.getInstance("SHA256withRSA"); signer.initSign(key); signer.update(data.getBytes("UTF-8")); byte[] rawSignature = signer.sign(); String encodedSignature = new String(Base64.encodeBase64(rawSignature, false), "UTF-8"); return encodedSignature; } } </code></pre> <p>Here is what I have tried:</p> <pre><code>public String signUrl(Long _songId, String _format) throws ResourceNotFoundException { final String googleAccessId = "XXXXXXXXXXXXXXXXXX@developer.gserviceaccount.com"; AppIdentityService service = AppIdentityServiceFactory.getAppIdentityService(); Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.MINUTE, 5); String httpVerb = "GET"; String contentMD5 = ""; String contentType = ""; long expiration = calendar.getTimeInMillis(); String canonicalizedExtensionHeaders = ""; String canonicalizedResource = "/myproj/foo.txt"; String stringToSign = httpVerb + "\n" + contentMD5 + "\n" + contentType + "\n" + expiration + "\n" + canonicalizedExtensionHeaders + canonicalizedResource; SigningResult key = service.signForApp(stringToSign.getBytes()); String baseURL = "https://storage.cloud.google.com/myproj/foo.txt"; String encodedUrl = baseURL + "?GoogleAccessId=" + googleAccessId + "&amp;Expires=" + expiration + "&amp;Signature=" + key.getKeyName(); return encodedUrl; } </code></pre> <p>The result is an expiring URL but requires me to authenticate with my google email / password so the signing isn't working properly. </p> <p>I was able to finally generate an encoded URL using Fabio's suggestion, however, I now get:</p> <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt; -&lt;Error&gt;&lt;Code&gt;SignatureDoesNotMatch&lt;/Code&gt;&lt;Message&gt;The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.&lt;/Message&gt; &lt;StringToSign&gt; GET 1374729586 /[my_bucket]/[my_folder]/file.png&lt;/StringToSign&gt; &lt;/Error&gt; </code></pre> <p>The code I am using to generate the URL is:</p> <pre><code>AppIdentityService service = AppIdentityServiceFactory.getAppIdentityService(); final String googleAccessId = service.getServiceAccountName(); String url = songUrl(_songId, _format); Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.MINUTE, 10); String httpVerb = "GET"; String contentMD5 = ""; String contentType = ""; long expiration = calendar.getTimeInMillis()/1000L; String canonicalizedExtensionHeaders = ""; String canonicalizedResource = "/[my_bucket]/[my_folder]/file.png"; String stringToSign = httpVerb + "\n" + contentMD5 + "\n" + contentType + "\n" + expiration + "\n" + canonicalizedExtensionHeaders + canonicalizedResource; try { String baseURL = http://[my_bucket].commondatastorage.googleapis.com/[my_folder]/file.png; SigningResult signingResult = service.signForApp(stringToSign.getBytes()); String encodedSignature = new String(Base64.encodeBase64(signingResult.getSignature(), false), "UTF-8"); String encodedUrl = baseURL + "?GoogleAccessId=" + googleAccessId + "&amp;Expires=" + expiration + "&amp;Signature=" + encodedSignature; return encodedUrl; } catch (UnsupportedEncodingException e) { throw new ResourceNotFoundException("Unable to encode URL. Unsupported encoding exception.", e); } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload