View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 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       * @return Authentication for request
86       * @throws ServerAuthException
87       */
88      public Authentication validateRequest(ServletRequest req, ServletResponse res, boolean mandatory) throws ServerAuthException
89      {
90          if (!mandatory)
91              return new DeferredAuthentication(this);
92  
93          HttpServletRequest request = (HttpServletRequest)req;
94          HttpServletResponse response = (HttpServletResponse)res;
95          X509Certificate[] certs = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
96  
97          try
98          {
99              // Need certificates.
100             if (certs != null && certs.length > 0)
101             {
102                 
103                 if (_validateCerts)
104                 {
105                     KeyStore trustStore = getKeyStore(null,
106                             _trustStorePath, _trustStoreType, _trustStoreProvider,
107                             _trustStorePassword == null ? null :_trustStorePassword.toString());
108                     Collection<? extends CRL> crls = loadCRL(_crlPath);
109                     CertificateValidator validator = new CertificateValidator(trustStore, crls);
110                     validator.validate(certs);
111                 }
112                 
113                 for (X509Certificate cert: certs)
114                 {
115                     if (cert==null)
116                         continue;
117 
118                     Principal principal = cert.getSubjectDN();
119                     if (principal == null) principal = cert.getIssuerDN();
120                     final String username = principal == null ? "clientcert" : principal.getName();
121 
122                     final char[] credential = B64Code.encode(cert.getSignature());
123 
124                     UserIdentity user = _loginService.login(username,credential);
125                     if (user!=null)
126                     {
127                         renewSession(request,response);
128                         return new UserAuthentication(getAuthMethod(),user);
129                     }
130                 }
131             }
132 
133             if (!DeferredAuthentication.isDeferred(response))
134             {
135                 response.sendError(HttpServletResponse.SC_FORBIDDEN);
136                 return Authentication.SEND_FAILURE;
137             }
138             
139             return Authentication.UNAUTHENTICATED;
140         }
141         catch (Exception e)
142         {
143             throw new ServerAuthException(e.getMessage());
144         }
145     }
146 
147     /* ------------------------------------------------------------ */
148     /**
149      * Loads keystore using an input stream or a file path in the same
150      * order of precedence.
151      *
152      * Required for integrations to be able to override the mechanism
153      * used to load a keystore in order to provide their own implementation.
154      *
155      * @param storeStream keystore input stream
156      * @param storePath path of keystore file
157      * @param storeType keystore type
158      * @param storeProvider keystore provider
159      * @param storePassword keystore password
160      * @return created keystore
161      * @throws Exception
162      */
163     protected KeyStore getKeyStore(InputStream storeStream, String storePath, String storeType, String storeProvider, String storePassword) throws Exception
164     {
165         return CertificateUtils.getKeyStore(storeStream, storePath, storeType, storeProvider, storePassword);
166     }
167 
168     /* ------------------------------------------------------------ */
169     /**
170      * Loads certificate revocation list (CRL) from a file.
171      *
172      * Required for integrations to be able to override the mechanism used to
173      * load CRL in order to provide their own implementation.
174      *
175      * @param crlPath path of certificate revocation list file
176      * @return a (possibly empty) collection view of java.security.cert.CRL objects initialized with the data from the
177      *         input stream.
178      * @throws Exception
179      */
180     protected Collection<? extends CRL> loadCRL(String crlPath) throws Exception
181     {
182         return CertificateUtils.loadCRL(crlPath);
183     }
184 
185     public boolean secureResponse(ServletRequest req, ServletResponse res, boolean mandatory, User validatedUser) throws ServerAuthException
186     {
187         return true;
188     }
189 
190     /* ------------------------------------------------------------ */
191     /**
192      * @return true if SSL certificate has to be validated
193      */
194     public boolean isValidateCerts()
195     {
196         return _validateCerts;
197     }
198 
199     /* ------------------------------------------------------------ */
200     /**
201      * @param validateCerts
202      *            true if SSL certificates have to be validated
203      */
204     public void setValidateCerts(boolean validateCerts)
205     {
206         _validateCerts = validateCerts;
207     }
208 
209     /* ------------------------------------------------------------ */
210     /**
211      * @return The file name or URL of the trust store location
212      */
213     public String getTrustStore()
214     {
215         return _trustStorePath;
216     }
217 
218     /* ------------------------------------------------------------ */
219     /**
220      * @param trustStorePath
221      *            The file name or URL of the trust store location
222      */
223     public void setTrustStore(String trustStorePath)
224     {
225         _trustStorePath = trustStorePath;
226     }
227 
228     /* ------------------------------------------------------------ */
229     /**
230      * @return The provider of the trust store
231      */
232     public String getTrustStoreProvider()
233     {
234         return _trustStoreProvider;
235     }
236 
237     /* ------------------------------------------------------------ */
238     /**
239      * @param trustStoreProvider
240      *            The provider of the trust store
241      */
242     public void setTrustStoreProvider(String trustStoreProvider)
243     {
244         _trustStoreProvider = trustStoreProvider;
245     }
246 
247     /* ------------------------------------------------------------ */
248     /**
249      * @return The type of the trust store (default "JKS")
250      */
251     public String getTrustStoreType()
252     {
253         return _trustStoreType;
254     }
255 
256     /* ------------------------------------------------------------ */
257     /**
258      * @param trustStoreType
259      *            The type of the trust store (default "JKS")
260      */
261     public void setTrustStoreType(String trustStoreType)
262     {
263         _trustStoreType = trustStoreType;
264     }
265 
266     /* ------------------------------------------------------------ */
267     /**
268      * @param password
269      *            The password for the trust store
270      */
271     public void setTrustStorePassword(String password)
272     {
273         _trustStorePassword = Password.getPassword(PASSWORD_PROPERTY,password,null);
274     }
275 
276     /* ------------------------------------------------------------ */
277     /** Get the crlPath.
278      * @return the crlPath
279      */
280     public String getCrlPath()
281     {
282         return _crlPath;
283     }
284 
285     /* ------------------------------------------------------------ */
286     /** Set the crlPath.
287      * @param crlPath the crlPath to set
288      */
289     public void setCrlPath(String crlPath)
290     {
291         _crlPath = crlPath;
292     }
293 
294     /**
295      * @return Maximum number of intermediate certificates in
296      * the certification path (-1 for unlimited)
297      */
298     public int getMaxCertPathLength()
299     {
300         return _maxCertPathLength;
301     }
302 
303     /* ------------------------------------------------------------ */
304     /**
305      * @param maxCertPathLength
306      *            maximum number of intermediate certificates in
307      *            the certification path (-1 for unlimited)
308      */
309     public void setMaxCertPathLength(int maxCertPathLength)
310     {
311         _maxCertPathLength = maxCertPathLength;
312     }
313     
314     /* ------------------------------------------------------------ */
315     /** 
316      * @return true if CRL Distribution Points support is enabled
317      */
318     public boolean isEnableCRLDP()
319     {
320         return _enableCRLDP;
321     }
322 
323     /* ------------------------------------------------------------ */
324     /** Enables CRL Distribution Points Support
325      * @param enableCRLDP true - turn on, false - turns off
326      */
327     public void setEnableCRLDP(boolean enableCRLDP)
328     {
329         _enableCRLDP = enableCRLDP;
330     }
331 
332     /* ------------------------------------------------------------ */
333     /** 
334      * @return true if On-Line Certificate Status Protocol support is enabled
335      */
336     public boolean isEnableOCSP()
337     {
338         return _enableOCSP;
339     }
340 
341     /* ------------------------------------------------------------ */
342     /** Enables On-Line Certificate Status Protocol support
343      * @param enableOCSP true - turn on, false - turn off
344      */
345     public void setEnableOCSP(boolean enableOCSP)
346     {
347         _enableOCSP = enableOCSP;
348     }
349 
350     /* ------------------------------------------------------------ */
351     /** 
352      * @return Location of the OCSP Responder
353      */
354     public String getOcspResponderURL()
355     {
356         return _ocspResponderURL;
357     }
358 
359     /* ------------------------------------------------------------ */
360     /** Set the location of the OCSP Responder.
361      * @param ocspResponderURL location of the OCSP Responder
362      */
363     public void setOcspResponderURL(String ocspResponderURL)
364     {
365         _ocspResponderURL = ocspResponderURL;
366     }
367 }