diff --git a/ChangeLog.txt b/ChangeLog.txt index bfa94c50772d..18378c9cde81 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,12 @@ +2013.07.03 Version 0.4.4 + * Windows Azure China environemnt support + * Service Bus metadata support updated to the latest version + * Rich Odata entity query support for Service Bus Queue/Topic/Subscription + * Added support for Service Bus message forwarding + * Added support for Service Bus message count details + * Made sure the response stream is drained to prevent socket exhaustion in Storage + * Added support for all flavors of SharedKey and SharedKeyLite message signing through AuthenticationScheme property on client classes in Storage + 2013.05.27 Version 0.4.3 * Added support for updating existing Queue/Topic/Subscription for Service Bus * Added support for message lock renewal to support long running message processing for Service Bus diff --git a/README.md b/README.md index f12d7aa79956..86248e1374fb 100644 --- a/README.md +++ b/README.md @@ -21,12 +21,14 @@ This project provides a client library in Java that makes it easy to consume Win * Create/Read/Update/Delete queues * Send/Receive/Unlock/Delete messages * Renew message lock + * Message forwarding * Topics * Create/Read/Update/Delete topics * Create/Read/Update/Delete subscriptions * Create/Read/Update/Delete rules * Send/Receive/Unlock/Delete messages * Renew message lock + * Message forwarding * Media Services * Create/Read/Update/Delete access policies * Create/Read/Update/Delete asset files @@ -57,7 +59,7 @@ within your project you can also have them installed by the Java package manager com.microsoft.windowsazure microsoft-windowsazure-api - 0.4.2 + 0.4.4 ``` diff --git a/microsoft-azure-api/pom.xml b/microsoft-azure-api/pom.xml index 5fc0ac258437..f3199d17474f 100644 --- a/microsoft-azure-api/pom.xml +++ b/microsoft-azure-api/pom.xml @@ -17,7 +17,7 @@ 4.0.0 com.microsoft.windowsazure microsoft-windowsazure-api - 0.4.3 + 0.4.4 jar Microsoft Windows Azure Client API diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlob.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlob.java index 84e345591cc5..578019fa34c0 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlob.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlob.java @@ -295,8 +295,9 @@ public String execute(final CloudBlobClient client, final CloudBlob blob, final final HttpURLConnection request = BlobRequest.lease(blob.getTransformedAddress(opContext), this .getRequestOptions().getTimeoutIntervalInMs(), LeaseAction.ACQUIRE, leaseTimeInSeconds, proposedLeaseId, null, accessCondition, blobOptions, opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, 0L); + this.signRequest(client, request, 0L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -407,8 +408,9 @@ public Long execute(final CloudBlobClient client, final CloudBlob blob, final Op final HttpURLConnection request = BlobRequest.lease(blob.getTransformedAddress(opContext), this .getRequestOptions().getTimeoutIntervalInMs(), LeaseAction.BREAK, null, null, breakPeriodInSeconds, accessCondition, blobOptions, opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, 0L); + this.signRequest(client, request, 0L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -540,9 +542,11 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op final HttpURLConnection request = BlobRequest.copyFrom(blob.getTransformedAddress(opContext), blobOptions.getTimeoutIntervalInMs(), source.toString(), blob.snapshotID, sourceAccessCondition, destinationAccessCondition, blobOptions, opContext); + this.setConnection(request); BlobRequest.addMetadata(request, blob.metadata, opContext); - client.getCredentials().signRequest(request, 0); + + this.signRequest(client, request, 0, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -620,8 +624,9 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op final HttpURLConnection request = BlobRequest.abortCopy(blob.getTransformedAddress(opContext), blobOptions.getTimeoutIntervalInMs(), copyId, accessCondition, blobOptions, opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, 0); + this.signRequest(client, request, 0, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -695,8 +700,9 @@ public CloudBlob execute(final CloudBlobClient client, final CloudBlob blob, final HttpURLConnection request = BlobRequest.snapshot(blob.getTransformedAddress(opContext), this .getRequestOptions().getTimeoutIntervalInMs(), accessCondition, blobOptions, opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, 0L); + this.signRequest(client, request, 0L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -784,8 +790,9 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op final HttpURLConnection request = BlobRequest.delete(blob.getTransformedAddress(opContext), this .getRequestOptions().getTimeoutIntervalInMs(), blob.snapshotID, deleteSnapshotsOption, accessCondition, blobOptions, opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, -1L); + this.signRequest(client, request, -1L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -875,8 +882,9 @@ public Boolean execute(final CloudBlobClient client, final CloudBlob blob, final final HttpURLConnection request = BlobRequest.delete(blob.getTransformedAddress(opContext), this .getRequestOptions().getTimeoutIntervalInMs(), blob.snapshotID, deleteSnapshotsOption, accessCondition, blobOptions, opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, -1L); + this.signRequest(client, request, -1L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -959,8 +967,10 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op final HttpURLConnection request = BlobRequest.get(blob.getTransformedAddress(opContext), blobOptions.getTimeoutIntervalInMs(), blob.snapshotID, accessCondition, blobOptions, opContext); + this.setConnection(request); + + this.signRequest(client, request, -1L, null); - client.getCredentials().signRequest(request, -1L); final InputStream streamRef = ExecutionEngine.getInputStream(request, opContext, this.getResult()); final String contentMD5 = request.getHeaderField(Constants.HeaderConstants.CONTENT_MD5); @@ -1137,8 +1147,9 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op final HttpURLConnection request = BlobRequest.getProperties(blob.getTransformedAddress(opContext), this .getRequestOptions().getTimeoutIntervalInMs(), blob.snapshotID, accessCondition, blobOptions, opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, -1L); + this.signRequest(client, request, -1L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -1290,12 +1301,13 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op final HttpURLConnection request = BlobRequest.get(blob.getTransformedAddress(opContext), blobOptions.getTimeoutIntervalInMs(), blob.snapshotID, blobOffset, length, accessCondition, blobOptions, opContext); + this.setConnection(request); if (blobOptions.getUseTransactionalContentMD5()) { request.setRequestProperty(Constants.HeaderConstants.RANGE_GET_CONTENT_MD5, "true"); } - client.getCredentials().signRequest(request, -1L); + this.signRequest(client, request, -1L, null); final InputStream sourceStream = ExecutionEngine.getInputStream(request, opContext, this.getResult()); @@ -1430,8 +1442,9 @@ public Boolean execute(final CloudBlobClient client, final CloudBlob blob, final final HttpURLConnection request = BlobRequest.getProperties(blob.getTransformedAddress(opContext), this .getRequestOptions().getTimeoutIntervalInMs(), blob.snapshotID, accessCondition, blobOptions, opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, -1L); + this.signRequest(client, request, -1L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -1917,8 +1930,9 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op final HttpURLConnection request = BlobRequest.lease(blob.getTransformedAddress(opContext), this .getRequestOptions().getTimeoutIntervalInMs(), LeaseAction.RELEASE, null, null, null, accessCondition, blobOptions, opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, 0L); + this.signRequest(client, request, 0L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -1997,8 +2011,9 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op final HttpURLConnection request = BlobRequest.lease(blob.getTransformedAddress(opContext), this .getRequestOptions().getTimeoutIntervalInMs(), LeaseAction.RENEW, null, null, null, accessCondition, blobOptions, opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, 0L); + this.signRequest(client, request, 0L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -2086,8 +2101,9 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op final HttpURLConnection request = BlobRequest.lease(blob.getTransformedAddress(opContext), this .getRequestOptions().getTimeoutIntervalInMs(), LeaseAction.CHANGE, null, proposedLeaseId, null, accessCondition, blobOptions, opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, 0L); + this.signRequest(client, request, 0L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -2213,8 +2229,9 @@ public Long execute(final CloudBlobClient client, final CloudBlob blob, final Op final HttpURLConnection request = BlobRequest.lease(blob.getTransformedAddress(opContext), this .getRequestOptions().getTimeoutIntervalInMs(), LeaseAction.BREAK, null, null, null, accessCondition, blobOptions, opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, 0L); + this.signRequest(client, request, 0L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -2351,10 +2368,11 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op final HttpURLConnection request = BlobRequest.put(blob.getTransformedAddress(opContext), this .getRequestOptions().getTimeoutIntervalInMs(), blob.properties, blob.properties.getBlobType(), 0, accessCondition, blobOptions, opContext); + this.setConnection(request); BlobRequest.addMetadata(request, blob.metadata, opContext); - client.getCredentials().signRequest(request, length); + this.signRequest(client, request, length, null); final StreamMd5AndLength descriptor = Utility.writeToOutputStream(sourceStream, request.getOutputStream(), length, true, false, null, opContext); @@ -2436,9 +2454,11 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op final HttpURLConnection request = BlobRequest.setMetadata(blob.getTransformedAddress(opContext), this .getRequestOptions().getTimeoutIntervalInMs(), accessCondition, blobOptions, opContext); + this.setConnection(request); BlobRequest.addMetadata(request, blob.metadata, opContext); - client.getCredentials().signRequest(request, 0L); + + this.signRequest(client, request, 0L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -2510,9 +2530,11 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op final HttpURLConnection request = BlobRequest.setProperties(blob.getTransformedAddress(opContext), this .getRequestOptions().getTimeoutIntervalInMs(), blob.properties, null, accessCondition, blobOptions, opContext); + this.setConnection(request); BlobRequest.addMetadata(request, blob.metadata, opContext); - client.getCredentials().signRequest(request, 0L); + + this.signRequest(client, request, 0L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlobClient.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlobClient.java index c000b97c98ed..5113afab641d 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlobClient.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlobClient.java @@ -385,8 +385,9 @@ ResultSegment listContainersCore(final String prefix, final HttpURLConnection listContainerRequest = ContainerRequest.list(this.getEndpoint(), options.getTimeoutIntervalInMs(), listingContext, detailsIncluded, opContext); + taskReference.setConnection(listContainerRequest); - this.getCredentials().signRequest(listContainerRequest, -1L); + taskReference.signRequest(this, listContainerRequest, -1L, null); ExecutionEngine.processRequest(listContainerRequest, opContext, taskReference.getResult()); diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlobContainer.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlobContainer.java index b1d1a7a6c8db..10e2a450a514 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlobContainer.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlobContainer.java @@ -220,9 +220,11 @@ public Void execute(final CloudBlobClient client, final CloudBlobContainer conta final OperationContext opContext) throws Exception { final HttpURLConnection request = ContainerRequest.create(container.uri, this.getRequestOptions() .getTimeoutIntervalInMs(), opContext); + this.setConnection(request); ContainerRequest.addMetadata(request, container.metadata, opContext); - client.getCredentials().signRequest(request, 0L); + + this.signRequest(client, request, 0L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -294,9 +296,11 @@ public Boolean execute(final CloudBlobClient client, final CloudBlobContainer co final OperationContext opContext) throws Exception { final HttpURLConnection request = ContainerRequest.create(container.uri, this.getRequestOptions() .getTimeoutIntervalInMs(), opContext); + this.setConnection(request); ContainerRequest.addMetadata(request, container.metadata, opContext); - client.getCredentials().signRequest(request, 0L); + + this.signRequest(client, request, 0L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -387,8 +391,9 @@ public Void execute(final CloudBlobClient client, final CloudBlobContainer conta final HttpURLConnection request = ContainerRequest.delete(container.uri, this.getRequestOptions() .getTimeoutIntervalInMs(), opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, -1L); + this.signRequest(client, request, -1L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -457,8 +462,9 @@ public Boolean execute(final CloudBlobClient client, final CloudBlobContainer co final HttpURLConnection request = ContainerRequest.delete(container.uri, this.getRequestOptions() .getTimeoutIntervalInMs(), opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, -1L); + this.signRequest(client, request, -1L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -530,8 +536,9 @@ public Void execute(final CloudBlobClient client, final CloudBlobContainer conta final OperationContext opContext) throws Exception { final HttpURLConnection request = ContainerRequest.getProperties(container.uri, this .getRequestOptions().getTimeoutIntervalInMs(), opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, -1L); + this.signRequest(client, request, -1L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -607,8 +614,9 @@ public BlobContainerPermissions execute(final CloudBlobClient client, final Clou final HttpURLConnection request = ContainerRequest.getAcl(container.uri, this.getRequestOptions() .getTimeoutIntervalInMs(), opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, -1L); + this.signRequest(client, request, -1L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -686,8 +694,9 @@ public Boolean execute(final CloudBlobClient client, final CloudBlobContainer co final OperationContext opContext) throws Exception { final HttpURLConnection request = ContainerRequest.getProperties(container.uri, this .getRequestOptions().getTimeoutIntervalInMs(), opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, -1L); + this.signRequest(client, request, -1L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -1105,8 +1114,9 @@ ResultSegment listBlobsCore(final String prefix, final boolean use final HttpURLConnection listBlobsRequest = BlobRequest.list(this.getTransformedAddress(), options.getTimeoutIntervalInMs(), listingContext, options, opContext); + taskReference.setConnection(listBlobsRequest); - this.blobServiceClient.getCredentials().signRequest(listBlobsRequest, -1L); + taskReference.signRequest(this.blobServiceClient, listBlobsRequest, -1L, null); ExecutionEngine.processRequest(listBlobsRequest, opContext, taskReference.getResult()); @@ -1529,9 +1539,11 @@ public Void execute(final CloudBlobClient client, final CloudBlobContainer conta final HttpURLConnection request = ContainerRequest.setMetadata(container.uri, this.getRequestOptions() .getTimeoutIntervalInMs(), opContext); + this.setConnection(request); ContainerRequest.addMetadata(request, container.metadata, opContext); - client.getCredentials().signRequest(request, 0L); + + this.signRequest(client, request, 0L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -1603,13 +1615,16 @@ public Void execute(final CloudBlobClient client, final CloudBlobContainer conta final HttpURLConnection request = ContainerRequest.setAcl(container.uri, this.getRequestOptions() .getTimeoutIntervalInMs(), permissions.getPublicAccess(), opContext); + this.setConnection(request); final StringWriter outBuffer = new StringWriter(); ContainerRequest.writeSharedAccessIdentifiersToStream(permissions.getSharedAccessPolicies(), outBuffer); final byte[] aclBytes = outBuffer.toString().getBytes("UTF8"); - client.getCredentials().signRequest(request, aclBytes.length); + + this.signRequest(client, request, aclBytes.length, null); + final OutputStream outStreamRef = request.getOutputStream(); outStreamRef.write(aclBytes); @@ -1707,8 +1722,9 @@ public String execute(final CloudBlobClient client, final CloudBlobContainer con final HttpURLConnection request = ContainerRequest.lease(container.uri, this.getRequestOptions() .getTimeoutIntervalInMs(), LeaseAction.ACQUIRE, leaseTimeInSeconds, proposedLeaseId, null, accessCondition, blobOptions, opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, 0L); + this.signRequest(client, request, 0L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -1789,8 +1805,9 @@ public Void execute(final CloudBlobClient client, final CloudBlobContainer conta final HttpURLConnection request = ContainerRequest.lease(container.uri, this.getRequestOptions() .getTimeoutIntervalInMs(), LeaseAction.RENEW, null, null, null, accessCondition, blobOptions, opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, 0L); + this.signRequest(client, request, 0L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -1871,8 +1888,9 @@ public Void execute(final CloudBlobClient client, final CloudBlobContainer conta final HttpURLConnection request = ContainerRequest.lease(container.uri, this.getRequestOptions() .getTimeoutIntervalInMs(), LeaseAction.RELEASE, null, null, null, accessCondition, blobOptions, opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, 0L); + this.signRequest(client, request, 0L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -1956,8 +1974,9 @@ public Long execute(final CloudBlobClient client, final CloudBlobContainer conta final HttpURLConnection request = ContainerRequest.lease(container.uri, this.getRequestOptions() .getTimeoutIntervalInMs(), LeaseAction.BREAK, null, null, breakPeriodInSeconds, accessCondition, blobOptions, opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, 0L); + this.signRequest(client, request, 0L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -2048,8 +2067,9 @@ public Void execute(final CloudBlobClient client, final CloudBlobContainer conta final HttpURLConnection request = ContainerRequest.lease(container.uri, this.getRequestOptions() .getTimeoutIntervalInMs(), LeaseAction.CHANGE, null, proposedLeaseId, null, accessCondition, blobOptions, opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, 0L); + this.signRequest(client, request, 0L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlockBlob.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlockBlob.java index 9ee73d83c1d1..d6724ed776ae 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlockBlob.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlockBlob.java @@ -184,6 +184,8 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op final HttpURLConnection request = BlobRequest.putBlockList(blob.getTransformedAddress(opContext), blobOptions.getTimeoutIntervalInMs(), blob.properties, accessCondition, blobOptions, opContext); + this.setConnection(request); + BlobRequest.addMetadata(request, blob.metadata, opContext); // Potential optimization, we can write this stream outside of @@ -200,7 +202,8 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op request.setRequestProperty(Constants.HeaderConstants.CONTENT_MD5, descriptor.getMd5()); - client.getCredentials().signRequest(request, descriptor.getLength()); + this.signRequest(client, request, descriptor.getLength(), null); + Utility.writeToOutputStream(blockListInputStream, request.getOutputStream(), descriptor.getLength(), false, false, null, opContext); @@ -290,8 +293,9 @@ public ArrayList execute(final CloudBlobClient client, final CloudBl final HttpURLConnection request = BlobRequest.getBlockList(blob.getTransformedAddress(opContext), blobOptions.getTimeoutIntervalInMs(), blob.snapshotID, blockListingFilter, accessCondition, blobOptions, opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, -1L); + this.signRequest(client, request, -1L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -615,12 +619,14 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op final HttpURLConnection request = BlobRequest.putBlock(blob.getTransformedAddress(opContext), blobOptions.getTimeoutIntervalInMs(), blockId, accessCondition, blobOptions, opContext); + this.setConnection(request); if (blobOptions.getUseTransactionalContentMD5()) { request.setRequestProperty(Constants.HeaderConstants.CONTENT_MD5, md5); } - client.getCredentials().signRequest(request, length); + this.signRequest(client, request, length, null); + Utility.writeToOutputStream(sourceStream, request.getOutputStream(), length, true /* rewindSourceStream */, false /* calculateMD5 */, null, opContext); diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudPageBlob.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudPageBlob.java index d81af25c6267..38611d54063e 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudPageBlob.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudPageBlob.java @@ -267,10 +267,11 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op final HttpURLConnection request = BlobRequest.put(blob.getTransformedAddress(opContext), this .getRequestOptions().getTimeoutIntervalInMs(), blob.properties, BlobType.PAGE_BLOB, length, accessCondition, blobOptions, opContext); + this.setConnection(request); BlobRequest.addMetadata(request, blob.metadata, opContext); - client.getCredentials().signRequest(request, 0L); + this.signRequest(client, request, 0L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -349,8 +350,9 @@ public ArrayList execute(final CloudBlobClient client, final CloudBlo final HttpURLConnection request = BlobRequest.getPageRanges(blob.getTransformedAddress(opContext), blobOptions.getTimeoutIntervalInMs(), blob.snapshotID, accessCondition, blobOptions, opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, -1L); + this.signRequest(client, request, -1L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -471,17 +473,19 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op final HttpURLConnection request = BlobRequest.putPage(blob.getTransformedAddress(opContext), blobOptions.getTimeoutIntervalInMs(), pageProperties, accessCondition, blobOptions, opContext); + this.setConnection(request); if (pageProperties.getPageOperation() == PageOperationType.UPDATE) { if (blobOptions.getUseTransactionalContentMD5()) { request.setRequestProperty(Constants.HeaderConstants.CONTENT_MD5, md5); } - client.getCredentials().signRequest(request, length); + this.signRequest(client, request, length, null); + request.getOutputStream().write(data); } else { - client.getCredentials().signRequest(request, 0L); + this.signRequest(client, request, 0L, null); } ExecutionEngine.processRequest(request, opContext, this.getResult()); diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/AccessPolicyResponseBase.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/AccessPolicyResponseBase.java index 7d03cb86b677..a1c748afcad1 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/AccessPolicyResponseBase.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/AccessPolicyResponseBase.java @@ -94,15 +94,9 @@ public void parseResponse() throws XMLStreamException, ParseException { if (eventType == XMLStreamConstants.START_ELEMENT && name.equals(Constants.SIGNED_IDENTIFIERS_ELEMENT)) { this.readPolicies(xmlr); - } - else if (eventType == XMLStreamConstants.END_ELEMENT - && name.equals(Constants.SIGNED_IDENTIFIERS_ELEMENT)) { break; } } - else if (eventType == XMLStreamConstants.END_DOCUMENT) { - break; - } } this.isParsed = true; diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/AuthenticationScheme.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/AuthenticationScheme.java new file mode 100644 index 000000000000..b2b898055046 --- /dev/null +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/AuthenticationScheme.java @@ -0,0 +1,30 @@ +/** + * Copyright Microsoft Corporation + * + * Licensed 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. + */ +package com.microsoft.windowsazure.services.core.storage; + +/** + * Specifies the authentication scheme used to sign HTTP requests. + */ +public enum AuthenticationScheme { + /** + * Signs HTTP requests using the Shared Key Lite authentication scheme. + */ + SHAREDKEYLITE, + + /** + * Signs HTTP requests using the Shared Key authentication scheme. + */ + SHAREDKEYFULL; +} diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/ServiceClient.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/ServiceClient.java index 8a6df9f916f3..1360b9cedfb4 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/ServiceClient.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/ServiceClient.java @@ -57,6 +57,11 @@ public abstract class ServiceClient { */ protected int timeoutInMs = Constants.DEFAULT_TIMEOUT_IN_MS; + /** + * Holds the AuthenticationScheme associated with this Service Client. + */ + protected AuthenticationScheme authenticationScheme = AuthenticationScheme.SHAREDKEYFULL; + /** * Creates an instance of the ServiceClient class using the specified service endpoint. * @@ -142,8 +147,10 @@ public ServiceProperties execute(final ServiceClient client, final Void v, final final HttpURLConnection request = BaseRequest.getServiceProperties(client.getEndpoint(), this .getRequestOptions().getTimeoutIntervalInMs(), null, opContext); + this.setConnection(request); + + this.signRequest(client, request, -1, null); - client.getCredentials().signRequest(request, -1); ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { @@ -167,6 +174,16 @@ public final StorageCredentials getCredentials() { return this.credentials; } + /** + * Returns the AuthenticationScheme associated with this service client. + * + * @return An {@link AuthenticationScheme} object that represents the authentication scheme associated with this + * client. + */ + public final AuthenticationScheme getAuthenticationScheme() { + return this.authenticationScheme; + } + /** * Returns the base URI for this service client. * @@ -229,6 +246,18 @@ protected final void setCredentials(final StorageCredentials credentials) { this.credentials = credentials; } + /** + * Sets the Authentication Scheme to use with this service client. + * + * @param scheme + * An AuthenticationScheme object that represents the authentication scheme being assigned + * for the service + * client. + */ + public final void setAuthenticationScheme(final AuthenticationScheme scheme) { + this.authenticationScheme = scheme; + } + /** * Sets the RetryPolicyFactory object to use when making service requests. * @@ -317,6 +346,7 @@ public Void execute(final ServiceClient client, final Void v, final OperationCon final HttpURLConnection request = BaseRequest.setServiceProperties(client.getEndpoint(), this .getRequestOptions().getTimeoutIntervalInMs(), null, opContext); + this.setConnection(request); final byte[] propertiesBytes = BaseRequest.serializeServicePropertiesToByteArray(properties, opContext); @@ -326,7 +356,8 @@ public Void execute(final ServiceClient client, final Void v, final OperationCon true /* rewindSourceStream */, true /* calculateMD5 */); request.setRequestProperty(Constants.HeaderConstants.CONTENT_MD5, descriptor.getMd5()); - client.getCredentials().signRequest(request, descriptor.getLength()); + this.signRequest(client, request, descriptor.getLength(), null); + Utility.writeToOutputStream(dataInputStream, request.getOutputStream(), descriptor.getLength(), false /* rewindSourceStream */, false /* calculateMD5 */, null, opContext); diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/StorageCredentials.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/StorageCredentials.java index 009a71655746..a766631e84b5 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/StorageCredentials.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/StorageCredentials.java @@ -39,8 +39,8 @@ public abstract class StorageCredentials { * Either include an account name with an account key (specifying values for * {@link CloudStorageAccount#ACCOUNT_NAME_NAME} and {@link CloudStorageAccount#ACCOUNT_KEY_NAME} ), or a * shared access signature (specifying a value for - * {@link CloudStorageAccount#SHARED_ACCESS_SIGNATURE_NAME} ). If you use an account name and account key, - * do not include a shared access signature, and vice versa. + * {@link CloudStorageAccount#SHARED_ACCESS_SIGNATURE_NAME} ). If you use an account name and account + * key, do not include a shared access signature, and vice versa. * * @return A {@link StorageCredentials} object representing the storage credentials determined from the name/value * pairs. @@ -81,8 +81,8 @@ protected static StorageCredentials tryParseCredentials(final HashMapString that contains the key/value pairs that represent the storage credentials. *

- * The format for the connection string is in the pattern "keyname=value". Multiple key/value pairs - * can be separated by a semi-colon, for example, "keyname1=value1;keyname2=value2". + * The format for the connection string is in the pattern "keyname=value". Multiple key/value + * pairs can be separated by a semi-colon, for example, "keyname1=value1;keyname2=value2". * * @return A {@link StorageCredentials} object representing the storage credentials determined from the connection * string. @@ -214,6 +214,9 @@ public static StorageCredentials tryParseCredentials(final String connectionStri /** * Signs a request under the Shared Key authentication scheme. * + * @deprecated This method has been deprecated. Please use either {@link signBlobAndQueueRequest} or + * {@link signBlobAndQueueRequestLite}, depending on your desired shared key authentication scheme. + * * @param request * An HttpURLConnection object that represents the request to sign. * @param contentLength @@ -225,12 +228,16 @@ public static StorageCredentials tryParseCredentials(final String connectionStri * @throws StorageException * If a storage service error occurred. */ + @Deprecated public abstract void signRequest(HttpURLConnection request, long contentLength) throws InvalidKeyException, StorageException; /** * Signs a request using the specified operation context under the Shared Key authentication scheme. * + * @deprecated This method has been deprecated. Please use either {@link signBlobAndQueueRequest} or + * {@link signBlobAndQueueRequestLite}, depending on your desired shared key authentication scheme. + * * @param request * An HttpURLConnection object that represents the request to sign. * @param contentLength @@ -245,11 +252,15 @@ public abstract void signRequest(HttpURLConnection request, long contentLength) * @throws StorageException * If a storage service error occurred. */ + @Deprecated public abstract void signRequest(HttpURLConnection request, long contentLength, OperationContext opContext) throws InvalidKeyException, StorageException; /** - * Signs a request under the Shared Key Lite authentication scheme. + * Signs a table request under the Shared Key Lite authentication scheme. + * + * @deprecated This method has been deprecated. Please use either {@link signTableRequest} or + * {@link signTableRequestLite}, depending on your desired shared key authentication scheme. * * @param request * An HttpURLConnection object that represents the request to sign. @@ -261,11 +272,15 @@ public abstract void signRequest(HttpURLConnection request, long contentLength, * @throws StorageException * If an unspecified storage exception occurs. */ + @Deprecated public abstract void signRequestLite(HttpURLConnection request, long contentLength) throws StorageException, InvalidKeyException; /** - * Signs a request using the specified operation context under the Shared Key Lite authentication scheme. + * Signs a table request using the specified operation context under the Shared Key Lite authentication scheme. + * + * @deprecated This method has been deprecated. Please use either {@link signTableRequest} or + * {@link signTableRequestLite}, depending on your desired shared key authentication scheme. * * @param request * An HttpURLConnection object that represents the request to sign. @@ -281,9 +296,157 @@ public abstract void signRequestLite(HttpURLConnection request, long contentLeng * @throws StorageException * If a storage service error occurred. */ + @Deprecated public abstract void signRequestLite(HttpURLConnection request, long contentLength, OperationContext opContext) throws StorageException, InvalidKeyException; + /** + * Signs a request under the Shared Key authentication scheme. + * + * @param request + * An HttpURLConnection object that represents the request to sign. + * @param contentLength + * The length of the content written to the output stream. If unknown, specify -1. + * + * @throws InvalidKeyException + * If the given key is invalid. + * + * @throws StorageException + * If a storage service error occurred. + */ + public abstract void signBlobAndQueueRequest(HttpURLConnection request, long contentLength) + throws InvalidKeyException, StorageException; + + /** + * Signs a request using the specified operation context under the Shared Key authentication scheme. + * + * @param request + * An HttpURLConnection object that represents the request to sign. + * @param contentLength + * The length of the content written to the output stream. If unknown, specify -1. + * @param opContext + * An {@link OperationContext} object that represents the context for the current operation. This object + * is used to track requests to the storage service, and to provide additional runtime information about + * the operation. + * + * @throws InvalidKeyException + * If the given key is invalid. + * @throws StorageException + * If a storage service error occurred. + */ + public abstract void signBlobAndQueueRequest(HttpURLConnection request, long contentLength, + OperationContext opContext) throws InvalidKeyException, StorageException; + + /** + * Signs a request under the Shared Key Lite authentication scheme. + * + * @param request + * An HttpURLConnection object that represents the request to sign. + * @param contentLength + * The length of the content written to the output stream. If unknown, specify -1. + * + * @throws InvalidKeyException + * If the given key is invalid. + * @throws StorageException + * If an unspecified storage exception occurs. + */ + public abstract void signBlobAndQueueRequestLite(HttpURLConnection request, long contentLength) + throws StorageException, InvalidKeyException; + + /** + * Signs a request using the specified operation context under the Shared Key Lite authentication scheme. + * + * @param request + * An HttpURLConnection object that represents the request to sign. + * @param contentLength + * The length of the content written to the output stream. If unknown, specify -1. + * @param opContext + * An {@link OperationContext} object that represents the context for the current operation. This object + * is used to track requests to the storage service, and to provide additional runtime information about + * the operation. + * + * @throws InvalidKeyException + * If the given key is invalid. + * @throws StorageException + * If a storage service error occurred. + */ + public abstract void signBlobAndQueueRequestLite(HttpURLConnection request, long contentLength, + OperationContext opContext) throws StorageException, InvalidKeyException; + + /** + * Signs a table request under the Shared Key authentication scheme. + * + * @param request + * An HttpURLConnection object that represents the request to sign. + * @param contentLength + * The length of the content written to the output stream. If unknown, specify -1. + * + * @throws InvalidKeyException + * If the given key is invalid. + * + * @throws StorageException + * If a storage service error occurred. + */ + public abstract void signTableRequest(HttpURLConnection request, long contentLength) throws InvalidKeyException, + StorageException; + + /** + * Signs a table request using the specified operation context under the Shared Key authentication scheme. + * + * @param request + * An HttpURLConnection object that represents the request to sign. + * @param contentLength + * The length of the content written to the output stream. If unknown, specify -1. + * @param opContext + * An {@link OperationContext} object that represents the context for the current operation. This object + * is used to track requests to the storage service, and to provide additional runtime information about + * the operation. + * + * @throws InvalidKeyException + * If the given key is invalid. + * @throws StorageException + * If a storage service error occurred. + */ + public abstract void signTableRequest(HttpURLConnection request, long contentLength, OperationContext opContext) + throws InvalidKeyException, StorageException; + + /** + * Signs a table request under the Shared Key Lite authentication scheme. + * + * @param request + * An HttpURLConnection object that represents the request to sign. + * @param contentLength + * The length of the content written to the output stream. If unknown, specify -1. + * + * @throws InvalidKeyException + * If the given key is invalid. + * @throws StorageException + * If an unspecified storage exception occurs. + */ + public abstract void signTableRequestLite(HttpURLConnection request, long contentLength) throws StorageException, + InvalidKeyException; + + /** + * Signs a table request using the specified operation context under the Shared Key Lite authentication scheme. + * + * @param request + * An HttpURLConnection object that represents the request to sign. + * @param contentLength + * The length of the content written to the output stream. If unknown, specify -1. + * @param opContext + * An {@link OperationContext} object that represents the context for the current operation. This object + * is used to track requests to the storage service, and to provide additional runtime information about + * the operation. + * + * @throws InvalidKeyException + * If the given key is invalid. + * @throws StorageException + * If a storage service error occurred. + */ + + public abstract void signTableRequestLite(HttpURLConnection request, long contentLength, OperationContext opContext) + throws StorageException, InvalidKeyException; + /** * Returns a String that represents this instance. * @@ -330,4 +493,5 @@ public abstract void signRequestLite(HttpURLConnection request, long contentLeng */ public abstract URI transformUri(URI resourceUri, OperationContext opContext) throws URISyntaxException, StorageException; + } diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/StorageCredentialsAccountAndKey.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/StorageCredentialsAccountAndKey.java index 2881295c1f26..27fd4f9cac3f 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/StorageCredentialsAccountAndKey.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/StorageCredentialsAccountAndKey.java @@ -244,6 +244,8 @@ public void setCredentials(final Credentials credentials) { /** * Signs a request under the Shared Key authentication scheme. * + * @deprecated This method has been deprecated. Please use either {@link signBlobAndQueueRequest} or + * {@link signBlobAndQueueRequestLite}, depending on your desired shared key authentication scheme. * @param request * An HttpURLConnection object that represents the request to sign. * @param contentLength @@ -255,14 +257,17 @@ public void setCredentials(final Credentials credentials) { * If a storage service error occurred. */ @Override + @Deprecated public void signRequest(final java.net.HttpURLConnection request, final long contentLength) throws InvalidKeyException, StorageException { - this.signRequest(request, contentLength, null); + this.signBlobAndQueueRequest(request, contentLength, null); } /** * Signs a request using the specified operation context under the Shared Key authentication scheme. * + * @deprecated This method has been deprecated. Please use either {@link signBlobAndQueueRequest} or + * {@link signBlobAndQueueRequestLite}, depending on your desired shared key authentication scheme. * @param request * An HttpURLConnection object that represents the request to sign. * @param contentLength @@ -278,6 +283,7 @@ public void signRequest(final java.net.HttpURLConnection request, final long con * If a storage service error occurred. */ @Override + @Deprecated public void signRequest(final java.net.HttpURLConnection request, final long contentLength, OperationContext opContext) throws InvalidKeyException, StorageException { opContext = opContext == null ? new OperationContext() : opContext; @@ -287,6 +293,9 @@ public void signRequest(final java.net.HttpURLConnection request, final long con /** * Signs a request using the Shared Key Lite authentication scheme. * + * @deprecated This method has been deprecated. Please use either {@link signTableRequest} or + * {@link signTableRequestLite}, depending on your desired shared key authentication scheme. + * * @param request * An HttpURLConnection object that represents the request to sign. * @param contentLength @@ -298,14 +307,18 @@ public void signRequest(final java.net.HttpURLConnection request, final long con * If an unspecified storage exception occurs. */ @Override + @Deprecated public void signRequestLite(final java.net.HttpURLConnection request, final long contentLength) throws InvalidKeyException, StorageException { - this.signRequestLite(request, contentLength, null); + this.signTableRequestLite(request, contentLength, null); } /** * Signs a request using the specified operation context under the Shared Key Lite authentication scheme. * + * @deprecated This method has been deprecated. Please use either {@link signTableRequest} or + * {@link signTableRequestLite}, depending on your desired shared key authentication scheme. + * * @param request * An HttpURLConnection object that represents the request to sign. * @param contentLength @@ -321,12 +334,185 @@ public void signRequestLite(final java.net.HttpURLConnection request, final long * If a storage service error occurred. */ @Override + @Deprecated public void signRequestLite(final java.net.HttpURLConnection request, final long contentLength, OperationContext opContext) throws StorageException, InvalidKeyException { opContext = opContext == null ? new OperationContext() : opContext; BaseRequest.signRequestForTableSharedKeyLite(request, this.credentials, contentLength, opContext); } + /** + * Signs a request under the Shared Key authentication scheme. + * + * @param request + * An HttpURLConnection object that represents the request to sign. + * @param contentLength + * The length of the content written to the output stream. If unknown, specify -1. + * + * @throws InvalidKeyException + * If the given key is invalid. + * @throws StorageException + * If a storage service error occurred. + */ + @Override + public void signBlobAndQueueRequest(final java.net.HttpURLConnection request, final long contentLength) + throws InvalidKeyException, StorageException { + this.signBlobAndQueueRequest(request, contentLength, null); + } + + /** + * Signs a request using the specified operation context under the Shared Key authentication scheme. + * + * @param request + * An HttpURLConnection object that represents the request to sign. + * @param contentLength + * The length of the content written to the output stream. If unknown, specify -1. + * @param opContext + * An {@link OperationContext} object that represents the context for the current operation. This object + * is used to track requests to the storage service, and to provide additional runtime information about + * the operation. + * + * @throws InvalidKeyException + * If the given key is invalid. + * @throws StorageException + * If a storage service error occurred. + */ + @Override + public void signBlobAndQueueRequest(final java.net.HttpURLConnection request, final long contentLength, + OperationContext opContext) throws InvalidKeyException, StorageException { + opContext = opContext == null ? new OperationContext() : opContext; + BaseRequest.signRequestForBlobAndQueue(request, this.credentials, contentLength, opContext); + } + + /** + * Signs a request using the Shared Key Lite authentication scheme. + * + * @param request + * An HttpURLConnection object that represents the request to sign. + * @param contentLength + * The length of the content written to the output stream. If unknown, specify -1. + * + * @throws InvalidKeyException + * If the given key is invalid. + * @throws StorageException + * If an unspecified storage exception occurs. + */ + @Override + public void signBlobAndQueueRequestLite(final java.net.HttpURLConnection request, final long contentLength) + throws InvalidKeyException, StorageException { + this.signBlobAndQueueRequestLite(request, contentLength, null); + } + + /** + * Signs a request using the specified operation context under the Shared Key Lite authentication scheme. + * + * @param request + * An HttpURLConnection object that represents the request to sign. + * @param contentLength + * The length of the content written to the output stream. If unknown, specify -1. + * @param opContext + * An {@link OperationContext} object that represents the context for the current operation. This object + * is used to track requests to the storage service, and to provide additional runtime information about + * the operation. + * + * @throws InvalidKeyException + * If the given key is invalid. + * @throws StorageException + * If a storage service error occurred. + */ + @Override + public void signBlobAndQueueRequestLite(final java.net.HttpURLConnection request, final long contentLength, + OperationContext opContext) throws StorageException, InvalidKeyException { + opContext = opContext == null ? new OperationContext() : opContext; + BaseRequest.signRequestForBlobAndQueueSharedKeyLite(request, this.credentials, contentLength, opContext); + } + + /** + * Signs a request under the Shared Key authentication scheme. + * + * @param request + * An HttpURLConnection object that represents the request to sign. + * @param contentLength + * The length of the content written to the output stream. If unknown, specify -1. + * + * @throws InvalidKeyException + * If the given key is invalid. + * @throws StorageException + * If a storage service error occurred. + */ + @Override + public void signTableRequest(final java.net.HttpURLConnection request, final long contentLength) + throws InvalidKeyException, StorageException { + this.signTableRequest(request, contentLength, null); + } + + /** + * Signs a request using the specified operation context under the Shared Key authentication scheme. + * + * @param request + * An HttpURLConnection object that represents the request to sign. + * @param contentLength + * The length of the content written to the output stream. If unknown, specify -1. + * @param opContext + * An {@link OperationContext} object that represents the context for the current operation. This object + * is used to track requests to the storage service, and to provide additional runtime information about + * the operation. + * + * @throws InvalidKeyException + * If the given key is invalid. + * @throws StorageException + * If a storage service error occurred. + */ + @Override + public void signTableRequest(final java.net.HttpURLConnection request, final long contentLength, + OperationContext opContext) throws InvalidKeyException, StorageException { + opContext = opContext == null ? new OperationContext() : opContext; + BaseRequest.signRequestForTableSharedKey(request, this.credentials, contentLength, opContext); + } + + /** + * Signs a request using the Shared Key Lite authentication scheme. + * + * @param request + * An HttpURLConnection object that represents the request to sign. + * @param contentLength + * The length of the content written to the output stream. If unknown, specify -1. + * + * @throws InvalidKeyException + * If the given key is invalid. + * @throws StorageException + * If an unspecified storage exception occurs. + */ + @Override + public void signTableRequestLite(final java.net.HttpURLConnection request, final long contentLength) + throws InvalidKeyException, StorageException { + this.signTableRequestLite(request, contentLength, null); + } + + /** + * Signs a request using the specified operation context under the Shared Key Lite authentication scheme. + * + * @param request + * An HttpURLConnection object that represents the request to sign. + * @param contentLength + * The length of the content written to the output stream. If unknown, specify -1. + * @param opContext + * An {@link OperationContext} object that represents the context for the current operation. This object + * is used to track requests to the storage service, and to provide additional runtime information about + * the operation. + * + * @throws InvalidKeyException + * If the given key is invalid. + * @throws StorageException + * If a storage service error occurred. + */ + @Override + public void signTableRequestLite(final java.net.HttpURLConnection request, final long contentLength, + OperationContext opContext) throws StorageException, InvalidKeyException { + opContext = opContext == null ? new OperationContext() : opContext; + BaseRequest.signRequestForTableSharedKeyLite(request, this.credentials, contentLength, opContext); + } + /** * Returns a String that represents this instance, optionally including sensitive data. * diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/StorageCredentialsAnonymous.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/StorageCredentialsAnonymous.java index baf4e16dd16d..7ceb94a78675 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/StorageCredentialsAnonymous.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/StorageCredentialsAnonymous.java @@ -172,12 +172,16 @@ public String getAccountName() { * Signs a request using the specified credentials under the Shared Key authentication scheme. This is not a valid * operation for objects of type StorageCredentialsAnonymous so the method performs a no-op. * + * @deprecated This method has been deprecated. Please use either {@link signBlobAndQueueRequest} or + * {@link signBlobAndQueueRequestLite}, depending on your desired shared key authentication scheme. + * * @param connection * the request, as an HttpURLConnection object, to sign * @param contentLength * the length of the content written to the output stream. If unknown, specify -1. */ @Override + @Deprecated public void signRequest(final java.net.HttpURLConnection connection, final long contentLength) { // No op } @@ -187,6 +191,9 @@ public void signRequest(final java.net.HttpURLConnection connection, final long * This is not a valid operation for objects of type StorageCredentialsAnonymous so the method performs * a no-op. * + * @deprecated This method has been deprecated. Please use either {@link signBlobAndQueueRequest} or + * {@link signBlobAndQueueRequestLite}, depending on your desired shared key authentication scheme. + * * @param request * the request, as an HttpURLConnection object, to sign * @param contentLength @@ -196,6 +203,7 @@ public void signRequest(final java.net.HttpURLConnection connection, final long * object, that represents the current operation */ @Override + @Deprecated public void signRequest(final java.net.HttpURLConnection request, final long contentLength, final OperationContext opContext) { // No op @@ -205,10 +213,14 @@ public void signRequest(final java.net.HttpURLConnection request, final long con * Signs a request using the specified credentials under the Shared Key Lite authentication scheme. This is not a * valid operation for objects of type StorageCredentialsAnonymous so the method performs a no-op. * + * @deprecated This method has been deprecated. Please use either {@link signTableRequest} or + * {@link signTableRequestLite}, depending on your desired shared key authentication scheme. + * * @param connection * the request, as an HttpURLConnection object, to sign */ @Override + @Deprecated public void signRequestLite(final java.net.HttpURLConnection connection, final long contentLength) { // No op } @@ -218,6 +230,9 @@ public void signRequestLite(final java.net.HttpURLConnection connection, final l * valid operation for objects of type StorageCredentialsSharedAccessSignature so the method performs a * no-op. * + * @deprecated This method has been deprecated. Please use either {@link signTableRequest} or + * {@link signTableRequestLite}, depending on your desired shared key authentication scheme. + * * @param request * the request, as an HttpURLConnection object, to sign * @param opContext @@ -225,11 +240,136 @@ public void signRequestLite(final java.net.HttpURLConnection connection, final l * object, that represents the current operation */ @Override + @Deprecated public void signRequestLite(final java.net.HttpURLConnection request, final long contentLength, final OperationContext opContext) { // No op } + /** + * Signs a request using the specified credentials under the Shared Key authentication scheme. This is not a valid + * operation for objects of type StorageCredentialsAnonymous so the method performs a no-op. + * + * @param connection + * the request, as an HttpURLConnection object, to sign + * @param contentLength + * the length of the content written to the output stream. If unknown, specify -1. + */ + @Override + public void signBlobAndQueueRequest(final java.net.HttpURLConnection connection, final long contentLength) { + // No op + } + + /** + * Signs a request using the specified credentials and operation context under the Shared Key authentication scheme. + * This is not a valid operation for objects of type StorageCredentialsAnonymous so the method performs + * a no-op. + * + * @param request + * the request, as an HttpURLConnection object, to sign + * @param contentLength + * the length of the content written to the output stream. If unknown, specify -1. + * @param opContext + * an operation context, as a {@link com.microsoft.windowsazure.services.core.storage.OperationContext} + * object, that represents the current operation + */ + @Override + public void signBlobAndQueueRequest(final java.net.HttpURLConnection request, final long contentLength, + final OperationContext opContext) { + // No op + } + + /** + * Signs a request using the specified credentials under the Shared Key Lite authentication scheme. This is not a + * valid operation for objects of type StorageCredentialsAnonymous so the method performs a no-op. + * + * @param connection + * the request, as an HttpURLConnection object, to sign + */ + @Override + public void signBlobAndQueueRequestLite(final java.net.HttpURLConnection connection, final long contentLength) { + // No op + } + + /** + * Signs a request using the specified credentials under the Shared Key Lite authentication scheme. This is not a + * valid operation for objects of type StorageCredentialsSharedAccessSignature so the method performs a + * no-op. + * + * @param request + * the request, as an HttpURLConnection object, to sign + * @param opContext + * an operation context, as a {@link com.microsoft.windowsazure.services.core.storage.OperationContext} + * object, that represents the current operation + */ + @Override + public void signBlobAndQueueRequestLite(final java.net.HttpURLConnection request, final long contentLength, + final OperationContext opContext) { + // No op + } + + /** + * Signs a request using the specified credentials under the Shared Key authentication scheme. This is not a valid + * operation for objects of type StorageCredentialsAnonymous so the method performs a no-op. + * + * @param connection + * the request, as an HttpURLConnection object, to sign + * @param contentLength + * the length of the content written to the output stream. If unknown, specify -1. + */ + @Override + public void signTableRequest(final java.net.HttpURLConnection connection, final long contentLength) { + // No op + } + + /** + * Signs a request using the specified credentials and operation context under the Shared Key authentication scheme. + * This is not a valid operation for objects of type StorageCredentialsAnonymous so the method performs + * a no-op. + * + * @param request + * the request, as an HttpURLConnection object, to sign + * @param contentLength + * the length of the content written to the output stream. If unknown, specify -1. + * @param opContext + * an operation context, as a {@link com.microsoft.windowsazure.services.core.storage.OperationContext} + * object, that represents the current operation + */ + @Override + public void signTableRequest(final java.net.HttpURLConnection request, final long contentLength, + final OperationContext opContext) { + // No op + } + + /** + * Signs a request using the specified credentials under the Shared Key Lite authentication scheme. This is not a + * valid operation for objects of type StorageCredentialsAnonymous so the method performs a no-op. + * + * @param connection + * the request, as an HttpURLConnection object, to sign + */ + @Override + public void signTableRequestLite(final java.net.HttpURLConnection connection, final long contentLength) { + // No op + } + + /** + * Signs a request using the specified credentials under the Shared Key Lite authentication scheme. This is not a + * valid operation for objects of type StorageCredentialsSharedAccessSignature so the method performs a + * no-op. + * + * @param request + * the request, as an HttpURLConnection object, to sign + * @param opContext + * an operation context, as a {@link com.microsoft.windowsazure.services.core.storage.OperationContext} + * object, that represents the current operation + */ + @Override + public void signTableRequestLite(final java.net.HttpURLConnection request, final long contentLength, + final OperationContext opContext) { + // No op + } + /** * Returns a String object that represents this instance. * diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/StorageCredentialsSharedAccessSignature.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/StorageCredentialsSharedAccessSignature.java index 4702824027ff..8e0d609f5fe6 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/StorageCredentialsSharedAccessSignature.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/StorageCredentialsSharedAccessSignature.java @@ -96,8 +96,8 @@ public String computeHmac256(final String value) { /** * Computes a signature for the specified string using the HMAC-SHA256 algorithm with the specified operation - * context. This is not a valid operation for objects of type StorageCredentialsSharedAccessSignature so - * the method merely returns null. + * context. This is not a valid operation for objects of type StorageCredentialsSharedAccessSignature + * so the method merely returns null. * * @param value * The UTF-8-encoded string to sign. @@ -130,8 +130,8 @@ public String computeHmac512(final String value) { /** * Computes a signature for the specified string using the HMAC-SHA512 algorithm with the specified operation - * context. This is not a valid operation for objects of type StorageCredentialsSharedAccessSignature so - * the method merely returns null. + * context. This is not a valid operation for objects of type StorageCredentialsSharedAccessSignature + * so the method merely returns null. * * @param value * The UTF-8-encoded string to sign. @@ -181,6 +181,84 @@ public String getToken() { return this.token; } + /** + * Signs a request using the specified credentials under the Shared Key authentication scheme. This is not a valid + * operation for objects of type StorageCredentialsAnonymous so the method performs a no-op. + * + * @deprecated This method has been deprecated. Please use either {@link signBlobAndQueueRequest} or + * {@link signBlobAndQueueRequestLite}, depending on your desired shared key authentication scheme. + * + * @param connection + * the request, as an HttpURLConnection object, to sign + * @param contentLength + * the length of the content written to the output stream. If unknown, specify -1. + */ + @Override + @Deprecated + public void signRequest(final java.net.HttpURLConnection connection, final long contentLength) { + // No op + } + + /** + * Signs a request using the specified credentials and operation context under the Shared Key authentication scheme. + * This is not a valid operation for objects of type StorageCredentialsAnonymous so the method performs + * a no-op. + * + * @deprecated This method has been deprecated. Please use either {@link signBlobAndQueueRequest} or + * {@link signBlobAndQueueRequestLite}, depending on your desired shared key authentication scheme. + * + * @param request + * the request, as an HttpURLConnection object, to sign + * @param contentLength + * the length of the content written to the output stream. If unknown, specify -1. + * @param opContext + * an operation context, as a {@link com.microsoft.windowsazure.services.core.storage.OperationContext} + * object, that represents the current operation + */ + @Override + @Deprecated + public void signRequest(final java.net.HttpURLConnection request, final long contentLength, + final OperationContext opContext) { + // No op + } + + /** + * Signs a request using the specified credentials under the Shared Key Lite authentication scheme. This is not a + * valid operation for objects of type StorageCredentialsAnonymous so the method performs a no-op. + * + * @deprecated This method has been deprecated. Please use either {@link signTableRequest} or + * {@link signTableRequestLite}, depending on your desired shared key authentication scheme. + * + * @param connection + * the request, as an HttpURLConnection object, to sign + */ + @Override + @Deprecated + public void signRequestLite(final java.net.HttpURLConnection connection, final long contentLength) { + // No op + } + + /** + * Signs a request using the specified credentials under the Shared Key Lite authentication scheme. This is not a + * valid operation for objects of type StorageCredentialsSharedAccessSignature so the method performs a + * no-op. + * + * @deprecated This method has been deprecated. Please use either {@link signTableRequest} or + * {@link signTableRequestLite}, depending on your desired shared key authentication scheme. + * + * @param request + * the request, as an HttpURLConnection object, to sign + * @param opContext + * an operation context, as a {@link com.microsoft.windowsazure.services.core.storage.OperationContext} + * object, that represents the current operation + */ + @Override + @Deprecated + public void signRequestLite(final java.net.HttpURLConnection request, final long contentLength, + final OperationContext opContext) { + // No op + } + /** * Signs a request under the Shared Key authentication scheme. This is not a valid operation for objects of type * StorageCredentialsSharedAccessSignature so the method performs a no-op. @@ -191,7 +269,7 @@ public String getToken() { * The length of the content written to the output stream. If unknown, specify -1. */ @Override - public void signRequest(final java.net.HttpURLConnection request, final long contentLength) { + public void signBlobAndQueueRequest(final java.net.HttpURLConnection request, final long contentLength) { // No op } @@ -210,7 +288,7 @@ public void signRequest(final java.net.HttpURLConnection request, final long con * the operation. */ @Override - public void signRequest(final java.net.HttpURLConnection request, final long contentLength, + public void signBlobAndQueueRequest(final java.net.HttpURLConnection request, final long contentLength, final OperationContext opContext) { // No op } @@ -225,7 +303,7 @@ public void signRequest(final java.net.HttpURLConnection request, final long con * The length of the content written to the output stream. If unknown, specify -1. */ @Override - public void signRequestLite(final java.net.HttpURLConnection request, final long contentLength) { + public void signBlobAndQueueRequestLite(final java.net.HttpURLConnection request, final long contentLength) { // No op } @@ -244,7 +322,75 @@ public void signRequestLite(final java.net.HttpURLConnection request, final long * the operation. */ @Override - public void signRequestLite(final java.net.HttpURLConnection request, final long contentLength, + public void signBlobAndQueueRequestLite(final java.net.HttpURLConnection request, final long contentLength, + final OperationContext opContext) { + // No op + } + + /** + * Signs a request under the Shared Key authentication scheme. This is not a valid operation for objects of type + * StorageCredentialsSharedAccessSignature so the method performs a no-op. + * + * @param request + * An HttpURLConnection object that represents the request to sign. + * @param contentLength + * The length of the content written to the output stream. If unknown, specify -1. + */ + @Override + public void signTableRequest(final java.net.HttpURLConnection request, final long contentLength) { + // No op + } + + /** + * Signs a request using the specified operation context under the Shared Key authentication scheme. This is not a + * valid operation for objects of type StorageCredentialsSharedAccessSignature so the method performs a + * no-op. + * + * @param request + * An HttpURLConnection object that represents the request to sign. + * @param contentLength + * The length of the content written to the output stream. If unknown, specify -1. + * @param opContext + * An {@link OperationContext} object that represents the context for the current operation. This object + * is used to track requests to the storage service, and to provide additional runtime information about + * the operation. + */ + @Override + public void signTableRequest(final java.net.HttpURLConnection request, final long contentLength, + final OperationContext opContext) { + // No op + } + + /** + * Signs a request under the Shared Key Lite authentication scheme. This is not a valid operation for objects of + * type StorageCredentialsSharedAccessSignature so the method performs a no-op. + * + * @param request + * An HttpURLConnection object that represents the request to sign. + * @param contentLength + * The length of the content written to the output stream. If unknown, specify -1. + */ + @Override + public void signTableRequestLite(final java.net.HttpURLConnection request, final long contentLength) { + // No op + } + + /** + * Signs a request using the specified operation context under the Shared Key Lite authentication scheme. This is + * not a valid operation for objects of type StorageCredentialsSharedAccessSignature so the method + * performs a no-op. + * + * @param request + * An HttpURLConnection object that represents the request to sign. + * @param contentLength + * The length of the content written to the output stream. If unknown, specify -1. + * @param opContext + * An {@link OperationContext} object that represents the context for the current operation. This object + * is used to track requests to the storage service, and to provide additional runtime information about + * the operation. + */ + @Override + public void signTableRequestLite(final java.net.HttpURLConnection request, final long contentLength, final OperationContext opContext) { // No op } diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/Utility.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/Utility.java index 37c099517e7d..54e66cd05b83 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/Utility.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/Utility.java @@ -1015,7 +1015,10 @@ public static StreamMd5AndLength writeToOutputStream(final InputStream sourceStr count = sourceStream.read(retrievedBuff, 0, nextCopy); while (nextCopy > 0 && count != -1) { - outStream.write(retrievedBuff, 0, count); + if (outStream != null) { + outStream.write(retrievedBuff, 0, count); + } + if (calculateMD5) { opContext.getIntermediateMD5().update(retrievedBuff, 0, count); } @@ -1029,7 +1032,9 @@ public static StreamMd5AndLength writeToOutputStream(final InputStream sourceStr count = sourceStream.read(retrievedBuff, 0, nextCopy); } - outStream.flush(); + if (outStream != null) { + outStream.flush(); + } if (calculateMD5) { retVal.setDigest(opContext.getIntermediateMD5()); diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/BaseRequest.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/BaseRequest.java index e5273db93f60..19538da0c985 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/BaseRequest.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/BaseRequest.java @@ -498,7 +498,40 @@ public static void signRequestForBlobAndQueueSharedKeyLite(final HttpURLConnecti /** * - * Signs the request appropriately to make it an authenticated request for Blob and Queue. + * Signs the request appropriately to make it an authenticated request for Table. + * + * @param request + * a HttpURLConnection for the operation. + * @param credentials + * the credentials to use for signing. + * @param contentLength + * the length of the content written to the output stream, -1 if unknown. + * @param opContext + * an object used to track the execution of the operation + * @throws InvalidKeyException + * if the credentials key is invalid. + * @throws StorageException + */ + public static void signRequestForTableSharedKey(final HttpURLConnection request, final Credentials credentials, + final Long contentLength, final OperationContext opContext) throws InvalidKeyException, StorageException { + request.setRequestProperty(Constants.HeaderConstants.DATE, Utility.getGMTTime()); + + final Canonicalizer canonicalizer = CanonicalizerFactory.getTableFullCanonicalizer(request); + + final String stringToSign = canonicalizer.canonicalize(request, credentials.getAccountName(), contentLength, + opContext); + + final String computedBase64Signature = StorageKey.computeMacSha256(credentials.getKey(), stringToSign); + + // TODO Vnext add logging + // System.out.println(String.format("Signing %s\r\n%s\r\n", stringToSign, computedBase64Signature)); + request.setRequestProperty(Constants.HeaderConstants.AUTHORIZATION, + String.format("%s %s:%s", "SharedKey", credentials.getAccountName(), computedBase64Signature)); + } + + /** + * + * Signs the request appropriately to make it an authenticated request for Table. * * @param request * a HttpURLConnection for the operation. diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/Canonicalizer.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/Canonicalizer.java index b78e9c258cd3..77c5f71d266d 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/Canonicalizer.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/Canonicalizer.java @@ -34,11 +34,26 @@ import com.microsoft.windowsazure.services.core.storage.utils.Utility; /** - * RESERVED FOR INTERNAL USE. This is a Version 2 Canoncicalization strategy conforming to the PDC 2009-09-19 + * RESERVED FOR INTERNAL USE. This is a Version 2 Canonicalization strategy conforming to the PDC 2009-09-19 * specification */ abstract class Canonicalizer { + /** + * The expected length for the canonicalized string when SharedKeyFull is used to sign requests. + */ + private static final int ExpectedBlobQueueCanonicalizedStringLength = 300; + + /** + * The expected length for the canonicalized string when SharedKeyLite is used to sign requests. + */ + private static final int ExpectedBlobQueueLiteCanonicalizedStringLength = 250; + + /** + * The expected length for the canonicalized string when SharedKeyFull is used to sign table requests. + */ + private static final int ExpectedTableCanonicalizedStringLength = 200; + /** * Add x-ms- prefixed headers in a fixed order. * @@ -130,7 +145,8 @@ protected static String canonicalizeHttpRequest(final java.net.URL address, fina // The first element should be the Method of the request. // I.e. GET, POST, PUT, or HEAD. - final StringBuilder canonicalizedString = new StringBuilder(conn.getRequestMethod()); + final StringBuilder canonicalizedString = new StringBuilder(ExpectedBlobQueueCanonicalizedStringLength); + canonicalizedString.append(conn.getRequestMethod()); // The next elements are // If any element is missing it may be empty. @@ -199,7 +215,9 @@ protected static String canonicalizeHttpRequestLite(final java.net.URL address, final HttpURLConnection conn, final OperationContext opContext) throws StorageException { // The first element should be the Method of the request. // I.e. GET, POST, PUT, or HEAD. - final StringBuilder canonicalizedString = new StringBuilder(conn.getRequestMethod()); + // + final StringBuilder canonicalizedString = new StringBuilder(ExpectedBlobQueueLiteCanonicalizedStringLength); + canonicalizedString.append(conn.getRequestMethod()); // The second element should be the MD5 value. // This is optional and may be empty. @@ -220,7 +238,59 @@ protected static String canonicalizeHttpRequestLite(final java.net.URL address, addCanonicalizedHeaders(conn, canonicalizedString); - appendCanonicalizedElement(canonicalizedString, getCanonicalizedResource(address, accountName)); + appendCanonicalizedElement(canonicalizedString, getCanonicalizedResourceLite(address, accountName)); + + return canonicalizedString.toString(); + } + + /** + * Constructs a canonicalized string that will be used to construct the signature string + * for signing a Table service request under the Shared Key authentication scheme. + * + * @param address + * the request URI + * @param accountName + * the account name associated with the request + * @param method + * the verb to be used for the HTTP request. + * @param contentType + * the content type of the HTTP request. + * @param contentLength + * the length of the content written to the outputstream in bytes, -1 if unknown + * @param date + * the date/time specification for the HTTP request + * @param conn + * the HttpURLConnection for the operation. + * @param opContext + * the OperationContext for the request. + * @return A canonicalized string. + * @throws StorageException + */ + protected static String canonicalizeTableHttpRequest(final java.net.URL address, final String accountName, + final String method, final String contentType, final long contentLength, final String date, + final HttpURLConnection conn, final OperationContext opContext) throws StorageException { + // The first element should be the Method of the request. + // I.e. GET, POST, PUT, or HEAD. + final StringBuilder canonicalizedString = new StringBuilder(ExpectedTableCanonicalizedStringLength); + canonicalizedString.append(conn.getRequestMethod()); + + // The second element should be the MD5 value. + // This is optional and may be empty. + final String httpContentMD5Value = Utility.getStandardHeaderValue(conn, Constants.HeaderConstants.CONTENT_MD5); + appendCanonicalizedElement(canonicalizedString, httpContentMD5Value); + + // The third element should be the content type. + appendCanonicalizedElement(canonicalizedString, contentType); + + // The fourth element should be the request date. + // See if there's an storage date header. + // If there's one, then don't use the date header. + + final String dateString = Utility.getStandardHeaderValue(conn, Constants.HeaderConstants.DATE); + // If x-ms-date header exists, Date should be that value. + appendCanonicalizedElement(canonicalizedString, dateString.equals(Constants.EMPTY_STRING) ? date : dateString); + + appendCanonicalizedElement(canonicalizedString, getCanonicalizedResourceLite(address, accountName)); return canonicalizedString.toString(); } diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/CanonicalizerFactory.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/CanonicalizerFactory.java index 54ae1d41fe3e..1ba789f44c40 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/CanonicalizerFactory.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/CanonicalizerFactory.java @@ -45,6 +45,11 @@ final class CanonicalizerFactory { /** * The Canonicalizer instance for Table */ + private static final TableFullCanonicalizer TABLE_FULL_INSTANCE = new TableFullCanonicalizer(); + + /** + * The Canonicalizer instance for Table Lite + */ private static final TableLiteCanonicalizer TABLE_LITE_INSTANCE = new TableLiteCanonicalizer(); /** @@ -81,7 +86,18 @@ protected static Canonicalizer getBlobQueueLiteCanonicalizer(final HttpURLConnec } /** - * Gets the Blob queue lite Canonicalizer + * Gets the table full Canonicalizer. + * + * @param conn + * the HttpURLConnection for the current operation + * @return the appropriate Canonicalizer for the operation. + */ + protected static Canonicalizer getTableFullCanonicalizer(final HttpURLConnection conn) { + return TABLE_FULL_INSTANCE; + } + + /** + * Gets the table lite Canonicalizer * * @param conn * the HttpURLConnection for the current operation @@ -93,7 +109,7 @@ protected static Canonicalizer getTableLiteCanonicalizer(final HttpURLConnection } else { throw new UnsupportedOperationException( - "Versions before 2009-09-19 do not support Shared Key Lite for Blob And Queue."); + "Versions before 2009-09-19 do not support Shared Key Lite for Table."); } } diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/ExecutionEngine.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/ExecutionEngine.java index 9d3ad41e569a..9e60f511677b 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/ExecutionEngine.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/ExecutionEngine.java @@ -36,6 +36,7 @@ import com.microsoft.windowsazure.services.core.storage.SendingRequestEvent; import com.microsoft.windowsazure.services.core.storage.StorageErrorCodeStrings; import com.microsoft.windowsazure.services.core.storage.StorageException; +import com.microsoft.windowsazure.services.core.storage.utils.Utility; import com.microsoft.windowsazure.services.table.client.TableServiceException; /** @@ -113,7 +114,25 @@ public static RESULT_TYPE executeWithRet opContext.setClientTimeInMs(new Date().getTime() - startTime); if (!task.isNonExceptionedRetryableFailure()) { - // Success return result, the rest of the return paths throw. + // Success return result and drain the input stream. + HttpURLConnection request = task.getConnection(); + if ((task.getResult().getStatusCode() >= 200) && (task.getResult().getStatusCode() < 300)) { + if (request != null) { + InputStream inStream = request.getInputStream(); + try { + Utility.writeToOutputStream(inStream, null, -1, false, false, task.getResult(), null); + } + // At this point, we already have a result / exception to return to the user. + // This is just an optimization to improve socket reuse. + catch (final IOException ex) { + } + catch (StorageException e) { + } + finally { + inStream.close(); + } + } + } return result; } else { diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/StorageOperation.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/StorageOperation.java index 803bbdfa5481..47ae9204e384 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/StorageOperation.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/StorageOperation.java @@ -15,10 +15,13 @@ package com.microsoft.windowsazure.services.core.storage.utils.implementation; import java.net.HttpURLConnection; +import java.security.InvalidKeyException; +import com.microsoft.windowsazure.services.core.storage.AuthenticationScheme; import com.microsoft.windowsazure.services.core.storage.OperationContext; import com.microsoft.windowsazure.services.core.storage.RequestOptions; import com.microsoft.windowsazure.services.core.storage.RequestResult; +import com.microsoft.windowsazure.services.core.storage.ServiceClient; import com.microsoft.windowsazure.services.core.storage.StorageException; /** @@ -39,7 +42,7 @@ public abstract class StorageOperation { private StorageException exceptionReference; /** - * A flag to indicate a failure which did not result in an exceptin, i.e a 400 class status code. + * A flag to indicate a failure which did not result in an exception, i.e a 400 class status code. */ private boolean nonExceptionedRetryableFailure; @@ -53,6 +56,11 @@ public abstract class StorageOperation { */ private RequestResult result; + /** + * Holds the url connection for the operation. + */ + private HttpURLConnection connection; + /** * Default Ctor. */ @@ -106,6 +114,13 @@ public final RequestResult getResult() { return this.result; } + /** + * @return the URL connection + */ + public final HttpURLConnection getConnection() { + return this.connection; + } + /** * Resets the operation status flags between operations. */ @@ -126,7 +141,7 @@ public final boolean isNonExceptionedRetryableFailure() { } /** - * Returns either the held exception from the operation if it is set, othwerwise the translated exception. + * Returns either the held exception from the operation if it is set, otherwise the translated exception. * * @param request * the reference to the HttpURLConnection for the operation. @@ -143,6 +158,26 @@ protected final StorageException materializeException(final HttpURLConnection re return StorageException.translateException(request, null, opContext); } + public final void signRequest(ServiceClient client, HttpURLConnection request, long contentLength, + OperationContext context) throws InvalidKeyException, StorageException { + if (client.getAuthenticationScheme() == AuthenticationScheme.SHAREDKEYFULL) { + client.getCredentials().signBlobAndQueueRequest(request, contentLength, context); + } + else { + client.getCredentials().signBlobAndQueueRequestLite(request, contentLength, context); + } + } + + public final void signTableRequest(ServiceClient client, HttpURLConnection request, long contentLength, + OperationContext context) throws InvalidKeyException, StorageException { + if (client.getAuthenticationScheme() == AuthenticationScheme.SHAREDKEYFULL) { + client.getCredentials().signTableRequest(request, contentLength, context); + } + else { + client.getCredentials().signTableRequestLite(request, contentLength, context); + } + } + /** * @param exceptionReference * the exception to set @@ -174,4 +209,12 @@ protected final void setRequestOptions(final RequestOptions requestOptions) { public final void setResult(final RequestResult result) { this.result = result; } + + /** + * @param connection + * the connection to set + */ + public final void setConnection(final HttpURLConnection connection) { + this.connection = connection; + } } diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/TableFullCanonicalizer.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/TableFullCanonicalizer.java new file mode 100644 index 000000000000..c3088315fb73 --- /dev/null +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/TableFullCanonicalizer.java @@ -0,0 +1,57 @@ +/** + * Copyright Microsoft Corporation + * + * Licensed 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. + */ +package com.microsoft.windowsazure.services.core.storage.utils.implementation; + +import java.net.HttpURLConnection; +import java.security.InvalidParameterException; + +import com.microsoft.windowsazure.services.core.storage.Constants; +import com.microsoft.windowsazure.services.core.storage.OperationContext; +import com.microsoft.windowsazure.services.core.storage.StorageException; +import com.microsoft.windowsazure.services.core.storage.utils.Utility; + +/** + * RESERVED FOR INTERNAL USE. Provides an implementation of the Canonicalizer class for requests against Table + * Service under the Shared Key authentication scheme. + */ +final class TableFullCanonicalizer extends Canonicalizer { + + /** + * Constructs a canonicalized string for signing a request. + * + * @param conn + * the HttpURLConnection to canonicalize + * @param accountName + * the account name associated with the request + * @param contentLength + * the length of the content written to the outputstream in bytes, -1 if unknown + * @param opContext + * the OperationContext for the given request + * @return a canonicalized string. + * @throws StorageException + */ + @Override + protected String canonicalize(final HttpURLConnection conn, final String accountName, final Long contentLength, + final OperationContext opContext) throws StorageException { + + if (contentLength < -1) { + throw new InvalidParameterException("ContentLength must be set to -1 or non-negative Long value"); + } + + return canonicalizeTableHttpRequest(conn.getURL(), accountName, conn.getRequestMethod(), + Utility.getStandardHeaderValue(conn, Constants.HeaderConstants.CONTENT_TYPE), contentLength, null, + conn, opContext); + } +} diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/TableLiteCanonicalizer.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/TableLiteCanonicalizer.java index 913ed76d908a..44211bf76946 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/TableLiteCanonicalizer.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/TableLiteCanonicalizer.java @@ -30,6 +30,12 @@ * under the Shared Key Lite authentication scheme. */ class TableLiteCanonicalizer extends Canonicalizer { + + /** + * The expected length for the canonicalized string when SharedKeyLite is used to sign table requests. + */ + private static final int ExpectedTableLiteCanonicalizedStringLength = 150; + /** * Constructs a canonicalized string for signing a request. * @@ -56,8 +62,8 @@ protected String canonicalize(final HttpURLConnection conn, final String account throw new IllegalArgumentException( "Canonicalization did not find a non empty x-ms-date header in the request. Please use a request with a valid x-ms-date header in RFC 123 format."); } - - final StringBuilder canonicalizedString = new StringBuilder(dateString); + final StringBuilder canonicalizedString = new StringBuilder(ExpectedTableLiteCanonicalizedStringLength); + canonicalizedString.append(dateString); appendCanonicalizedElement(canonicalizedString, getCanonicalizedResourceLite(conn.getURL(), accountName)); return canonicalizedString.toString(); diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/client/CloudQueue.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/client/CloudQueue.java index c29f1067844c..4190dd58ac73 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/client/CloudQueue.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/client/CloudQueue.java @@ -213,10 +213,12 @@ public Void execute(final CloudQueueClient client, final CloudQueue queue, final final HttpURLConnection request = QueueRequest.putMessage(queue.getMessageRequestAddress(opContext), this.getRequestOptions().getTimeoutIntervalInMs(), initialVisibilityDelayInSeconds, timeToLiveInSeconds, opContext); + this.setConnection(request); final byte[] messageBytes = QueueRequest.generateMessageRequestBody(stringToSend); - client.getCredentials().signRequest(request, messageBytes.length); + this.signRequest(client, request, messageBytes.length, null); + final OutputStream outStreamRef = request.getOutputStream(); outStreamRef.write(messageBytes); @@ -283,8 +285,9 @@ public Void execute(final CloudQueueClient client, final CloudQueue queue, final final HttpURLConnection request = QueueRequest.clearMessages(queue.getMessageRequestAddress(opContext), this.getRequestOptions().getTimeoutIntervalInMs(), opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, -1L); + this.signRequest(client, request, -1L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -347,9 +350,11 @@ public Void execute(final CloudQueueClient client, final CloudQueue queue, final throws Exception { final HttpURLConnection request = QueueRequest.create(queue.getTransformedAddress(opContext), this .getRequestOptions().getTimeoutIntervalInMs(), opContext); + this.setConnection(request); QueueRequest.addMetadata(request, queue.metadata, opContext); - client.getCredentials().signRequest(request, 0L); + + this.signRequest(client, request, 0L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -420,9 +425,11 @@ public Boolean execute(final CloudQueueClient client, final CloudQueue queue, final OperationContext opContext) throws Exception { final HttpURLConnection request = QueueRequest.create(queue.getTransformedAddress(opContext), this .getRequestOptions().getTimeoutIntervalInMs(), opContext); + this.setConnection(request); QueueRequest.addMetadata(request, queue.metadata, opContext); - client.getCredentials().signRequest(request, 0L); + + this.signRequest(client, request, 0L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -506,8 +513,9 @@ public Void execute(final CloudQueueClient client, final CloudQueue queue, final throws Exception { final HttpURLConnection request = QueueRequest.delete(queue.getTransformedAddress(opContext), this .getRequestOptions().getTimeoutIntervalInMs(), opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, -1L); + this.signRequest(client, request, -1L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -577,8 +585,9 @@ public Boolean execute(final CloudQueueClient client, final CloudQueue queue, final OperationContext opContext) throws Exception { final HttpURLConnection request = QueueRequest.delete(queue.getTransformedAddress(opContext), this .getRequestOptions().getTimeoutIntervalInMs(), opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, -1L); + this.signRequest(client, request, -1L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -664,8 +673,9 @@ public Void execute(final CloudQueueClient client, final CloudQueue queue, final final HttpURLConnection request = QueueRequest.deleteMessage(queue.getIndividualMessageAddress( messageId, opContext), this.getRequestOptions().getTimeoutIntervalInMs(), messagePopReceipt, opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, -1L); + this.signRequest(client, request, -1L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -730,8 +740,9 @@ public Void execute(final CloudQueueClient client, final CloudQueue queue, final final HttpURLConnection request = QueueRequest.downloadAttributes( queue.getTransformedAddress(opContext), this.getRequestOptions().getTimeoutIntervalInMs(), opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, -1L); + this.signRequest(client, request, -1L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -803,8 +814,9 @@ public Boolean execute(final CloudQueueClient client, final CloudQueue queue, final HttpURLConnection request = QueueRequest.downloadAttributes( queue.getTransformedAddress(opContext), this.getRequestOptions().getTimeoutIntervalInMs(), opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, -1L); + this.signRequest(client, request, -1L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -1018,8 +1030,9 @@ public ArrayList execute(final CloudQueueClient client, final final HttpURLConnection request = QueueRequest.peekMessages(queue.getMessageRequestAddress(opContext), this.getRequestOptions().getTimeoutIntervalInMs(), numberOfMessages, opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, -1L); + this.signRequest(client, request, -1L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -1152,8 +1165,9 @@ public ArrayList execute(final CloudQueueClient client, final final HttpURLConnection request = QueueRequest.retrieveMessages( queue.getMessageRequestAddress(opContext), this.getRequestOptions().getTimeoutIntervalInMs(), numberOfMessages, visibilityTimeoutInSeconds, opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, -1L); + this.signRequest(client, request, -1L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -1280,17 +1294,20 @@ public Void execute(final CloudQueueClient client, final CloudQueue queue, final final HttpURLConnection request = QueueRequest.updateMessage(queue.getIndividualMessageAddress( message.getId(), opContext), this.getRequestOptions().getTimeoutIntervalInMs(), message .getPopReceipt(), visibilityTimeoutInSeconds, opContext); + this.setConnection(request); if (messageUpdateFields.contains(MessageUpdateFields.CONTENT)) { final byte[] messageBytes = QueueRequest.generateMessageRequestBody(stringToSend); - client.getCredentials().signRequest(request, messageBytes.length); + this.signRequest(client, request, messageBytes.length, null); + final OutputStream outStreamRef = request.getOutputStream(); outStreamRef.write(messageBytes); } else { request.setFixedLengthStreamingMode(0); - client.getCredentials().signRequest(request, 0L); + + this.signRequest(client, request, 0L, null); } ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -1362,9 +1379,10 @@ public Void execute(final CloudQueueClient client, final CloudQueue queue, final final HttpURLConnection request = QueueRequest.setMetadata(queue.getTransformedAddress(opContext), this .getRequestOptions().getTimeoutIntervalInMs(), opContext); + this.setConnection(request); QueueRequest.addMetadata(request, queue.metadata, opContext); - client.getCredentials().signRequest(request, 0L); + this.signRequest(client, request, 0L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -1435,13 +1453,16 @@ public Void execute(final CloudQueueClient client, final CloudQueue queue, final final HttpURLConnection request = QueueRequest.setAcl(queue.getTransformedAddress(opContext), this .getRequestOptions().getTimeoutIntervalInMs(), opContext); + this.setConnection(request); final StringWriter outBuffer = new StringWriter(); QueueRequest.writeSharedAccessIdentifiersToStream(permissions.getSharedAccessPolicies(), outBuffer); final byte[] aclBytes = outBuffer.toString().getBytes("UTF8"); - client.getCredentials().signRequest(request, aclBytes.length); + + this.signRequest(client, request, aclBytes.length, null); + final OutputStream outStreamRef = request.getOutputStream(); outStreamRef.write(aclBytes); @@ -1512,8 +1533,9 @@ public QueuePermissions execute(final CloudQueueClient client, final CloudQueue final HttpURLConnection request = QueueRequest.getAcl(queue.getTransformedAddress(opContext), this .getRequestOptions().getTimeoutIntervalInMs(), opContext); + this.setConnection(request); - client.getCredentials().signRequest(request, -1L); + this.signRequest(client, request, -1L, null); ExecutionEngine.processRequest(request, opContext, this.getResult()); diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/client/CloudQueueClient.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/client/CloudQueueClient.java index addec40b3b9c..b4b1f97c2bed 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/client/CloudQueueClient.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/client/CloudQueueClient.java @@ -224,8 +224,9 @@ ResultSegment listQueuesCore(final String prefix, final QueueListing final HttpURLConnection listQueueRequest = QueueRequest.list(this.getEndpoint(), options.getTimeoutIntervalInMs(), listingContext, detailsIncluded, opContext); + taskReference.setConnection(listQueueRequest); - this.getCredentials().signRequest(listQueueRequest, -1L); + taskReference.signRequest(this, listQueueRequest, -1L, null); ExecutionEngine.processRequest(listQueueRequest, opContext, taskReference.getResult()); diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/CloudTable.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/CloudTable.java index f13eac657acf..298f2a8f6064 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/CloudTable.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/CloudTable.java @@ -483,13 +483,16 @@ public Void execute(final CloudTableClient client, final CloudTable table, final final HttpURLConnection request = TableRequest.setAcl(table.uri, this.getRequestOptions() .getTimeoutIntervalInMs(), opContext); + this.setConnection(request); final StringWriter outBuffer = new StringWriter(); TableRequest.writeSharedAccessIdentifiersToStream(permissions.getSharedAccessPolicies(), outBuffer); final byte[] aclBytes = outBuffer.toString().getBytes("UTF8"); - client.getCredentials().signRequestLite(request, aclBytes.length, opContext); + + this.signTableRequest(client, request, aclBytes.length, opContext); + final OutputStream outStreamRef = request.getOutputStream(); outStreamRef.write(aclBytes); @@ -561,8 +564,9 @@ public TablePermissions execute(final CloudTableClient client, final CloudTable final HttpURLConnection request = TableRequest.getAcl(table.uri, tableName, this.getRequestOptions() .getTimeoutIntervalInMs(), opContext); + this.setConnection(request); - client.getCredentials().signRequestLite(request, -1L, opContext); + this.signTableRequest(client, request, -1L, opContext); ExecutionEngine.processRequest(request, opContext, this.getResult()); diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/CloudTableClient.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/CloudTableClient.java index 26a506cc39a6..ca181e471aa6 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/CloudTableClient.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/CloudTableClient.java @@ -797,8 +797,9 @@ protected ResultSegment executeQuerySegmentedCore( final HttpURLConnection queryRequest = TableRequest.query(this.getTransformedEndPoint(opContext), queryToExecute.getSourceTableName(), null/* identity */, options.getTimeoutIntervalInMs(), queryToExecute.generateQueryBuilder(), continuationToken, options, opContext); + taskReference.setConnection(queryRequest); - this.getCredentials().signRequestLite(queryRequest, -1L, opContext); + taskReference.signTableRequest(this, queryRequest, -1L, opContext); ExecutionEngine.processRequest(queryRequest, opContext, taskReference.getResult()); @@ -812,18 +813,13 @@ protected ResultSegment executeQuerySegmentedCore( InputStream inStream = queryRequest.getInputStream(); - try { - if (resolver == null) { - clazzResponse = (ODataPayload) AtomPubParser.parseResponse(inStream, queryToExecute.getClazzType(), - null, opContext); - } - else { - resolvedResponse = (ODataPayload) AtomPubParser.parseResponse(inStream, - queryToExecute.getClazzType(), resolver, opContext); - } + if (resolver == null) { + clazzResponse = (ODataPayload) AtomPubParser.parseResponse(inStream, queryToExecute.getClazzType(), + null, opContext); } - finally { - inStream.close(); + else { + resolvedResponse = (ODataPayload) AtomPubParser.parseResponse(inStream, queryToExecute.getClazzType(), + resolver, opContext); } final ResultContinuation nextToken = TableResponse.getTableContinuationFromResponse(queryRequest); diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/QueryTableOperation.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/QueryTableOperation.java index 14c130540b18..48a01577e808 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/QueryTableOperation.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/QueryTableOperation.java @@ -186,8 +186,9 @@ public TableResult execute(final CloudTableClient client, final QueryTableOperat tableName, generateRequestIdentity(isTableEntry, operation.getPartitionKey(), false), options.getTimeoutIntervalInMs(), null/* Query Builder */, null/* Continuation Token */, options, opContext); + this.setConnection(request); - client.getCredentials().signRequestLite(request, -1L, opContext); + this.signTableRequest(client, request, -1L, opContext); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -197,13 +198,8 @@ tableName, generateRequestIdentity(isTableEntry, operation.getPartitionKey(), fa final XMLStreamReader xmlr = Utility.createXMLStreamReaderFromStream(inStream); TableResult res = null; - try { - res = AtomPubParser.parseSingleOpResponse(xmlr, this.getResult().getStatusCode(), - operation.getClazzType(), operation.getResolver(), opContext); - } - finally { - inStream.close(); - } + res = AtomPubParser.parseSingleOpResponse(xmlr, this.getResult().getStatusCode(), + operation.getClazzType(), operation.getResolver(), opContext); return res; } diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/TableBatchOperation.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/TableBatchOperation.java index a2e814a92e00..cef17a1c030b 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/TableBatchOperation.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/TableBatchOperation.java @@ -393,30 +393,27 @@ public ArrayList execute(final CloudTableClient client, final Table final HttpURLConnection request = TableRequest.batch(client.getTransformedEndPoint(opContext), options.getTimeoutIntervalInMs(), batchID, null, options, opContext); + this.setConnection(request); - client.getCredentials().signRequestLite(request, -1L, opContext); + this.signTableRequest(client, request, -1L, opContext); MimeHelper.writeBatchToStream(request.getOutputStream(), tableName, batch, batchID, changeSet, opContext); final InputStream streamRef = ExecutionEngine.getInputStream(request, opContext, this.getResult()); ArrayList responseParts = null; - try { - final String contentType = request.getHeaderField(Constants.HeaderConstants.CONTENT_TYPE); - - final String[] headerVals = contentType.split("multipart/mixed; boundary="); - if (headerVals == null || headerVals.length != 2) { - throw new StorageException(StorageErrorCodeStrings.OUT_OF_RANGE_INPUT, - "An incorrect Content-type was returned from the server.", - Constants.HeaderConstants.HTTP_UNUSED_306, null, null); - } - responseParts = MimeHelper.readBatchResponseStream(streamRef, headerVals[1], opContext); - } - finally { - streamRef.close(); + final String contentType = request.getHeaderField(Constants.HeaderConstants.CONTENT_TYPE); + + final String[] headerVals = contentType.split("multipart/mixed; boundary="); + if (headerVals == null || headerVals.length != 2) { + throw new StorageException(StorageErrorCodeStrings.OUT_OF_RANGE_INPUT, + "An incorrect Content-type was returned from the server.", + Constants.HeaderConstants.HTTP_UNUSED_306, null, null); } + responseParts = MimeHelper.readBatchResponseStream(streamRef, headerVals[1], opContext); + ExecutionEngine.getResponseCode(this.getResult(), request, opContext); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_ACCEPTED) { diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/TableOperation.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/TableOperation.java index 65987567691c..81b030426817 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/TableOperation.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/TableOperation.java @@ -259,8 +259,9 @@ public TableResult execute(final CloudTableClient client, final TableOperation o final HttpURLConnection request = TableRequest.delete(client.getTransformedEndPoint(opContext), tableName, generateRequestIdentity(isTableEntry, tableIdentity, false), operation.getEntity() .getEtag(), options.getTimeoutIntervalInMs(), null, options, opContext); + this.setConnection(request); - client.getCredentials().signRequestLite(request, -1L, opContext); + this.signTableRequest(client, request, -1L, opContext); ExecutionEngine.processRequest(request, opContext, this.getResult()); @@ -327,8 +328,9 @@ public TableResult execute(final CloudTableClient client, final TableOperation o tableName, generateRequestIdentity(isTableEntry, tableIdentity, false), operation.opType != TableOperationType.INSERT ? operation.getEntity().getEtag() : null, operation.opType.getUpdateType(), options.getTimeoutIntervalInMs(), null, options, opContext); + this.setConnection(request); - client.getCredentials().signRequestLite(request, -1L, opContext); + this.signTableRequest(client, request, -1L, opContext); AtomPubParser.writeSingleEntityToStream(operation.getEntity(), isTableEntry, request.getOutputStream(), opContext); @@ -348,13 +350,8 @@ tableName, generateRequestIdentity(isTableEntry, tableIdentity, false), InputStream inStream = request.getInputStream(); TableResult res = null; - try { - final XMLStreamReader xmlr = Utility.createXMLStreamReaderFromStream(inStream); - res = operation.parseResponse(xmlr, this.getResult().getStatusCode(), null, opContext); - } - finally { - inStream.close(); - } + final XMLStreamReader xmlr = Utility.createXMLStreamReaderFromStream(inStream); + res = operation.parseResponse(xmlr, this.getResult().getStatusCode(), null, opContext); return res; } @@ -413,8 +410,9 @@ public TableResult execute(final CloudTableClient client, final TableOperation o final HttpURLConnection request = TableRequest.merge(client.getTransformedEndPoint(opContext), tableName, generateRequestIdentity(false, null, false), operation.getEntity().getEtag(), options.getTimeoutIntervalInMs(), null, options, opContext); + this.setConnection(request); - client.getCredentials().signRequestLite(request, -1L, opContext); + this.signTableRequest(client, request, -1L, opContext); AtomPubParser.writeSingleEntityToStream(operation.getEntity(), false, request.getOutputStream(), opContext); @@ -479,8 +477,9 @@ public TableResult execute(final CloudTableClient client, final TableOperation o final HttpURLConnection request = TableRequest.update(client.getTransformedEndPoint(opContext), tableName, generateRequestIdentity(false, null, false), operation.getEntity().getEtag(), options.getTimeoutIntervalInMs(), null, options, opContext); + this.setConnection(request); - client.getCredentials().signRequestLite(request, -1L, opContext); + this.signTableRequest(client, request, -1L, opContext); AtomPubParser.writeSingleEntityToStream(operation.getEntity(), false, request.getOutputStream(), opContext); diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/blob/client/BlobTestBase.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/blob/client/BlobTestBase.java index cba0245c4270..1b69119c1e48 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/blob/client/BlobTestBase.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/blob/client/BlobTestBase.java @@ -21,6 +21,7 @@ import org.junit.AfterClass; import org.junit.BeforeClass; +import com.microsoft.windowsazure.services.core.storage.AuthenticationScheme; import com.microsoft.windowsazure.services.core.storage.CloudStorageAccount; import com.microsoft.windowsazure.services.core.storage.StorageException; @@ -30,7 +31,7 @@ */ public class BlobTestBase { public static boolean USE_DEV_FABRIC = false; - public static final String CLOUD_ACCOUNT_HTTP = "DefaultEndpointsProtocol=https;AccountName=[ACCOUNT NAME];AccountKey=[ACCOUNT KEY]"; + public static final String CLOUD_ACCOUNT_HTTP = "DefaultEndpointsProtocol=http;AccountName=[ACCOUNT NAME];AccountKey=[ACCOUNT KEY]"; public static final String CLOUD_ACCOUNT_HTTPS = "DefaultEndpointsProtocol=https;AccountName=[ACCOUNT NAME];AccountKey=[ACCOUNT KEY]"; protected static CloudStorageAccount httpAcc; @@ -52,6 +53,7 @@ public static void setup() throws URISyntaxException, StorageException, InvalidK } bClient = httpAcc.createCloudBlobClient(); + bClient.setAuthenticationScheme(AuthenticationScheme.SHAREDKEYFULL); testSuiteContainerName = generateRandomContainerName(); CloudBlobContainer container = bClient.getContainerReference(testSuiteContainerName); container.create(); diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/blob/client/CloudBlobContainerTests.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/blob/client/CloudBlobContainerTests.java index e007c4151140..36a73da82be8 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/blob/client/CloudBlobContainerTests.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/blob/client/CloudBlobContainerTests.java @@ -36,6 +36,7 @@ import org.junit.Test; import com.microsoft.windowsazure.services.core.storage.AccessCondition; +import com.microsoft.windowsazure.services.core.storage.AuthenticationScheme; import com.microsoft.windowsazure.services.core.storage.OperationContext; import com.microsoft.windowsazure.services.core.storage.ResultSegment; import com.microsoft.windowsazure.services.core.storage.RetryNoRetry; @@ -808,4 +809,46 @@ public void testCurrentOperationByteCount() throws URISyntaxException, StorageEx blobRef.delete(); } + + @Test + public void testContainerSharedKeyLite() throws StorageException, URISyntaxException { + bClient.setAuthenticationScheme(AuthenticationScheme.SHAREDKEYLITE); + String name = generateRandomContainerName(); + CloudBlobContainer newContainer = bClient.getContainerReference(name); + newContainer.create(); + + BlobContainerPermissions expectedPermissions; + BlobContainerPermissions testPermissions; + + try { + // Test new permissions. + expectedPermissions = new BlobContainerPermissions(); + testPermissions = newContainer.downloadPermissions(); + assertTablePermissionsEqual(expectedPermissions, testPermissions); + + // Test setting empty permissions. + newContainer.uploadPermissions(expectedPermissions); + testPermissions = newContainer.downloadPermissions(); + assertTablePermissionsEqual(expectedPermissions, testPermissions); + + // Add a policy, check setting and getting. + SharedAccessBlobPolicy policy1 = new SharedAccessBlobPolicy(); + Calendar now = GregorianCalendar.getInstance(); + policy1.setSharedAccessStartTime(now.getTime()); + now.add(Calendar.MINUTE, 10); + policy1.setSharedAccessExpiryTime(now.getTime()); + + policy1.setPermissions(EnumSet.of(SharedAccessBlobPermissions.READ, SharedAccessBlobPermissions.DELETE, + SharedAccessBlobPermissions.LIST, SharedAccessBlobPermissions.DELETE)); + expectedPermissions.getSharedAccessPolicies().put(UUID.randomUUID().toString(), policy1); + + newContainer.uploadPermissions(expectedPermissions); + testPermissions = newContainer.downloadPermissions(); + assertTablePermissionsEqual(expectedPermissions, testPermissions); + } + finally { + // cleanup + newContainer.deleteIfExists(); + } + } } diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/MediaProcessorIntegrationTest.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/MediaProcessorIntegrationTest.java index 824c34d2dc93..8132e3d52e67 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/MediaProcessorIntegrationTest.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/MediaProcessorIntegrationTest.java @@ -38,13 +38,13 @@ private void verifyMediaProcessorInfo(String message, MediaProcessorInfo mediaPr } private void verifyMediaProcessorInfo(String message, String id, String name, String description, String sku, - String vendor, String version, MediaProcessorInfo mediaProcessorInfo) { + String vendor, MediaProcessorInfo mediaProcessorInfo) { assertEquals(message + " id", id, mediaProcessorInfo.getId()); assertEquals(message + " name", name, mediaProcessorInfo.getName()); assertEquals(message + " description", description, mediaProcessorInfo.getDescription()); assertEquals(message + " sku", sku, mediaProcessorInfo.getSku()); assertEquals(message + " vendor", vendor, mediaProcessorInfo.getVendor()); - assertEquals(message + " version", version, mediaProcessorInfo.getVersion()); + assertTrue(message + "version length > 0", mediaProcessorInfo.getVersion().length() > 0); } @Test @@ -73,6 +73,6 @@ public void listMediaProcessorWithOptionSuccess() throws ServiceException { assertEquals("listMediaProcessors size", 1, listMediaProcessorsResult.size()); MediaProcessorInfo mediaProcessorInfo = listMediaProcessorsResult.get(0); verifyMediaProcessorInfo("mediaProcessorInfo", "nb:mpid:UUID:aec03716-7c5e-4f68-b592-f4850eba9f10", - "Storage Decryption", "Storage Decryption", "", "Microsoft", "1.6", mediaProcessorInfo); + "Storage Decryption", "Storage Decryption", "", "Microsoft", mediaProcessorInfo); } } diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/queue/client/CloudQueueTests.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/queue/client/CloudQueueTests.java index 53c95807d465..2f91a392326c 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/queue/client/CloudQueueTests.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/queue/client/CloudQueueTests.java @@ -34,6 +34,7 @@ import org.junit.Test; +import com.microsoft.windowsazure.services.core.storage.AuthenticationScheme; import com.microsoft.windowsazure.services.core.storage.OperationContext; import com.microsoft.windowsazure.services.core.storage.StorageCredentialsSharedAccessSignature; import com.microsoft.windowsazure.services.core.storage.StorageErrorCodeStrings; @@ -1359,4 +1360,35 @@ public void testSASClientParse() throws StorageException, URISyntaxException, In CloudQueue queue2 = new CloudQueue(queueUri, queueClient2); queue2.getName(); } + + @Test + public void testQueueSharedKeyLite() throws URISyntaxException, StorageException { + qClient.setAuthenticationScheme(AuthenticationScheme.SHAREDKEYLITE); + String queueName = UUID.randomUUID().toString().toLowerCase(); + CloudQueue queue = qClient.getQueueReference(queueName); + Assert.assertEquals(queueName, queue.getName()); + + OperationContext createQueueContext = new OperationContext(); + queue.create(null, createQueueContext); + Assert.assertEquals(createQueueContext.getLastResult().getStatusCode(), HttpURLConnection.HTTP_CREATED); + + try { + HashMap metadata1 = new HashMap(); + metadata1.put("ExistingMetadata1", "ExistingMetadataValue1"); + queue.setMetadata(metadata1); + queue.create(); + Assert.fail(); + } + catch (StorageException e) { + Assert.assertTrue(e.getHttpStatusCode() == HttpURLConnection.HTTP_CONFLICT); + + } + + queue.downloadAttributes(); + OperationContext createQueueContext2 = new OperationContext(); + queue.create(null, createQueueContext2); + Assert.assertEquals(createQueueContext2.getLastResult().getStatusCode(), HttpURLConnection.HTTP_NO_CONTENT); + + queue.delete(); + } } diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/queue/client/QueueTestBase.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/queue/client/QueueTestBase.java index e44acb2a2100..4ccfa9f78136 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/queue/client/QueueTestBase.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/queue/client/QueueTestBase.java @@ -22,6 +22,7 @@ import org.junit.AfterClass; import org.junit.BeforeClass; +import com.microsoft.windowsazure.services.core.storage.AuthenticationScheme; import com.microsoft.windowsazure.services.core.storage.CloudStorageAccount; import com.microsoft.windowsazure.services.core.storage.StorageException; @@ -31,7 +32,7 @@ */ public class QueueTestBase { public static boolean USE_DEV_FABRIC = false; - public static final String CLOUD_ACCOUNT_HTTP = "DefaultEndpointsProtocol=https;AccountName=[ACCOUNT NAME];AccountKey=[ACCOUNT KEY]"; + public static final String CLOUD_ACCOUNT_HTTP = "DefaultEndpointsProtocol=http;AccountName=[ACCOUNT NAME];AccountKey=[ACCOUNT KEY]"; public static final String CLOUD_ACCOUNT_HTTPS = "DefaultEndpointsProtocol=https;AccountName=[ACCOUNT NAME];AccountKey=[ACCOUNT KEY]"; protected static CloudStorageAccount httpAcc; @@ -53,6 +54,7 @@ public static void setup() throws URISyntaxException, StorageException, InvalidK } qClient = httpAcc.createCloudQueueClient(); + qClient.setAuthenticationScheme(AuthenticationScheme.SHAREDKEYFULL); testSuiteQueueName = generateRandomQueueName(); queue = qClient.getQueueReference(testSuiteQueueName); queue.create(); diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/scenarios/MediaServiceWrapper.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/scenarios/MediaServiceWrapper.java index bb996eb10b77..bc92439348ea 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/scenarios/MediaServiceWrapper.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/scenarios/MediaServiceWrapper.java @@ -272,13 +272,13 @@ public Task.CreateBatchOperation createTaskOptions(String taskName, int inputAss String configuration = null; switch (encoderType) { case WindowsAzureMediaEncoder: - processor = getMediaProcessorIdByName(MEDIA_PROCESSOR_WINDOWS_AZURE_MEDIA_ENCODER, "2.3"); + processor = getMediaProcessorIdByName(MEDIA_PROCESSOR_WINDOWS_AZURE_MEDIA_ENCODER); // Full list of configurations strings for version 2.1 is at: // http://msdn.microsoft.com/en-us/library/jj129582.aspx configuration = "VC1 Broadband SD 4x3"; break; case StorageDecryption: - processor = getMediaProcessorIdByName(MEDIA_PROCESSOR_STORAGE_DECRYPTION, "1.6"); + processor = getMediaProcessorIdByName(MEDIA_PROCESSOR_STORAGE_DECRYPTION); configuration = null; break; default: @@ -296,10 +296,9 @@ private String getTaskBody(int inputAssetId, int outputAssetId) { + "JobOutputAsset(" + outputAssetId + ")"; } - private String getMediaProcessorIdByName(String processorName, String version) throws ServiceException { + private String getMediaProcessorIdByName(String processorName) throws ServiceException { EntityListOperation operation = MediaProcessor.list(); - operation.getQueryParameters().putSingle("$filter", - "(Name eq '" + processorName + "') and (Version eq '" + version + "')"); + operation.getQueryParameters().putSingle("$filter", "(Name eq '" + processorName + "')"); MediaProcessorInfo processor = service.list(operation).get(0); return processor.getId(); } diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/serviceBus/ServiceBusIntegrationTest.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/serviceBus/ServiceBusIntegrationTest.java index 971df258c02c..391a080279ae 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/serviceBus/ServiceBusIntegrationTest.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/serviceBus/ServiceBusIntegrationTest.java @@ -486,6 +486,7 @@ public void receiveUpdatedSubscriptionForwardToTopicMessageSuccess() throws Exce new SubscriptionInfo(sourceSubscriptionName)).getValue(); service.updateSubscription(sourceTopicName, sourceSubscriptionInfo.setForwardTo(destinationTopicInfo.getUri().toString())); + Thread.sleep(1000); // Act service.sendTopicMessage(sourceTopicName, new BrokeredMessage("Hello source queue!")); diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/serviceBus/implementation/ServiceBusConnectionSettingsTest.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/serviceBus/implementation/ServiceBusConnectionSettingsTest.java index ec64e7d76eff..263213071b87 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/serviceBus/implementation/ServiceBusConnectionSettingsTest.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/serviceBus/implementation/ServiceBusConnectionSettingsTest.java @@ -1,25 +1,26 @@ /** * Copyright Microsoft Corporation - * + * * Licensed 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. + * 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. */ package com.microsoft.windowsazure.services.serviceBus.implementation; -import com.microsoft.windowsazure.services.core.Configuration; -import com.microsoft.windowsazure.services.serviceBus.ServiceBusConfiguration; +import static junit.framework.Assert.*; + import org.junit.Test; -import static junit.framework.Assert.*; +import com.microsoft.windowsazure.services.core.Configuration; +import com.microsoft.windowsazure.services.serviceBus.ServiceBusConfiguration; public class ServiceBusConnectionSettingsTest { @@ -31,7 +32,8 @@ public void settingsAreParsedFromConnectionString() throws Exception { String connectionString = getConnectionString(ns, issuer, secret); - ServiceBusConnectionSettings settings = new ServiceBusConnectionSettings(connectionString, null, null, null, null); + ServiceBusConnectionSettings settings = new ServiceBusConnectionSettings(connectionString, null, null, null, + null); assertEquals(String.format("https://%1$s.servicebus.windows.net/", ns), settings.getUri()); assertEquals(String.format("https://%1$s-sb.accesscontrol.windows.net/WRAPv0.9", ns), settings.getWrapUri()); @@ -41,15 +43,16 @@ public void settingsAreParsedFromConnectionString() throws Exception { private String getConnectionString(String ns, String issuer, String secret) { return String.format( - "Endpoint=sb://%1$s.servicebus.windows.net/;SharedSecretIssuer=%2$s;SharedSecretValue=%3$s", - ns, issuer, secret); + "Endpoint=sb://%1$s.servicebus.windows.net/;SharedSecretIssuer=%2$s;SharedSecretValue=%3$s", ns, + issuer, secret); } private String getConnectionString(String ns, String stsEndpoint, String issuer, String secret) { - return String.format( - "Endpoint=sb://%1$s.servicebus.windows.net/;StsEndpoint=https://%1$s%4$s;SharedSecretIssuer=%2$s;SharedSecretValue=%3$s", - ns, issuer, secret, stsEndpoint); + return String + .format("Endpoint=sb://%1$s.servicebus.windows.net/;StsEndpoint=https://%1$s%4$s;SharedSecretIssuer=%2$s;SharedSecretValue=%3$s", + ns, issuer, secret, stsEndpoint); } + @Test public void settingsAreUsedFromConnectionStringInConfig() throws Exception { Configuration config = Configuration.load(); @@ -68,8 +71,8 @@ public void settingsAreUsedFromConnectionStringInConfig() throws Exception { public void settingsAreUsedFromIndividualSettingsInConfiguration() throws Exception { Configuration config = Configuration.load(); - ServiceBusConfiguration.configureWithWrapAuthentication(config, - "myNamespace", "owner", "secret", ".servicebus.windows.net/", "-sb.accesscontrol.windows.net/WRAPv0.9"); + ServiceBusConfiguration.configureWithWrapAuthentication(config, "myNamespace", "owner", "secret", + ".servicebus.windows.net/", "-sb.accesscontrol.windows.net/WRAPv0.9"); ServiceBusConnectionSettings settings = config.create(ServiceBusConnectionSettings.class); @@ -83,9 +86,8 @@ public void settingsAreUsedFromIndividualSettingsInConfiguration() throws Except public void settingsPreferConnectionStringIfBothPresentInConfiguration() throws Exception { Configuration config = Configuration.load(); - ServiceBusConfiguration.configureWithWrapAuthentication(config, - "myIndividualNamespace", "individualowner", "individualsecret", - ".servicebus.windows.net/", "-sb.accesscontrol.windows.net/WRAPv0.9"); + ServiceBusConfiguration.configureWithWrapAuthentication(config, "myIndividualNamespace", "individualowner", + "individualsecret", ".servicebus.windows.net/", "-sb.accesscontrol.windows.net/WRAPv0.9"); ServiceBusConfiguration.configureWithConnectionString(null, config, getConnectionString("myNamespaceCS", "ownerCS", "secretCS")); @@ -100,12 +102,11 @@ public void settingsPreferConnectionStringIfBothPresentInConfiguration() throws @Test public void canSetStSEndPointInConnectionString() throws Exception { - ServiceBusConnectionSettings settings = new ServiceBusConnectionSettings( - getConnectionString("myNs", "-some.accesscontrol.net", "owner", "secret"), - null, null, null, null); + ServiceBusConnectionSettings settings = new ServiceBusConnectionSettings(getConnectionString("myNs", + "-some.accesscontrol.net", "owner", "secret"), null, null, null, null); assertEquals("https://myNs.servicebus.windows.net/", settings.getUri()); - assertEquals("https://myNs-some.accesscontrol.net", settings.getWrapUri()); + assertEquals("https://myNs-some.accesscontrol.net/WRAPv0.9", settings.getWrapUri()); assertEquals("owner", settings.getWrapName()); assertEquals("secret", settings.getWrapPassword()); } diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/client/TableClientTests.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/client/TableClientTests.java index 3f9bf6fa9a75..dda98602e798 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/client/TableClientTests.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/client/TableClientTests.java @@ -33,6 +33,7 @@ import org.junit.Test; +import com.microsoft.windowsazure.services.core.storage.AuthenticationScheme; import com.microsoft.windowsazure.services.core.storage.ResultSegment; import com.microsoft.windowsazure.services.core.storage.StorageCredentialsSharedAccessSignature; import com.microsoft.windowsazure.services.core.storage.StorageException; @@ -641,6 +642,30 @@ public void testTableSASFromPermission() throws StorageException, URISyntaxExcep } } + @Test + public void tableCreateAndAttemptCreateOnceExistsSharedKeyLite() throws StorageException, URISyntaxException { + tClient.setAuthenticationScheme(AuthenticationScheme.SHAREDKEYLITE); + String tableName = generateRandomTableName(); + CloudTable table = tClient.getTableReference(tableName); + try { + table.create(); + Assert.assertTrue(table.exists()); + + // Should fail as it already exists + try { + table.create(); + fail(); + } + catch (StorageException ex) { + Assert.assertEquals(ex.getErrorCode(), "TableAlreadyExists"); + } + } + finally { + // cleanup + table.deleteIfExists(); + } + } + private CloudTableClient getTableForSas(CloudTable table, SharedAccessTablePolicy policy, String accessIdentifier, String startPk, String startRk, String endPk, String endRk) throws InvalidKeyException, StorageException { String sasString = table diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/client/TableTestBase.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/client/TableTestBase.java index 80c7ce30738a..32f9a19837e6 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/client/TableTestBase.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/client/TableTestBase.java @@ -26,6 +26,7 @@ import org.junit.BeforeClass; import com.microsoft.windowsazure.services.blob.client.CloudBlobClient; +import com.microsoft.windowsazure.services.core.storage.AuthenticationScheme; import com.microsoft.windowsazure.services.core.storage.CloudStorageAccount; import com.microsoft.windowsazure.services.core.storage.StorageException; import com.microsoft.windowsazure.services.queue.client.CloudQueueClient; @@ -35,7 +36,7 @@ */ public class TableTestBase { public static boolean USE_DEV_FABRIC = false; - public static final String CLOUD_ACCOUNT_HTTP = "DefaultEndpointsProtocol=https;AccountName=[ACCOUNT NAME];AccountKey=[ACCOUNT KEY]"; + public static final String CLOUD_ACCOUNT_HTTP = "DefaultEndpointsProtocol=http;AccountName=[ACCOUNT NAME];AccountKey=[ACCOUNT KEY]"; public static final String CLOUD_ACCOUNT_HTTPS = "DefaultEndpointsProtocol=https;AccountName=[ACCOUNT NAME];AccountKey=[ACCOUNT KEY]"; public static class class1 extends TableServiceEntity { @@ -176,7 +177,7 @@ public void assertEquality(ComplexEntity other) { Assert.assertEquals(this.getPartitionKey(), other.getPartitionKey()); Assert.assertEquals(this.getRowKey(), other.getRowKey()); - assertDateApproxEquals(this.getDateTime(), other.getDateTime(), 100); + Assert.assertEquals(this.getDateTime().toString(), other.getDateTime().toString()); Assert.assertEquals(this.getGuid(), other.getGuid()); Assert.assertEquals(this.getString(), other.getString()); @@ -595,6 +596,7 @@ public static void setup() throws URISyntaxException, StorageException, InvalidK tClient = httpAcc.createCloudTableClient(); qClient = httpAcc.createCloudQueueClient(); testSuiteTableName = generateRandomTableName(); + tClient.setAuthenticationScheme(AuthenticationScheme.SHAREDKEYFULL); CloudTable table = tClient.getTableReference(testSuiteTableName); table.create(); }