/* * Copyright 2010-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. This file 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. */ package com.amazonaws.tvm; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.security.SecureRandom; import java.text.ParseException; import java.util.Date; import java.util.logging.Level; import java.util.logging.Logger; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import javax.servlet.http.HttpServletRequest; import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Hex; import com.amazonaws.services.securitytoken.model.Credentials; import com.amazonaws.util.DateUtils; import com.amazonaws.util.HttpUtils; public class Utilities { protected static final Logger log = TokenVendingMachineLogger.getLogger(); private static String RAW_POLICY_OBJECT = null; private static SecureRandom RANDOM = new SecureRandom(); static { RANDOM.generateSeed(16); } public static String prepareJsonResponseForTokens(Credentials sessionCredentials, String key) { StringBuilder responseBody = new StringBuilder(); responseBody.append("{"); responseBody.append("\taccessKey: \"").append(sessionCredentials.getAccessKeyId()).append("\","); responseBody.append("\tsecretKey: \"").append(sessionCredentials.getSecretAccessKey()).append("\","); responseBody.append("\tsecurityToken: \"").append(sessionCredentials.getSessionToken()).append("\","); responseBody.append("\texpirationDate: \"").append(sessionCredentials.getExpiration().getTime()).append("\""); responseBody.append("}"); // Encrypting the response return AESEncryption.wrap(responseBody.toString(), key); } public static String prepareJsonResponseForKey(String data, String key) { StringBuilder responseBody = new StringBuilder(); responseBody.append("{"); responseBody.append("\tkey: \"").append(data).append("\""); responseBody.append("}"); // Encrypting the response return AESEncryption.wrap(responseBody.toString(), key.substring(0, 32)); } public static String sign(String content, String key) { try { byte[] data = content.getBytes(Constants.ENCODING_FORMAT); Mac mac = Mac.getInstance(Constants.SIGNATURE_METHOD); mac.init(new SecretKeySpec(key.getBytes(Constants.ENCODING_FORMAT), Constants.SIGNATURE_METHOD)); byte[] signature = Base64.encodeBase64(mac.doFinal(data)); return new String(signature, Constants.ENCODING_FORMAT); } catch (Exception exception) { log.log(Level.SEVERE, "Exception during sign", exception); } return null; } public static String identitySign(String content, String key) { try { byte[] data = content.getBytes(Constants.ENCODING_FORMAT); Mac mac = Mac.getInstance(Constants.SIGNATURE_METHOD); mac.init(new SecretKeySpec(key.getBytes(Constants.ENCODING_FORMAT), Constants.SIGNATURE_METHOD)); char[] signature = Hex.encodeHex(mac.doFinal(data)); return new String(signature); } catch (Exception e) { log.log(Level.SEVERE, "Exception during sign", e); } return null; } public static String getSaltedPassword(String username, String endPointUri, String password) { return identitySign((username + Configuration.APP_NAME + endPointUri.toLowerCase()), password); } public static String base64(String data) throws UnsupportedEncodingException { byte[] signature = Base64.encodeBase64(data.getBytes(Constants.ENCODING_FORMAT)); return new String(signature, Constants.ENCODING_FORMAT); } public static String getEndPoint(HttpServletRequest request) { if (null == request) { return null; } else { String endpoint = request.getServerName().toLowerCase(); log.info("Endpoint : " + encode(endpoint)); return endpoint; } } /** * Checks to see if the request has valid timestamp. If given timestamp * falls in 30 mins window from current server timestamp */ public static boolean isTimestampValid(String timestamp) { long timestampLong = 0L; final long window = 15 * 60 * 1000L; if (null == timestamp) { return false; } try { timestampLong = new DateUtils().parseIso8601Date(timestamp).getTime(); } catch (ParseException exception) { log.warning("Error parsing timestamp sent from client : " + timestamp); return false; } Long now = new Date().getTime(); long before15Mins = new Date(now - window).getTime(); long after15Mins = new Date(now + window).getTime(); return (timestampLong >= before15Mins && timestampLong <= after15Mins); } public static String generateRandomString() { byte[] randomBytes = new byte[16]; RANDOM.nextBytes(randomBytes); String randomString = new String(Hex.encodeHex(randomBytes)); return randomString; } public static boolean isValidUsername(String username) { int length = username.length(); if (length < 3 || length > 128) { return false; } char c = 0; for (int i = 0; i < length; i++) { c = username.charAt(i); if (!Character.isLetterOrDigit(c) && '_' != c && '.' != c && '@' != c) { return false; } } return true; } public static boolean isValidPassword(String password) { int length = password.length(); return (length >= 6 && length <= 128); } public static boolean isValidUID(String uid) { return (null == uid || uid.length() < 24) ? false : true; } public static boolean isValidKey(String key) { return isValidUID(key); } public static String getSystemProperty( String property ) { return getSystemProperty( property, null ); } public static String getSystemProperty( String property, String defaultValue ) { String value = System.getProperty( property ); if ( isEmpty( value ) ) { return defaultValue; } else { return value; } } public static boolean isEmpty(String str) { if (null == str || str.trim().length() == 0) return true; return false; } public static String encode(String s) { if (null == s) return s; return HttpUtils.urlEncode(s, false); } public static String getRawPolicyFile( String policyFile ) { if (RAW_POLICY_OBJECT == null) { ByteArrayOutputStream baos = new ByteArrayOutputStream(8196); InputStream in = null; try { in = Utilities.class.getResourceAsStream( policyFile ); byte[] buffer = new byte[1024]; int length = 0; while ((length = in.read(buffer)) != -1) { baos.write(buffer, 0, length); } RAW_POLICY_OBJECT = baos.toString(); } catch (IOException e) { log.log(Level.SEVERE, "Unable to load policy object.", e); RAW_POLICY_OBJECT = ""; } finally { try { baos.close(); in.close(); } catch (IOException e) { log.log(Level.SEVERE, "Unable to close streams.", e); } in = null; baos = null; } } return RAW_POLICY_OBJECT; } /** * This method is low performance string comparison function. The purpose of * this method is to prevent timing attack. */ public static boolean slowStringComparison(String givenSignature, String computedSignature) { if (null == givenSignature || null == computedSignature || givenSignature.length() != computedSignature.length()) return false; int n = computedSignature.length(); boolean signaturesMatch = true; for (int i = 0; i < n; i++) { signaturesMatch &= (computedSignature.charAt(i) == givenSignature.charAt(i)); } return signaturesMatch; } /** * Extract element from a JSON string * * @param json * A string of JSON blob * @param element * JSON key * @return the corresponding string value of the element */ public static String extractElement(String json, String element) { boolean hasElement = (json.indexOf(element) != -1); if (hasElement) { int elementIndex = json.indexOf(element); int startIndex = json.indexOf("\"", elementIndex); int endIndex = json.indexOf("\"", startIndex + 1); return json.substring(startIndex + 1, endIndex); } return null; } }