Skip to content

Instantly share code, notes, and snippets.

@fabito
Created October 28, 2014 19:38
Show Gist options
  • Save fabito/54b4b157f1b1996f99c6 to your computer and use it in GitHub Desktop.
Save fabito/54b4b157f1b1996f99c6 to your computer and use it in GitHub Desktop.
package com.ciandt.ko.fwc.api.infrastructure.gcs;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Calendar;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.ciandt.ko.fwc.api.domain.model.photo.StorageService.StorageName;
import com.google.appengine.api.appidentity.AppIdentityService;
import com.google.appengine.api.appidentity.AppIdentityService.SigningResult;
import com.google.appengine.api.appidentity.AppIdentityServiceFactory;
import com.google.common.base.Charsets;
import com.google.common.io.BaseEncoding;
public class GcsAppIdentityServiceUrlSigner implements GcsUrlSigner {
private static final String NEW_LINE = "\n";
private static final Logger LOGGER = Logger.getLogger(GcsAppIdentityServiceUrlSigner.class.getName());
private static final String BASE_URL = "https://storage.googleapis.com";
/**
* AppIdentityService.
*/
private final AppIdentityService identityService = AppIdentityServiceFactory.getAppIdentityService();
@Override
public String getSignedUrl(final String httpVerb, final StorageName storageName, final int expirationTime) {
LOGGER.fine("Signing URL with bucketName = " + storageName.getBucketName() + " and objectName = " + storageName.getObjectName());
return getSignedUrl(httpVerb, storageName.getStorageFullName(), expirationTime);
}
@Override
public String getSignedUrl(final String httpVerb, final String targetName, final int expirationTime) {
LOGGER.fine("Signing URL with targetName = " + targetName);
final long expiration = expiration(expirationTime);
final String unsigned = stringToSign(httpVerb, expiration, targetName);
final String signature = signUrlEncoded(unsigned);
return url(targetName, expiration, signature);
}
private static long expiration(final int expirationTime) {
final Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, expirationTime);
final long convert = 1000l;
return calendar.getTimeInMillis() / convert;
}
private String stringToSign(final String httpVerb, final long expiration, final String storageFullName) {
final String contentType = "";
final String contentMD5 = "";
final String canonicalizedExtensionHeaders = "";
final String canonicalizedResource = "/" + storageFullName;
return httpVerb +
NEW_LINE + contentMD5 +
NEW_LINE + contentType +
NEW_LINE + expiration +
NEW_LINE + canonicalizedExtensionHeaders + canonicalizedResource;
}
private String signUrlEncoded(final String stringToSign) {
final String signatureBase64 = sign(stringToSign);
try {
return URLEncoder.encode(signatureBase64 , Charsets.UTF_8.name());
} catch (final UnsupportedEncodingException e) {
LOGGER.log(Level.WARNING, String.format("Error while signing URL [%s]", stringToSign), e);
return null;
}
}
private String sign(final String stringToSign) {
final SigningResult signingResult = identityService.signForApp(stringToSign.getBytes());
final byte[] signatureBytes = signingResult.getSignature();
return BaseEncoding.base64().encode(signatureBytes);
}
/**
* @param targetName
* @param expiration
* @param signature
* @return
*/
protected String url(final String targetName, final long expiration,
final String signature) {
return new StringBuilder(BASE_URL).
append("/").
append(targetName).
append("?GoogleAccessId=").
append(identityService.getServiceAccountName()).
append("&Expires=").
append(expiration).
append("&Signature=").
append(signature).
toString();
}
@Override
public String getGoogleAccessId() {
return identityService.getServiceAccountName();
}
@Override
public String signature(final GcsPolicyDocument policy) {
return sign(policy.asJsonBase64Encoded());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment