Skip to content
This repository was archived by the owner on Jul 19, 2024. It is now read-only.

Commit c07aeb2

Browse files
authored
Merge pull request #484 from Azure/legacy-dev
Legacy dev
2 parents 4af82f0 + 524c1d2 commit c07aeb2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+4975
-430
lines changed

ChangeLog.txt

+11
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
2019.08.05 Version 8.4.0
2+
* Support for 2019-02-02 REST version. Please see our REST API documentation and blogs for information about the related added features.
3+
* Added support for setting rehydrate priority for SetBlobTier and CopyBlob APIs.
4+
* Added support for PutRangeFromURL API to writes bytes from one Azure File endpoint into the specified range of another Azure File endpoint.
5+
* Added setDirectoryProperties, createPermission, and getPermission APIs to the File package.
6+
* Added required headers for creatFile, createDirectory, setFileProperties, getFileProperties, getDirectoryProperties, getFile APIs.
7+
* Updated getFileProperties, getDirectoryProperties, and getFile calls to update SMB properties.
8+
* Added support for setting access tier for PutBlob/PutBlockList and CopyBlob APIs.
9+
* Added support for batching blob operations. Currently the only batchable apis are deleteBlob and setBlobTier.
10+
111
2019.04.23 Version 8.3.0
212
* Fixed a bug in the range download to InputStream that would throw an exception if the source blob was empty.
313
* Added support for List/Close File Handles APIs.
@@ -9,6 +19,7 @@
919
* Fixed a bug in which putBlockFromURI accessConditions were indicated as being on the destination when in actuality they only apply to the source.
1020
* Added a method to get share stats in bytes.
1121
* Support for snapshot-level shared access signature tokens on blobs.
22+
* Support for customer-provided keys with server-side encryption.
1223

