blob: 7c24fccd9838de5483414ac329aac568954d8e69 [file] [log] [blame]
Jake Slack03928ae2014-05-13 18:41:56 -07001//
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
19package org.eclipse.jetty.security.authentication;
20
21import java.io.InputStream;
22import java.security.KeyStore;
23import java.security.Principal;
24import java.security.cert.CRL;
25import java.security.cert.X509Certificate;
26import java.util.Collection;
27
28import javax.servlet.ServletRequest;
29import javax.servlet.ServletResponse;
30import javax.servlet.http.HttpServletRequest;
31import javax.servlet.http.HttpServletResponse;
32
33import org.eclipse.jetty.security.ServerAuthException;
34import org.eclipse.jetty.security.UserAuthentication;
35import org.eclipse.jetty.server.Authentication;
36import org.eclipse.jetty.server.Authentication.User;
37import org.eclipse.jetty.server.UserIdentity;
38import org.eclipse.jetty.util.B64Code;
39import org.eclipse.jetty.util.security.CertificateUtils;
40import org.eclipse.jetty.util.security.CertificateValidator;
41import org.eclipse.jetty.util.security.Constraint;
42import 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 */
47public 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}