You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by co...@apache.org on 2017/09/08 08:58:51 UTC

knox git commit: KNOX-1027 - Add support to configure the issuer for the JWT filters

Repository: knox
Updated Branches:
  refs/heads/master 5f413f35e -> ca9247f4d


KNOX-1027 - Add support to configure the issuer for the JWT filters


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

Branch: refs/heads/master
Commit: ca9247f4d06eaeb8eb24b1696fd5a7b80cb13340
Parents: 5f413f3
Author: Colm O hEigeartaigh <co...@apache.org>
Authored: Thu Sep 7 10:14:20 2017 +0100
Committer: Colm O hEigeartaigh <co...@apache.org>
Committed: Fri Sep 8 09:58:27 2017 +0100

----------------------------------------------------------------------
 .../jwt/filter/AbstractJWTFilter.java           | 26 ++++++--
 .../jwt/filter/JWTFederationFilter.java         |  8 ++-
 .../jwt/filter/SSOCookieFederationFilter.java   |  6 +-
 .../federation/AbstractJWTFilterTest.java       | 66 +++++++++++++++++++-
 4 files changed, 95 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/knox/blob/ca9247f4/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 e938480..d4c6717 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
@@ -60,15 +60,24 @@ import org.apache.hadoop.gateway.services.security.token.impl.JWTToken;
  *
  */
 public abstract class AbstractJWTFilter implements Filter {
+  /**
+   * If specified, this configuration property refers to a value which the issuer of a received
+   * token must match. Otherwise, the default value "KNOXSSO" is used
+   */
+  public static final String JWT_EXPECTED_ISSUER = "jwt.expected.issuer";
+  public static final String JWT_DEFAULT_ISSUER = "KNOXSSO";
+
   static JWTMessages log = MessagesFactory.get( JWTMessages.class );
-  protected List<String> audiences;
-  protected JWTokenAuthority authority;
-  protected RSAPublicKey publicKey = null;
   private static AuditService auditService = AuditServiceFactory.getAuditService();
   private static Auditor auditor = auditService.getAuditor(
       AuditConstants.DEFAULT_AUDITOR_NAME, AuditConstants.KNOX_SERVICE_NAME,
       AuditConstants.KNOX_COMPONENT_NAME );
 
+  protected List<String> audiences;
+  protected JWTokenAuthority authority;
+  protected RSAPublicKey publicKey = null;
+  private String expectedIssuer;
+
   public abstract void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
       throws IOException, ServletException;
 
@@ -90,6 +99,13 @@ public abstract class AbstractJWTFilter implements Filter {
     }
   }
 
