Skip to content

Commit

Permalink
Merge pull request #144 from IABTechLab/gdm-UID2-1503-hotfix
Browse files Browse the repository at this point in the history
Added authorizable cache invalidation for invalid keys
  • Loading branch information
gmsdelmundo authored Sep 28, 2023
2 parents 19764ed + 263dc6b commit 9c8d22d
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 7 deletions.
11 changes: 11 additions & 0 deletions src/main/java/com/uid2/shared/auth/AuthorizableStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public AuthorizableStore(Class<T> cls) {

public void refresh(Collection<T> authorizablesToRefresh) {
authorizables.set(new AuthorizableStoreSnapshot(authorizablesToRefresh));
invalidateInvalidKeys();
}

public T getAuthorizableByKey(String key) {
Expand Down Expand Up @@ -100,6 +101,16 @@ private Cache<String, String> createCache() {
.build();
}

private void invalidateInvalidKeys() {
List<String> invalidKeys = keyToHashCache.asMap()
.entrySet()
.stream()
.filter(entry -> entry.getValue().isBlank())
.map(Map.Entry::getKey)
.collect(Collectors.toList());
invalidKeys.forEach(keyToHashCache::invalidate);
}

private ByteBuffer wrapHashToByteBuffer(String hash) {
byte[] hashBytes = convertBase64StringToBytes(hash);
return hashBytes == null ? null : ByteBuffer.wrap(hashBytes);
Expand Down
58 changes: 51 additions & 7 deletions src/test/java/com/uid2/shared/auth/AuthorizableStoreTest.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.uid2.shared.auth;

import com.github.benmanes.caffeine.cache.Cache;
import com.uid2.shared.secret.KeyHashResult;
import com.uid2.shared.secret.KeyHasher;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.lang.reflect.Field;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
Expand All @@ -22,16 +25,16 @@ public class AuthorizableStoreTest {
private static final String SITE_13_CLIENT_KEY_LEGACY = "abcdef.abcdefabcdefabcdefabcdefabcdefabcdefab";

private AuthorizableStore<ClientKey> clientKeyStore;
private List<ClientKey> clients;

@BeforeEach
public void setup() {
List<ClientKey> clients = List.of(
createClientKey(KEY_HASHER.hashKey(SITE_11_CLIENT_KEY), "client11", 11),
createClientKey(KEY_HASHER.hashKey(SITE_12_CLIENT_KEY_1), "client12_1", 12),
createClientKey(KEY_HASHER.hashKey(SITE_12_CLIENT_KEY_2), "client12_2", 12),
createClientKey(KEY_HASHER.hashKey(SITE_13_CLIENT_KEY), "client13", 13),
createClientKey(KEY_HASHER.hashKey(SITE_13_CLIENT_KEY_LEGACY), "client13_legacy", 13)
);
clients = new ArrayList<>();
clients.add(createClientKey(KEY_HASHER.hashKey(SITE_11_CLIENT_KEY), "client11", 11));
clients.add(createClientKey(KEY_HASHER.hashKey(SITE_12_CLIENT_KEY_1), "client12_1", 12));
clients.add(createClientKey(KEY_HASHER.hashKey(SITE_12_CLIENT_KEY_2), "client12_2", 12));
clients.add(createClientKey(KEY_HASHER.hashKey(SITE_13_CLIENT_KEY), "client13", 13));
clients.add(createClientKey(KEY_HASHER.hashKey(SITE_13_CLIENT_KEY_LEGACY), "client13_legacy", 13));

this.clientKeyStore = new AuthorizableStore<>(ClientKey.class);
this.clientKeyStore.refresh(clients);
Expand Down Expand Up @@ -135,6 +138,47 @@ public void refresh_returnsNewClients_afterRefresh() {
);
}

@Test
public void refresh_returnsPreviouslyInvalidClients_afterRefresh() throws Exception {
Field cacheField = clientKeyStore.getClass().getDeclaredField("keyToHashCache");
cacheField.setAccessible(true);
Cache<String, String> cache = (Cache<String, String>) cacheField.get(clientKeyStore);

clientKeyStore.getAuthorizableByKey(SITE_11_CLIENT_KEY);

String key = "UID2-C-L-14-abcdef.abcdefabcdefabcdefabcdefabcdefabcdefab";
ClientKey invalidClientKey = clientKeyStore.getAuthorizableByKey(key);
String invalidCacheValue = cache.getIfPresent(key);

KeyHashResult khr = KEY_HASHER.hashKey(key);
ClientKey client = createClientKey(khr, "client14", 14);
clients.add(client);
clientKeyStore.refresh(clients);

String existingCacheValue = cache.getIfPresent(SITE_11_CLIENT_KEY);

ClientKey validClientKey = clientKeyStore.getAuthorizableByKey(key);
String validCacheValue = cache.getIfPresent(key);

assertAll(
"refresh returns previously invalid clients after refresh",
() -> assertAll(
"refresh returns previously invalid clients after refresh - invalid values were previously invalid",
() -> assertNull(invalidClientKey),
() -> assertEquals("", invalidCacheValue)
),
() -> assertAll(
"refresh returns previously invalid clients after refresh - invalid values are now valid",
() -> assertEquals("client14", validClientKey.getName()),
() -> assertEquals(khr.getHash(), validCacheValue)
),
() -> assertAll(
"refresh returns previously invalid clients after refresh - valid values are still valid",
() -> assertEquals(clients.get(0).getKeyHash(), existingCacheValue)
)
);
}

private ClientKey createClientKey(KeyHashResult khr, String name, int siteId) {
return new ClientKey(khr.getHash(), khr.getSalt(), "", name, NOW, Set.of(), siteId);
}
Expand Down

0 comments on commit 9c8d22d

Please sign in to comment.