Repository: knox
Updated Branches:
  refs/heads/master 9c7aa7e1c -> bb467b8c4


KNOX-1082 - Add support to validate the "nbf" claim for JWTs


Project: http://git-wip-us.apache.org/repos/asf/knox/repo
Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/bb467b8c
Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/bb467b8c
Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/bb467b8c

Branch: refs/heads/master
Commit: bb467b8c4ecd87fc83ec1cf2863767b0330f171e
Parents: 9c7aa7e
Author: Colm O hEigeartaigh <cohei...@apache.org>
Authored: Tue Oct 17 12:49:04 2017 +0100
Committer: Colm O hEigeartaigh <cohei...@apache.org>
Committed: Tue Oct 17 12:49:04 2017 +0100

----------------------------------------------------------------------
 .../provider/federation/jwt/JWTMessages.java    |  3 ++
 .../jwt/filter/AbstractJWTFilter.java           |  9 ++++-
 .../federation/AbstractJWTFilterTest.java       | 40 ++++++++++++++++++--
 .../services/security/token/impl/JWT.java       |  3 ++
 .../services/security/token/impl/JWTToken.java  | 11 ++++++
 5 files changed, 61 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/knox/blob/bb467b8c/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/JWTMessages.java
----------------------------------------------------------------------
diff --git 
a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/JWTMessages.java
 