+  protected void configureExpectedIssuer(FilterConfig filterConfig) {
+    expectedIssuer = filterConfig.getInitParameter(JWT_EXPECTED_ISSUER);;
+    if (expectedIssuer == null) {
+      expectedIssuer = JWT_DEFAULT_ISSUER;
+    }
+  }
+
   /**
    * @param expectedAudiences
    * @return
@@ -222,8 +238,8 @@ public abstract class AbstractJWTFilter implements Filter {
     }
 
     if (verified) {
-      // confirm that issue matches intended target - which for this filter must be KNOXSSO
-      if (token.getIssuer().equals("KNOXSSO")) {
+      // confirm that issue matches intended target
+      if (expectedIssuer.equals(token.getIssuer())) {
         // 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

http://git-wip-us.apache.org/repos/asf/knox/blob/ca9247f4/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTFederationFilter.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTFederationFilter.java b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTFederationFilter.java
index 2cbccf6..401e449 100644
--- a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTFederationFilter.java
+++ b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTFederationFilter.java
@@ -62,12 +62,14 @@ public class JWTFederationFilter extends AbstractJWTFilter {
     if (verificationPEM != null) {
       publicKey = CertificateUtils.parseRSAPublicKey(verificationPEM);
     }
+
+    configureExpectedIssuer(filterConfig);
   }
 
   public void destroy() {
   }
 
-  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
+  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
       throws IOException, ServletException {
     String header = ((HttpServletRequest) request).getHeader("Authorization");
     String wireToken = null;
@@ -79,7 +81,7 @@ public class JWTFederationFilter extends AbstractJWTFilter {
       // check for query param
       wireToken = ((HttpServletRequest) request).getParameter(paramName);
     }
-    
+
     if (wireToken != null) {
       try {
         JWTToken token = new JWTToken(wireToken);
@@ -100,7 +102,7 @@ public class JWTFederationFilter extends AbstractJWTFilter {
   protected void handleValidationError(HttpServletRequest request, HttpServletResponse response, int status,
                                        String error) throws IOException {
     if (error != null) {
-      response.sendError(status, error);   
+      response.sendError(status, error);
     }
     else {
       response.sendError(status);

http://git-wip-us.apache.org/repos/asf/knox/blob/ca9247f4/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/SSOCookieFederationFilter.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/SSOCookieFederationFilter.java b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/SSOCookieFederationFilter.java
index 2e37c76..cf14863 100644
--- a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/SSOCookieFederationFilter.java
+++ b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/SSOCookieFederationFilter.java
@@ -51,7 +51,7 @@ public class SSOCookieFederationFilter extends AbstractJWTFilter {
   @Override
   public void init( FilterConfig filterConfig ) throws ServletException {
     super.init(filterConfig);
-    
+
     // configured cookieName
     cookieName = filterConfig.getInitParameter(SSO_COOKIE_NAME);
     if (cookieName == null) {
@@ -77,13 +77,15 @@ public class SSOCookieFederationFilter extends AbstractJWTFilter {
     if (verificationPEM != null) {
       publicKey = CertificateUtils.parseRSAPublicKey(verificationPEM);
     }
+
+    configureExpectedIssuer(filterConfig);
   }
 
   public void destroy() {
   }
 
   @Override
-  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
+  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
       throws IOException, ServletException {
     String wireToken = null;
     HttpServletRequest req = (HttpServletRequest) request;

http://git-wip-us.apache.org/repos/asf/knox/blob/ca9247f4/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 1893647..6f221a9 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
@@ -400,6 +400,65 @@ public abstract class AbstractJWTFilterTest  {
     }
   }
 
+  @Test
+  public void testInvalidIssuer() throws Exception {
+    try {
+      Properties props = getProperties();
+      handler.init(new TestFilterConfig(props));
+
+      SignedJWT jwt = getJWT("new-issuer", "alice", new Date(new Date().getTime() + 5000), privateKey);
+
+      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 true.", !chain.doFilterCalled);
+      Assert.assertTrue("No Subject should be returned.", chain.subject == null);
+    } catch (ServletException se) {
+      fail("Should NOT have thrown a ServletException.");
+    }
+  }
+
+  @Test
+  public void testValidIssuerViaConfig() throws Exception {
+    try {
+      Properties props = getProperties();
+      props.setProperty(AbstractJWTFilter.JWT_EXPECTED_ISSUER, "new-issuer");
+      handler.init(new TestFilterConfig(props));
+
+      SignedJWT jwt = getJWT("new-issuer", "alice", new Date(new Date().getTime() + 5000), privateKey);
+
+      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);
+      Set<PrimaryPrincipal> principals = chain.subject.getPrincipals(PrimaryPrincipal.class);
+      Assert.assertTrue("No PrimaryPrincipal", principals.size() > 0);
+      Assert.assertEquals("Not the expected principal", "alice", ((Principal)principals.toArray()[0]).getName());
+    } catch (ServletException se) {
+      fail("Should NOT have thrown a ServletException.");
+    }
+  }
+
   protected Properties getProperties() {
     Properties props = new Properties();
     props.setProperty(
@@ -410,11 +469,16 @@ public abstract class AbstractJWTFilterTest  {
 
   protected SignedJWT getJWT(String sub, Date expires, RSAPrivateKey privateKey,
       Properties props) throws Exception {
+    return getJWT(AbstractJWTFilter.JWT_DEFAULT_ISSUER, sub, expires, privateKey);
+  }
+
+  protected SignedJWT getJWT(String issuer, String sub, Date expires, RSAPrivateKey privateKey)
+      throws Exception {
     List<String> aud = new ArrayList<String>();
     aud.add("bar");
 
     JWTClaimsSet claims = new JWTClaimsSet.Builder()
-    .issuer("KNOXSSO")
+    .issuer(issuer)
     .subject(sub)
     .audience(aud)
     .expirationTime(expires)