You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by pz...@apache.org on 2020/06/16 13:30:56 UTC
[knox] branch master updated: KNOX-2389 -
AliasBasedTokenStateService stops processing persisted journal entries if
one is malformed (#346)
This is an automated email from the ASF dual-hosted git repository.
pzampino pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/knox.git
The following commit(s) were added to refs/heads/master by this push:
new dcdeace KNOX-2389 - AliasBasedTokenStateService stops processing persisted journal entries if one is malformed (#346)
dcdeace is described below
commit dcdeace47a179851ee0810d446d2ad903ac826c2
Author: Phil Zampino <pz...@apache.org>
AuthorDate: Tue Jun 16 09:30:45 2020 -0400
KNOX-2389 - AliasBasedTokenStateService stops processing persisted journal entries if one is malformed (#346)
---
.../token/impl/AliasBasedTokenStateService.java | 26 +++--
.../token/impl/TokenStateServiceMessages.java | 6 +
.../token/impl/state/FileTokenStateJournal.java | 6 +-
.../impl/AliasBasedTokenStateServiceTest.java | 126 +++++++++++++++++++++
4 files changed, 152 insertions(+), 12 deletions(-)
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/AliasBasedTokenStateService.java b/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/AliasBasedTokenStateService.java
index 24d3fb9..28ca807 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/AliasBasedTokenStateService.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/AliasBasedTokenStateService.java
@@ -74,17 +74,21 @@ public class AliasBasedTokenStateService extends DefaultTokenStateService {
List<JournalEntry> entries = journal.get();
for (JournalEntry entry : entries) {
String id = entry.getTokenId();
- long issueTime = Long.parseLong(entry.getIssueTime());
- long expiration = Long.parseLong(entry.getExpiration());
- long maxLifetime = Long.parseLong(entry.getMaxLifetime());
-
- // Add the token state to memory
- super.addToken(id, issueTime, expiration, maxLifetime);
-
- synchronized (unpersistedState) {
- // The max lifetime entry is added by way of the call to super.addToken(),
- // so only need to add the expiration entry here.
- unpersistedState.add(new TokenExpiration(id, expiration));
+ try {
+ long issueTime = Long.parseLong(entry.getIssueTime());
+ long expiration = Long.parseLong(entry.getExpiration());
+ long maxLifetime = Long.parseLong(entry.getMaxLifetime());
+
+ // Add the token state to memory
+ super.addToken(id, issueTime, expiration, maxLifetime);
+
+ synchronized (unpersistedState) {
+ // The max lifetime entry is added by way of the call to super.addToken(),
+ // so only need to add the expiration entry here.
+ unpersistedState.add(new TokenExpiration(id, expiration));
+ }
+ } catch (Exception e) {
+ log.failedToLoadJournalEntry(id, e);
}
}
} catch (IOException e) {
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/TokenStateServiceMessages.java b/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/TokenStateServiceMessages.java
index a3d7502..735abc9 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/TokenStateServiceMessages.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/TokenStateServiceMessages.java
@@ -118,6 +118,12 @@ public interface TokenStateServiceMessages {
@Message(level = MessageLevel.DEBUG, text = "Persisting token state journal entry as {0}")
void persistingJournalEntry(String journalEntryFilename);
+ @Message(level = MessageLevel.ERROR, text = "Failed to load persisted token state journal entry for {0} : {1}")
+ void failedToLoadJournalEntry(String tokenId, @StackTrace(level = MessageLevel.DEBUG) Exception e);
+
+ @Message(level = MessageLevel.ERROR, text = "Failed to load persisted token state journal entry : {0}")
+ void failedToLoadJournalEntry(@StackTrace(level = MessageLevel.DEBUG) Exception e);
+
@Message(level = MessageLevel.ERROR, text = "Failed to persisting token state journal entry for {0} : {1}")
void failedToPersistJournalEntry(String tokenId, @StackTrace(level = MessageLevel.DEBUG) Exception e);
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/state/FileTokenStateJournal.java b/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/state/FileTokenStateJournal.java
index 31a8954..11dd702 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/state/FileTokenStateJournal.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/state/FileTokenStateJournal.java
@@ -108,7 +108,11 @@ abstract class FileTokenStateJournal implements TokenStateJournal {
BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
String line;
while ((line = reader.readLine()) != null) {
- entries.add(FileJournalEntry.parse(line));
+ try {
+ entries.add(FileJournalEntry.parse(line));
+ } catch (Exception e) {
+ log.failedToLoadJournalEntry(e);
+ }
}
}
diff --git a/gateway-server/src/test/java/org/apache/knox/gateway/services/token/impl/AliasBasedTokenStateServiceTest.java b/gateway-server/src/test/java/org/apache/knox/gateway/services/token/impl/AliasBasedTokenStateServiceTest.java
index 6a08635..606b3aa 100644
--- a/gateway-server/src/test/java/org/apache/knox/gateway/services/token/impl/AliasBasedTokenStateServiceTest.java
+++ b/gateway-server/src/test/java/org/apache/knox/gateway/services/token/impl/AliasBasedTokenStateServiceTest.java
@@ -22,6 +22,7 @@ import org.apache.knox.gateway.services.security.AliasService;
import org.apache.knox.gateway.services.security.AliasServiceException;
import org.apache.knox.gateway.services.security.token.TokenStateService;
import org.apache.knox.gateway.services.security.token.impl.JWTToken;
+import org.apache.knox.gateway.services.token.state.JournalEntry;
import org.apache.knox.gateway.services.token.state.TokenStateJournal;
import org.apache.knox.gateway.services.token.impl.state.TokenStateJournalFactory;
import org.easymock.EasyMock;
@@ -43,6 +44,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -564,6 +566,90 @@ public class AliasBasedTokenStateServiceTest extends DefaultTokenStateServiceTes
EasyMock.verify(aliasService);
}
+ @Test
+ public void testLoadTokenStateJournalDuringInitWithInvalidEntries() throws Exception {
+ final int TOKEN_COUNT = 5;
+
+ AliasService aliasService = EasyMock.createMock(AliasService.class);
+ aliasService.getAliasesForCluster(anyString());
+ EasyMock.expectLastCall().andReturn(Collections.emptyList()).anyTimes();
+ EasyMock.replay(aliasService);
+
+ // Create some test tokens
+ final Set<JWTToken> testTokens = new HashSet<>();
+ for (int i = 0; i < TOKEN_COUNT ; i++) {
+ JWTToken token = createMockToken(System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(60));
+ testTokens.add(token);
+ }
+
+ // Persist the token state journal entries before initializing the TokenStateService
+ TokenStateJournal journal = TokenStateJournalFactory.create(createMockGatewayConfig(false));
+ for (JWTToken token : testTokens) {
+ journal.add(token.getClaim(JWTToken.KNOX_ID_CLAIM),
+ System.currentTimeMillis(),
+ token.getExpiresDate().getTime(),
+ System.currentTimeMillis() + TimeUnit.HOURS.toMillis(24));
+ }
+
+ // Add an entry with an invalid token identifier
+ journal.add(" ",
+ System.currentTimeMillis(),
+ System.currentTimeMillis(),
+ System.currentTimeMillis());
+
+ // Add an entry with an invalid issue time
+ journal.add(new TestJournalEntry(UUID.randomUUID().toString(),
+ "invalidLongValue",
+ String.valueOf(System.currentTimeMillis()),
+ String.valueOf(System.currentTimeMillis())));
+
+ // Add an entry with an invalid expiration time
+ journal.add(new TestJournalEntry(UUID.randomUUID().toString(),
+ String.valueOf(System.currentTimeMillis()),
+ "invalidLongValue",
+ String.valueOf(System.currentTimeMillis())));
+
+ // Add an entry with an invalid max lifetime
+ journal.add(new TestJournalEntry(UUID.randomUUID().toString(),
+ String.valueOf(System.currentTimeMillis()),
+ String.valueOf(System.currentTimeMillis()),
+ "invalidLongValue"));
+
+ AliasBasedTokenStateService tss = new AliasBasedTokenStateService();
+ tss.setAliasService(aliasService);
+
+ // Initialize the service, and presumably load the previously-persisted journal entries
+ initTokenStateService(tss);
+
+ Field tokenExpirationsField = tss.getClass().getSuperclass().getDeclaredField("tokenExpirations");
+ tokenExpirationsField.setAccessible(true);
+ Map<String, Long> tokenExpirations = (Map<String, Long>) tokenExpirationsField.get(tss);
+
+ Field maxTokenLifetimesField = tss.getClass().getSuperclass().getDeclaredField("maxTokenLifetimes");
+ maxTokenLifetimesField.setAccessible(true);
+ Map<String, Long> maxTokenLifetimes = (Map<String, Long>) maxTokenLifetimesField.get(tss);
+
+ Field unpersistedStateField = tss.getClass().getDeclaredField("unpersistedState");
+ unpersistedStateField.setAccessible(true);
+ List<AliasBasedTokenStateService.TokenState> unpersistedState =
+ (List<AliasBasedTokenStateService.TokenState>) unpersistedStateField.get(tss);
+
+ assertEquals("Expected the tokens expirations to have been added in the base class cache.",
+ TOKEN_COUNT,
+ tokenExpirations.size());
+
+ assertEquals("Expected the tokens lifetimes to have been added in the base class cache.",
+ TOKEN_COUNT,
+ maxTokenLifetimes.size());
+
+ assertEquals("Expected the unpersisted state to have been added.",
+ (TOKEN_COUNT * 2), // Two TokenState entries per token (expiration, max lifetime)
+ unpersistedState.size());
+
+ // Verify that the expected methods were invoked
+ EasyMock.verify(aliasService);
+ }
+
@Override
protected TokenStateService createTokenStateService() throws Exception {
AliasBasedTokenStateService tss = new AliasBasedTokenStateService();
@@ -718,4 +804,44 @@ public class AliasBasedTokenStateServiceTest extends DefaultTokenStateServiceTes
}
}
}
+
+ private static class TestJournalEntry implements JournalEntry {
+
+ private String tokenId;
+ private String issueTime;
+ private String expiration;
+ private String maxLifetime;
+
+ TestJournalEntry(String tokenId, String issueTime, String expiration, String maxLifetime) {
+ this.tokenId = tokenId;
+ this.issueTime = issueTime;
+ this.expiration = expiration;
+ this.maxLifetime = maxLifetime;
+ }
+
+ @Override
+ public String getTokenId() {
+ return tokenId;
+ }
+
+ @Override
+ public String getIssueTime() {
+ return issueTime;
+ }
+
+ @Override
+ public String getExpiration() {
+ return expiration;
+ }
+
+ @Override
+ public String getMaxLifetime() {
+ return maxLifetime;
+ }
+
+ @Override
+ public String toString() {
+ return tokenId + "," + issueTime + "," + expiration + "," + maxLifetime;
+ }
+ }
}