b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/JWTMessages.java
index f6969c6..f38d13b 100644
--- 
a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/JWTMessages.java
+++ 
b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/JWTMessages.java
@@ -34,6 +34,9 @@ public interface JWTMessages {
   @Message( level = MessageLevel.INFO, text = "Access token has expired; a new 
one must be acquired." )
   void tokenHasExpired();
 
+  @Message( level = MessageLevel.INFO, text = "The NotBefore check failed." )
+  void notBeforeCheckFailed();
+
   @Message( level = MessageLevel.WARN, text = "Expected Bearer token is 
missing." )
   void missingBearerToken();
 

http://git-wip-us.apache.org/repos/asf/knox/blob/bb467b8c/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/AbstractJWTFilter.java
----------------------------------------------------------------------
diff --git 
a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/AbstractJWTFilter.java
 
b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/AbstractJWTFilter.java
index deb3d5b..0d8ecb8 100644
--- 
a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/AbstractJWTFilter.java
+++ 
b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/AbstractJWTFilter.java
@@ -275,7 +275,14 @@ public abstract class AbstractJWTFilter implements Filter {
         if (tokenIsStillValid(token)) {
           boolean audValid = validateAudiences(token);
           if (audValid) {
-            return true;
+              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();

http://git-wip-us.apache.org/repos/asf/knox/blob/bb467b8c/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/AbstractJWTFilterTest.java
----------------------------------------------------------------------
diff --git 
a/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/AbstractJWTFilterTest.java
 
b/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/AbstractJWTFilterTest.java
index b261081..54c596b 100644
--- 
a/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/AbstractJWTFilterTest.java
+++ 
b/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/AbstractJWTFilterTest.java
@@ -505,7 +505,7 @@ public abstract class AbstractJWTFilterTest  {
       handler.init(new TestFilterConfig(props));
 
       SignedJWT jwt = getJWT(AbstractJWTFilter.JWT_DEFAULT_ISSUER, "alice", 
new Date(new Date().getTime() + 5000),
-                             privateKey, JWSAlgorithm.RS512.getName());
+                             new Date(), privateKey, 
JWSAlgorithm.RS512.getName());
 
       HttpServletRequest request = 
EasyMock.createNiceMock(HttpServletRequest.class);
       setTokenOnRequest(request, jwt);
@@ -536,7 +536,7 @@ public abstract class AbstractJWTFilterTest  {
       handler.init(new TestFilterConfig(props));
 
       SignedJWT jwt = getJWT(AbstractJWTFilter.JWT_DEFAULT_ISSUER, "alice", 
new Date(new Date().getTime() + 5000),
-                             privateKey, JWSAlgorithm.RS384.getName());
+                             new Date(), privateKey, 
JWSAlgorithm.RS384.getName());
 
       HttpServletRequest request = 
EasyMock.createNiceMock(HttpServletRequest.class);
       setTokenOnRequest(request, jwt);
@@ -558,6 +558,37 @@ public abstract class AbstractJWTFilterTest  {
     }
   }
 
+  @Test
+  public void testNotBeforeJWT() throws Exception {
+    try {
+      Properties props = getProperties();
+      handler.init(new TestFilterConfig(props));
+
+      SignedJWT jwt = getJWT(AbstractJWTFilter.JWT_DEFAULT_ISSUER, "alice",
+                             new Date(new Date().getTime() + 5000),
+                             new Date(new Date().getTime() + 5000), privateKey,
+                             JWSAlgorithm.RS256.getName());
+
+      HttpServletRequest request = 
EasyMock.createNiceMock(HttpServletRequest.class);
+      setTokenOnRequest(request, jwt);
+
+      EasyMock.expect(request.getRequestURL()).andReturn(
+          new StringBuffer(SERVICE_URL)).anyTimes();
+      EasyMock.expect(request.getQueryString()).andReturn(null);
+      HttpServletResponse response = 
EasyMock.createNiceMock(HttpServletResponse.class);
+      EasyMock.expect(response.encodeRedirectURL(SERVICE_URL)).andReturn(
+          SERVICE_URL);
+      EasyMock.replay(request);
+
+      TestFilterChain chain = new TestFilterChain();
+      handler.doFilter(request, response, chain);
+      Assert.assertTrue("doFilterCalled should not be false.", 
!chain.doFilterCalled);
+      Assert.assertTrue("No Subject should be returned.", chain.subject == 
null);
+    } catch (ServletException se) {
+      fail("Should NOT have thrown a ServletException.");
+    }
+  }
+
   protected Properties getProperties() {
     Properties props = new Properties();
     props.setProperty(
@@ -568,10 +599,10 @@ public abstract class AbstractJWTFilterTest  {
 
   protected SignedJWT getJWT(String issuer, String sub, Date expires, 
RSAPrivateKey privateKey)
       throws Exception {
-    return getJWT(issuer, sub, expires, privateKey, 
JWSAlgorithm.RS256.getName());
+    return getJWT(issuer, sub, expires, new Date(), privateKey, 
JWSAlgorithm.RS256.getName());
   }
 
-  protected SignedJWT getJWT(String issuer, String sub, Date expires, 
RSAPrivateKey privateKey,
+  protected SignedJWT getJWT(String issuer, String sub, Date expires, Date 
nbf, RSAPrivateKey privateKey,
                              String signatureAlgorithm)
       throws Exception {
     List<String> aud = new ArrayList<String>();
@@ -582,6 +613,7 @@ public abstract class AbstractJWTFilterTest  {
     .subject(sub)
     .audience(aud)
     .expirationTime(expires)
+    .notBeforeTime(nbf)
     .claim("scope", "openid")
     .build();
 

http://git-wip-us.apache.org/repos/asf/knox/blob/bb467b8c/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/token/impl/JWT.java
----------------------------------------------------------------------
diff --git 
a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/token/impl/JWT.java
 
b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/token/impl/JWT.java
index 1a6f4f9..fa9076e 100644
--- 
a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/token/impl/JWT.java
+++ 
b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/token/impl/JWT.java
@@ -29,6 +29,7 @@ public interface JWT {
   String ISSUER = "iss";
   String AUDIENCE = "aud";
   String EXPIRES = "exp";
+  String NOT_BEFORE = "nbf";
 
   String getPayload();
 
@@ -50,6 +51,8 @@ public interface JWT {
 
   Date getExpiresDate();
 
+  Date getNotBeforeDate();
+
   String getSubject();
 
   String getHeader();

http://git-wip-us.apache.org/repos/asf/knox/blob/bb467b8c/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/token/impl/JWTToken.java
----------------------------------------------------------------------
diff --git 
a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/token/impl/JWTToken.java
 
b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/token/impl/JWTToken.java
index be2a331..f985caf 100644
--- 
a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/token/impl/JWTToken.java
+++ 
b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/token/impl/JWTToken.java
@@ -231,6 +231,17 @@ public class JWTToken implements JWT {
     return date;
   }
 
+  @Override
+  public Date getNotBeforeDate() {
+    Date date = null;
+    try {
+      date = jwt.getJWTClaimsSet().getNotBeforeTime();
+    } catch (ParseException e) {
+      log.unableToParseToken(e);
+    }
+    return date;
+  }
+
   /* (non-Javadoc)
    * @see 
org.apache.hadoop.gateway.services.security.token.impl.JWT#getPrincipal()
    */

Reply via email to