diff --git a/azure-keyvault-complete/pom.xml b/azure-keyvault-complete/pom.xml
index 1099d7cbe38db..11fd13065e2eb 100644
--- a/azure-keyvault-complete/pom.xml
+++ b/azure-keyvault-complete/pom.xml
@@ -7,13 +7,13 @@ the MIT License. See License.txt in the project root for license information. --
com.microsoft.azure
azure-keyvault-parent
- 1.1.1
+ 1.1.2
../pom.xml
com.microsoft.azure
azure-keyvault-complete
- 1.1.1
+ 1.1.2
pom
@@ -69,4 +69,4 @@ the MIT License. See License.txt in the project root for license information. --
-
\ No newline at end of file
+
diff --git a/azure-keyvault-core/pom.xml b/azure-keyvault-core/pom.xml
index 84142415edfc5..cee82573a28b9 100644
--- a/azure-keyvault-core/pom.xml
+++ b/azure-keyvault-core/pom.xml
@@ -8,12 +8,12 @@
com.microsoft.azure
azure-keyvault-parent
- 1.1.1
+ 1.1.2
../pom.xml
azure-keyvault-core
- 1.1.1
+ 1.1.2
jar
Microsoft Azure SDK for Key Vault Core
diff --git a/azure-keyvault-cryptography/pom.xml b/azure-keyvault-cryptography/pom.xml
index d8763febb6c83..edcde42ea81d1 100644
--- a/azure-keyvault-cryptography/pom.xml
+++ b/azure-keyvault-cryptography/pom.xml
@@ -7,12 +7,12 @@
com.microsoft.azure
azure-keyvault-parent
- 1.1.1
+ 1.1.2
../pom.xml
azure-keyvault-cryptography
- 1.1.1
+ 1.1.2
jar
Microsoft Azure SDK for Key Vault Cryptography
diff --git a/azure-keyvault-extensions/pom.xml b/azure-keyvault-extensions/pom.xml
index 98e695712e37b..6c3af7a2693f1 100644
--- a/azure-keyvault-extensions/pom.xml
+++ b/azure-keyvault-extensions/pom.xml
@@ -8,12 +8,12 @@
com.microsoft.azure
azure-keyvault-parent
- 1.1.1
+ 1.1.2
../pom.xml
azure-keyvault-extensions
- 1.1.1
+ 1.1.2
jar
Microsoft Azure SDK for Key Vault Extensions
@@ -64,7 +64,6 @@
com.microsoft.azure
azure-keyvault
- 1.1.1
diff --git a/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/CachingKeyResolver.java b/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/CachingKeyResolver.java
index cfefd7312dc6e..62bca3fabfdbb 100644
--- a/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/CachingKeyResolver.java
+++ b/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/CachingKeyResolver.java
@@ -10,6 +10,8 @@
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.microsoft.azure.keyvault.KeyIdentifier;
import com.microsoft.azure.keyvault.core.IKey;
import com.microsoft.azure.keyvault.core.IKeyResolver;
@@ -18,25 +20,46 @@
*/
public class CachingKeyResolver implements IKeyResolver {
+ private final IKeyResolver keyResolver;
private final LoadingCache> cache;
-
+
/**
* Constructor.
* @param capacity the cache size
* @param keyResolver the key resolver
*/
public CachingKeyResolver(int capacity, final IKeyResolver keyResolver) {
+ this.keyResolver = keyResolver;
cache = CacheBuilder.newBuilder().maximumSize(capacity)
.build(new CacheLoader>() {
@Override
public ListenableFuture load(String kid) {
return keyResolver.resolveKeyAsync(kid);
- } });
+ }
+ });
}
@Override
public ListenableFuture resolveKeyAsync(String kid) {
- return cache.getUnchecked(kid);
+ KeyIdentifier keyIdentifier = new KeyIdentifier(kid);
+ if (keyIdentifier.version() == null) {
+ final ListenableFuture key = keyResolver.resolveKeyAsync(kid);
+ key.addListener(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ cache.put(key.get().getKid(), key);
+ } catch (Exception e) {
+ // Key caching will occur on first read
+ }
+ }
+ },
+ MoreExecutors.directExecutor()
+ );
+ return key;
+ } else {
+ return cache.getUnchecked(kid);
+ }
}
}
diff --git a/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/KeyVaultKey.java b/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/KeyVaultKey.java
index f903de9527da9..bfb58a8a7b8a7 100644
--- a/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/KeyVaultKey.java
+++ b/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/KeyVaultKey.java
@@ -7,6 +7,8 @@
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
+
+import com.google.common.util.concurrent.MoreExecutors;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
@@ -160,7 +162,7 @@ public ListenableFuture decryptAsync(byte[] ciphertext, byte[] iv, byte[
new JsonWebKeyEncryptionAlgorithm(algorithm),
ciphertext,
null);
- return Futures.transform(futureCall, new DecryptResultTransform());
+ return Futures.transform(futureCall, new DecryptResultTransform(), MoreExecutors.directExecutor());
}
@Override
@@ -198,7 +200,7 @@ public ListenableFuture unwrapKeyAsync(byte[] ciphertext, String algorit
new JsonWebKeyEncryptionAlgorithm(algorithm),
ciphertext,
null);
- return Futures.transform(futureCall, new DecryptResultTransform());
+ return Futures.transform(futureCall, new DecryptResultTransform(), MoreExecutors.directExecutor());
}
@Override
@@ -218,7 +220,7 @@ public ListenableFuture> signAsync(byte[] digest, String al
new JsonWebKeySignatureAlgorithm(algorithm),
digest,
null);
- return Futures.transform(futureCall, new SignResultTransform(algorithm));
+ return Futures.transform(futureCall, new SignResultTransform(algorithm), MoreExecutors.directExecutor());
}
@Override
diff --git a/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/KeyVaultKeyResolver.java b/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/KeyVaultKeyResolver.java
index a969082fac1cd..3e8cc130cf7d9 100644
--- a/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/KeyVaultKeyResolver.java
+++ b/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/KeyVaultKeyResolver.java
@@ -7,6 +7,8 @@
package com.microsoft.azure.keyvault.extensions;
import java.security.Provider;
+
+import com.google.common.util.concurrent.MoreExecutors;
import org.apache.commons.codec.binary.Base64;
import com.google.common.base.Function;
@@ -98,13 +100,13 @@ public KeyVaultKeyResolver(KeyVaultClient client, Provider provider) {
private ListenableFuture resolveKeyFromSecretAsync(String kid) {
ListenableFuture futureCall = client.getSecretAsync(kid, null);
- return Futures.transform(futureCall, new FutureKeyFromSecret());
+ return Futures.transform(futureCall, new FutureKeyFromSecret(), MoreExecutors.directExecutor());
}
private ListenableFuture resolveKeyFromKeyAsync(String kid) {
ListenableFuture futureCall = client.getKeyAsync(kid, null);
- return Futures.transform(futureCall, new FutureKeyFromKey());
+ return Futures.transform(futureCall, new FutureKeyFromKey(), MoreExecutors.directExecutor());
}
@Override
diff --git a/azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/CachingKeyResolverTest.java b/azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/CachingKeyResolverTest.java
index a5263c820a6dd..39e15a5941855 100644
--- a/azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/CachingKeyResolverTest.java
+++ b/azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/CachingKeyResolverTest.java
@@ -18,27 +18,32 @@
package com.microsoft.azure.keyvault.extensions.test;
-import static org.junit.Assert.*;
-
-import org.junit.Test;
-
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.UncheckedExecutionException;
import com.microsoft.azure.keyvault.core.IKey;
import com.microsoft.azure.keyvault.core.IKeyResolver;
import com.microsoft.azure.keyvault.extensions.CachingKeyResolver;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.concurrent.Executor;
+
+import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
public class CachingKeyResolverTest {
-
+
@SuppressWarnings("unchecked")
final ListenableFuture ikeyAsync = mock(ListenableFuture.class);
- final static String keyId = "keyID";
- final static String keyId2 = "keyID2";
- final static String keyId3 = "keyID3";
-
+ final static String keyId = "https://test.vault.azure.net/keys/keyID/version";
+ final static String keyId2 = "https://test.vault.azure.net/keys/keyID2/version";
+ final static String keyId3 = "https://test.vault.azure.net/keys/keyID3/version";
+ final static String newerKeyId3 = "https://test.vault.azure.net/keys/keyID3/version2";
+ final static String unversionnedKeyId3 = "https://test.vault.azure.net/keys/keyID3";
+
- /*
+ /*
* Tests the capacity limit of CachingKeyResolver by adding more keys
* than the cache limit and verifying that least recently used entity is evicted.
*/
@@ -47,51 +52,100 @@ public void KeyVault_CapacityLimitOfCachingKeyResolver()
{
IKeyResolver mockedKeyResolver = mock(IKeyResolver.class);
CachingKeyResolver resolver = new CachingKeyResolver(2, mockedKeyResolver);
-
+
when(mockedKeyResolver.resolveKeyAsync(keyId)).thenReturn(ikeyAsync);
when(mockedKeyResolver.resolveKeyAsync(keyId2)).thenReturn(ikeyAsync);
when(mockedKeyResolver.resolveKeyAsync(keyId3)).thenReturn(ikeyAsync);
-
+
resolver.resolveKeyAsync(keyId);
resolver.resolveKeyAsync(keyId2);
resolver.resolveKeyAsync(keyId3);
-
+
resolver.resolveKeyAsync(keyId2);
resolver.resolveKeyAsync(keyId3);
resolver.resolveKeyAsync(keyId);
resolver.resolveKeyAsync(keyId3);
-
+
verify(mockedKeyResolver, times(1)).resolveKeyAsync(keyId2);
verify(mockedKeyResolver, times(1)).resolveKeyAsync(keyId3);
verify(mockedKeyResolver, times(2)).resolveKeyAsync(keyId);
}
-
- /*
- * Tests the behavior of CachingKeyResolver when resolving key throws
- * and validate that the failed entity is not added to the cache.
+
+ /*
+ * Tests the behavior of CachingKeyResolver when resolving key throws
+ * and validate that the failed entity is not added to the cache.
*/
@Test
public void KeyVault_CachingKeyResolverThrows()
{
IKeyResolver mockedKeyResolver = mock(IKeyResolver.class);
CachingKeyResolver resolver = new CachingKeyResolver(10, mockedKeyResolver);
-
+
// First throw exception and for the second call return a value
when(mockedKeyResolver.resolveKeyAsync(keyId))
.thenThrow(new RuntimeException("test"))
.thenReturn(ikeyAsync);
-
+
try {
resolver.resolveKeyAsync(keyId);
- assertFalse("Should have thrown an exception.", true);
+ fail("Should have thrown an exception.");
}
catch (UncheckedExecutionException e) {
assertTrue("RuntimeException is expected.", e.getCause() instanceof RuntimeException);
}
-
+
resolver.resolveKeyAsync(keyId);
resolver.resolveKeyAsync(keyId);
-
+
verify(mockedKeyResolver, times(2)).resolveKeyAsync(keyId);
}
+
+ /*
+ * Tests that CachingKeyResolver does not cache unversionned keys,
+ * but does cache the result versionned key
+ */
+ @Test
+ public void KeyVault_CachingUnversionnedKey() throws Exception {
+ IKeyResolver mockedKeyResolver = mock(IKeyResolver.class);
+ CachingKeyResolver resolver = new CachingKeyResolver(2, mockedKeyResolver);
+
+ IKey key = mock(IKey.class);
+
+ when(mockedKeyResolver.resolveKeyAsync(unversionnedKeyId3)).thenReturn(ikeyAsync);
+ when(ikeyAsync.get()).thenReturn(key);
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
+ invocationOnMock.getArgumentAt(0, Runnable.class).run();
+ return null;
+ }
+ }).when(ikeyAsync).addListener(any(Runnable.class), any(Executor.class));
+ when(key.getKid()).thenReturn(keyId3);
+
+ /*
+ * First resolve unversionned key
+ */
+ ListenableFuture result = resolver.resolveKeyAsync(unversionnedKeyId3);
+ assertEquals(result.get().getKid(), keyId3);
+ verify(mockedKeyResolver, times(1)).resolveKeyAsync(unversionnedKeyId3);
+ verify(mockedKeyResolver, times(0)).resolveKeyAsync(keyId3);
+
+ /*
+ * Second resolve unversionned key, but the result should be a newer key
+ */
+ when(key.getKid()).thenReturn(newerKeyId3);
+ result = resolver.resolveKeyAsync(unversionnedKeyId3);
+ assertEquals(result.get().getKid(), newerKeyId3);
+ verify(mockedKeyResolver, times(2)).resolveKeyAsync(unversionnedKeyId3);
+ verify(mockedKeyResolver, times(0)).resolveKeyAsync(keyId3);
+ verify(mockedKeyResolver, times(0)).resolveKeyAsync(newerKeyId3);
+
+ /*
+ * Check that versionned keys were added to the cache, and do not get resolved again
+ */
+ resolver.resolveKeyAsync(keyId3);
+ resolver.resolveKeyAsync(newerKeyId3);
+ verify(mockedKeyResolver, times(0)).resolveKeyAsync(keyId3);
+ verify(mockedKeyResolver, times(0)).resolveKeyAsync(newerKeyId3);
+ }
}
diff --git a/azure-keyvault-webkey/pom.xml b/azure-keyvault-webkey/pom.xml
index 258ec05bef0ef..19c30eeed8a05 100644
--- a/azure-keyvault-webkey/pom.xml
+++ b/azure-keyvault-webkey/pom.xml
@@ -6,12 +6,12 @@
com.microsoft.azure
azure-keyvault-parent
- 1.1.1
+ 1.1.2
../pom.xml
azure-keyvault-webkey
- 1.1.1
+ 1.1.2
jar
Microsoft Azure SDK for Key Vault WebKey
diff --git a/azure-keyvault/pom.xml b/azure-keyvault/pom.xml
index 0e8da25bc78d9..b6da877337b19 100644
--- a/azure-keyvault/pom.xml
+++ b/azure-keyvault/pom.xml
@@ -6,12 +6,12 @@ the MIT License. See License.txt in the project root for license information. --
com.microsoft.azure
azure-keyvault-parent
- 1.1.1
+ 1.1.2
../pom.xml
azure-keyvault
- 1.1.1
+ 1.1.2
jar
Microsoft Azure SDK for Key Vault
diff --git a/pom.xml b/pom.xml
index ca2cd918327b7..a87523e1e15a4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
4.0.0
com.microsoft.azure
- 1.1.1
+ 1.1.2
azure-keyvault-parent
pom
@@ -90,27 +90,27 @@
com.microsoft.azure
azure-keyvault-webkey
- 1.1.1
+ 1.1.2
com.microsoft.azure
azure-keyvault-cryptography
- 1.1.1
+ 1.1.2
com.microsoft.azure
azure-keyvault-core
- 1.1.1
+ 1.1.2
com.microsoft.azure
azure-keyvault
- 1.1.1
+ 1.1.2
com.microsoft.azure
azure-keyvault-extensions
- 1.1.1
+ 1.1.2