blob: 4e0dfa10ba6b3302ea4965acc340b92b33b51f99 [file] [log] [blame]
<#-- FreeMarker template (see http://freemarker.org/)
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<#assign licenseFirst = "/*">
<#assign licensePrefix = " * ">
<#assign licenseLast = " */">
<#include "${project.licensePath}">
<#if package?? && package != "">
package ${package};
</#if>
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
/**
*
* @author ${user}
*/
public class ${name} {
private static String accessKey;
private static String secret;
private static final String PROP_FILE = ${name}.class.getSimpleName().toLowerCase() + ".properties";
static {
try {
Properties props = new Properties();
props.load(${name}.class.getResourceAsStream(PROP_FILE));
accessKey = props.getProperty("access_key");
secret = props.getProperty("secret");
} catch (IOException ex) {
Logger.getLogger(${name}.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static String sign(String[][] headers) throws IOException {
if (accessKey == null || accessKey.length() == 0 ||
secret == null || secret.length() == 0) {
throw new IOException("Please specify your access key and secret in the " + PROP_FILE + " file.");
}
if (headers == null) return "";
HashMap<String, String> headerMap = new HashMap<String, String>();
for (int i = 0; i < headers.length; i++) {
headerMap.put(headers[i][0], headers[i][1]);
}
return "AWS " + accessKey + ":" + encodeBytes(
HmacSha1(secret, utf8Encode(getStringToSign(headerMap))));
}
private static String getStringToSign(HashMap<String, String> headerMap) {
String httpVerb = headerMap.get("HTTP-Verb");
if (httpVerb == null) httpVerb = "";
String contentMD5 = headerMap.get("Content-MD5");
if (contentMD5 == null) contentMD5 = "";
String contentType = headerMap.get("Content-Type");
if (contentType == null) contentType = "";
String date = headerMap.get("Date");
if (date == null) date = "";
String stringToSign = httpVerb + "\n" +
contentMD5 + "\n" +
contentType + "\n" +
date + "\n" +
getCanonicalAmazonHeaders(headerMap) +
getCanonicalResource(headerMap);
return stringToSign;
}
private static String getCanonicalAmazonHeaders(HashMap<String, String> headerMap) {
return "";
}
private static String getCanonicalResource(HashMap<String, String> headerParam) {
String prefix = "";
String bucket = headerParam.get("Bucket");
if (bucket != null && bucket.length() > 0) {
prefix = "/" + bucket;
}
String suffix = "";
String uri = headerParam.get("HTTP-Request-URI");
if (uri == null || uri.length() == 0) {
uri = "/";
}
int index = uri.indexOf("?");
if (index != -1) {
suffix += uri.substring(0, index);
String query = uri.substring(index);
if (query.contains("?acl")) {
suffix += "?acl";
} else if (query.contains("?location")) {
suffix += "?location";
} else if (query.contains("?logging")) {
suffix += "?logging";
} else if (query.contains("?torrent")) {
suffix += "?torrent";
}
} else {
suffix += uri;
}
return prefix + suffix;
}
private static byte[] utf8Encode(String data) {
try {
//printBytes(data.getBytes("UTF-8"));
return data.getBytes("UTF-8");
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(${name}.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
private static byte[] HmacSha1(String secretKey, byte[] data) {
try {
Mac mac = Mac.getInstance("HmacSHA1");
//printBytes(secretKey.getBytes());
SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA1");
mac.init(keySpec);
return mac.doFinal(data);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
/* ******** P R I V A T E F I E L D S ******** */
/** Maximum line length (76) of Base64 output. */
private final static int MAX_LINE_LENGTH = 76;
/** The equals sign (=) as a byte. */
private final static byte EQUALS_SIGN = (byte) '=';
/** The new line character (\n) as a byte. */
private final static byte NEW_LINE = (byte) '\n';
/** Preferred encoding. */
private final static String PREFERRED_ENCODING = "UTF-8";
/* ******** S T A N D A R D B A S E 6 4 A L P H A B E T ******** */
/** The 64 valid Base64 values. */
//private final static byte[] ALPHABET;
/* Host platform me be something funny like EBCDIC, so we hardcode these values. */
private final static byte[] _STANDARD_ALPHABET = {
(byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G',
(byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N',
(byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U',
(byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z',
(byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g',
(byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n',
(byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u',
(byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z',
(byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5',
(byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) '+', (byte) '/'
};
/**
* <p>Encodes up to three bytes of the array <var>source</var>
* and writes the resulting four Base64 bytes to <var>destination</var>.
* The source and destination arrays can be manipulated
* anywhere along their length by specifying
* <var>srcOffset</var> and <var>destOffset</var>.
* This method does not check to make sure your arrays
* are large enough to accomodate <var>srcOffset</var> + 3 for
* the <var>source</var> array or <var>destOffset</var> + 4 for
* the <var>destination</var> array.
* The actual number of significant bytes in your array is
* given by <var>numSigBytes</var>.</p>
* <p>This is the lowest level of the encoding methods with
* all possible parameters.</p>
*
* @param source the array to convert
* @param srcOffset the index where conversion begins
* @param numSigBytes the number of significant bytes in your array
* @param destination the array to hold the conversion
* @param destOffset the index where output will be put
* @return the <var>destination</var> array
* @since 1.3
*/
private static byte[] encode3to4(
byte[] source, int srcOffset, int numSigBytes,
byte[] destination, int destOffset) {
byte[] ALPHABET = _STANDARD_ALPHABET;
// 1 2 3
// 01234567890123456789012345678901 Bit position
// --------000000001111111122222222 Array position from threeBytes
// --------| || || || | Six bit groups to index ALPHABET
// >>18 >>12 >> 6 >> 0 Right shift necessary
// 0x3f 0x3f 0x3f Additional AND
// Create buffer with zero-padding if there are only one or two
// significant bytes passed in the array.
// We have to shift left 24 in order to flush out the 1's that appear
// when Java treats a value as negative that is cast from a byte to an int.
int inBuff = (numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8) : 0) | (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0) | (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0);
switch (numSigBytes) {
case 3:
destination[destOffset] = ALPHABET[(inBuff >>> 18)];
destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f];
destination[destOffset + 3] = ALPHABET[(inBuff) & 0x3f];
return destination;
case 2:
destination[destOffset] = ALPHABET[(inBuff >>> 18)];
destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f];
destination[destOffset + 3] = EQUALS_SIGN;
return destination;
case 1:
destination[destOffset] = ALPHABET[(inBuff >>> 18)];
destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
destination[destOffset + 2] = EQUALS_SIGN;
destination[destOffset + 3] = EQUALS_SIGN;
return destination;
default:
return destination;
} // end switch
}
public static String encodeBytes(byte[] source) {
boolean breakLines = false;
int len = source.length;
int len43 = len * 4 / 3;
byte[] outBuff = new byte[(len43) // Main 4:3
+ ((len % 3) > 0 ? 4 : 0) // Account for padding
+ (breakLines ? (len43 / MAX_LINE_LENGTH) : 0)]; // New lines
int d = 0;
int e = 0;
int len2 = len - 2;
int lineLength = 0;
for (; d < len2; d += 3, e += 4) {
encode3to4(source, d, 3, outBuff, e);
lineLength += 4;
if (breakLines && lineLength == MAX_LINE_LENGTH) {
outBuff[e + 4] = NEW_LINE;
e++;
lineLength = 0;
} // end if: end of line
} // en dfor: each piece of array
if (d < len) {
encode3to4(source, d, len - d, outBuff, e);
e += 4;
} // end if: some padding needed
// Return value according to relevant encoding.
try {
return new String(outBuff, 0, e, PREFERRED_ENCODING);
} // end try
catch (java.io.UnsupportedEncodingException uue) {
return new String(outBuff, 0, e);
} // end catch
} // end encodeBytes
}