1324
2019.03.01 Version 8.1.0
1425
* Added support for the deep sync copy blob api.

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ To get the binaries of this library as distributed by Microsoft, ready for use w
3939
<dependency>
4040
<groupId>com.microsoft.azure</groupId>
4141
<artifactId>azure-storage</artifactId>
42-
<version>8.3.0</version>
42+
<version>8.4.0</version>
4343
</dependency>
4444
```
4545

microsoft-azure-storage-samples/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
<dependency>
2727
<groupId>com.microsoft.azure</groupId>
2828
<artifactId>azure-storage</artifactId>
29-
<version>8.3.0</version>
29+
<version>8.4.0</version>
3030
</dependency>
3131
<dependency>
3232
<groupId>com.microsoft.azure</groupId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package com.microsoft.azure.storage.blob.gettingstarted;
2+
3+
import com.microsoft.azure.storage.BatchException;
4+
import com.microsoft.azure.storage.CloudStorageAccount;
5+
import com.microsoft.azure.storage.OperationContext;
6+
import com.microsoft.azure.storage.StorageException;
7+
import com.microsoft.azure.storage.blob.*;
8+
import com.microsoft.azure.storage.util.Utility;
9+
10+
import java.net.InetSocketAddress;
11+
import java.net.Proxy;
12+
import java.net.URISyntaxException;
13+
import java.security.InvalidKeyException;
14+
import java.util.ArrayList;
15+
import java.util.List;
16+
import java.util.Map;
17+
import java.util.UUID;
18+
19+
public class BlobBatch {
20+
private static final String SAMPLE_NAME = "BlobBatch";
21+
22+
public static void main(String[] args) throws URISyntaxException, InvalidKeyException, StorageException {
23+
Utility.printSampleStartInfo(SAMPLE_NAME);
24+
25+
// Setup the cloud storage account.
26+
CloudStorageAccount account = CloudStorageAccount.parse(Utility.storageConnectionString);
27+
28+
// Create a blob service client
29+
CloudBlobClient blobClient = account.createCloudBlobClient();
30+
31+
// Get a reference to a container
32+
// The container name must be lower case
33+
// Append a random UUID to the end of the container name so that
34+
// this sample can be run more than once in quick succession.
35+
CloudBlobContainer container = blobClient.getContainerReference("blobbasicscontainer"
36+
+ UUID.randomUUID().toString().replace("-", ""));
37+
38+
try {
39+
// create the container
40+
container.create();
41+
42+
// add some blobs
43+
final int NUM_BLOBS = 3;
44+
List<CloudBlob> blobs = new ArrayList<>();
45+
for (int i = 0; i < NUM_BLOBS; i++) {
46+
// blobs have more relaxed naming constraints than containers
47+
CloudBlockBlob blob = container.getBlockBlobReference("blobtobatchdelete" + UUID.randomUUID());
48+
blob.uploadText("Sample data.");
49+
blobs.add(blob);
50+
51+
System.out.println(String.format("Created blob %s", blob.getName()));
52+
}
53+
54+
// create a blob object on client, but don't upload it to the service, to cause a bad request in the batch
55+
// comment this line out to get a success state
56+
blobs.add(container.getBlockBlobReference("blobtobatchdelete" + UUID.randomUUID()));
57+
58+
// assemble batch request, in this case: delete
59+
BlobDeleteBatchOperation batch = new BlobDeleteBatchOperation();
60+
for (CloudBlob blob : blobs) {
61+
batch.addSubOperation(blob);
62+
63+
System.out.println(String.format("Added delete request for blob %s", blob.getName()));
64+
}
65+
66+
try {
67+
// send the batch request
68+
Map<CloudBlob, Void> batchResponse = container.getServiceClient().executeBatch(batch);
69+
70+
// for each blob, view the result
71+
// Delete returns void, so its batch response maps to Void, but other requests may return data to process
72+
for (CloudBlob blob : blobs) {
73+
Void result = batchResponse.get(blob);
74+
75+
System.out.println(String.format("Result from deleting blob %s: %s", blob.getName(), result));
76+
}
77+
}
78+
79+
// when one or more requests in the batch fail
80+
catch (BatchException e) {
81+
/*
82+
* Subclasses of java.lang.Throwable cannot be generic, so the collections of successful and
83+
* unsuccessful responses cannot be typed correctly on the class. However, the types will directly
84+
* relate to the batched operation. Meaning: for a BlobBatchOperation<P, R>,
85+
* e.getSuccessfulResponses() can be safely cast to Map<P, R>, and e.getExceptions() can be
86+
* safely cast to Map<P, StorageException>. BlobDeleteBatchOperation extends
87+
* BlobBatchOperation<CloudBlob, Void> so we cast as follows.
88+
*/
89+
Map<CloudBlob, Void> successes = (Map<CloudBlob, Void>) e.getSuccessfulResponses();
90+
Map<CloudBlob, StorageException> failures = (Map<CloudBlob, StorageException>) e.getExceptions();
91+
92+
// handle successes
93+
for (Map.Entry<CloudBlob, Void> entry : successes.entrySet()) {
94+
System.out.println(String.format("Result from deleting blob %s: %s",
95+
entry.getKey().getName(), entry.getValue()));
96+
}
97+
98+
// handle failures
99+
for (Map.Entry<CloudBlob, StorageException> entry : failures.entrySet()) {
100+
System.out.println(String.format("Failed to delete blob %s. Exception: %s",
101+
entry.getKey().getName(), entry.getValue().getErrorCode()));
102+
}
103+
}
104+
}
105+
catch (Throwable t) {
106+
Utility.printException(t);
107+
}
108+
finally {
109+
// clean up sample
110+
container.deleteIfExists();
111+
}
112+
113+
Utility.printSampleCompleteInfo(SAMPLE_NAME);
114+
}
115+
}

microsoft-azure-storage-samples/src/com/microsoft/azure/storage/logging/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
<dependency>
2727
<groupId>com.microsoft.azure</groupId>
2828
<artifactId>azure-storage</artifactId>
29-
<version>8.3.0</version>
29+
<version>8.4.0</version>
3030
</dependency>
3131
<dependency>
3232
<groupId>com.microsoft.azure</groupId>

microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/Utility.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ public final class Utility {
3333
*
3434
* Stores the storage connection string.
3535
*/
36-
public static final String storageConnectionString = "DefaultEndpointsProtocol=https;"
37-
+ "AccountName=[MY_ACCOUNT_NAME];"
38-
+ "AccountKey=[MY_ACCOUNT_KEY]";
36+
public static final String storageConnectionString = "DefaultEndpointsProtocol=http;"
37+
+ "AccountName=jamesschreppler;"
38+
+ "AccountKey=5POtFgqT5vsDYmIUOSsEpoXnbd3iw+mpBiXB4jiMvdqOcprfPX3gZXGU/sGZviLbIIFDMq+5c00w7O2eG0UT6Q==";
3939

4040
/**
4141
* You only need to modify the following values if you want to run the

microsoft-azure-storage-test/res/TestConfigurations.xml

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
<ActiveDirectoryApplicationId>[APPLICATION_ID]</ActiveDirectoryApplicationId>
3131
<ActiveDirectoryApplicationSecret>[APPLICATION_SECRET]</ActiveDirectoryApplicationSecret>
3232
<ActiveDirectoryTenantId>[TENANT_ID]</ActiveDirectoryTenantId>
33+
<ActiveDirectoryAuthEndpoint>[ENDPOINT]</ActiveDirectoryAuthEndpoint>
3334
</TenantConfiguration>
3435
</TenantConfigurations>
3536
</TestConfigurations>

microsoft-azure-storage-test/src/com/microsoft/azure/storage/OAuthTests.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public void testOAuthTokenWithBlobClient() throws StorageException, URISyntaxExc
4040
blobClient.downloadServiceProperties();
4141
fail();
4242
} catch (StorageException e) {
43-
assertEquals("AuthenticationFailed", e.getErrorCode());
43+
assertEquals("InvalidAuthenticationInfo", e.getErrorCode());
4444
}
4545

4646
// change the token again to see it succeed

microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/BlobTestHelper.java

+25
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,13 @@
2121
import com.microsoft.azure.storage.TestHelper;
2222
import com.microsoft.azure.storage.ServiceProperties;
2323

24+
import javax.crypto.KeyGenerator;
25+
import javax.crypto.SecretKey;
2426
import java.io.ByteArrayInputStream;
2527
import java.io.IOException;
2628
import java.net.URI;
2729
import java.net.URISyntaxException;
30+
import java.security.NoSuchAlgorithmException;
2831
import java.util.ArrayList;
2932
import java.util.HashMap;
3033
import java.util.List;
@@ -479,4 +482,26 @@ public static HashMap<String, String> generateSampleMetadata(final int entries)
479482

480483
return result;
481484
}
485+
486+
public static BlobCustomerProvidedKey generateCPK() {
487+
KeyGenerator keyGen;
488+
try {
489+
keyGen = KeyGenerator.getInstance("AES");
490+
}
491+
catch (NoSuchAlgorithmException e) {
492+
throw new RuntimeException(e);
493+
}
494+
495+
keyGen.init(256);
496+
SecretKey key = keyGen.generateKey();
497+
498+
BlobCustomerProvidedKey result;
499+
try {
500+
result = new BlobCustomerProvidedKey(key.getEncoded());
501+
} catch (NoSuchAlgorithmException e) {
502+
throw new RuntimeException(e);
503+
}
504+
505+
return result;
506+
}
482507
}

microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudAppendBlobTests.java

+121
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@
3333
import java.io.FileOutputStream;
3434
import java.io.IOException;
3535
import java.net.HttpURLConnection;
36+
import java.net.URI;
3637
import java.net.URISyntaxException;
38+
import java.net.URL;
39+
import java.security.InvalidKeyException;
3740
import java.security.MessageDigest;
3841
import java.security.NoSuchAlgorithmException;
3942
import java.util.Calendar;
@@ -1404,4 +1407,122 @@ public void testAppendBlobAppendFromStreamWithLength() throws StorageException,
14041407
blob.downloadAttributes();
14051408
assertEquals(15 * 1024 * 1024, blob.getProperties().getLength());
14061409
}
1410+
1411+
@Test
1412+
public void testAppendBlockCPK() throws URISyntaxException, StorageException, IOException {
1413+
1414+
final int BLOB_SIZE = 128 * Constants.KB;
1415+
1416+
// load CPK into options
1417+
BlobRequestOptions options = new BlobRequestOptions();
1418+
options.setCustomerProvidedKey(BlobTestHelper.generateCPK());
1419+
1420+
// get blob reference
1421+
CloudAppendBlob blob = this.container.getAppendBlobReference(
1422+
BlobTestHelper.generateRandomBlobNameWithPrefix("testAppendBlob"));
1423+
// force https
1424+
blob = new CloudAppendBlob(
1425+
new URL(blob.getUri().toString().replace("http", "https")).toURI(),
1426+
container.getServiceClient().getCredentials());
1427+
1428+
OperationContext operationContext = new OperationContext();
1429+
blob.createOrReplace(null, options, operationContext);
1430+
1431+
// validate response
1432+
assertTrue(operationContext.getRequestResults().get(0).isRequestServiceEncrypted());
1433+
assertEquals(
1434+
options.getCustomerProvidedKey().getKeySHA256(),
1435+
operationContext.getRequestResults().get(0).getEncryptionKeySHA256());
1436+
1437+
// generate random data
1438+
byte[] buffer = BlobTestHelper.getRandomBuffer(BLOB_SIZE);
1439+
ByteArrayInputStream stream = new ByteArrayInputStream(buffer);
1440+
1441+
// append blocks with CPK
1442+
operationContext = new OperationContext();
1443+
blob.appendBlock(stream, BLOB_SIZE, null, options, operationContext);
1444+
stream.close();
1445+
1446+
// validate response
1447+
assertTrue(operationContext.getRequestResults().get(0).isRequestServiceEncrypted());
1448+
assertEquals(
1449+
options.getCustomerProvidedKey().getKeySHA256(),
1450+
operationContext.getRequestResults().get(0).getEncryptionKeySHA256());
1451+
}
1452+
1453+
@Test
1454+
public void testAppendBlockFromURLCPK() throws URISyntaxException, StorageException, IOException, InvalidKeyException {
1455+
// CPK on source blobs for append block from URL is not yet supported
1456+
// TODO uncomment the marked comments AND the work in the actual web request factories when the feature is ready
1457+
1458+
////// SETUP
1459+
1460+
final int BLOB_SIZE = 128 * Constants.KB;
1461+
1462+
// make key for this blob
1463+
// NOT YET SUPPORTED // BlobCustomerProvidedKey srcBlobKey = BlobTestHelper.generateCPK();
1464+
1465+
// load CPK into srcOptions
1466+
BlobRequestOptions srcOptions = new BlobRequestOptions();
1467+
// NOT YET SUPPORTED // srcOptions.setCustomerProvidedKey(srcBlobKey);
1468+
1469+
// get blob reference
1470+
CloudBlockBlob temp = this.container.getBlockBlobReference(
1471+
BlobTestHelper.generateRandomBlobNameWithPrefix("testAppendBlob"));
1472+
// force https
1473+
temp = new CloudBlockBlob(
1474+
new URL(temp.getUri().toString().replace("http", "https")).toURI(),
1475+
container.getServiceClient().getCredentials());
1476+
1477+
// generate random data
1478+
byte[] buffer = BlobTestHelper.getRandomBuffer(BLOB_SIZE);
1479+
ByteArrayInputStream stream = new ByteArrayInputStream(buffer);
1480+
1481+
// upload blob with CPK
1482+
temp.upload(stream, buffer.length, null, srcOptions, null);
1483+
1484+
// save blob URI with SAS authentication (important for later when this is a source URL)
1485+
SharedAccessBlobPolicy policy = new SharedAccessBlobPolicy();
1486+
policy.setPermissions(EnumSet.of(SharedAccessBlobPermissions.READ, SharedAccessBlobPermissions.WRITE));
1487+
Calendar cal = Calendar.getInstance();
1488+
cal.add(Calendar.MINUTE, 10);
1489+
policy.setSharedAccessExpiryTime(cal.getTime());
1490+
String sas = temp.generateSharedAccessSignature(policy, null);
1491+
URI srcBlobURI = new URI(temp.getUri().toString() + "?" + sas);
1492+
1493+
// get blob reference
1494+
CloudAppendBlob blob = this.container.getAppendBlobReference(
1495+
BlobTestHelper.generateRandomBlobNameWithPrefix("testAppendBlob"));
1496+
// force https
1497+
blob = new CloudAppendBlob(
1498+
new URL(blob.getUri().toString().replace("http", "https")).toURI(),
1499+
container.getServiceClient().getCredentials());
1500+
1501+
////// ACT
1502+
1503+
// load CPK into srcOptions
1504+
BlobCustomerProvidedKey blobKey = BlobTestHelper.generateCPK();
1505+
BlobRequestOptions options = new BlobRequestOptions();
1506+
options.setCustomerProvidedKey(blobKey);
1507+
1508+
// create append blob
1509+
OperationContext operationContext = new OperationContext();
1510+
blob.createOrReplace(null, options, operationContext);
1511+
1512+
// validate response
1513+
assertTrue(operationContext.getRequestResults().get(0).isRequestServiceEncrypted());
1514+
assertEquals(
1515+
options.getCustomerProvidedKey().getKeySHA256(),
1516+
operationContext.getRequestResults().get(0).getEncryptionKeySHA256());
1517+
1518+
// append blocks from URI
1519+
operationContext = new OperationContext();
1520+
blob.appendBlockFromURI(srcBlobURI, null, null, null, null, null, options, operationContext);
1521+
1522+
// validate response
1523+
assertTrue(operationContext.getRequestResults().get(0).isRequestServiceEncrypted());
1524+
assertEquals(
1525+
options.getCustomerProvidedKey().getKeySHA256(),
1526+
operationContext.getRequestResults().get(0).getEncryptionKeySHA256());
1527+
}
14071528
}

0 commit comments

Comments
 (0)