From fe2ae4a2c8851f780642e1494377bee1f6abc249 Mon Sep 17 00:00:00 2001 From: Emily Gerner Date: Fri, 9 Oct 2015 10:24:08 -0700 Subject: [PATCH] Encryption samples --- microsoft-azure-storage-samples/pom.xml | 7 +- .../gettingstarted/BlobGettingStarted.java | 120 ++++++++++++ .../KeyVaultGettingStarted.java | 182 +++++++++++++++++ .../KeyRotationGettingStarted.java | 183 ++++++++++++++++++ .../gettingstarted/QueueGettingStarted.java | 112 +++++++++++ .../attributes/EncryptedEntity.java | 63 ++++++ .../TableGettingStartedAttributes.java | 92 +++++++++ .../resolver/TableGettingStartedResolver.java | 115 +++++++++++ .../azure/storage/util/KVCredentials.java | 115 +++++++++++ .../azure/storage/util/KeyVaultUtility.java | 182 +++++++++++++++++ .../azure/storage/util/LocalResolver.java | 54 ++++++ .../microsoft/azure/storage/util/Utility.java | 96 +++++---- 12 files changed, 1285 insertions(+), 36 deletions(-) create mode 100644 microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/blob/gettingstarted/BlobGettingStarted.java create mode 100644 microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/keyvault/gettingstarted/KeyVaultGettingStarted.java create mode 100644 microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/keyvault/keyrotation/gettingstarted/KeyRotationGettingStarted.java create mode 100644 microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/queue/gettingstarted/QueueGettingStarted.java create mode 100644 microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/table/gettingstarted/attributes/EncryptedEntity.java create mode 100644 microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/table/gettingstarted/attributes/TableGettingStartedAttributes.java create mode 100644 microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/table/gettingstarted/resolver/TableGettingStartedResolver.java create mode 100644 microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/KVCredentials.java create mode 100644 microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/KeyVaultUtility.java create mode 100644 microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/LocalResolver.java diff --git a/microsoft-azure-storage-samples/pom.xml b/microsoft-azure-storage-samples/pom.xml index 8306b5cc2206..60414f8b1adb 100644 --- a/microsoft-azure-storage-samples/pom.xml +++ b/microsoft-azure-storage-samples/pom.xml @@ -26,7 +26,12 @@ com.microsoft.azure azure-storage - 4.0.0 + 4.0-alpha-1 + + + com.microsoft.azure + azure-keyvault-extensions + 0.8.0 \ No newline at end of file diff --git a/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/blob/gettingstarted/BlobGettingStarted.java b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/blob/gettingstarted/BlobGettingStarted.java new file mode 100644 index 000000000000..51f17a7ac400 --- /dev/null +++ b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/blob/gettingstarted/BlobGettingStarted.java @@ -0,0 +1,120 @@ +/** + * 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.azure.storage.encryption.blob.gettingstarted; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.URISyntaxException; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.util.Random; +import java.util.UUID; + +import com.microsoft.azure.keyvault.extensions.RsaKey; +import com.microsoft.azure.storage.CloudStorageAccount; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.blob.BlobEncryptionPolicy; +import com.microsoft.azure.storage.blob.BlobRequestOptions; +import com.microsoft.azure.storage.blob.CloudBlobClient; +import com.microsoft.azure.storage.blob.CloudBlobContainer; +import com.microsoft.azure.storage.blob.CloudBlockBlob; +import com.microsoft.azure.storage.util.LocalResolver; +import com.microsoft.azure.storage.util.Utility; + +/** + * Demonstrates how to use encryption with the Azure Blob service. + */ +public class BlobGettingStarted { + + public static void main(String[] args) throws InvalidKeyException, + URISyntaxException, StorageException, NoSuchAlgorithmException, + IOException { + Utility.printSampleStartInfo("BlobBasicsEncryption"); + + // Retrieve storage account information from connection string + // How to create a storage connection string - + // https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/ + CloudStorageAccount account = CloudStorageAccount + .parse(Utility.storageConnectionString); + CloudBlobClient blobClient = account.createCloudBlobClient(); + + // Get a reference to a container + // The container name must be lower case + // Append a random UUID to the end of the container name so that + // this sample can be run more than once in quick succession. + CloudBlobContainer container = blobClient + .getContainerReference("blobencryptioncontainer" + + UUID.randomUUID().toString().replace("-", "")); + + try { + // Create the container if it does not exist + container.createIfNotExists(); + + int size = 5 * 1024 * 1024; + byte[] buffer = new byte[size]; + + Random rand = new Random(); + rand.nextBytes(buffer); + + CloudBlockBlob blob = container.getBlockBlobReference("blockBlob"); + + // Create the IKey used for encryption. + final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); + keyGen.initialize(1024); + final KeyPair wrapKey = keyGen.generateKeyPair(); + RsaKey key = new RsaKey("rsaKey1", wrapKey); + + // Create the encryption policy to be used for upload. + BlobEncryptionPolicy uploadPolicy = new BlobEncryptionPolicy(key, + null); + + // Set the encryption policy on the request options. + BlobRequestOptions uploadOptions = new BlobRequestOptions(); + uploadOptions.setEncryptionPolicy(uploadPolicy); + + System.out.println("Uploading the encrypted blob."); + + // Upload the encrypted contents to the blob. + ByteArrayInputStream inputStream = new ByteArrayInputStream(buffer); + blob.upload(inputStream, size, null, uploadOptions, null); + + // Download the encrypted blob. + // For downloads, a resolver can be set up that will help pick the + // key based on the key id. + // Create the encryption policy to be used for download. + LocalResolver resolver = new LocalResolver(); + resolver.add(key); + BlobEncryptionPolicy downloadPolicy = new BlobEncryptionPolicy( + null, resolver); + + // Set the decryption policy on the request options. + BlobRequestOptions downloadOptions = new BlobRequestOptions(); + downloadOptions.setEncryptionPolicy(downloadPolicy); + + System.out.println("Downloading the encrypted blob."); + + // Download and decrypt the encrypted contents from the blob. + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + blob.download(outputStream, null, downloadOptions, null); + } finally { + // Delete the container + container.deleteIfExists(); + Utility.printSampleCompleteInfo("BlobBasicsEncryption"); + } + } +} diff --git a/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/keyvault/gettingstarted/KeyVaultGettingStarted.java b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/keyvault/gettingstarted/KeyVaultGettingStarted.java new file mode 100644 index 000000000000..3f6b14166873 --- /dev/null +++ b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/keyvault/gettingstarted/KeyVaultGettingStarted.java @@ -0,0 +1,182 @@ +/** + * 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.azure.storage.encryption.keyvault.gettingstarted; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.URISyntaxException; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.util.Random; +import java.util.UUID; +import java.util.concurrent.ExecutionException; + +import com.microsoft.azure.keyvault.core.IKey; +import com.microsoft.azure.keyvault.extensions.AggregateKeyResolver; +import com.microsoft.azure.keyvault.extensions.CachingKeyResolver; +import com.microsoft.azure.keyvault.extensions.KeyVaultKeyResolver; +import com.microsoft.azure.keyvault.extensions.RsaKey; +import com.microsoft.azure.storage.CloudStorageAccount; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.blob.BlobEncryptionPolicy; +import com.microsoft.azure.storage.blob.BlobRequestOptions; +import com.microsoft.azure.storage.blob.CloudBlobClient; +import com.microsoft.azure.storage.blob.CloudBlobContainer; +import com.microsoft.azure.storage.blob.CloudBlockBlob; +import com.microsoft.azure.storage.util.KeyVaultUtility; +import com.microsoft.azure.storage.util.LocalResolver; +import com.microsoft.azure.storage.util.Utility; + +public class KeyVaultGettingStarted { + + public static void main(String[] args) throws StorageException, + NoSuchAlgorithmException, InterruptedException, ExecutionException, + URISyntaxException, InvalidKeyException, IOException { + Utility.printSampleStartInfo("KeyVaultGettingStarted"); + + // Get the key ID from App.config if it exists. + String keyID = Utility.keyVaultKeyID; + + // If no key ID was specified, we will create a new secret in Key Vault. + // To create a new secret, this client needs full permission to Key + // Vault secrets. + // Once the secret is created, its ID can be added to App.config. Once + // this is done, + // this client only needs read access to secrets. + if (keyID == null || keyID.isEmpty()) { + keyID = KeyVaultUtility.createSecret("KVGettingStartedSecret"); + } + + // Retrieve storage account information from connection string + // How to create a storage connection string - + // https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/ + CloudStorageAccount storageAccount = CloudStorageAccount + .parse(Utility.storageConnectionString); + + CloudBlobClient client = storageAccount.createCloudBlobClient(); + CloudBlobContainer container = client + .getContainerReference("blobencryptioncontainer" + + UUID.randomUUID().toString().replace("-", "")); + + // Construct a resolver capable of looking up keys and secrets stored in + // Key Vault. + + KeyVaultKeyResolver cloudResolver = new KeyVaultKeyResolver( + KeyVaultUtility.GetKeyVaultClient()); + + // To demonstrate how multiple different types of key can be used, we + // also create a local key and resolver. + // This key is temporary and won't be persisted. + final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); + keyGen.initialize(1024); + final KeyPair wrapKey = keyGen.generateKeyPair(); + + RsaKey rsaKey = new RsaKey("rsaKey1", wrapKey); + LocalResolver resolver = new LocalResolver(); + resolver.add(rsaKey); + + // If there are multiple key sources like Azure Key Vault and local KMS, + // set up an aggregate resolver as follows. + // This helps users to define a plug-in model for all the different key + // providers they support. + AggregateKeyResolver aggregateResolver = new AggregateKeyResolver(); + aggregateResolver.Add(resolver); + aggregateResolver.Add(cloudResolver); + + // Set up a caching resolver so the secrets can be cached on the client. + // This is the recommended usage + // pattern since the throttling targets for Storage and Key Vault + // services are orders of magnitude + // different. + CachingKeyResolver cachingResolver = new CachingKeyResolver(2, + aggregateResolver); + + // Create a key instance corresponding to the key ID. This will cache + // the secret. + IKey cloudKey = cachingResolver.resolveKeyAsync(keyID).get(); + + try { + container.createIfNotExists(); + int size = 5 * 1024 * 1024; + byte[] buffer = new byte[size]; + + Random rand = new Random(); + rand.nextBytes(buffer); + + // The first blob will use the key stored in Azure Key Vault. + CloudBlockBlob blob = container.getBlockBlobReference("blockblob1"); + + // Create the encryption policy using the secret stored in Azure Key + // Vault to be used for upload. + BlobEncryptionPolicy uploadPolicy = new BlobEncryptionPolicy( + cloudKey, null); + + // Set the encryption policy on the request options. + BlobRequestOptions uploadOptions = new BlobRequestOptions(); + uploadOptions.setEncryptionPolicy(uploadPolicy); + + System.out.println("Uploading the 1st encrypted blob."); + + // Upload the encrypted contents to the blob. + ByteArrayInputStream inputStream = new ByteArrayInputStream(buffer); + blob.upload(inputStream, size, null, uploadOptions, null); + + // Download the encrypted blob. + BlobEncryptionPolicy downloadPolicy = new BlobEncryptionPolicy( + null, cachingResolver); + + // Set the decryption policy on the request options. + BlobRequestOptions downloadOptions = new BlobRequestOptions(); + downloadOptions.setEncryptionPolicy(downloadPolicy); + + System.out.println("Downloading the 1st encrypted blob."); + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + blob.download(outputStream, null, downloadOptions, null); + + // Upload second blob using the local key. + blob = container.getBlockBlobReference("blockblob2"); + + // Create the encryption policy using the local key. + uploadPolicy = new BlobEncryptionPolicy(rsaKey, null); + + // Set the encryption policy on the request options. + uploadOptions = new BlobRequestOptions(); + uploadOptions.setEncryptionPolicy(uploadPolicy); + + System.out.println("Uploading the 2nd encrypted blob."); + + // Upload the encrypted contents to the blob. + inputStream = new ByteArrayInputStream(buffer); + blob.upload(inputStream, size, null, uploadOptions, null); + + // Download the encrypted blob. The same policy and options created + // before can be used because the aggregate resolver contains both + // resolvers and will pick the right one based on the key ID stored + // in blob metadata on the service. + System.out.println("Downloading the 2nd encrypted blob."); + + // Download and decrypt the encrypted contents from the blob. + outputStream = new ByteArrayOutputStream(); + blob.download(outputStream, null, downloadOptions, null); + } finally { + container.deleteIfExists(); + Utility.printSampleCompleteInfo("KeyVaultGettingStarted"); + } + } +} diff --git a/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/keyvault/keyrotation/gettingstarted/KeyRotationGettingStarted.java b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/keyvault/keyrotation/gettingstarted/KeyRotationGettingStarted.java new file mode 100644 index 000000000000..ba2fec7db216 --- /dev/null +++ b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/keyvault/keyrotation/gettingstarted/KeyRotationGettingStarted.java @@ -0,0 +1,183 @@ +/** + * 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.azure.storage.encryption.keyvault.keyrotation.gettingstarted; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.URISyntaxException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Random; +import java.util.UUID; +import java.util.concurrent.ExecutionException; + +import com.microsoft.azure.keyvault.core.IKey; +import com.microsoft.azure.keyvault.extensions.CachingKeyResolver; +import com.microsoft.azure.keyvault.extensions.KeyVaultKeyResolver; +import com.microsoft.azure.storage.CloudStorageAccount; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.blob.BlobEncryptionPolicy; +import com.microsoft.azure.storage.blob.BlobRequestOptions; +import com.microsoft.azure.storage.blob.CloudBlobClient; +import com.microsoft.azure.storage.blob.CloudBlobContainer; +import com.microsoft.azure.storage.blob.CloudBlockBlob; +import com.microsoft.azure.storage.util.KeyVaultUtility; +import com.microsoft.azure.storage.util.Utility; + +public class KeyRotationGettingStarted { + + public static void main(String[] args) throws StorageException, + InterruptedException, ExecutionException, URISyntaxException, + NoSuchAlgorithmException, InvalidKeyException, IOException { + Utility.printSampleStartInfo("KeyRotationGettingStarted"); + + // Create two secrets and obtain their IDs. This is normally a one-time + // setup step. + // Although it is possible to use keys (rather than secrets) stored in + // Key Vault, this prevents caching. + // Therefore it is recommended to use secrets along with a caching + // resolver (see below). + String keyID1 = Utility.keyVaultKeyIDForRotation1; + String keyID2 = Utility.keyVaultKeyIDForRotation2; + + if (keyID1 == null || keyID1.isEmpty()) { + keyID1 = KeyVaultUtility.createSecret("KeyRotationSampleSecret1"); + } + + if (keyID2 == null || keyID2.isEmpty()) { + keyID2 = KeyVaultUtility.createSecret("KeyRotationSampleSecret2"); + } + + // Retrieve storage account information from connection string + // How to create a storage connection string - + // https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/ + CloudStorageAccount storageAccount = CloudStorageAccount + .parse(Utility.storageConnectionString); + CloudBlobClient client = storageAccount.createCloudBlobClient(); + CloudBlobContainer container = client + .getContainerReference("blobencryptioncontainer" + + UUID.randomUUID().toString().replace("-", "")); + + // Construct a resolver capable of looking up keys and secrets stored in + // Key Vault. + KeyVaultKeyResolver cloudResolver = new KeyVaultKeyResolver( + KeyVaultUtility.GetKeyVaultClient()); + + // Set up a caching resolver so the secrets can be cached on the client. + // This is the recommended usage + // pattern since the throttling targets for Storage and Key Vault + // services are orders of magnitude + // different. + CachingKeyResolver cachingResolver = new CachingKeyResolver(2, + cloudResolver); + + // Create key instances corresponding to the key IDs. This will cache + // the secrets. + IKey cloudKey1 = cachingResolver.resolveKeyAsync(keyID1).get(); + IKey cloudKey2 = cachingResolver.resolveKeyAsync(keyID2).get(); + + // We begin with cloudKey1, and a resolver capable of resolving and + // caching Key Vault secrets. + BlobEncryptionPolicy encryptionPolicy = new BlobEncryptionPolicy( + cloudKey1, cachingResolver); + BlobRequestOptions defaultRequestOptions = client + .getDefaultRequestOptions(); + defaultRequestOptions.setEncryptionPolicy(encryptionPolicy); + defaultRequestOptions.setRequireEncryption(true); + + try { + container.createIfNotExists(); + int size = 5 * 1024 * 1024; + byte[] buffer1 = new byte[size]; + byte[] buffer2 = new byte[size]; + + Random rand = new Random(); + rand.nextBytes(buffer1); + rand.nextBytes(buffer2); + + // Upload the first blob using the secret stored in Azure Key Vault. + CloudBlockBlob blob = container.getBlockBlobReference("blockblob1"); + + System.out.println("Uploading Blob 1 using Key 1."); + + // Upload the encrypted contents to the first blob. + ByteArrayInputStream inputStream = new ByteArrayInputStream(buffer1); + blob.upload(inputStream, size); + + System.out.println("Downloading and decrypting Blob 1."); + + // Download and decrypt the encrypted contents from the first blob. + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + blob.download(outputStream); + + // At this point we will rotate our keys so new encrypted content + // will use the + // second key. Note that the same resolver is used, as this resolver + // is capable + // of decrypting blobs encrypted using either key. + System.out.println("Rotating the active encryption key to Key 2."); + + client.getDefaultRequestOptions().setEncryptionPolicy( + new BlobEncryptionPolicy(cloudKey2, cachingResolver)); + + // Upload the second blob using the key stored in Azure Key Vault. + CloudBlockBlob blob2 = container + .getBlockBlobReference("blockblob2"); + + System.out.println("Uploading Blob 2 using Key 2."); + + // Upload the encrypted contents to the second blob. + inputStream = new ByteArrayInputStream(buffer2); + blob2.upload(inputStream, size); + + System.out.println("Downloading and decrypting Blob 2."); + + // Download and decrypt the encrypted contents from the second blob. + outputStream = new ByteArrayOutputStream(); + blob2.download(outputStream); + + // Here we download and re-upload the first blob. This has the + // effect of updating + // the blob to use the new key. + System.out.println("Downloading and decrypting Blob 1."); + outputStream = new ByteArrayOutputStream(); + blob.download(outputStream); + + System.out.println("Re-uploading Blob 1 using Key 2."); + inputStream = new ByteArrayInputStream(outputStream.toByteArray()); + blob.upload(inputStream, size); + + // For the purposes of demonstration, we now override the encryption + // policy to only recognize key 2. + BlobEncryptionPolicy key2OnlyPolicy = new BlobEncryptionPolicy( + cloudKey2, null); + BlobRequestOptions key2OnlyOptions = new BlobRequestOptions(); + key2OnlyOptions.setEncryptionPolicy(key2OnlyPolicy); + + System.out.println("Downloading and decrypting Blob 1."); + + outputStream = new ByteArrayOutputStream(); + blob.download(outputStream, null, key2OnlyOptions, null); + // The first blob can still be decrypted because it is using the + // second key. + } finally { + container.deleteIfExists(); + Utility.printSampleCompleteInfo("KeyRotationGettingStarted"); + } + + } + +} diff --git a/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/queue/gettingstarted/QueueGettingStarted.java b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/queue/gettingstarted/QueueGettingStarted.java new file mode 100644 index 000000000000..98fedfcc6a40 --- /dev/null +++ b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/queue/gettingstarted/QueueGettingStarted.java @@ -0,0 +1,112 @@ +/** + * 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.azure.storage.encryption.queue.gettingstarted; + +import java.net.URISyntaxException; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.util.EnumSet; +import java.util.UUID; + +import com.microsoft.azure.keyvault.extensions.RsaKey; +import com.microsoft.azure.storage.CloudStorageAccount; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.queue.CloudQueue; +import com.microsoft.azure.storage.queue.CloudQueueClient; +import com.microsoft.azure.storage.queue.CloudQueueMessage; +import com.microsoft.azure.storage.queue.MessageUpdateFields; +import com.microsoft.azure.storage.queue.QueueEncryptionPolicy; +import com.microsoft.azure.storage.queue.QueueRequestOptions; +import com.microsoft.azure.storage.util.LocalResolver; +import com.microsoft.azure.storage.util.Utility; + +public class QueueGettingStarted { + + public static void main(String[] args) throws InvalidKeyException, + URISyntaxException, StorageException { + + Utility.printSampleStartInfo("QueueBasicsEncryption"); + + // Retrieve storage account information from connection string + // How to create a storage connection string - + // https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/ + CloudStorageAccount account = CloudStorageAccount + .parse(Utility.storageConnectionString); + CloudQueueClient client = account.createCloudQueueClient(); + CloudQueue queue = client.getQueueReference("encryptionqueue" + + UUID.randomUUID().toString().replace("-", "")); + + try { + queue.createIfNotExists(); + + // Create the IKey used for encryption. + final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); + keyGen.initialize(1024); + final KeyPair wrapKey = keyGen.generateKeyPair(); + + RsaKey key = new RsaKey("rsaKey1", wrapKey); + + // Create the encryption policy to be used for insert and update. + QueueEncryptionPolicy insertPolicy = new QueueEncryptionPolicy(key, + null); + + // Set the encryption policy on the request options. + QueueRequestOptions insertOptions = new QueueRequestOptions(); + insertOptions.setEncryptionPolicy(insertPolicy); + + String messageStr = UUID.randomUUID().toString(); + CloudQueueMessage message = new CloudQueueMessage(messageStr); + + // Add message + System.out.println("Inserting the encrypted message."); + queue.addMessage(message, 0, 0, insertOptions, null); + + // For retrieves, a resolver can be set up that will help pick the + // key based on the key id. + LocalResolver resolver = new LocalResolver(); + resolver.add(key); + + QueueEncryptionPolicy retrPolicy = new QueueEncryptionPolicy(null, + resolver); + QueueRequestOptions retrieveOptions = new QueueRequestOptions(); + retrieveOptions.setEncryptionPolicy(retrPolicy); + + // Retrieve message + System.out.println("Retrieving the encrypted message."); + CloudQueueMessage retrMessage = queue.retrieveMessage(1, + retrieveOptions, null); + + // Update message + System.out.println("Updating the encrypted message."); + String updatedMessage = UUID.randomUUID().toString(); + retrMessage.setMessageContent(updatedMessage); + queue.updateMessage(retrMessage, 0, EnumSet + .of(MessageUpdateFields.CONTENT, + MessageUpdateFields.VISIBILITY), insertOptions, + null); + + // Retrieve updated message + System.out.println("Retrieving the updated encrypted message."); + retrMessage = queue.retrieveMessage(1, retrieveOptions, null); + } catch (Throwable t) { + Utility.printException(t); + } finally { + queue.deleteIfExists(); + Utility.printSampleCompleteInfo("QueueBasicsEncryption"); + } + } + +} diff --git a/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/table/gettingstarted/attributes/EncryptedEntity.java b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/table/gettingstarted/attributes/EncryptedEntity.java new file mode 100644 index 000000000000..ab5b049249c4 --- /dev/null +++ b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/table/gettingstarted/attributes/EncryptedEntity.java @@ -0,0 +1,63 @@ +package com.microsoft.azure.storage.encryption.table.gettingstarted.attributes; + +import com.microsoft.azure.storage.table.Encrypt; +import com.microsoft.azure.storage.table.TableServiceEntity; + +public class EncryptedEntity extends TableServiceEntity { + + private String encryptedProperty1; + private String encryptedProperty2; + private String notEncryptedProperty; + private int notEncryptedIntProperty; + + @Encrypt + public String getEncryptedProperty1() { + return this.encryptedProperty1; + } + + @Encrypt + public String getEncryptedProperty2() { + return this.encryptedProperty2; + } + + public String getNotEncryptedProperty() { + return this.notEncryptedProperty; + } + + public int getNotEncryptedIntProperty() { + return this.notEncryptedIntProperty; + } + + @Encrypt + public void setEncryptedProperty1(String encryptedProperty1) { + this.encryptedProperty1 = encryptedProperty1; + } + + @Encrypt + public void setEncryptedProperty2(String encryptedProperty2) { + this.encryptedProperty2 = encryptedProperty2; + } + + public void setNotEncryptedProperty(String notEncryptedProperty) { + this.notEncryptedProperty = notEncryptedProperty; + } + + public void setNotEncryptedIntProperty(int notEncryptedIntProperty) { + this.notEncryptedIntProperty = notEncryptedIntProperty; + } + + public EncryptedEntity() { + + } + + public EncryptedEntity(String pk, String rk) { + super(pk, rk); + } + + public void Populate() { + this.setEncryptedProperty1(""); + this.setEncryptedProperty2("foo"); + this.setNotEncryptedProperty("b"); + this.setNotEncryptedIntProperty(1234); + } +} diff --git a/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/table/gettingstarted/attributes/TableGettingStartedAttributes.java b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/table/gettingstarted/attributes/TableGettingStartedAttributes.java new file mode 100644 index 000000000000..0f4faf30fd4d --- /dev/null +++ b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/table/gettingstarted/attributes/TableGettingStartedAttributes.java @@ -0,0 +1,92 @@ +/** + * 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.azure.storage.encryption.table.gettingstarted.attributes; + +import java.net.URISyntaxException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Date; +import java.util.UUID; + +import com.microsoft.azure.keyvault.extensions.RsaKey; +import com.microsoft.azure.storage.CloudStorageAccount; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.table.CloudTable; +import com.microsoft.azure.storage.table.CloudTableClient; +import com.microsoft.azure.storage.table.TableEncryptionPolicy; +import com.microsoft.azure.storage.table.TableOperation; +import com.microsoft.azure.storage.table.TableRequestOptions; +import com.microsoft.azure.storage.table.TableResult; +import com.microsoft.azure.storage.util.LocalResolver; +import com.microsoft.azure.storage.util.Utility; + +public class TableGettingStartedAttributes { + + public static void main(String[] args) throws URISyntaxException, + StorageException, InvalidKeyException, NoSuchAlgorithmException { + Utility.printSampleStartInfo("TableResolverAttributes"); + + // Retrieve storage account information from connection string + // How to create a storage connection string - + // https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/ + CloudStorageAccount storageAccount = CloudStorageAccount + .parse(Utility.storageConnectionString); + CloudTableClient client = storageAccount.createCloudTableClient(); + CloudTable table = client.getTableReference("encryptiontableattributes" + + UUID.randomUUID().toString().replace("-", "")); + + try { + table.createIfNotExists(); + + // Create the IKey used for encryption. + RsaKey key = new RsaKey("private:key1"); + + EncryptedEntity ent = new EncryptedEntity(UUID.randomUUID() + .toString(), String.valueOf(new Date().getTime())); + ent.Populate(); + + TableRequestOptions insertOptions = new TableRequestOptions(); + insertOptions.setEncryptionPolicy(new TableEncryptionPolicy(key, + null)); + + // Insert Entity + System.out.println("Inserting the encrypted entity."); + table.execute(TableOperation.insert(ent), insertOptions, null); + + // For retrieves, a resolver can be set up that will help pick the + // key based on the key id. + LocalResolver resolver = new LocalResolver(); + resolver.add(key); + + TableRequestOptions retrieveOptions = new TableRequestOptions(); + retrieveOptions.setEncryptionPolicy(new TableEncryptionPolicy(null, + resolver)); + + // Retrieve Entity + System.out.println("Retrieving the encrypted entity."); + TableOperation operation = TableOperation.retrieve( + ent.getPartitionKey(), ent.getRowKey(), + EncryptedEntity.class); + TableResult result = table + .execute(operation, retrieveOptions, null); + EncryptedEntity resultEntity = result.getResultAsType(); + System.out.println("EncryptedProperty2 = " + + resultEntity.getEncryptedProperty2()); + } finally { + table.deleteIfExists(); + Utility.printSampleCompleteInfo("TableResolverAttributes"); + } + } +} diff --git a/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/table/gettingstarted/resolver/TableGettingStartedResolver.java b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/table/gettingstarted/resolver/TableGettingStartedResolver.java new file mode 100644 index 000000000000..1544bd30a76c --- /dev/null +++ b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/table/gettingstarted/resolver/TableGettingStartedResolver.java @@ -0,0 +1,115 @@ +/** + * 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.azure.storage.encryption.table.gettingstarted.resolver; + +import java.net.URISyntaxException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Date; +import java.util.UUID; + +import com.microsoft.azure.storage.table.CloudTable; +import com.microsoft.azure.storage.table.CloudTableClient; +import com.microsoft.azure.storage.table.DynamicTableEntity; +import com.microsoft.azure.storage.table.EntityProperty; +import com.microsoft.azure.storage.table.TableEncryptionPolicy; +import com.microsoft.azure.storage.table.TableOperation; +import com.microsoft.azure.storage.table.TableRequestOptions; +import com.microsoft.azure.storage.table.TableRequestOptions.EncryptionResolver; +import com.microsoft.azure.storage.table.TableResult; +import com.microsoft.azure.storage.util.LocalResolver; +import com.microsoft.azure.storage.util.Utility; +import com.microsoft.azure.keyvault.extensions.RsaKey; +import com.microsoft.azure.storage.CloudStorageAccount; +import com.microsoft.azure.storage.StorageException; + +public class TableGettingStartedResolver { + + public static void main(String[] args) throws StorageException, + URISyntaxException, InvalidKeyException, NoSuchAlgorithmException { + Utility.printSampleStartInfo("TableResolverEncryption"); + + // Retrieve storage account information from connection string + // How to create a storage connection string - + // https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/ + CloudStorageAccount storageAccount = CloudStorageAccount + .parse(Utility.storageConnectionString); + CloudTableClient client = storageAccount.createCloudTableClient(); + CloudTable table = client.getTableReference("encryptiontableresolver" + + UUID.randomUUID().toString().replace("-", "")); + + try { + table.createIfNotExists(); + + // Create the IKey used for encryption. + RsaKey key = new RsaKey("private:key1"); + + DynamicTableEntity ent = new DynamicTableEntity(); + ent.setPartitionKey(UUID.randomUUID().toString()); + ent.setRowKey(String.valueOf(new Date().getTime())); + ent.getProperties().put("EncryptedProp1", new EntityProperty("")); + ent.getProperties() + .put("EncryptedProp2", new EntityProperty("bar")); + ent.getProperties().put("NotEncryptedProp", + new EntityProperty(1234)); + + // This is used to indicate whether a property should be encrypted + // or not given the partition key, row key, + // and the property name. + EncryptionResolver encryptionResolver = new EncryptionResolver() { + public boolean encryptionResolver(String pk, String rk, + String key) { + if (key.startsWith("EncryptedProp")) { + return true; + } + return false; + } + }; + + TableRequestOptions insertOptions = new TableRequestOptions(); + insertOptions.setEncryptionPolicy(new TableEncryptionPolicy(key, + null)); + insertOptions.setEncryptionResolver(encryptionResolver); + + // Insert Entity + System.out.println("Inserting the encrypted entity."); + table.execute(TableOperation.insert(ent), insertOptions, null); + + // For retrieves, a resolver can be set up that will help pick the + // key based on the key id. + LocalResolver resolver = new LocalResolver(); + resolver.add(key); + + TableRequestOptions retrieveOptions = new TableRequestOptions(); + retrieveOptions.setEncryptionPolicy(new TableEncryptionPolicy(null, + resolver)); + + // Retrieve Entity + System.out.println("Retrieving the encrypted entity."); + TableOperation operation = TableOperation.retrieve( + ent.getPartitionKey(), ent.getRowKey(), + DynamicTableEntity.class); + TableResult result = table + .execute(operation, retrieveOptions, null); + DynamicTableEntity resultEntity = result.getResultAsType(); + System.out.println("EncryptedProp2 = " + + resultEntity.getProperties().get("EncryptedProp2") + .getValueAsString()); + } finally { + table.deleteIfExists(); + Utility.printSampleCompleteInfo("TableResolverEncryption"); + } + } +} diff --git a/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/KVCredentials.java b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/KVCredentials.java new file mode 100644 index 000000000000..2732eae5c027 --- /dev/null +++ b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/KVCredentials.java @@ -0,0 +1,115 @@ +/** + * 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.azure.storage.util; + +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import org.apache.http.Header; +import org.apache.http.message.BasicHeader; + +import com.microsoft.aad.adal4j.AuthenticationContext; +import com.microsoft.aad.adal4j.AuthenticationResult; +import com.microsoft.aad.adal4j.ClientCredential; +import com.microsoft.azure.keyvault.authentication.KeyVaultCredentials; +import com.microsoft.windowsazure.core.pipeline.filter.ServiceRequestContext; + +/** + * A class that stores KeyVault credentials and knows how to respond to + * authentication challenges. See KeyVaultCredentials for more information. + */ +public class KVCredentials extends KeyVaultCredentials { + + private String authClientID; + + // Note: It's very important, in a real application, to keep this secure. + private String authClientSecret; + + /** + * Constructs a new KVCredentials object. + * + * @param clientID + * The ClientID for this application + * @param clientSecret + * The client secret for this application + */ + public KVCredentials(String clientID, String clientSecret) { + this.authClientID = clientID; + this.authClientSecret = clientSecret; + } + + /** + * Actually do the authentication. This method will be called by the super + * class. + * + * @param request + * The request being sent + * @param challenge + * Information about the challenge from the service. + */ + @Override + public Header doAuthenticate(ServiceRequestContext request, + Map challenge) { + String authorization = challenge.get("authorization"); + String resource = challenge.get("resource"); + String clientId = this.authClientID; + String clientKey = this.authClientSecret; + AuthenticationResult token = getAccessTokenFromClientCredentials( + authorization, resource, clientId, clientKey); + return new BasicHeader("Authorization", token.getAccessTokenType() + + " " + token.getAccessToken()); + } + + /** + * Creates the access token + * + * @param authorization + * The authorization from the service + * @param resource + * The resource being accessed + * @param clientId + * The ClientID for this application + * @param clientKey + * The Client Secret for this application + * @return The access token to use to authenticate to the service + */ + private static AuthenticationResult getAccessTokenFromClientCredentials( + String authorization, String resource, String clientId, + String clientKey) { + AuthenticationContext context = null; + AuthenticationResult result = null; + ExecutorService service = null; + try { + service = Executors.newFixedThreadPool(1); + context = new AuthenticationContext(authorization, false, service); + ClientCredential credentials = new ClientCredential(clientId, + clientKey); + Future future = context.acquireToken( + resource, credentials, null); + result = future.get(); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + service.shutdown(); + } + + if (result == null) { + throw new RuntimeException("authentication result was null"); + } + return result; + } +} diff --git a/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/KeyVaultUtility.java b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/KeyVaultUtility.java new file mode 100644 index 000000000000..330d1641e34e --- /dev/null +++ b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/KeyVaultUtility.java @@ -0,0 +1,182 @@ +/** + * 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.azure.storage.util; + +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.security.NoSuchAlgorithmException; +import java.util.HashMap; +import java.util.Map; +import java.util.Scanner; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; + +import org.apache.commons.codec.binary.Base64; +import org.apache.http.impl.client.HttpClientBuilder; + +import com.microsoft.azure.keyvault.KeyVaultClient; +import com.microsoft.azure.keyvault.KeyVaultClientImpl; +import com.microsoft.azure.keyvault.models.Secret; +import com.microsoft.windowsazure.exception.ServiceException; + +/** + * A utility class for interacting with KeyVault + */ +public class KeyVaultUtility { + /** + * Creates a secret in Azure Key Vault and returns its ID. + * + * @param secretName + * The name of the secret to create + * @return The ID of the created secret + * @throws InterruptedException + * @throws ExecutionException + * @throws NoSuchAlgorithmException + * @throws URISyntaxException + * @throws MalformedURLException + */ + public static String SetUpKeyVaultSecret(String secretName) + throws InterruptedException, ExecutionException, + NoSuchAlgorithmException, URISyntaxException, MalformedURLException { + KeyVaultClient cloudVault = GetKeyVaultClient(); + + if (Utility.vaultURL == null || Utility.vaultURL.isEmpty()) { + throw new IllegalArgumentException("No Keyvault URL specified."); + } + + try { + // Delete the secret if it exists. + cloudVault.deleteSecretAsync(Utility.vaultURL, secretName).get(); + } catch (ExecutionException ex) { + boolean keyNotFound = false; + if (ex.getCause().getClass() == ServiceException.class) { + ServiceException serviceException = (ServiceException) ex + .getCause(); + if (serviceException.getHttpStatusCode() == 404) { + keyNotFound = true; + } + } + + if (!keyNotFound) { + System.out + .println("Unable to access the specified vault. Please confirm the KVClientId, KVClientKey, and VaultUri are valid in the app.config file."); + System.out + .println("Also ensure that the client ID has previously been granted full permissions for Key Vault secrets using the Set-AzureKeyVaultAccessPolicy command with the -PermissionsToSecrets parameter."); + System.out.println("Press any key to exit"); + Scanner input = new Scanner(System.in); + input.nextLine(); + input.close(); + throw ex; + } + } + + // Create a 256bit symmetric key and convert it to Base64. + KeyGenerator keyGen = KeyGenerator.getInstance("AES"); + keyGen.init(256); // Note that we cannot use SymmetricKey.KeySize256, + // because this resolves to '0x20'. + SecretKey wrapKey = keyGen.generateKey(); + + // Store the Base64 of the key in the key vault. Note that the + // content-type of the secret must + // be application/octet-stream or the KeyVaultKeyResolver will not load + // it as a key. + Map headers = new HashMap(); + headers.put("Content-Type", "application/octet-stream"); + Secret cloudSecret = cloudVault.setSecretAsync(Utility.vaultURL, + secretName, Base64.encodeBase64String(wrapKey.getEncoded()), + "application/octet-stream", null, null).get(); + + // Return the base identifier of the secret. This will be resolved to + // the current version of the secret. + return cloudSecret.getSecretIdentifier().getBaseIdentifier(); + } + + /** + * Creates the KeyVaultClient using the credentials specified in the Utility + * class. + * + * @return + * @throws URISyntaxException + * @throws MalformedURLException + * @throws InterruptedException + * @throws ExecutionException + */ + public static KeyVaultClient GetKeyVaultClient() throws URISyntaxException, + MalformedURLException, InterruptedException, ExecutionException { + if (Utility.AuthClientId == null || Utility.AuthClientId.isEmpty() + || Utility.AuthClientSecret == null + || Utility.AuthClientSecret.isEmpty()) { + throw new IllegalArgumentException( + "Invalid AuthClientID or AuthClientSecret specified."); + } + + HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); + ExecutorService executorService = Executors.newCachedThreadPool(); + KVCredentials creds = new KVCredentials(Utility.AuthClientId, + Utility.AuthClientSecret); + KeyVaultClient cloudVault = new KeyVaultClientImpl(httpClientBuilder, + executorService, creds); + return cloudVault; + } + + /** + * Helper method to create a new secret on the KeyVault service. + * + * @param defaultKeyName + * The default key name to use if the user does not provide one + * @return The keyID for the newly-created secret (or the existing secret, + * if one was passed in.) + * @throws InterruptedException + * @throws ExecutionException + * @throws NoSuchAlgorithmException + * @throws URISyntaxException + * @throws MalformedURLException + */ + public static String createSecret(String defaultKeyName) + throws InterruptedException, ExecutionException, + NoSuchAlgorithmException, URISyntaxException, MalformedURLException { + System.out.println("No secret specified in Utility class."); + System.out + .println("Please enter the name of a new secret to create in Key Vault."); + System.out + .println("WARNING: This will delete any existing secret with the same name."); + System.out.println("If nothing is entered, the value \"" + + defaultKeyName + "\" will be used."); + + @SuppressWarnings("resource") + Scanner input = new Scanner(System.in); + String newSecretName = input.nextLine(); + + if (newSecretName == null || newSecretName.isEmpty()) { + newSecretName = defaultKeyName; + } + + // Although it is possible to use keys (rather than secrets) stored in + // Key Vault, this prevents caching. + // Therefore it is recommended to use secrets along with a caching + // resolver (see below). + String keyID = KeyVaultUtility.SetUpKeyVaultSecret(newSecretName); + + System.out.println(); + System.out.println("Created a secret with ID: " + keyID); + System.out.println("Copy the secret ID to App.config to reuse."); + System.out.println(); + return keyID; + } +} diff --git a/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/LocalResolver.java b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/LocalResolver.java new file mode 100644 index 000000000000..75a8faf8fdd4 --- /dev/null +++ b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/LocalResolver.java @@ -0,0 +1,54 @@ +/** + * 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.azure.storage.util; + +import java.util.HashMap; +import java.util.concurrent.Future; + +import org.apache.commons.lang3.concurrent.ConcurrentUtils; + +import com.microsoft.azure.keyvault.core.IKey; +import com.microsoft.azure.keyvault.core.IKeyResolver; + +/** + * A sample key resolver class + * + */ +public class LocalResolver implements IKeyResolver { + + private HashMap keys = new HashMap(); + + /** + * Map from a keyID to a key. This will be called when decrypting. The data + * to decrypt will include the keyID used to encrypt it. + * + * @param keyId + * The KeyID to map to a key + */ + @Override + public Future resolveKeyAsync(String keyId) { + return ConcurrentUtils.constantFuture(this.keys.get(keyId)); + } + + /** + * Add a key to the local resolver. + * + * @param key + * The key to add to the local resolver. + */ + public void add(IKey key) { + keys.put(key.getKid(), key); + } +} diff --git a/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/Utility.java b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/Utility.java index e9df627cec40..3762892866d9 100644 --- a/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/Utility.java +++ b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/Utility.java @@ -22,43 +22,69 @@ * */ public final class Utility { - static { - // Uncomment the following to use Fiddler - // System.setProperty("http.proxyHost", "localhost"); - // System.setProperty("http.proxyPort", "8888"); - } + static { + // Uncomment the following to use Fiddler + // System.setProperty("http.proxyHost", "localhost"); + // System.setProperty("http.proxyPort", "8888"); + } - /** - * MODIFY THIS! - * - * Stores the storage connection string. - */ - public static final String storageConnectionString = "DefaultEndpointsProtocol=https;" - + "AccountName=[MY_ACCOUNT_NAME];" - + "AccountKey=[MY_ACCOUNT_KEY]"; + /** + * MODIFY THIS! + * + * Stores the storage connection string. + */ + public static final String storageConnectionString = "DefaultEndpointsProtocol=https;" + + "AccountName=[MY_ACCOUNT_NAME];" + + "AccountKey=[MY_ACCOUNT_KEY]"; - /** - * Prints out the exception information . - */ - public static void printException(Throwable t) { - StringWriter stringWriter = new StringWriter(); - PrintWriter printWriter = new PrintWriter(stringWriter); - t.printStackTrace(printWriter); - System.out.println(String.format("Got an exception from running samples. Exception details:\n%s\n", - stringWriter.toString())); - } + /** + * You only need to modify the following values if you want to run the + * KeyVault Encryption samples. Otherwise, leave empty. + */ + public static final String vaultURL = null; + public static final String AuthClientId = null; + public static final String AuthClientSecret = null; - /** - * Prints out the sample start information . - */ - public static void printSampleStartInfo(String sampleName) { - System.out.println(String.format("The Azure storage client library sample %s starting...", sampleName)); - } + /** + * Optional. Modify this if you want to run the KeyVaultGettingStarted + * sample. + */ + public static final String keyVaultKeyID = null; - /** - * Prints out the sample complete information . - */ - public static void printSampleCompleteInfo(String sampleName) { - System.out.println(String.format("The Azure storage client library sample %s completed.", sampleName)); - } + /** + * Optional. Modify these if you want to run the KeyRotationGettingStarted + * sample. + */ + public static final String keyVaultKeyIDForRotation1 = null; + public static final String keyVaultKeyIDForRotation2 = null; + + /** + * Prints out the exception information . + */ + public static void printException(Throwable t) { + StringWriter stringWriter = new StringWriter(); + PrintWriter printWriter = new PrintWriter(stringWriter); + t.printStackTrace(printWriter); + System.out.println(String.format( + "Got an exception from running samples. Exception details:\n%s\n", + stringWriter.toString())); + } + + /** + * Prints out the sample start information . + */ + public static void printSampleStartInfo(String sampleName) { + System.out.println(String.format( + "The Azure storage client library sample %s starting...", + sampleName)); + } + + /** + * Prints out the sample complete information . + */ + public static void printSampleCompleteInfo(String sampleName) { + System.out.println(String.format( + "The Azure storage client library sample %s completed.", + sampleName)); + } }