Created
October 28, 2014 19:38
-
-
Save fabito/54b4b157f1b1996f99c6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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