knox-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From lmc...@apache.org
Subject knox git commit: KNOX-947 - SSOCookieProvider to be configurable for signature verification key/PEM
Date Sat, 03 Jun 2017 17:15:28 GMT
Repository: knox
Updated Branches:
  refs/heads/master 947efa214 -> ebdb1d793


KNOX-947 - SSOCookieProvider to be configurable for signature verification key/PEM

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

Branch: refs/heads/master
Commit: ebdb1d793c33ac67962dbe712167dd328cc7d010
Parents: 947efa2
Author: Larry McCay <lmccay@hortonworks.com>
Authored: Sat Jun 3 13:14:32 2017 -0400
Committer: Larry McCay <lmccay@hortonworks.com>
Committed: Sat Jun 3 13:14:52 2017 -0400

----------------------------------------------------------------------
 .../jwt/filter/AbstractJWTFilter.java           | 16 +++-
 .../jwt/filter/JWTFederationFilter.java         |  8 ++
 .../jwt/filter/SSOCookieFederationFilter.java   |  9 ++
 .../federation/AbstractJWTFilterTest.java       | 93 +++++++++++++++++---
 .../federation/JWTFederationFilterTest.java     |  5 ++
 .../federation/SSOCookieProviderTest.java       |  8 +-
 .../impl/DefaultTokenAuthorityService.java      | 14 ++-
 .../security/token/JWTokenAuthority.java        |  4 +
 .../hadoop/gateway/util/CertificateUtils.java   | 65 ++++++++++++++
 9 files changed, 201 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/knox/blob/ebdb1d79/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 16862ee..d887340 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
@@ -21,6 +21,7 @@ import java.io.IOException;
 import java.security.Principal;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
