Creating a signed URL to access Google Cloud Bucket.

I'm looking to create an API which will create a signed URL to access a Google Cloud CDN bucket. The key will be provided by Google Cloud CDN.

This will be a on-prem apigee installation so I do not have access to cloud utilities. In other words it must be self contained within on-prem Apigee platform.

I was able to test the process with gsutil and all works fine but now I need to adapt to a API (product/app).

Thanks in advance for any support given.

0 10 2,732
10 REPLIES 10

I guess by "create a signed URL", you want to implement the signing mechanism described here,

https://cloud.google.com/storage/docs/access-control/signed-urls

This part looks pretty straightforward.

StringToSign = HTTP_Verb + "\n" +
               Content_MD5 + "\n" +
               Content_Type + "\n" +
               Expiration + "\n" +
               Canonicalized_Extension_Headers +
               Canonicalized_Resource

And then you need to use an RSA signing with SHA256. That bit is a slightly more difficult. You can do it with the sjcl for JavaScript, or you could do it with standard libraries within a Java callout. The latter would be my preference, as it would be much more reliable and would perform better at runtime.

I have the ability to write the Java code, but I don't have a good way to test this. (I know nothing about signed URLs beyond what I read in about 5 minutes) . The approach is pretty similar to that used in OAuth1.0a, or HttpSignature, or HAWK.

Edit: See here for a first cut. https://github.com/DinoChiesa/ApigeeEdge-Java-GoogleUrlSigner

This callout produces only the signature, not the URL containing the signature.

This page says the final URL should be:

BASE_URL + "?GoogleAccessId=" + GOOGLE_ACCESS_STORAGE_ID + 
           "&Expires=" + EXPIRATION + 
           "&Signature=" + URL_ENCODED_SIGNATURE

This callout only produces the url-encoded signature. You have to assemble the URL yourself.

Edit: this callout produces the signature, and the full URL. You need to supply the resource name to get the full URL as output (in a context variable).

That was supposed to be gsutil as referenced in the google cloud article you read.

To test I could provide inputs (bucket, key, etc) and working example from gsutil. Once the signed URL is built it should successfully return a item from the bucket.

Bill, checkout the Java callout I produced and see if that works correctly.

I zipped up apiproxy folder and tried the import The ui is hanging. I will retry again and get back to you.

Ok project imported now and it will round trip. I need to resurrect my GCP bucket and get my signing key. I'll post my results here as soon as I have them.

Thanks for the help thus far.

Bill - GREAT to hear that you've got it to import.

While you were working, I noticed a problem in the signing code: it was using milliseconds for the expiry, and not seconds. So the signature will be invalid.

I've updated the JAR to v1.0.2, to fix this problem.

Also I changed the name of the output variables.

So please do... "git pull" and re-import. (Delete the previously imported proxy)

Dino,

I made small change in your code.

It starts working with JSON Google Service account key, that distributed in step 1 of This page.

Also I am going to made outVariable with exact url that we need.

After I clean everything up and test I will do another post.

Thank you, Dino.

Yuriy Shleymovich

yes I'm interested in understanding the change you made.

Maybe your change reads the .json containing the Google Service Account key, instead of reading a PEM-encoded private key directly.

Dino,

In sort, the key from json provides PrivateKeyInfo object for which you throws Exception.

Instead It should be processed the same way, as PKCS8EncryptedPrivateKeyInfo Object, except 3 lines:

PrivateKeyInfo privateKeyInfo = (PrivateKeyInfo) o;
//JceOpenSSLPKCS8DecryptorProviderBuilder decryptorProviderBuilder = new JceOpenSSLPKCS8DecryptorProviderBuilder(); //InputDecryptorProvider decryptorProvider = decryptorProviderBuilder.build(password.toCharArray());
//PrivateKeyInfo privateKeyInfo = pkcs8EncryptedPrivateKeyInfo.decryptPrivateKeyInfo(decryptorProvider);

I will cleanup the duplicate code and will create separate a variable(s) to make an additional output that satisfy use case to access storage resources.

When I am done, I will provide you the code.

Thank you,

Yuriy Shleymovich

Ahhhh, very good. I would like to see the final code. Thanks for sharing it.