You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by lm...@apache.org on 2013/09/21 18:11:54 UTC

git commit: KNOX-137 - added the ability to get the public cert of the gateway to AliasService and utilized it to log certificate CN/hostname and validity period on startup to the JettySSLService

Updated Branches:
  refs/heads/master a4fa09b74 -> 3d2afec68


KNOX-137 - added the ability to get the public cert of the gateway to AliasService and utilized it to log certificate CN/hostname and validity period on startup to the JettySSLService

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

Branch: refs/heads/master
Commit: 3d2afec68f44d7eb866e46f56dab368cce4e5511
Parents: a4fa09b
Author: Larry McCay <lm...@hortonworks.com>
Authored: Sat Sep 21 12:11:45 2013 -0400
Committer: Larry McCay <lm...@hortonworks.com>
Committed: Sat Sep 21 12:11:45 2013 -0400

----------------------------------------------------------------------
 .../apache/hadoop/gateway/GatewayMessages.java  |   7 +
 .../security/impl/DefaultAliasService.java      |  19 +-
 .../services/security/impl/JettySSLService.java |  19 ++
 .../services/security/CryptoServiceTest.java    |   7 +
 .../gateway/services/security/AliasService.java |   4 +-
 .../gateway/util/X500PrincipalParser.java       | 189 +++++++++++++++++++
 6 files changed, 241 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/3d2afec6/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayMessages.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayMessages.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayMessages.java
index 6efef71..fc17fd4 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayMessages.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayMessages.java
@@ -25,6 +25,7 @@ import org.apache.hadoop.gateway.i18n.messages.StackTrace;
 
 import java.io.File;
 import java.net.URI;
+import java.util.Date;
 import java.util.Map;
 
 /**
@@ -266,4 +267,10 @@ public interface GatewayMessages {
 
   @Message( level = MessageLevel.DEBUG, text = "Gateway services have not been initialized." )
   void gatewayServicesNotInitialized();
+
+  @Message( level = MessageLevel.INFO, text = "The Gateway SSL certificate is issued to hostname: {0}." )
+  void certificateHostNameForGateway(String cn);
+
+  @Message( level = MessageLevel.INFO, text = "The Gateway SSL certificate is valid between: {0} and {1}." )
+  void certificateValidityPeriod(Date notBefore, Date notAfter);
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/3d2afec6/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultAliasService.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultAliasService.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultAliasService.java
index 5fd2883..4d38400 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultAliasService.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultAliasService.java
@@ -17,8 +17,8 @@
  */
 package org.apache.hadoop.gateway.services.security.impl;
 
-import java.security.Key;
-import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.cert.Certificate;
 import java.util.Map;
 import java.util.Random;
 
@@ -26,7 +26,6 @@ import org.apache.hadoop.gateway.config.GatewayConfig;
 import org.apache.hadoop.gateway.services.ServiceLifecycleException;
 import org.apache.hadoop.gateway.services.security.AliasService;
 import org.apache.hadoop.gateway.services.security.KeystoreService;
