package org.odata4j.consumer.behaviors;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.ws.rs.core.MediaType;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.odata4j.consumer.ODataClientRequest;
import org.odata4j.consumer.ODataConsumer;
import org.odata4j.core.ODataConstants;
import org.odata4j.core.Throwables;
import org.odata4j.repack.org.apache.commons.codec.binary.Base64;
public class AzureTableBehavior implements OClientBehavior {
private final String account;
private final String key;
public AzureTableBehavior(String account, String key) {
this.account = account;
this.key = key;
}
@Override
public ODataClientRequest transform(ODataClientRequest request) {
try {
String utc = new DateTime(DateTimeZone.UTC).toString("EEE, dd MMM yyyy HH:mm:ss zzz");
String date = utc.substring(0, utc.lastIndexOf(' ') + 1) + "GMT";
// VERB + "\n" +
// Content-MD5 + "\n" +
// Content-Type + "\n" +
// Date + "\n" +
// CanonicalizedResource;
String path = request.getUrl().substring(request.getUrl().indexOf('/', 8) + 1);
boolean isTableRequest = path.startsWith("Tables(");
String contentType = request.getHeaders().get(ODataConstants.Headers.CONTENT_TYPE);
contentType = contentType == null ? "" : contentType;
boolean isPut = request.getMethod().equals("PUT");
boolean isPost = request.getMethod().equals("POST");
boolean isDelete = request.getMethod().equals("DELETE");
if (isPut || isPost || isDelete) {
contentType = MediaType.APPLICATION_ATOM_XML;
request = request.header(ODataConstants.Headers.CONTENT_TYPE, MediaType.APPLICATION_ATOM_XML);
}
String canonicalizedResource = "/" + account + "/" + path;
String stringToSign = request.getMethod() + "\n\n" + contentType + "\n" + date + "\n" + canonicalizedResource;
if (ODataConsumer.dump.requestHeaders())
System.out.println("stringToSign: " + stringToSign);
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(base64Decode(key), mac.getAlgorithm()));
mac.update(stringToSign.getBytes("utf8"));
byte[] sigBytes = mac.doFinal();
String sig = base64Encode(sigBytes);
String auth = "SharedKey " + account + ":" + sig;
if (ODataConsumer.dump.requestHeaders())
System.out.println("auth: " + auth);
request = request
.header("x-ms-version", "2009-09-19")
.header("x-ms-date", date)
.header("Authorization", auth)
.header("DataServiceVersion", "1.0;NetFx")
.header("MaxDataServiceVersion", "1.0;NetFx");
if (isPut
|| (isDelete && !isTableRequest)
|| (isPost && request.getHeaders().containsKey(ODataConstants.Headers.X_HTTP_METHOD)))
request = request.header("If-Match", "*"); // azure tables require for put,delete,merge
if (isDelete) {
request = request.header("Content-Length", "0");
}
return request;
} catch (NoSuchAlgorithmException e) {
throw Throwables.propagate(e);
} catch (InvalidKeyException e) {
throw Throwables.propagate(e);
} catch (UnsupportedEncodingException e) {
throw Throwables.propagate(e);
}
}
private static String base64Encode(byte[] value) {
return Base64.encodeBase64String(value).trim();
}
private static byte[] base64Decode(String value) {
return Base64.decodeBase64(value);
}
}