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