Skip to content

Commit

Permalink
Merging Dev to Master (Azure#69)
Browse files Browse the repository at this point in the history
* Do not cache unversionned keys

* Brihicks/fix gauva26.0 problems (Azure#63)

* Fixed issues resulting from incompatibilities with Guava 26.0
* Updated versioning

* Update pom.xml (Azure#66)

* Versioning fix

* Update pom.xml

* Updated versions of all files 1.1.2
  • Loading branch information
schaabs authored and bhicks2 committed Nov 2, 2018
1 parent bdee224 commit 02233df
Show file tree
Hide file tree
Showing 11 changed files with 131 additions and 51 deletions.
6 changes: 3 additions & 3 deletions azure-keyvault-complete/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ the MIT License. See License.txt in the project root for license information. --
<parent>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-keyvault-parent</artifactId>
<version>1.1.1</version>
<version>1.1.2</version>
<relativePath>../pom.xml</relativePath>
</parent>

<groupId>com.microsoft.azure</groupId>
<artifactId>azure-keyvault-complete</artifactId>
<version>1.1.1</version>
<version>1.1.2</version>
<packaging>pom</packaging>

<licenses>
Expand Down Expand Up @@ -69,4 +69,4 @@ the MIT License. See License.txt in the project root for license information. --
</dependency>
</dependencies>

</project>
</project>
4 changes: 2 additions & 2 deletions azure-keyvault-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
<parent>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-keyvault-parent</artifactId>
<version>1.1.1</version>
<version>1.1.2</version>
<relativePath>../pom.xml</relativePath>
</parent>

<artifactId>azure-keyvault-core</artifactId>
<version>1.1.1</version>
<version>1.1.2</version>
<packaging>jar</packaging>

<name>Microsoft Azure SDK for Key Vault Core</name>
Expand Down
4 changes: 2 additions & 2 deletions azure-keyvault-cryptography/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
<parent>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-keyvault-parent</artifactId>
<version>1.1.1</version>
<version>1.1.2</version>
<relativePath>../pom.xml</relativePath>
</parent>

<artifactId>azure-keyvault-cryptography</artifactId>
<version>1.1.1</version>
<version>1.1.2</version>
<packaging>jar</packaging>

<name>Microsoft Azure SDK for Key Vault Cryptography</name>
Expand Down
5 changes: 2 additions & 3 deletions azure-keyvault-extensions/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
<parent>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-keyvault-parent</artifactId>
<version>1.1.1</version>
<version>1.1.2</version>
<relativePath>../pom.xml</relativePath>
</parent>

<artifactId>azure-keyvault-extensions</artifactId>
<version>1.1.1</version>
<version>1.1.2</version>
<packaging>jar</packaging>

<name>Microsoft Azure SDK for Key Vault Extensions</name>
Expand Down Expand Up @@ -64,7 +64,6 @@
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-keyvault</artifactId>
<version>1.1.1</version>
</dependency>

<!-- Other Microsoft Azure Dependencies -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -18,25 +20,46 @@
*/
public class CachingKeyResolver implements IKeyResolver {

private final IKeyResolver keyResolver;
private final LoadingCache<String, ListenableFuture<IKey>> 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<String, ListenableFuture<IKey>>() {

@Override
public ListenableFuture<IKey> load(String kid) {
return keyResolver.resolveKeyAsync(kid);
} });
}
});
}

@Override
public ListenableFuture<IKey> resolveKeyAsync(String kid) {
return cache.getUnchecked(kid);
KeyIdentifier keyIdentifier = new KeyIdentifier(kid);
if (keyIdentifier.version() == null) {
final ListenableFuture<IKey> 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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -160,7 +162,7 @@ public ListenableFuture<byte[]> 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
Expand Down Expand Up @@ -198,7 +200,7 @@ public ListenableFuture<byte[]> 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
Expand All @@ -218,7 +220,7 @@ public ListenableFuture<Pair<byte[], String>> 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -98,13 +100,13 @@ public KeyVaultKeyResolver(KeyVaultClient client, Provider provider) {
private ListenableFuture<IKey> resolveKeyFromSecretAsync(String kid) {

ListenableFuture<SecretBundle> futureCall = client.getSecretAsync(kid, null);
return Futures.transform(futureCall, new FutureKeyFromSecret());
return Futures.transform(futureCall, new FutureKeyFromSecret(), MoreExecutors.directExecutor());
}

private ListenableFuture<IKey> resolveKeyFromKeyAsync(String kid) {

ListenableFuture<KeyBundle> futureCall = client.getKeyAsync(kid, null);
return Futures.transform(futureCall, new FutureKeyFromKey());
return Futures.transform(futureCall, new FutureKeyFromKey(), MoreExecutors.directExecutor());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<IKey> 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.
*/
Expand All @@ -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<IKey> 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);
}
}
4 changes: 2 additions & 2 deletions azure-keyvault-webkey/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
<parent>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-keyvault-parent</artifactId>
<version>1.1.1</version>
<version>1.1.2</version>
<relativePath>../pom.xml</relativePath>
</parent>

<artifactId>azure-keyvault-webkey</artifactId>
<version>1.1.1</version>
<version>1.1.2</version>
<packaging>jar</packaging>

<name>Microsoft Azure SDK for Key Vault WebKey</name>
Expand Down
4 changes: 2 additions & 2 deletions azure-keyvault/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ the MIT License. See License.txt in the project root for license information. --
<parent>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-keyvault-parent</artifactId>
<version>1.1.1</version>
<version>1.1.2</version>
<relativePath>../pom.xml</relativePath>
</parent>

<artifactId>azure-keyvault</artifactId>
<version>1.1.1</version>
<version>1.1.2</version>
<packaging>jar</packaging>

<name>Microsoft Azure SDK for Key Vault</name>
Expand Down
Loading

0 comments on commit 02233df

Please sign in to comment.