-import org.apache.hadoop.gateway.services.security.KeystoreServiceException;
 
 public class DefaultAliasService implements AliasService {
 
@@ -111,4 +110,18 @@ public class DefaultAliasService implements AliasService {
     generateAliasForCluster("__gateway", alias);
   }
 
+  /* (non-Javadoc)
+   * @see org.apache.hadoop.gateway.services.security.AliasService#getCertificateForGateway(java.lang.String)
+   */
+  @Override
+  public Certificate getCertificateForGateway(String alias) {
+    Certificate cert = null;
+    try {
+      cert = this.keystoreService.getKeystoreForGateway().getCertificate(alias);
+    } catch (KeyStoreException e) {
+      // TODO: log appropriately
+      // should we throw an exception?
+    }
+    return cert;
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/3d2afec6/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/JettySSLService.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/JettySSLService.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/JettySSLService.java
index 4a9e1c7..0e40e99 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/JettySSLService.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/JettySSLService.java
@@ -18,8 +18,13 @@
 package org.apache.hadoop.gateway.services.security.impl;
 
 import java.io.File;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.Date;
 import java.util.Map;
 
+import javax.security.auth.x500.X500Principal;
+
 import org.apache.hadoop.gateway.GatewayMessages;
 import org.apache.hadoop.gateway.config.GatewayConfig;
 import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
@@ -29,6 +34,7 @@ import org.apache.hadoop.gateway.services.security.KeystoreService;
 import org.apache.hadoop.gateway.services.security.KeystoreServiceException;
 import org.apache.hadoop.gateway.services.security.MasterService;
 import org.apache.hadoop.gateway.services.security.SSLService;
+import org.apache.hadoop.gateway.util.X500PrincipalParser;
 import org.eclipse.jetty.server.ssl.SslConnector;
 import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
 import org.eclipse.jetty.util.ssl.SslContextFactory;
@@ -81,6 +87,19 @@ public class JettySSLService implements SSLService {
       else {
         log.keyStoreForGatewayFoundNotCreating();
       }
+      // let's log the hostname (CN) and cert expiry from the gateway's public cert to aid in SSL debugging
+      Certificate cert = as.getCertificateForGateway("gateway-identity");
+      if (cert instanceof X509Certificate) {
+        X500Principal x500Principal = ((X509Certificate)cert).getSubjectX500Principal();
+        X500PrincipalParser parser = new X500PrincipalParser(x500Principal);
+        log.certificateHostNameForGateway(parser.getCN());
+        Date notBefore = ((X509Certificate) cert).getNotBefore();
+        Date notAfter = ((X509Certificate) cert).getNotAfter();
+        log.certificateValidityPeriod(notBefore, notAfter);
+      }
+      else {
+        throw new ServiceLifecycleException("Public certificate for the gateway is not of the expected type of X509Certificate. Something is wrong with the gateway keystore.");
+      }
     } catch (KeystoreServiceException e) {
       throw new ServiceLifecycleException("Keystore was not loaded properly - the provided (or persisted) master secret may not match the password for the keystore.", e);
     }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/3d2afec6/gateway-server/src/test/java/org/apache/hadoop/gateway/services/security/CryptoServiceTest.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/services/security/CryptoServiceTest.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/services/security/CryptoServiceTest.java
index d014242..af6ba43 100644
--- a/gateway-server/src/test/java/org/apache/hadoop/gateway/services/security/CryptoServiceTest.java
+++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/services/security/CryptoServiceTest.java
@@ -27,6 +27,7 @@ import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
+import java.security.cert.Certificate;
 import java.util.Map;
 
 import static org.junit.Assert.assertEquals;
@@ -85,6 +86,12 @@ public class CryptoServiceTest {
         // TODO Auto-generated method stub
         
       }
+
+      @Override
+      public Certificate getCertificateForGateway(String alias) {
+        // TODO Auto-generated method stub
+        return null;
+      }
     };
     cs = new DefaultCryptoService().setAliasService(as);
   }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/3d2afec6/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/AliasService.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/AliasService.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/AliasService.java
index b32bbb1..a34cf29 100644
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/AliasService.java
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/AliasService.java
@@ -17,7 +17,7 @@
  */
 package org.apache.hadoop.gateway.services.security;
 
-import java.security.Key;
+import java.security.cert.Certificate;
 
 import org.apache.hadoop.gateway.services.Service;
 