+import java.security.interfaces.RSAPublicKey;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashSet;
@@ -53,6 +54,8 @@ public abstract class AbstractJWTFilter implements Filter {
   static JWTMessages log = MessagesFactory.get( JWTMessages.class );
   protected List<String> audiences;
   protected JWTokenAuthority authority;
+  protected String verificationPEM = null;
+  protected RSAPublicKey publicKey = null;
 
   public abstract void doFilter(ServletRequest request, ServletResponse response, FilterChain
chain)
       throws IOException, ServletException;
@@ -63,7 +66,7 @@ public abstract class AbstractJWTFilter implements Filter {
   public AbstractJWTFilter() {
     super();
   }
-  
+
   @Override
   public void init( FilterConfig filterConfig ) throws ServletException {
     ServletContext context = filterConfig.getServletContext();
@@ -94,13 +97,13 @@ public abstract class AbstractJWTFilter implements Filter {
   }
 
   protected boolean tokenIsStillValid(JWTToken jwtToken) {
-    // if there is no expiration data then the lifecycle is tied entirely to
+    // if there is no expiration date then the lifecycle is tied entirely to
     // the cookie validity - otherwise ensure that the current time is before
     // the designated expiration time
     Date expires = jwtToken.getExpiresDate();
     return (expires == null || expires != null && new Date().before(expires));
   }
-  
+
   /**
    * Validate whether any of the accepted audience claims is present in the
    * issued token claims list for audience. Override this method in subclasses
@@ -186,7 +189,12 @@ public abstract class AbstractJWTFilter implements Filter {
       throws IOException, ServletException {
     boolean verified = false;
     try {
-      verified = authority.verifyToken(token);
+      if (publicKey == null) {
+        verified = authority.verifyToken(token);
+      }
+      else {
+        verified = authority.verifyToken(token, publicKey);
+      }
     } catch (TokenServiceException e) {
       log.unableToVerifyToken(e);
     }

http://git-wip-us.apache.org/repos/asf/knox/blob/ebdb1d79/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 e61ff80..2cbccf6 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
@@ -18,6 +18,7 @@
 package org.apache.hadoop.gateway.provider.federation.jwt.filter;
 
 import org.apache.hadoop.gateway.services.security.token.impl.JWTToken;
+import org.apache.hadoop.gateway.util.CertificateUtils;
 
 import javax.security.auth.Subject;
 import javax.servlet.FilterChain;
@@ -34,6 +35,7 @@ import java.text.ParseException;
 public class JWTFederationFilter extends AbstractJWTFilter {
 
   public static final String KNOX_TOKEN_AUDIENCES = "knox.token.audiences";
+  public static final String TOKEN_VERIFICATION_PEM = "knox.token.verification.pem";
   private static final String KNOX_TOKEN_QUERY_PARAM_NAME = "knox.token.query.param.name";
   private static final String BEARER = "Bearer ";
   private String paramName = "knoxtoken";
@@ -54,6 +56,12 @@ public class JWTFederationFilter extends AbstractJWTFilter {
       paramName = queryParamName;
     }
 
+    // token verification pem
+    String verificationPEM = filterConfig.getInitParameter(TOKEN_VERIFICATION_PEM);
+    // setup the public key of the token issuer for verification
+    if (verificationPEM != null) {
+      publicKey = CertificateUtils.parseRSAPublicKey(verificationPEM);
+    }
   }
 
   public void destroy() {

http://git-wip-us.apache.org/repos/asf/knox/blob/ebdb1d79/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 205010c..2e37c76 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
@@ -34,11 +34,13 @@ import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
 import org.apache.hadoop.gateway.provider.federation.jwt.JWTMessages;
 import org.apache.hadoop.gateway.security.PrimaryPrincipal;
 import org.apache.hadoop.gateway.services.security.token.impl.JWTToken;
+import org.apache.hadoop.gateway.util.CertificateUtils;
 
 public class SSOCookieFederationFilter extends AbstractJWTFilter {
   public static final String SSO_COOKIE_NAME = "sso.cookie.name";
   public static final String SSO_EXPECTED_AUDIENCES = "sso.expected.audiences";
   public static final String SSO_AUTHENTICATION_PROVIDER_URL = "sso.authentication.provider.url";
+  public static final String SSO_VERIFICATION_PEM = "sso.token.verification.pem";
   private static JWTMessages log = MessagesFactory.get( JWTMessages.class );
   private static final String ORIGINAL_URL_QUERY_PARAM = "originalUrl=";
   private static final String DEFAULT_SSO_COOKIE_NAME = "hadoop-jwt";
@@ -68,6 +70,13 @@ public class SSOCookieFederationFilter extends AbstractJWTFilter {
       log.missingAuthenticationProviderUrlConfiguration();
       throw new ServletException("Required authentication provider URL is missing.");
     }
+
+    // token verification pem
+    String verificationPEM = filterConfig.getInitParameter(SSO_VERIFICATION_PEM);
+    // setup the public key of the token issuer for verification
+    if (verificationPEM != null) {
+      publicKey = CertificateUtils.parseRSAPublicKey(verificationPEM);
+    }
   }
 
   public void destroy() {

http://git-wip-us.apache.org/repos/asf/knox/blob/ebdb1d79/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 ab6c4bc..58ba3ba 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
@@ -20,13 +20,16 @@ package org.apache.hadoop.gateway.provider.federation;
 import static org.junit.Assert.fail;
 
 import java.io.IOException;
+import java.net.InetAddress;
 import java.security.AccessController;
 import java.security.KeyPair;
 import java.security.KeyPairGenerator;
 import java.security.NoSuchAlgorithmException;
 import java.security.Principal;
+import java.security.cert.Certificate;
 import java.security.interfaces.RSAPrivateKey;
 import java.security.interfaces.RSAPublicKey;
+import java.text.MessageFormat;
 import java.util.Enumeration;
 import java.util.List;
 import java.util.ArrayList;
@@ -44,9 +47,11 @@ import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.commons.codec.binary.Base64;
 import org.apache.hadoop.gateway.provider.federation.jwt.filter.AbstractJWTFilter;
 import org.apache.hadoop.gateway.provider.federation.jwt.filter.SSOCookieFederationFilter;
 import org.apache.hadoop.gateway.security.PrimaryPrincipal;
+import org.apache.hadoop.gateway.services.security.impl.X509CertificateUtil;
 import org.apache.hadoop.gateway.services.security.token.JWTokenAuthority;
 import org.apache.hadoop.gateway.services.security.token.TokenServiceException;
 import org.apache.hadoop.gateway.services.security.token.impl.JWT;
@@ -65,23 +70,39 @@ import com.nimbusds.jose.util.Base64URL;
 
 public abstract class AbstractJWTFilterTest  {
   private static final String SERVICE_URL = "https://localhost:8888/resource";
-  
+  private static final String dnTemplate = "CN={0},OU=Test,O=Hadoop,L=Test,ST=Test,C=US";
+
   protected AbstractJWTFilter handler = null;
   protected RSAPublicKey publicKey = null;
   protected RSAPrivateKey privateKey = null;
+  protected String pem = null;
 
   protected abstract void setTokenOnRequest(HttpServletRequest request, SignedJWT jwt);
   protected abstract void setGarbledTokenOnRequest(HttpServletRequest request, SignedJWT
jwt);
   protected abstract String getAudienceProperty();
+  protected abstract String getVerificationPemProperty();
+
+  private String buildDistinguishedName(String hostname) {
+    MessageFormat headerFormatter = new MessageFormat(dnTemplate);
+    String[] paramArray = new String[1];
+    paramArray[0] = hostname;
+    String dn = headerFormatter.format(paramArray);
+    return dn;
+  }
 
   @Before
   public void setup() throws Exception, NoSuchAlgorithmException {
     KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
     kpg.initialize(2048);
-
-    KeyPair kp = kpg.genKeyPair();
-    publicKey = (RSAPublicKey) kp.getPublic();
-    privateKey = (RSAPrivateKey) kp.getPrivate();
+    KeyPair KPair = kpg.generateKeyPair();
+    String dn = buildDistinguishedName(InetAddress.getLocalHost().getHostName());
+    Certificate cert = X509CertificateUtil.generateCertificate(dn, KPair, 365, "SHA1withRSA");
+    byte[] data = cert.getEncoded();
+    Base64 encoder = new Base64( 76, "\n".getBytes( "ASCII" ) );
+    pem = new String(encoder.encodeToString( data ).getBytes( "ASCII" )).trim();
+
+    publicKey = (RSAPublicKey) KPair.getPublic();
+    privateKey = (RSAPrivateKey) KPair.getPrivate();
   }
 
   @After
@@ -95,7 +116,7 @@ public abstract class AbstractJWTFilterTest  {
       Properties props = getProperties();
       handler.init(new TestFilterConfig(props));
 
-      SignedJWT jwt = getJWT("alice", new Date(new Date().getTime() + 5000), privateKey);
+      SignedJWT jwt = getJWT("alice", new Date(new Date().getTime() + 5000), privateKey,
props);
 
       HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
       setTokenOnRequest(request, jwt);
@@ -126,7 +147,7 @@ public abstract class AbstractJWTFilterTest  {
       props.put(getAudienceProperty(), "bar");
       handler.init(new TestFilterConfig(props));
 
-      SignedJWT jwt = getJWT("alice", new Date(new Date().getTime() + 5000), privateKey);
+      SignedJWT jwt = getJWT("alice", new Date(new Date().getTime() + 5000), privateKey,
props);
 
       HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
       setTokenOnRequest(request, jwt);
@@ -149,15 +170,17 @@ public abstract class AbstractJWTFilterTest  {
       fail("Should NOT have thrown a ServletException.");
     }
   }
-  
+
   @Test
   public void testInvalidAudienceJWT() throws Exception {
     try {
       Properties props = getProperties();
       props.put(getAudienceProperty(), "foo");
+      props.put("sso.authentication.provider.url", "https://localhost:8443/gateway/knoxsso/api/v1/websso");
+
       handler.init(new TestFilterConfig(props));
 
-      SignedJWT jwt = getJWT("alice", new Date(new Date().getTime() + 5000), privateKey);
+      SignedJWT jwt = getJWT("alice", new Date(new Date().getTime() + 5000), privateKey,
props);
 
       HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
       setTokenOnRequest(request, jwt);
@@ -172,7 +195,7 @@ public abstract class AbstractJWTFilterTest  {
 
       TestFilterChain chain = new TestFilterChain();
       handler.doFilter(request, response, chain);
-      Assert.assertTrue("doFilterCalled should not be false.", chain.doFilterCalled == false);
+      Assert.assertTrue("doFilterCalled should not be true.", chain.doFilterCalled == false);
       Assert.assertTrue("No Subject should be returned.", chain.subject == null);
     } catch (ServletException se) {
       fail("Should NOT have thrown a ServletException.");
@@ -180,12 +203,48 @@ public abstract class AbstractJWTFilterTest  {
   }
 
   @Test
+  public void testValidVerificationPEM() throws Exception {
+    try {
+      Properties props = getProperties();
+      
+//      System.out.println("+" + pem + "+");
+
+      props.put(getAudienceProperty(), "bar");
+      props.put("sso.authentication.provider.url", "https://localhost:8443/gateway/knoxsso/api/v1/websso");
+      props.put(getVerificationPemProperty(), pem);
+      handler.init(new TestFilterConfig(props));
+
+      SignedJWT jwt = getJWT("alice", new Date(new Date().getTime() + 50000), privateKey,
props);
+
+      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 == true);
+      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.");
+    }
+  }
+
+  @Test
   public void testExpiredJWT() throws Exception {
     try {
       Properties props = getProperties();
       handler.init(new TestFilterConfig(props));
 
-      SignedJWT jwt = getJWT("alice", new Date(new Date().getTime() - 1000), privateKey);
+      SignedJWT jwt = getJWT("alice", new Date(new Date().getTime() - 1000), privateKey,
props);
 
       HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
       setTokenOnRequest(request, jwt);
@@ -213,7 +272,7 @@ public abstract class AbstractJWTFilterTest  {
       Properties props = getProperties();
       handler.init(new TestFilterConfig(props));
 
-      SignedJWT jwt = getJWT("alice", null, privateKey);
+      SignedJWT jwt = getJWT("alice", null, privateKey, props);
 
       HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
       setTokenOnRequest(request, jwt);
@@ -273,8 +332,8 @@ public abstract class AbstractJWTFilterTest  {
     return props;
   }
 
-  protected SignedJWT getJWT(String sub, Date expires, RSAPrivateKey privateKey)
-      throws Exception {
+  protected SignedJWT getJWT(String sub, Date expires, RSAPrivateKey privateKey,
+      Properties props) throws Exception {
     List<String> aud = new ArrayList<String>();
     aud.add("bar");
 
@@ -403,6 +462,12 @@ public abstract class AbstractJWTFilterTest  {
       // TODO Auto-generated method stub
       return null;
     }
+
+    @Override
+    public boolean verifyToken(JWTToken token, RSAPublicKey publicKey) throws TokenServiceException
{
+      // TODO Auto-generated method stub
+      return true;
+    }
     
   }
   

http://git-wip-us.apache.org/repos/asf/knox/blob/ebdb1d79/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/JWTFederationFilterTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/JWTFederationFilterTest.java
b/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/JWTFederationFilterTest.java
index d1d9b56..8d41423 100644
--- a/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/JWTFederationFilterTest.java
+++ b/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/JWTFederationFilterTest.java
@@ -57,6 +57,11 @@ public class JWTFederationFilterTest extends AbstractJWTFilterTest {
         authority = ts;
       }
         
+    }
+
+    @Override
+    protected String getVerificationPemProperty() {
+      return TestJWTFederationFilter.TOKEN_VERIFICATION_PEM;
     };
     
 }

http://git-wip-us.apache.org/repos/asf/knox/blob/ebdb1d79/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/SSOCookieProviderTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/SSOCookieProviderTest.java
b/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/SSOCookieProviderTest.java
index 98d8207..396aec9 100644
--- a/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/SSOCookieProviderTest.java
+++ b/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/SSOCookieProviderTest.java
@@ -74,7 +74,7 @@ public class SSOCookieProviderTest extends AbstractJWTFilterTest {
       handler.init(new TestFilterConfig(props));
 
       SignedJWT jwt = getJWT("alice", new Date(new Date().getTime() + 5000),
-          privateKey);
+          privateKey, props);
 
       Cookie cookie = new Cookie("jowt", jwt.serialize());
       HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
@@ -185,6 +185,12 @@ public class SSOCookieProviderTest extends AbstractJWTFilterTest {
     Assert.assertNotNull("LoginURL should not be null.", loginURL);
     Assert.assertEquals("https://localhost:8443/authserver?originalUrl=" + SERVICE_URL, loginURL);
   }
+  
+
+  @Override
+  protected String getVerificationPemProperty() {
+    return SSOCookieFederationFilter.SSO_VERIFICATION_PEM;
+  };
 
   private static class TestSSOCookieFederationProvider extends SSOCookieFederationFilter
{
     public String testConstructLoginURL(HttpServletRequest req) {

http://git-wip-us.apache.org/repos/asf/knox/blob/ebdb1d79/gateway-server/src/main/java/org/apache/hadoop/gateway/services/token/impl/DefaultTokenAuthorityService.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/token/impl/DefaultTokenAuthorityService.java
b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/token/impl/DefaultTokenAuthorityService.java
index 26c83fa..fc0a266 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/token/impl/DefaultTokenAuthorityService.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/token/impl/DefaultTokenAuthorityService.java
@@ -161,10 +161,21 @@ public class DefaultTokenAuthorityService implements JWTokenAuthority,
Service {
   @Override
   public boolean verifyToken(JWTToken token)
       throws TokenServiceException {
+    return verifyToken(token, null);
+  }
+
+  @Override
+  public boolean verifyToken(JWTToken token, RSAPublicKey publicKey)
+      throws TokenServiceException {
     boolean rc = false;
     PublicKey key;
     try {
-      key = ks.getSigningKeystore().getCertificate(getSigningKeyAlias()).getPublicKey();
+      if (publicKey == null) {
+        key = ks.getSigningKeystore().getCertificate(getSigningKeyAlias()).getPublicKey();
+      }
+      else {
+        key = publicKey;
+      }
       JWSVerifier verifier = new RSASSAVerifier((RSAPublicKey) key);
       // TODO: interrogate the token for issuer claim in order to determine the public key
to use for verification
       // consider jwk for specifying the key too
@@ -211,5 +222,4 @@ public class DefaultTokenAuthorityService implements JWTokenAuthority,
Service {
   @Override
   public void stop() throws ServiceLifecycleException {
   }
-
 }

http://git-wip-us.apache.org/repos/asf/knox/blob/ebdb1d79/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/token/JWTokenAuthority.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/token/JWTokenAuthority.java
b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/token/JWTokenAuthority.java
index 8cf1676..9cb82ec 100644
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/token/JWTokenAuthority.java
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/token/JWTokenAuthority.java
@@ -18,6 +18,7 @@
 package org.apache.hadoop.gateway.services.security.token;
 
 import java.security.Principal;
+import java.security.interfaces.RSAPublicKey;
 import java.util.List;
 
 import javax.security.auth.Subject;
@@ -38,6 +39,9 @@ public interface JWTokenAuthority {
 
   boolean verifyToken(JWTToken token) throws TokenServiceException;
 
+  boolean verifyToken(JWTToken token, RSAPublicKey publicKey)
+      throws TokenServiceException;
+
   JWTToken issueToken(Principal p, String audience, String algorithm,
       long expires) throws TokenServiceException;
 

http://git-wip-us.apache.org/repos/asf/knox/blob/ebdb1d79/gateway-util-common/src/main/java/org/apache/hadoop/gateway/util/CertificateUtils.java
----------------------------------------------------------------------
diff --git a/gateway-util-common/src/main/java/org/apache/hadoop/gateway/util/CertificateUtils.java
b/gateway-util-common/src/main/java/org/apache/hadoop/gateway/util/CertificateUtils.java
new file mode 100644
index 0000000..b63f7d1
--- /dev/null
+++ b/gateway-util-common/src/main/java/org/apache/hadoop/gateway/util/CertificateUtils.java
@@ -0,0 +1,65 @@
+/**
+ * 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.hadoop.gateway.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.UnsupportedEncodingException;
+import java.security.PublicKey;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.RSAPublicKey;
+
+import javax.servlet.ServletException;
+
+public class CertificateUtils {
+  private static final String PEM_HEADER = "-----BEGIN CERTIFICATE-----\n";
+  private static final String PEM_FOOTER = "\n-----END CERTIFICATE-----";
+
+  /**
+   * Gets an RSAPublicKey from the provided PEM encoding.
+   *
+   * @param pem
+   *          - the pem encoding from config without the header and footer
+   * @return RSAPublicKey
+   */
+  public static RSAPublicKey parseRSAPublicKey(String pem) throws ServletException {
+    String fullPem = PEM_HEADER + pem + PEM_FOOTER;
+    PublicKey key = null;
+    try {
+      CertificateFactory fact = CertificateFactory.getInstance("X.509");
+      ByteArrayInputStream is = new ByteArrayInputStream(
+          fullPem.getBytes("UTF8"));
+
+      X509Certificate cer = (X509Certificate) fact.generateCertificate(is);
+      key = cer.getPublicKey();
+    } catch (CertificateException ce) {
+      String message = null;
+      if (pem.startsWith(PEM_HEADER)) {
+        message = "CertificateException - be sure not to include PEM header "
+            + "and footer in the PEM configuration element.";
+      } else {
+        message = "CertificateException - PEM may be corrupt";
+      }
+      throw new ServletException(message, ce);
+    } catch (UnsupportedEncodingException uee) {
+      throw new ServletException(uee);
+    }
+    return (RSAPublicKey) key;
+  }
+}


Mime
View raw message