knox-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pzamp...@apache.org
Subject [knox] branch master updated: KNOX-2230 - Token State Service should throw UnknownTokenException instead of IllegalArgumentException (#268)
Date Thu, 20 Feb 2020 20:40:35 GMT
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 <pzampino@apache.org>
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);
+  }
+
+}


Mime
View raw message