// This software code is made available "AS IS" without warranties of any // kind. You may copy, display, modify and redistribute the software // code either by itself or as incorporated into your code; provided that // you do not remove any proprietary notices. Your use of this software // code is at your own risk and you waive any claim against Amazon // Digital Services, Inc. or its affiliates with respect to your use of // this software code. (c) 2006-2007 Amazon Digital Services, Inc. or its // affiliates. package com.amazon.s3; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TreeMap; /** * This class mimics the behavior of AWSAuthConnection, except instead of actually performing * the operation, QueryStringAuthGenerator will return URLs with query string parameters that * can be used to do the same thing. These parameters include an expiration date, so that * if you hand them off to someone else, they will only work for a limited amount of time. */ public class QueryStringAuthGenerator { private String awsAccessKeyId; private String awsSecretAccessKey; private boolean isSecure; private String server; private int port; private CallingFormat callingFormat; private Long expiresIn = null; private Long expires = null; // by default, expire in 1 minute. private static final Long DEFAULT_EXPIRES_IN = new Long(60 * 1000); public QueryStringAuthGenerator(String awsAccessKeyId, String awsSecretAccessKey) { this(awsAccessKeyId, awsSecretAccessKey, true); } public QueryStringAuthGenerator(String awsAccessKeyId, String awsSecretAccessKey, boolean isSecure) { this(awsAccessKeyId, awsSecretAccessKey, isSecure, Utils.DEFAULT_HOST); } public QueryStringAuthGenerator(String awsAccessKeyId, String awsSecretAccessKey, boolean isSecure, String server) { this(awsAccessKeyId, awsSecretAccessKey, isSecure, server, isSecure ? Utils.SECURE_PORT : Utils.INSECURE_PORT); } public QueryStringAuthGenerator(String awsAccessKeyId, String awsSecretAccessKey, boolean isSecure, String server, int port) { this(awsAccessKeyId, awsSecretAccessKey, isSecure, server, port, CallingFormat.getSubdomainCallingFormat()); } public QueryStringAuthGenerator(String awsAccessKeyId, String awsSecretAccessKey, boolean isSecure, String server, CallingFormat callingFormat) { this(awsAccessKeyId, awsSecretAccessKey, isSecure, server, isSecure ? Utils.SECURE_PORT : Utils.INSECURE_PORT, callingFormat); } public QueryStringAuthGenerator(String awsAccessKeyId, String awsSecretAccessKey, boolean isSecure, String server, int port, CallingFormat callingFormat) { this.awsAccessKeyId = awsAccessKeyId; this.awsSecretAccessKey = awsSecretAccessKey; this.isSecure = isSecure; this.server = server; this.port = port; this.callingFormat = callingFormat; this.expiresIn = DEFAULT_EXPIRES_IN; this.expires = null; } public void setCallingFormat(CallingFormat format) { this.callingFormat = format; } public void setExpires(long millisSinceEpoch) { expires = new Long(millisSinceEpoch); expiresIn = null; } public void setExpiresIn(long millis) { expiresIn = new Long(millis); expires = null; } public String createBucket(String bucket, Map headers) { // validate bucket name if (!Utils.validateBucketName(bucket, callingFormat, false)) throw new IllegalArgumentException("Invalid Bucket Name: "+bucket); Map pathArgs = new HashMap(); return generateURL("PUT", bucket, "", pathArgs, headers); } public String listBucket(String bucket, String prefix, String marker, Integer maxKeys, Map headers){ return listBucket(bucket, prefix, marker, maxKeys, null, headers); } public String listBucket(String bucket, String prefix, String marker, Integer maxKeys, String delimiter, Map headers) { Map pathArgs = Utils.paramsForListOptions(prefix, marker, maxKeys, delimiter); return generateURL("GET", bucket, "", pathArgs, headers); } public String deleteBucket(String bucket, Map headers) { Map pathArgs = new HashMap(); return generateURL("DELETE", bucket, "", pathArgs, headers); } public String put(String bucket, String key, S3Object object, Map headers) { Map metadata = null; Map pathArgs = new HashMap(); if (object != null) { metadata = object.metadata; } return generateURL("PUT", bucket, Utils.urlencode(key), pathArgs, mergeMeta(headers, metadata)); } public String get(String bucket, String key, Map headers) { Map pathArgs = new HashMap(); return generateURL("GET", bucket, Utils.urlencode(key), pathArgs, headers); } public String delete(String bucket, String key, Map headers) { Map pathArgs = new HashMap(); return generateURL("DELETE", bucket, Utils.urlencode(key), pathArgs, headers); } public String getBucketLogging(String bucket, Map headers) { Map pathArgs = new HashMap(); pathArgs.put("logging", null); return generateURL("GET", bucket, "", pathArgs, headers); } public String putBucketLogging(String bucket, String loggingXMLDoc, Map headers) { Map pathArgs = new HashMap(); pathArgs.put("logging", null); return generateURL("PUT", bucket, "", pathArgs, headers); } public String getBucketACL(String bucket, Map headers) { return getACL(bucket, "", headers); } public String getACL(String bucket, String key, Map headers) { Map pathArgs = new HashMap(); pathArgs.put("acl", null); return generateURL("GET", bucket, Utils.urlencode(key), pathArgs, headers); } public String putBucketACL(String bucket, String aclXMLDoc, Map headers) { return putACL(bucket, "", aclXMLDoc, headers); } public String putACL(String bucket, String key, String aclXMLDoc, Map headers) { Map pathArgs = new HashMap(); pathArgs.put("acl", null); return generateURL("PUT", bucket, Utils.urlencode(key), pathArgs, headers); } public String listAllMyBuckets(Map headers) { Map pathArgs = new HashMap(); return generateURL("GET", "", "", pathArgs, headers); } public String makeBareURL(String bucket, String key) { StringBuffer buffer = new StringBuffer(); if (this.isSecure) { buffer.append("https://"); } else { buffer.append("http://"); } buffer.append(this.server).append(":").append(this.port).append("/").append(bucket); buffer.append("/").append(Utils.urlencode(key)); return buffer.toString(); } private String generateURL(String method, String bucketName, String key, Map pathArgs, Map headers) { long expires = 0L; if (this.expiresIn != null) { expires = System.currentTimeMillis() + this.expiresIn.longValue(); } else if (this.expires != null) { expires = this.expires.longValue(); } else { throw new RuntimeException("Illegal expires state"); } // convert to seconds expires /= 1000; String canonicalString = Utils.makeCanonicalString(method, bucketName, key, pathArgs, headers, ""+expires); String encodedCanonical = Utils.encode(this.awsSecretAccessKey, canonicalString, true); pathArgs.put("Signature", encodedCanonical); pathArgs.put("Expires", Long.toString(expires)); pathArgs.put("AWSAccessKeyId", this.awsAccessKeyId); String returnString; try { URL url = this.callingFormat.getURL(this.isSecure, server, port, bucketName, key, pathArgs); returnString = url.toString(); } catch (MalformedURLException e) { returnString = "Exception generating url " + e; } return returnString; } private Map mergeMeta(Map headers, Map metadata) { Map merged = new TreeMap(); if (headers != null) { for (Iterator i = headers.keySet().iterator(); i.hasNext(); ) { String key = (String)i.next(); merged.put(key, headers.get(key)); } } if (metadata != null) { for (Iterator i = metadata.keySet().iterator(); i.hasNext(); ) { String key = (String)i.next(); String metadataKey = Utils.METADATA_PREFIX + key; if (merged.containsKey(metadataKey)) { ((List)merged.get(metadataKey)).addAll((List)metadata.get(key)); } else { merged.put(metadataKey, metadata.get(key)); } } } return merged; } }