--- /dev/null
+//
+// ========================================================================
+// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.security.authentication;
+
+import java.io.InputStream;
+import java.security.KeyStore;
+import java.security.Principal;
+import java.security.cert.CRL;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.security.ServerAuthException;
+import org.eclipse.jetty.security.UserAuthentication;
+import org.eclipse.jetty.server.Authentication;
+import org.eclipse.jetty.server.Authentication.User;
+import org.eclipse.jetty.server.UserIdentity;
+import org.eclipse.jetty.util.B64Code;
+import org.eclipse.jetty.util.security.CertificateUtils;
+import org.eclipse.jetty.util.security.CertificateValidator;
+import org.eclipse.jetty.util.security.Constraint;
+import org.eclipse.jetty.util.security.Password;
+
+/**
+ * @version $Rev: 4793 $ $Date: 2009-03-19 00:00:01 +0100 (Thu, 19 Mar 2009) $
+ */
+public class ClientCertAuthenticator extends LoginAuthenticator
+{
+ /** String name of keystore password property. */
+ private static final String PASSWORD_PROPERTY = "org.eclipse.jetty.ssl.password";
+
+ /** Truststore path */
+ private String _trustStorePath;
+ /** Truststore provider name */
+ private String _trustStoreProvider;
+ /** Truststore type */
+ private String _trustStoreType = "JKS";
+ /** Truststore password */
+ private transient Password _trustStorePassword;
+
+ /** Set to true if SSL certificate validation is required */
+ private boolean _validateCerts;
+ /** Path to file that contains Certificate Revocation List */
+ private String _crlPath;
+ /** Maximum certification path length (n - number of intermediate certs, -1 for unlimited) */
+ private int _maxCertPathLength = -1;
+ /** CRL Distribution Points (CRLDP) support */
+ private boolean _enableCRLDP = false;
+ /** On-Line Certificate Status Protocol (OCSP) support */
+ private boolean _enableOCSP = false;
+ /** Location of OCSP Responder */
+ private String _ocspResponderURL;
+
+ public ClientCertAuthenticator()
+ {
+ super();
+ }
+
+ @Override
+ public String getAuthMethod()
+ {
+ return Constraint.__CERT_AUTH;
+ }
+
+
+
+ /**
+ * @return Authentication for request
+ * @throws ServerAuthException
+ */
+ @Override
+ public Authentication validateRequest(ServletRequest req, ServletResponse res, boolean mandatory) throws ServerAuthException
+ {
+ if (!mandatory)
+ return new DeferredAuthentication(this);
+
+ HttpServletRequest request = (HttpServletRequest)req;
+ HttpServletResponse response = (HttpServletResponse)res;
+ X509Certificate[] certs = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
+
+ try
+ {
+ // Need certificates.
+ if (certs != null && certs.length > 0)
+ {
+
+ if (_validateCerts)
+ {
+ KeyStore trustStore = getKeyStore(null,
+ _trustStorePath, _trustStoreType, _trustStoreProvider,
+ _trustStorePassword == null ? null :_trustStorePassword.toString());
+ Collection<? extends CRL> crls = loadCRL(_crlPath);
+ CertificateValidator validator = new CertificateValidator(trustStore, crls);
+ validator.validate(certs);
+ }
+
+ for (X509Certificate cert: certs)
+ {
+ if (cert==null)
+ continue;
+
+ Principal principal = cert.getSubjectDN();
+ if (principal == null) principal = cert.getIssuerDN();
+ final String username = principal == null ? "clientcert" : principal.getName();
+
+ final char[] credential = B64Code.encode(cert.getSignature());
+
+ UserIdentity user = login(username, credential, req);
+ if (user!=null)
+ {
+ return new UserAuthentication(getAuthMethod(),user);
+ }
+ }
+ }
+
+ if (!DeferredAuthentication.isDeferred(response))
+ {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ return Authentication.SEND_FAILURE;
+ }
+
+ return Authentication.UNAUTHENTICATED;
+ }
+ catch (Exception e)
+ {
+ throw new ServerAuthException(e.getMessage());
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Loads keystore using an input stream or a file path in the same
+ * order of precedence.
+ *
+ * Required for integrations to be able to override the mechanism
+ * used to load a keystore in order to provide their own implementation.
+ *
+ * @param storeStream keystore input stream
+ * @param storePath path of keystore file
+ * @param storeType keystore type
+ * @param storeProvider keystore provider
+ * @param storePassword keystore password
+ * @return created keystore
+ * @throws Exception
+ */
+ protected KeyStore getKeyStore(InputStream storeStream, String storePath, String storeType, String storeProvider, String storePassword) throws Exception
+ {
+ return CertificateUtils.getKeyStore(storeStream, storePath, storeType, storeProvider, storePassword);
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Loads certificate revocation list (CRL) from a file.
+ *
+ * Required for integrations to be able to override the mechanism used to
+ * load CRL in order to provide their own implementation.
+ *
+ * @param crlPath path of certificate revocation list file
+ * @return a (possibly empty) collection view of java.security.cert.CRL objects initialized with the data from the
+ * input stream.
+ * @throws Exception
+ */
+ protected Collection<? extends CRL> loadCRL(String crlPath) throws Exception
+ {
+ return CertificateUtils.loadCRL(crlPath);
+ }
+
+ @Override
+ public boolean secureResponse(ServletRequest req, ServletResponse res, boolean mandatory, User validatedUser) throws ServerAuthException
+ {
+ return true;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return true if SSL certificate has to be validated
+ */
+ public boolean isValidateCerts()
+ {
+ return _validateCerts;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param validateCerts
+ * true if SSL certificates have to be validated
+ */
+ public void setValidateCerts(boolean validateCerts)
+ {
+ _validateCerts = validateCerts;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return The file name or URL of the trust store location
+ */
+ public String getTrustStore()
+ {
+ return _trustStorePath;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param trustStorePath
+ * The file name or URL of the trust store location
+ */
+ public void setTrustStore(String trustStorePath)
+ {
+ _trustStorePath = trustStorePath;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return The provider of the trust store
+ */
+ public String getTrustStoreProvider()
+ {
+ return _trustStoreProvider;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param trustStoreProvider
+ * The provider of the trust store
+ */
+ public void setTrustStoreProvider(String trustStoreProvider)
+ {
+ _trustStoreProvider = trustStoreProvider;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return The type of the trust store (default "JKS")
+ */
+ public String getTrustStoreType()
+ {
+ return _trustStoreType;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param trustStoreType
+ * The type of the trust store (default "JKS")
+ */
+ public void setTrustStoreType(String trustStoreType)
+ {
+ _trustStoreType = trustStoreType;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param password
+ * The password for the trust store
+ */
+ public void setTrustStorePassword(String password)
+ {
+ _trustStorePassword = Password.getPassword(PASSWORD_PROPERTY,password,null);
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Get the crlPath.
+ * @return the crlPath
+ */
+ public String getCrlPath()
+ {
+ return _crlPath;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Set the crlPath.
+ * @param crlPath the crlPath to set
+ */
+ public void setCrlPath(String crlPath)
+ {
+ _crlPath = crlPath;
+ }
+
+ /**
+ * @return Maximum number of intermediate certificates in
+ * the certification path (-1 for unlimited)
+ */
+ public int getMaxCertPathLength()
+ {
+ return _maxCertPathLength;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param maxCertPathLength
+ * maximum number of intermediate certificates in
+ * the certification path (-1 for unlimited)
+ */
+ public void setMaxCertPathLength(int maxCertPathLength)
+ {
+ _maxCertPathLength = maxCertPathLength;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return true if CRL Distribution Points support is enabled
+ */
+ public boolean isEnableCRLDP()
+ {
+ return _enableCRLDP;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Enables CRL Distribution Points Support
+ * @param enableCRLDP true - turn on, false - turns off
+ */
+ public void setEnableCRLDP(boolean enableCRLDP)
+ {
+ _enableCRLDP = enableCRLDP;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return true if On-Line Certificate Status Protocol support is enabled
+ */
+ public boolean isEnableOCSP()
+ {
+ return _enableOCSP;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Enables On-Line Certificate Status Protocol support
+ * @param enableOCSP true - turn on, false - turn off
+ */
+ public void setEnableOCSP(boolean enableOCSP)
+ {
+ _enableOCSP = enableOCSP;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return Location of the OCSP Responder
+ */
+ public String getOcspResponderURL()
+ {
+ return _ocspResponderURL;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Set the location of the OCSP Responder.
+ * @param ocspResponderURL location of the OCSP Responder
+ */
+ public void setOcspResponderURL(String ocspResponderURL)
+ {
+ _ocspResponderURL = ocspResponderURL;
+ }
+}