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 61e513e KNOX-2230 - Token State Service should throw
UnknownTokenException instead of IllegalArgumentException (#268)
61e513e is described below
commit 61e513e1a828a18ec2ced0ffec470384477c277c
Author: Phil Zampino <[email protected]>
AuthorDate: Thu Feb 20 15:40:27 2020 -0500
KNOX-2230 - Token State Service should throw UnknownTokenException instead
of IllegalArgumentException (#268)
---
.../federation/jwt/filter/AbstractJWTFilter.java | 54 +++++++++++-----------
.../jwt/filter/AccessTokenFederationFilter.java | 22 +++++----
.../provider/federation/CommonJWTFilterTest.java | 20 ++++++--
.../token/impl/AliasBasedTokenStateService.java | 30 ++++++------
.../token/impl/DefaultTokenStateService.java | 48 +++++++++----------
.../token/impl/DefaultTokenStateServiceTest.java | 34 +++++++-------
.../gateway/service/knoxtoken/TokenResource.java | 3 +-
.../services/security/token/TokenStateService.java | 18 ++++----
.../services/security/token/TokenUtils.java | 27 +++++++++++
.../security/token/UnknownTokenException.java | 36 +++++++++++++++
10 files changed, 187 insertions(+), 105 deletions(-)
diff --git
a/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/AbstractJWTFilter.java
b/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/AbstractJWTFilter.java
index 5b885a3..af33275 100644
---
a/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/AbstractJWTFilter.java
+++
b/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/AbstractJWTFilter.java
@@ -59,6 +59,7 @@ import org.apache.knox.gateway.services.ServiceType;
import org.apache.knox.gateway.services.security.token.JWTokenAuthority;
import org.apache.knox.gateway.services.security.token.TokenServiceException;
import org.apache.knox.gateway.services.security.token.TokenStateService;
+import org.apache.knox.gateway.services.security.token.UnknownTokenException;
import org.apache.knox.gateway.services.security.token.impl.JWT;
import com.nimbusds.jose.JWSHeader;
@@ -167,16 +168,10 @@ public abstract class AbstractJWTFilter implements Filter
{
return audList;
}
- protected boolean tokenIsStillValid(JWT jwtToken) {
+ protected boolean tokenIsStillValid(JWT jwtToken) throws
UnknownTokenException {
Date expires;
if (tokenStateService != null) {
- long timestamp = 0;
- try {
- timestamp = tokenStateService.getTokenExpiration(jwtToken.toString());
- } catch (Exception e) {
- log.unableToVerifyExpiration(e);
- }
- expires = new Date(timestamp);
+ expires = new
Date(tokenStateService.getTokenExpiration(jwtToken.toString()));
} else {
// if there is no expiration date then the lifecycle is tied entirely to
// the cookie validity - otherwise ensure that the current time is before
@@ -317,27 +312,32 @@ public abstract class AbstractJWTFilter implements Filter
{
// if there is no expiration data then the lifecycle is tied entirely
to
// the cookie validity - otherwise ensure that the current time is
before
// the designated expiration time
- if (tokenIsStillValid(token)) {
- boolean audValid = validateAudiences(token);
- if (audValid) {
- Date nbf = token.getNotBeforeDate();
- if (nbf == null || new Date().after(nbf)) {
- return true;
- } else {
- log.notBeforeCheckFailed();
- handleValidationError(request, response,
HttpServletResponse.SC_BAD_REQUEST,
- "Bad request: the NotBefore check
failed");
- }
- }
- else {
- log.failedToValidateAudience();
+ try {
+ if (tokenIsStillValid(token)) {
+ boolean audValid = validateAudiences(token);
+ if (audValid) {
+ Date nbf = token.getNotBeforeDate();
+ if (nbf == null || new Date().after(nbf)) {
+ return true;
+ } else {
+ log.notBeforeCheckFailed();
+ handleValidationError(request, response,
HttpServletResponse.SC_BAD_REQUEST,
+ "Bad request: the NotBefore check
failed");
+ }
+ }
+ else {
+ log.failedToValidateAudience();
+ handleValidationError(request, response,
HttpServletResponse.SC_BAD_REQUEST,
+ "Bad request: missing required token
audience");
+ }
+ } else {
+ log.tokenHasExpired();
handleValidationError(request, response,
HttpServletResponse.SC_BAD_REQUEST,
- "Bad request: missing required token
audience");
+ "Bad request: token has expired");
}
- } else {
- log.tokenHasExpired();
- handleValidationError(request, response,
HttpServletResponse.SC_BAD_REQUEST,
- "Bad request: token has expired");
+ } catch (UnknownTokenException e) {
+ log.unableToVerifyExpiration(e);
+ handleValidationError(request, response,
HttpServletResponse.SC_UNAUTHORIZED, e.getMessage());
}
}
else {
diff --git
a/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/AccessTokenFederationFilter.java
b/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/AccessTokenFederationFilter.java
index 1b82fa0..57696d6 100644
---
a/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/AccessTokenFederationFilter.java
+++
b/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/AccessTokenFederationFilter.java
@@ -25,6 +25,7 @@ import org.apache.knox.gateway.services.GatewayServices;
import org.apache.knox.gateway.services.security.token.JWTokenAuthority;
import org.apache.knox.gateway.services.security.token.TokenServiceException;
import org.apache.knox.gateway.services.security.token.TokenStateService;
+import org.apache.knox.gateway.services.security.token.UnknownTokenException;
import org.apache.knox.gateway.services.security.token.impl.JWTToken;
import javax.security.auth.Subject;
@@ -88,16 +89,21 @@ public class AccessTokenFederationFilter implements Filter {
log.unableToVerifyToken(e);
}
if (verified) {
- if (!isExpired(token)) {
- if (((HttpServletRequest)
request).getRequestURL().indexOf(token.getAudience().toLowerCase(Locale.ROOT))
!= -1) {
- Subject subject = createSubjectFromToken(token);
- continueWithEstablishedSecurityContext(subject,
(HttpServletRequest)request, (HttpServletResponse)response, chain);
+ try {
+ if (!isExpired(token)) {
+ if (((HttpServletRequest)
request).getRequestURL().indexOf(token.getAudience().toLowerCase(Locale.ROOT))
!= -1) {
+ Subject subject = createSubjectFromToken(token);
+ continueWithEstablishedSecurityContext(subject,
(HttpServletRequest)request, (HttpServletResponse)response, chain);
+ } else {
+ log.failedToValidateAudience();
+ sendUnauthorized(response);
+ }
} else {
- log.failedToValidateAudience();
+ log.tokenHasExpired();
sendUnauthorized(response);
}
- } else {
- log.tokenHasExpired();
+ } catch (UnknownTokenException e) {
+ log.unableToVerifyExpiration(e);
sendUnauthorized(response);
}
} else {
@@ -110,7 +116,7 @@ public class AccessTokenFederationFilter implements Filter {
}
}
- private boolean isExpired(JWTToken token) {
+ private boolean isExpired(JWTToken token) throws UnknownTokenException {
return (tokenStateService != null) ?
tokenStateService.isExpired(token.toString()) :
(Long.parseLong(token.getExpires()) <= System.currentTimeMillis());
}
diff --git
a/gateway-provider-security-jwt/src/test/java/org/apache/knox/gateway/provider/federation/CommonJWTFilterTest.java
b/gateway-provider-security-jwt/src/test/java/org/apache/knox/gateway/provider/federation/CommonJWTFilterTest.java
index 68fd502..8c46900 100644
---
a/gateway-provider-security-jwt/src/test/java/org/apache/knox/gateway/provider/federation/CommonJWTFilterTest.java
+++
b/gateway-provider-security-jwt/src/test/java/org/apache/knox/gateway/provider/federation/CommonJWTFilterTest.java
@@ -19,6 +19,7 @@ package org.apache.knox.gateway.provider.federation;
import org.apache.knox.gateway.config.GatewayConfig;
import
org.apache.knox.gateway.provider.federation.jwt.filter.AbstractJWTFilter;
import org.apache.knox.gateway.services.security.token.TokenStateService;
+import org.apache.knox.gateway.services.security.token.UnknownTokenException;
import org.apache.knox.gateway.services.security.token.impl.JWT;
import org.easymock.EasyMock;
import org.junit.After;
@@ -35,6 +36,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import static org.easymock.EasyMock.anyObject;
@@ -124,16 +126,15 @@ public class CommonJWTFilterTest {
doTestIsStillValid(System.currentTimeMillis() - 300000)); // 5
minutes ago
}
- @Test
+ @Test(expected = UnknownTokenException.class)
public void testIsStillValidUnknownToken() throws Exception {
TokenStateService tss = EasyMock.createNiceMock(TokenStateService.class);
EasyMock.expect(tss.getTokenExpiration(anyObject()))
- .andThrow(new IllegalArgumentException("Unknown token"))
+ .andThrow(new UnknownTokenException("eyjhbgcioi1234567890neg"))
.anyTimes();
EasyMock.replay(tss);
- assertFalse("Expected the token to be invalid because it in an unknown
token.",
- doTestIsStillValid(tss));
+ doTestIsStillValid(tss);
}
private boolean doTestIsStillValid(final Long expiration) throws Exception {
@@ -163,7 +164,16 @@ public class CommonJWTFilterTest {
Method m = AbstractJWTFilter.class.getDeclaredMethod("tokenIsStillValid",
JWT.class);
m.setAccessible(true);
- return (Boolean) m.invoke(handler, jwt);
+ try {
+ return (Boolean) m.invoke(handler, jwt);
+ } catch (InvocationTargetException e) {
+ Throwable cause = e.getCause();
+ if (cause instanceof Exception) {
+ throw (Exception) cause;
+ } else {
+ throw e;
+ }
+ }
}
static final class TestHandler extends AbstractJWTFilter {
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 84a439e..9f6fa1a 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
@@ -20,6 +20,8 @@ import org.apache.knox.gateway.config.GatewayConfig;
import org.apache.knox.gateway.services.ServiceLifecycleException;
import org.apache.knox.gateway.services.security.AliasService;
import org.apache.knox.gateway.services.security.AliasServiceException;
+import org.apache.knox.gateway.services.security.token.TokenUtils;
+import org.apache.knox.gateway.services.security.token.UnknownTokenException;
import java.util.ArrayList;
import java.util.List;
@@ -55,9 +57,9 @@ public class AliasBasedTokenStateService extends
DefaultTokenStateService {
try {
aliasService.addAliasForCluster(AliasService.NO_CLUSTER_NAME, token,
String.valueOf(expiration));
setMaxLifetime(token, issueTime, maxLifetimeDuration);
- log.addedToken(getTokenDisplayText(token),
getTimestampDisplay(expiration));
+ log.addedToken(TokenUtils.getTokenDisplayText(token),
getTimestampDisplay(expiration));
} catch (AliasServiceException e) {
- log.failedToSaveTokenState(getTokenDisplayText(token), e);
+ log.failedToSaveTokenState(TokenUtils.getTokenDisplayText(token), e);
}
}
@@ -68,7 +70,7 @@ public class AliasBasedTokenStateService extends
DefaultTokenStateService {
token + TOKEN_MAX_LIFETIME_POSTFIX,
String.valueOf(issueTime +
maxLifetimeDuration));
} catch (AliasServiceException e) {
- log.failedToSaveTokenState(getTokenDisplayText(token), e);
+ log.failedToSaveTokenState(TokenUtils.getTokenDisplayText(token), e);
}
}
@@ -82,13 +84,13 @@ public class AliasBasedTokenStateService extends
DefaultTokenStateService {
result = Long.parseLong(new String(maxLifetimeStr));
}
} catch (AliasServiceException e) {
- log.errorAccessingTokenState(getTokenDisplayText(token), e);
+ log.errorAccessingTokenState(TokenUtils.getTokenDisplayText(token), e);
}
return result;
}
@Override
- public long getTokenExpiration(final String token) {
+ public long getTokenExpiration(final String token) throws
UnknownTokenException {
long expiration = 0;
validateToken(token);
@@ -99,17 +101,17 @@ public class AliasBasedTokenStateService extends
DefaultTokenStateService {
expiration = Long.parseLong(new String(expStr));
}
} catch (Exception e) {
- log.errorAccessingTokenState(getTokenDisplayText(token), e);
+ log.errorAccessingTokenState(TokenUtils.getTokenDisplayText(token), e);
}
return expiration;
}
@Override
- public void revokeToken(final String token) {
+ public void revokeToken(final String token) throws UnknownTokenException {
/* no reason to keep revoked tokens around */
removeToken(token);
- log.revokedToken(getTokenDisplayText(token));
+ log.revokedToken(TokenUtils.getTokenDisplayText(token));
}
@Override
@@ -118,28 +120,28 @@ public class AliasBasedTokenStateService extends
DefaultTokenStateService {
try {
isUnknown =
(aliasService.getPasswordFromAliasForCluster(AliasService.NO_CLUSTER_NAME,
token) == null);
} catch (AliasServiceException e) {
- log.errorAccessingTokenState(getTokenDisplayText(token), e);
+ log.errorAccessingTokenState(TokenUtils.getTokenDisplayText(token), e);
}
return isUnknown;
}
@Override
- protected void removeToken(final String token) {
+ protected void removeToken(final String token) throws UnknownTokenException {
validateToken(token);
try {
aliasService.removeAliasForCluster(AliasService.NO_CLUSTER_NAME, token);
aliasService.removeAliasForCluster(AliasService.NO_CLUSTER_NAME,token +
TOKEN_MAX_LIFETIME_POSTFIX);
- log.removedTokenState(getTokenDisplayText(token));
+ log.removedTokenState(TokenUtils.getTokenDisplayText(token));
} catch (AliasServiceException e) {
- log.failedToRemoveTokenState(getTokenDisplayText(token), e);
+ log.failedToRemoveTokenState(TokenUtils.getTokenDisplayText(token), e);
}
}
@Override
protected void updateExpiration(final String token, long expiration) {
if (isUnknown(token)) {
- log.unknownToken(getTokenDisplayText(token));
+ log.unknownToken(TokenUtils.getTokenDisplayText(token));
throw new IllegalArgumentException("Unknown token.");
}
@@ -147,7 +149,7 @@ public class AliasBasedTokenStateService extends
DefaultTokenStateService {
aliasService.removeAliasForCluster(AliasService.NO_CLUSTER_NAME, token);
aliasService.addAliasForCluster(AliasService.NO_CLUSTER_NAME, token,
String.valueOf(expiration));
} catch (AliasServiceException e) {
- log.failedToUpdateTokenExpiration(getTokenDisplayText(token), e);
+ log.failedToUpdateTokenExpiration(TokenUtils.getTokenDisplayText(token),
e);
}
}
diff --git
a/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/DefaultTokenStateService.java
b/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/DefaultTokenStateService.java
index b4b7681..13b728c 100644
---
a/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/DefaultTokenStateService.java
+++
b/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/DefaultTokenStateService.java
@@ -20,12 +20,13 @@ import org.apache.knox.gateway.config.GatewayConfig;
import org.apache.knox.gateway.i18n.messages.MessagesFactory;
import org.apache.knox.gateway.services.ServiceLifecycleException;
import org.apache.knox.gateway.services.security.token.TokenStateService;
+import org.apache.knox.gateway.services.security.token.TokenUtils;
+import org.apache.knox.gateway.services.security.token.UnknownTokenException;
import org.apache.knox.gateway.services.security.token.impl.JWTToken;
import java.time.Instant;
import java.util.HashMap;
import java.util.List;
-import java.util.Locale;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@@ -111,11 +112,11 @@ public class DefaultTokenStateService implements
TokenStateService {
tokenExpirations.put(token, expiration);
}
setMaxLifetime(token, issueTime, maxLifetimeDuration);
- log.addedToken(getTokenDisplayText(token),
getTimestampDisplay(expiration));
+ log.addedToken(TokenUtils.getTokenDisplayText(token),
getTimestampDisplay(expiration));
}
@Override
- public long getTokenExpiration(final String token) {
+ public long getTokenExpiration(final String token) throws
UnknownTokenException {
long expiration;
validateToken(token);
@@ -128,12 +129,12 @@ public class DefaultTokenStateService implements
TokenStateService {
}
@Override
- public long renewToken(final JWTToken token) {
+ public long renewToken(final JWTToken token) throws UnknownTokenException {
return renewToken(token, DEFAULT_RENEWAL_INTERVAL);
}
@Override
- public long renewToken(final JWTToken token, long renewInterval) {
+ public long renewToken(final JWTToken token, long renewInterval) throws
UnknownTokenException {
if (token == null) {
throw new IllegalArgumentException("Token data cannot be null.");
}
@@ -141,12 +142,12 @@ public class DefaultTokenStateService implements
TokenStateService {
}
@Override
- public long renewToken(final String token) { // Should return new expiration?
+ public long renewToken(final String token) throws UnknownTokenException {
return renewToken(token, DEFAULT_RENEWAL_INTERVAL);
}
@Override
- public long renewToken(final String token, long renewInterval) {
+ public long renewToken(final String token, long renewInterval) throws
UnknownTokenException {
long expiration;
validateToken(token);
@@ -155,7 +156,7 @@ public class DefaultTokenStateService implements
TokenStateService {
if (hasRemainingRenewals(token, renewInterval)) {
expiration = System.currentTimeMillis() + renewInterval;
updateExpiration(token, expiration);
- log.renewedToken(getTokenDisplayText(token),
getTimestampDisplay(expiration));
+ log.renewedToken(TokenUtils.getTokenDisplayText(token),
getTimestampDisplay(expiration));
} else {
log.renewalLimitExceeded(token);
throw new IllegalArgumentException("The renewal limit for the token has
been exceeded");
@@ -165,7 +166,7 @@ public class DefaultTokenStateService implements
TokenStateService {
}
@Override
- public void revokeToken(final JWTToken token) {
+ public void revokeToken(final JWTToken token) throws UnknownTokenException {
if (token == null) {
throw new IllegalArgumentException("Token data cannot be null.");
}
@@ -174,19 +175,19 @@ public class DefaultTokenStateService implements
TokenStateService {
}
@Override
- public void revokeToken(final String token) {
+ public void revokeToken(final String token) throws UnknownTokenException {
/* no reason to keep revoked tokens around */
removeToken(token);
- log.revokedToken(getTokenDisplayText(token));
+ log.revokedToken(TokenUtils.getTokenDisplayText(token));
}
@Override
- public boolean isExpired(final JWTToken token) {
+ public boolean isExpired(final JWTToken token) throws UnknownTokenException {
return isExpired(token.getPayload());
}
@Override
- public boolean isExpired(final String token) {
+ public boolean isExpired(final String token) throws UnknownTokenException {
boolean isExpired;
isExpired = isUnknown(token); // Check if the token exist
if (!isExpired) {
@@ -222,7 +223,7 @@ public class DefaultTokenStateService implements
TokenStateService {
}
}
- protected void removeToken(final String token) {
+ protected void removeToken(final String token) throws UnknownTokenException {
validateToken(token);
synchronized (tokenExpirations) {
tokenExpirations.remove(token);
@@ -230,7 +231,7 @@ public class DefaultTokenStateService implements
TokenStateService {
synchronized (maxTokenLifetimes) {
maxTokenLifetimes.remove(token);
}
- log.removedTokenState(getTokenDisplayText(token));
+ log.removedTokenState(TokenUtils.getTokenDisplayText(token));
}
protected boolean hasRemainingRenewals(final String token, long
renewInterval) {
@@ -256,23 +257,20 @@ public class DefaultTokenStateService implements
TokenStateService {
* @param token The token identifier to validate.
*
* @throws IllegalArgumentException if the specified token in invalid.
+ * @throws UnknownTokenException if the specified token in valid, but not
known to the service.
*/
- protected void validateToken(final String token) throws
IllegalArgumentException {
+ protected void validateToken(final String token) throws
IllegalArgumentException, UnknownTokenException {
if (!isValidIdentifier(token)) {
throw new IllegalArgumentException("Token data cannot be null.");
}
// First, make sure the token is one we know about
if (isUnknown(token)) {
- log.unknownToken(getTokenDisplayText(token));
- throw new IllegalArgumentException("Unknown token");
+ log.unknownToken(TokenUtils.getTokenDisplayText(token));
+ throw new UnknownTokenException(token);
}
}
- protected String getTokenDisplayText(final String token) {
- return String.format(Locale.ROOT, "%s...%s", token.substring(0, 10),
token.substring(token.length() - 3));
- }
-
protected String getTimestampDisplay(long timestamp) {
return Instant.ofEpochMilli(timestamp).toString();
}
@@ -284,11 +282,11 @@ public class DefaultTokenStateService implements
TokenStateService {
for (final String token : getTokens()) {
try {
if (needsEviction(token)) {
- log.evictToken(getTokenDisplayText(token));
+ log.evictToken(TokenUtils.getTokenDisplayText(token));
removeToken(token);
}
} catch (final Exception e) {
- log.failedExpiredTokenEviction(getTokenDisplayText(token), e);
+ log.failedExpiredTokenEviction(TokenUtils.getTokenDisplayText(token),
e);
}
}
}
@@ -299,7 +297,7 @@ public class DefaultTokenStateService implements
TokenStateService {
* @param token
* @return
*/
- protected boolean needsEviction(final String token) {
+ protected boolean needsEviction(final String token) throws
UnknownTokenException {
return ((getTokenExpiration(token) +
TimeUnit.SECONDS.toMillis(tokenEvictionGracePeriod)) <=
System.currentTimeMillis());
}
diff --git
a/gateway-server/src/test/java/org/apache/knox/gateway/services/token/impl/DefaultTokenStateServiceTest.java
b/gateway-server/src/test/java/org/apache/knox/gateway/services/token/impl/DefaultTokenStateServiceTest.java
index ce32e3d..44eaa19 100644
---
a/gateway-server/src/test/java/org/apache/knox/gateway/services/token/impl/DefaultTokenStateServiceTest.java
+++
b/gateway-server/src/test/java/org/apache/knox/gateway/services/token/impl/DefaultTokenStateServiceTest.java
@@ -19,6 +19,8 @@ package org.apache.knox.gateway.services.token.impl;
import org.apache.knox.gateway.config.GatewayConfig;
import org.apache.knox.gateway.services.ServiceLifecycleException;
import org.apache.knox.gateway.services.security.token.TokenStateService;
+import org.apache.knox.gateway.services.security.token.TokenUtils;
+import org.apache.knox.gateway.services.security.token.UnknownTokenException;
import org.apache.knox.gateway.services.security.token.impl.JWTToken;
import org.easymock.EasyMock;
import org.junit.Test;
@@ -38,7 +40,7 @@ public class DefaultTokenStateServiceTest {
private static long EVICTION_INTERVAL = 2L;
@Test
- public void testGetExpiration() {
+ public void testGetExpiration() throws Exception {
final JWTToken token = createMockToken(System.currentTimeMillis() + 60000);
final TokenStateService tss = createTokenStateService();
@@ -48,27 +50,27 @@ public class DefaultTokenStateServiceTest {
}
@Test(expected = IllegalArgumentException.class)
- public void testGetExpiration_NullToken() {
+ public void testGetExpiration_NullToken() throws Exception {
// Expecting an IllegalArgumentException because the token is null
createTokenStateService().getTokenExpiration(null);
}
@Test(expected = IllegalArgumentException.class)
- public void testGetExpiration_EmptyToken() {
+ public void testGetExpiration_EmptyToken() throws Exception {
// Expecting an IllegalArgumentException because the token is empty
createTokenStateService().getTokenExpiration("");
}
- @Test(expected = IllegalArgumentException.class)
- public void testGetExpiration_InvalidToken() {
+ @Test(expected = UnknownTokenException.class)
+ public void testGetExpiration_InvalidToken() throws Exception {
final JWTToken token = createMockToken(System.currentTimeMillis() + 60000);
- // Expecting an IllegalArgumentException because the token is not known to
the TokenStateService
+ // Expecting an UnknownTokenException because the token is not known to
the TokenStateService
createTokenStateService().getTokenExpiration(token.getPayload());
}
@Test
- public void testGetExpiration_AfterRenewal() {
+ public void testGetExpiration_AfterRenewal() throws Exception {
final JWTToken token = createMockToken(System.currentTimeMillis() + 60000);
final TokenStateService tss = createTokenStateService();
@@ -82,7 +84,7 @@ public class DefaultTokenStateServiceTest {
}
@Test
- public void testIsExpired_Negative() {
+ public void testIsExpired_Negative() throws Exception {
final JWTToken token = createMockToken(System.currentTimeMillis() + 60000);
final TokenStateService tss = createTokenStateService();
@@ -91,7 +93,7 @@ public class DefaultTokenStateServiceTest {
}
@Test
- public void testIsExpired_Positive() {
+ public void testIsExpired_Positive() throws Exception {
final JWTToken token = createMockToken(System.currentTimeMillis() - 60000);
final TokenStateService tss = createTokenStateService();
@@ -101,7 +103,7 @@ public class DefaultTokenStateServiceTest {
@Test
- public void testIsExpired_Revoked() {
+ public void testIsExpired_Revoked() throws Exception {
final JWTToken token = createMockToken(System.currentTimeMillis() + 60000);
final TokenStateService tss = createTokenStateService();
@@ -114,7 +116,7 @@ public class DefaultTokenStateServiceTest {
@Test
- public void testRenewal() {
+ public void testRenewal() throws Exception {
final JWTToken token = createMockToken(System.currentTimeMillis() - 60000);
final TokenStateService tss = createTokenStateService();
@@ -128,7 +130,7 @@ public class DefaultTokenStateServiceTest {
@Test
- public void testRenewalBeyondMaxLifetime() {
+ public void testRenewalBeyondMaxLifetime() throws Exception {
long issueTime = System.currentTimeMillis();
long expiration = issueTime + 5000;
final JWTToken token = createMockToken(expiration);
@@ -148,7 +150,7 @@ public class DefaultTokenStateServiceTest {
}
@Test
- public void testNegativeTokenEviction() throws InterruptedException {
+ public void testNegativeTokenEviction() throws InterruptedException,
UnknownTokenException {
final JWTToken token = createMockToken(System.currentTimeMillis() - 60000);
final TokenStateService tss = createTokenStateService();
@@ -164,7 +166,7 @@ public class DefaultTokenStateServiceTest {
@Test
public void testTokenEviction()
- throws InterruptedException, ServiceLifecycleException {
+ throws InterruptedException, ServiceLifecycleException,
UnknownTokenException {
final JWTToken token = createMockToken(System.currentTimeMillis() - 60000);
final TokenStateService tss = createTokenStateService();
try {
@@ -176,8 +178,8 @@ public class DefaultTokenStateServiceTest {
Thread.sleep(TimeUnit.SECONDS.toMillis(EVICTION_INTERVAL + 1));
/* expect the renew call to fail since the token is evicted */
- final IllegalArgumentException e =
assertThrows(IllegalArgumentException.class, () -> tss.renewToken(token));
- assertEquals("Unknown token", e.getMessage());
+ final UnknownTokenException e =
assertThrows(UnknownTokenException.class, () -> tss.renewToken(token));
+ assertEquals("Unknown token: " +
TokenUtils.getTokenDisplayText(token.getPayload()), e.getMessage());
} finally {
tss.stop();
}
diff --git
a/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/TokenResource.java
b/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/TokenResource.java
index 70cd59d..01c3073 100644
---
a/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/TokenResource.java
+++
b/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/TokenResource.java
@@ -50,6 +50,7 @@ import
org.apache.knox.gateway.services.security.KeystoreServiceException;
import org.apache.knox.gateway.services.security.token.JWTokenAuthority;
import org.apache.knox.gateway.services.security.token.TokenServiceException;
import org.apache.knox.gateway.services.security.token.TokenStateService;
+import org.apache.knox.gateway.services.security.token.UnknownTokenException;
import org.apache.knox.gateway.services.security.token.impl.JWT;
import org.apache.knox.gateway.util.JsonUtils;
@@ -287,7 +288,7 @@ public class TokenResource {
if (allowedRenewers.contains(renewer)) {
try {
tokenStateService.revokeToken(token);
- } catch (IllegalArgumentException e) {
+ } catch (UnknownTokenException e) {
error = e.getMessage();
}
} else {
diff --git
a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/TokenStateService.java
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/TokenStateService.java
index dc0b736..4de9295 100644
---
a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/TokenStateService.java
+++
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/TokenStateService.java
@@ -69,7 +69,7 @@ public interface TokenStateService extends Service {
*
* @return true, if the token has expired; Otherwise, false.
*/
- boolean isExpired(JWTToken token);
+ boolean isExpired(JWTToken token) throws UnknownTokenException;
/**
*
@@ -77,21 +77,21 @@ public interface TokenStateService extends Service {
*
* @return true, if the token has expired; Otherwise, false.
*/
- boolean isExpired(String token);
+ boolean isExpired(String token) throws UnknownTokenException;
/**
* Disable any subsequent use of the specified token.
*
* @param token The token.
*/
- void revokeToken(JWTToken token);
+ void revokeToken(JWTToken token) throws UnknownTokenException;
/**
* Disable any subsequent use of the specified token.
*
* @param token The token.
*/
- void revokeToken(String token);
+ void revokeToken(String token) throws UnknownTokenException;
/**
* Extend the lifetime of the specified token by the default amount of time.
@@ -100,7 +100,7 @@ public interface TokenStateService extends Service {
*
* @return The token's updated expiration time in milliseconds.
*/
- long renewToken(JWTToken token);
+ long renewToken(JWTToken token) throws UnknownTokenException;
/**
* Extend the lifetime of the specified token by the specified amount of
time.
@@ -110,7 +110,7 @@ public interface TokenStateService extends Service {
*
* @return The token's updated expiration time in milliseconds.
*/
- long renewToken(JWTToken token, long renewInterval);
+ long renewToken(JWTToken token, long renewInterval) throws
UnknownTokenException;
/**
* Extend the lifetime of the specified token by the default amount of time.
@@ -119,7 +119,7 @@ public interface TokenStateService extends Service {
*
* @return The token's updated expiration time in milliseconds.
*/
- long renewToken(String token);
+ long renewToken(String token) throws UnknownTokenException;
/**
* Extend the lifetime of the specified token by the specified amount of
time.
@@ -129,7 +129,7 @@ public interface TokenStateService extends Service {
*
* @return The token's updated expiration time in milliseconds.
*/
- long renewToken(String token, long renewInterval);
+ long renewToken(String token, long renewInterval) throws
UnknownTokenException;
/**
*
@@ -137,6 +137,6 @@ public interface TokenStateService extends Service {
*
* @return The token's expiration time in milliseconds.
*/
- long getTokenExpiration(String token);
+ long getTokenExpiration(String token) throws UnknownTokenException;
}
diff --git
a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/TokenUtils.java
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/TokenUtils.java
new file mode 100644
index 0000000..ab630c0
--- /dev/null
+++
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/TokenUtils.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you 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 org.apache.knox.gateway.services.security.token;
+
+import java.util.Locale;
+
+public class TokenUtils {
+
+ public static String getTokenDisplayText(final String token) {
+ return String.format(Locale.ROOT, "%s...%s", token.substring(0, 10),
token.substring(token.length() - 3));
+ }
+
+}
diff --git
a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/UnknownTokenException.java
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/UnknownTokenException.java
new file mode 100644
index 0000000..265e878
--- /dev/null
+++
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/UnknownTokenException.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you 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 org.apache.knox.gateway.services.security.token;
+
+public class UnknownTokenException extends Exception {
+
+ private String token;
+
+ public UnknownTokenException(final String token) {
+ this.token = token;
+ }
+
+ public String getToken() {
+ return token;
+ }
+
+ @Override
+ public String getMessage() {
+ return "Unknown token: " + TokenUtils.getTokenDisplayText(token);
+ }
+
+}