// 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 Amazon Digital Services, Inc. or its // affiliates. package com.amazon.s3; 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 Long expiresIn = null; private Long expires = null; // by default, expire in 1 minute. private static final Long DEFAULT_EXPIRES_IN = Long.valueOf(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 = awsAccessKeyId; this.awsSecretAccessKey = awsSecretAccessKey; this.isSecure = isSecure; this.server = server; this.port = port; expiresIn = DEFAULT_EXPIRES_IN; expires = null; } public void setExpires(long millisSinceEpoch) { expires = Long.valueOf(millisSinceEpoch); expiresIn = null; } public void setExpiresIn(long millis) { expiresIn = Long.valueOf(millis); expires = null; } public String createBucket(String bucket, Map headers) { return generateURL("PUT", bucket, headers); } public String listBucket(String bucket, String prefix, String marker, Integer maxKeys, Map headers) { String path = Utils.pathForListOptions(bucket, prefix, marker, maxKeys); return generateURL("GET", path, headers); } public String deleteBucket(String bucket, Map headers) { return generateURL("DELETE", bucket, headers); } public String put(String bucket, String key, S3Object object, Map headers) { Map metadata = null; if (object != null) { metadata = object.metadata; } return generateURL("PUT", bucket + "/" + Utils.urlencode(key), mergeMeta(headers, metadata)); } public String get(String bucket, String key, Map headers) { return generateURL("GET", bucket + "/" + Utils.urlencode(key), headers); } public String delete(String bucket, String key, Map headers) { return generateURL("DELETE", bucket + "/" + Utils.urlencode(key), headers); } public String getBucketACL(String bucket, Map headers) { return getACL(bucket, "", headers); } public String getACL(String bucket, String key, Map headers) { return generateURL("GET", bucket + "/" + Utils.urlencode(key) + "?acl", 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) { return generateURL("PUT", bucket + "/" + Utils.urlencode(key) + "?acl", headers); } public String listAllMyBuckets(Map headers) { return generateURL("GET", "", headers); } public String makeBareURL(String bucket, String key) { StringBuilder buffer = new StringBuilder(); if (isSecure) { buffer.append("https://"); } else { buffer.append("http://"); } buffer.append(server).append(':').append(port).append('/').append(bucket); buffer.append('/').append(Utils.urlencode(key)); return buffer.toString(); } private String generateURL(String method, String path, Map headers) { long expires = 0L; if (expiresIn != null) { expires = System.currentTimeMillis() + 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, path, headers, ""+expires); String encodedCanonical = Utils.encode(awsSecretAccessKey, canonicalString, true); StringBuilder buffer = new StringBuilder(); if (isSecure) { buffer.append("https://"); } else { buffer.append("http://"); } buffer.append(server).append(':').append(port).append('/').append(path); if (path.indexOf('?') == -1) { // no other query parameters buffer.append('?'); } else { // there exist other query parameters buffer.append('&'); } buffer.append("Signature=").append(encodedCanonical); buffer.append("&Expires=").append(expires); buffer.append("&AWSAccessKeyId=").append(awsAccessKeyId); return buffer.toString(); } 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; } }