Home | History | Annotate | Download | only in authentication
      1 //
      2 //  ========================================================================
      3 //  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
      4 //  ------------------------------------------------------------------------
      5 //  All rights reserved. This program and the accompanying materials
      6 //  are made available under the terms of the Eclipse Public License v1.0
      7 //  and Apache License v2.0 which accompanies this distribution.
      8 //
      9 //      The Eclipse Public License is available at
     10 //      http://www.eclipse.org/legal/epl-v10.html
     11 //
     12 //      The Apache License v2.0 is available at
     13 //      http://www.opensource.org/licenses/apache2.0.php
     14 //
     15 //  You may elect to redistribute this code under either of these licenses.
     16 //  ========================================================================
     17 //
     18 
     19 package org.eclipse.jetty.security.authentication;
     20 
     21 import java.io.InputStream;
     22 import java.security.KeyStore;
     23 import java.security.Principal;
     24 import java.security.cert.CRL;
     25 import java.security.cert.X509Certificate;
     26 import java.util.Collection;
     27 
     28 import javax.servlet.ServletRequest;
     29 import javax.servlet.ServletResponse;
     30 import javax.servlet.http.HttpServletRequest;
     31 import javax.servlet.http.HttpServletResponse;
     32 
     33 import org.eclipse.jetty.security.ServerAuthException;
     34 import org.eclipse.jetty.security.UserAuthentication;
     35 import org.eclipse.jetty.server.Authentication;
     36 import org.eclipse.jetty.server.Authentication.User;
     37 import org.eclipse.jetty.server.UserIdentity;
     38 import org.eclipse.jetty.util.B64Code;
     39 import org.eclipse.jetty.util.security.CertificateUtils;
     40 import org.eclipse.jetty.util.security.CertificateValidator;
     41 import org.eclipse.jetty.util.security.Constraint;
     42 import org.eclipse.jetty.util.security.Password;
     43 
     44 /**
     45  * @version $Rev: 4793 $ $Date: 2009-03-19 00:00:01 +0100 (Thu, 19 Mar 2009) $
     46  */
     47 public class ClientCertAuthenticator extends LoginAuthenticator
     48 {
     49     /** String name of keystore password property. */
     50     private static final String PASSWORD_PROPERTY = "org.eclipse.jetty.ssl.password";
     51 
     52     /** Truststore path */
     53     private String _trustStorePath;
     54     /** Truststore provider name */
     55     private String _trustStoreProvider;
     56     /** Truststore type */
     57     private String _trustStoreType = "JKS";
     58     /** Truststore password */
     59     private transient Password _trustStorePassword;
     60 
     61     /** Set to true if SSL certificate validation is required */
     62     private boolean _validateCerts;
     63     /** Path to file that contains Certificate Revocation List */
     64     private String _crlPath;
     65     /** Maximum certification path length (n - number of intermediate certs, -1 for unlimited) */
     66     private int _maxCertPathLength = -1;
     67     /** CRL Distribution Points (CRLDP) support */
     68     private boolean _enableCRLDP = false;
     69     /** On-Line Certificate Status Protocol (OCSP) support */
     70     private boolean _enableOCSP = false;
     71     /** Location of OCSP Responder */
     72     private String _ocspResponderURL;
     73 
     74     public ClientCertAuthenticator()
     75     {
     76         super();
     77     }
     78 
     79     public String getAuthMethod()
     80     {
     81         return Constraint.__CERT_AUTH;
     82     }
     83 
     84 
     85 
     86     /**
     87      * @return Authentication for request
     88      * @throws ServerAuthException
     89      */
     90     public Authentication validateRequest(ServletRequest req, ServletResponse res, boolean mandatory) throws ServerAuthException
     91     {
     92         if (!mandatory)
     93             return new DeferredAuthentication(this);
     94 
     95         HttpServletRequest request = (HttpServletRequest)req;
     96         HttpServletResponse response = (HttpServletResponse)res;
     97         X509Certificate[] certs = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
     98 
     99         try
    100         {
    101             // Need certificates.
    102             if (certs != null && certs.length > 0)
    103             {
    104 
    105                 if (_validateCerts)
    106                 {
    107                     KeyStore trustStore = getKeyStore(null,
    108                             _trustStorePath, _trustStoreType, _trustStoreProvider,
    109                             _trustStorePassword == null ? null :_trustStorePassword.toString());
    110                     Collection<? extends CRL> crls = loadCRL(_crlPath);
    111                     CertificateValidator validator = new CertificateValidator(trustStore, crls);
    112                     validator.validate(certs);
    113                 }
    114 
    115                 for (X509Certificate cert: certs)
    116                 {
    117                     if (cert==null)
    118                         continue;
    119 
    120                     Principal principal = cert.getSubjectDN();
    121                     if (principal == null) principal = cert.getIssuerDN();
    122                     final String username = principal == null ? "clientcert" : principal.getName();
    123 
    124                     final char[] credential = B64Code.encode(cert.getSignature());
    125 
    126                     UserIdentity user = login(username, credential, req);
    127                     if (user!=null)
    128                     {
    129                         return new UserAuthentication(getAuthMethod(),user);
    130                     }
    131                 }
    132             }
    133 
    134             if (!DeferredAuthentication.isDeferred(response))
    135             {
    136                 response.sendError(HttpServletResponse.SC_FORBIDDEN);
    137                 return Authentication.SEND_FAILURE;
    138             }
    139 
    140             return Authentication.UNAUTHENTICATED;
    141         }
    142         catch (Exception e)
    143         {
    144             throw new ServerAuthException(e.getMessage());
    145         }
    146     }
    147 
    148     /* ------------------------------------------------------------ */
    149     /**
    150      * Loads keystore using an input stream or a file path in the same
    151      * order of precedence.
    152      *
    153      * Required for integrations to be able to override the mechanism
    154      * used to load a keystore in order to provide their own implementation.
    155      *
    156      * @param storeStream keystore input stream
    157      * @param storePath path of keystore file
    158      * @param storeType keystore type
    159      * @param storeProvider keystore provider
    160      * @param storePassword keystore password
    161      * @return created keystore
    162      * @throws Exception
    163      */
    164     protected KeyStore getKeyStore(InputStream storeStream, String storePath, String storeType, String storeProvider, String storePassword) throws Exception
    165     {
    166         return CertificateUtils.getKeyStore(storeStream, storePath, storeType, storeProvider, storePassword);
    167     }
    168 
    169     /* ------------------------------------------------------------ */
    170     /**
    171      * Loads certificate revocation list (CRL) from a file.
    172      *
    173      * Required for integrations to be able to override the mechanism used to
    174      * load CRL in order to provide their own implementation.
    175      *
    176      * @param crlPath path of certificate revocation list file
    177      * @return a (possibly empty) collection view of java.security.cert.CRL objects initialized with the data from the
    178      *         input stream.
    179      * @throws Exception
    180      */
    181     protected Collection<? extends CRL> loadCRL(String crlPath) throws Exception
    182     {
    183         return CertificateUtils.loadCRL(crlPath);
    184     }
    185 
    186     public boolean secureResponse(ServletRequest req, ServletResponse res, boolean mandatory, User validatedUser) throws ServerAuthException
    187     {
    188         return true;
    189     }
    190 
    191     /* ------------------------------------------------------------ */
    192     /**
    193      * @return true if SSL certificate has to be validated
    194      */
    195     public boolean isValidateCerts()
    196     {
    197         return _validateCerts;
    198     }
    199 
    200     /* ------------------------------------------------------------ */
    201     /**
    202      * @param validateCerts
    203      *            true if SSL certificates have to be validated
    204      */
    205     public void setValidateCerts(boolean validateCerts)
    206     {
    207         _validateCerts = validateCerts;
    208     }
    209 
    210     /* ------------------------------------------------------------ */
    211     /**
    212      * @return The file name or URL of the trust store location
    213      */
    214     public String getTrustStore()
    215     {
    216         return _trustStorePath;
    217     }
    218 
    219     /* ------------------------------------------------------------ */
    220     /**
    221      * @param trustStorePath
    222      *            The file name or URL of the trust store location
    223      */
    224     public void setTrustStore(String trustStorePath)
    225     {
    226         _trustStorePath = trustStorePath;
    227     }
    228 
    229     /* ------------------------------------------------------------ */
    230     /**
    231      * @return The provider of the trust store
    232      */
    233     public String getTrustStoreProvider()
    234     {
    235         return _trustStoreProvider;
    236     }
    237 
    238     /* ------------------------------------------------------------ */
    239     /**
    240      * @param trustStoreProvider
    241      *            The provider of the trust store
    242      */
    243     public void setTrustStoreProvider(String trustStoreProvider)
    244     {
    245         _trustStoreProvider = trustStoreProvider;
    246     }
    247 
    248     /* ------------------------------------------------------------ */
    249     /**
    250      * @return The type of the trust store (default "JKS")
    251      */
    252     public String getTrustStoreType()
    253     {
    254         return _trustStoreType;
    255     }
    256 
    257     /* ------------------------------------------------------------ */
    258     /**
    259      * @param trustStoreType
    260      *            The type of the trust store (default "JKS")
    261      */
    262     public void setTrustStoreType(String trustStoreType)
    263     {
    264         _trustStoreType = trustStoreType;
    265     }
    266 
    267     /* ------------------------------------------------------------ */
    268     /**
    269      * @param password
    270      *            The password for the trust store
    271      */
    272     public void setTrustStorePassword(String password)
    273     {
    274         _trustStorePassword = Password.getPassword(PASSWORD_PROPERTY,password,null);
    275     }
    276 
    277     /* ------------------------------------------------------------ */
    278     /** Get the crlPath.
    279      * @return the crlPath
    280      */
    281     public String getCrlPath()
    282     {
    283         return _crlPath;
    284     }
    285 
    286     /* ------------------------------------------------------------ */
    287     /** Set the crlPath.
    288      * @param crlPath the crlPath to set
    289      */
    290     public void setCrlPath(String crlPath)
    291     {
    292         _crlPath = crlPath;
    293     }
    294 
    295     /**
    296      * @return Maximum number of intermediate certificates in
    297      * the certification path (-1 for unlimited)
    298      */
    299     public int getMaxCertPathLength()
    300     {
    301         return _maxCertPathLength;
    302     }
    303 
    304     /* ------------------------------------------------------------ */
    305     /**
    306      * @param maxCertPathLength
    307      *            maximum number of intermediate certificates in
    308      *            the certification path (-1 for unlimited)
    309      */
    310     public void setMaxCertPathLength(int maxCertPathLength)
    311     {
    312         _maxCertPathLength = maxCertPathLength;
    313     }
    314 
    315     /* ------------------------------------------------------------ */
    316     /**
    317      * @return true if CRL Distribution Points support is enabled
    318      */
    319     public boolean isEnableCRLDP()
    320     {
    321         return _enableCRLDP;
    322     }
    323 
    324     /* ------------------------------------------------------------ */
    325     /** Enables CRL Distribution Points Support
    326      * @param enableCRLDP true - turn on, false - turns off
    327      */
    328     public void setEnableCRLDP(boolean enableCRLDP)
    329     {
    330         _enableCRLDP = enableCRLDP;
    331     }
    332 
    333     /* ------------------------------------------------------------ */
    334     /**
    335      * @return true if On-Line Certificate Status Protocol support is enabled
    336      */
    337     public boolean isEnableOCSP()
    338     {
    339         return _enableOCSP;
    340     }
    341 
    342     /* ------------------------------------------------------------ */
    343     /** Enables On-Line Certificate Status Protocol support
    344      * @param enableOCSP true - turn on, false - turn off
    345      */
    346     public void setEnableOCSP(boolean enableOCSP)
    347     {
    348         _enableOCSP = enableOCSP;
    349     }
    350 
    351     /* ------------------------------------------------------------ */
    352     /**
    353      * @return Location of the OCSP Responder
    354      */
    355     public String getOcspResponderURL()
    356     {
    357         return _ocspResponderURL;
    358     }
    359 
    360     /* ------------------------------------------------------------ */
    361     /** Set the location of the OCSP Responder.
    362      * @param ocspResponderURL location of the OCSP Responder
    363      */
    364     public void setOcspResponderURL(String ocspResponderURL)
    365     {
    366         _ocspResponderURL = ocspResponderURL;
    367     }
    368 }
    369