@@ -34,4 +34,6 @@ public interface AliasService extends Service {
   public abstract char[] getPasswordFromAliasForGateway(String alias);
 
   void generateAliasForGateway(String alias);
+  
+  Certificate getCertificateForGateway(String alias);
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/3d2afec6/gateway-util-common/src/main/java/org/apache/hadoop/gateway/util/X500PrincipalParser.java
----------------------------------------------------------------------
diff --git a/gateway-util-common/src/main/java/org/apache/hadoop/gateway/util/X500PrincipalParser.java b/gateway-util-common/src/main/java/org/apache/hadoop/gateway/util/X500PrincipalParser.java
new file mode 100644
index 0000000..c7d65d9
--- /dev/null
+++ b/gateway-util-common/src/main/java/org/apache/hadoop/gateway/util/X500PrincipalParser.java
@@ -0,0 +1,189 @@
+/**
+ * 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.util.ArrayList;
+import java.util.Iterator;
+
+import javax.security.auth.x500.X500Principal;
+
+public class X500PrincipalParser
+{
+  public static int LEASTSIGNIFICANT = 0;
+  public static int MOSTSIGNIFICANT = 1;
+  
+  public final static String attrCN = "CN";
+  public final static String attrOU = "OU";
+  public final static String attrO = "O";
+  public final static String attrC = "C";
+  public final static String attrL = "L";
+  public final static String attrST = "ST";
+  public final static String attrSTREET = "STREET";
+  public final static String attrEMAIL = "EMAILADDRESS";
+  public final static String attrUID = "UID";
+
+  ArrayList rdnNameArray = new ArrayList();
+
+  private final static String attrTerminator = "=";
+
+  public X500PrincipalParser(X500Principal principal)
+  {
+    parseDN(principal.getName(X500Principal.RFC2253));
+  }
+
+  public ArrayList getAllValues(String attributeID)
+  {
+    ArrayList retList = new ArrayList();
+    String searchPart = attributeID + attrTerminator;
+
+    for(Iterator iter = rdnNameArray.iterator(); iter.hasNext();)
+    {
+      ArrayList nameList = (ArrayList)iter.next();
+      String namePart = (String)nameList.get(0);
+
+      if(namePart.startsWith(searchPart))
+      {
+        // Return the string starting after the ID string and the = sign that follows it.
+        retList.add(namePart.toString().substring(searchPart.length()));
+      }
+    }
+
+    return retList;
+
+  }
+
+  public String getC()
+  {
+    return findPart(attrC);
+  }
+
+  public String getCN()
+  {
+    return findPart(attrCN);
+  }
+
+  public String getEMAILDDRESS()
+  {
+    return findPart(attrEMAIL);
+  }
+
+  public String getL()
+  {
+    return findPart(attrL);
+  }
+
+  public String getO()
+  {
+    return findPart(attrO);
+
+  }
+
+  public String getOU()
+  {
+    return findPart(attrOU);
+
+  }
+
+  public String getST()
+  {
+    return findPart(attrST);
+  }
+
+  public String getSTREET()
+  {
+    return findPart(attrSTREET);
+  }
+
+  public String getUID()
+  {
+    return findPart(attrUID);
+  }
+
+  private String findPart(String attributeID)
+  {
+    return findSignificantPart(attributeID, MOSTSIGNIFICANT);
+  }
+
+  private String findSignificantPart(String attributeID, int significance)
+  {
+    String retNamePart = null;
+    String searchPart = attributeID + attrTerminator;
+
+    for(Iterator iter = rdnNameArray.iterator(); iter.hasNext();)
+    {
+      ArrayList nameList = (ArrayList)iter.next();
+      String namePart = (String)nameList.get(0);
+
+      if(namePart.startsWith(searchPart))
+      {
+        // Return the string starting after the ID string and the = sign that follows it.
+        retNamePart = namePart.toString().substring(searchPart.length());
+        // By definition the first one is most significant
+        if(significance == MOSTSIGNIFICANT)
+          break;
+      }
+    }
+
+    return retNamePart;
+  }
+
+  private void parseDN(String dn) throws IllegalArgumentException
+  {
+    int startIndex = 0;
+    char c = '\0';
+    ArrayList nameValues = new ArrayList();
+
+    rdnNameArray.clear();
+
+    while(startIndex < dn.length())
+    {
+      int endIndex;
+      for(endIndex = startIndex; endIndex < dn.length(); endIndex++)
+      {
+        c = dn.charAt(endIndex);
+        if(c == ',' || c == '+')
+          break;
+        if(c == '\\')
+        {
+          endIndex++; // skip the escaped char
+        }
+      }
+
+      if(endIndex > dn.length())
+        throw new IllegalArgumentException("unterminated escape " + dn);
+
+      nameValues.add(dn.substring(startIndex, endIndex));
+
+      if(c != '+')
+      {
+        rdnNameArray.add(nameValues);
+        if(endIndex != dn.length())
+          nameValues = new ArrayList();
+        else
+          nameValues = null;
+      }
+      startIndex = endIndex + 1;
+    }
+    if(nameValues != null)
+    {
+      throw new IllegalArgumentException("improperly terminated DN " + dn);
+    }
+  }
+
+}
\ No newline at end of file