1 40 package org.dspace.eperson; 41 42 import javax.servlet.ServletException ; 43 import javax.servlet.http.HttpServletRequest ; 44 import javax.servlet.http.HttpServletResponse ; 45 import javax.servlet.jsp.PageContext ; 46 import javax.servlet.jsp.jstl.fmt.LocaleSupport; 47 import java.sql.SQLException ; 48 import java.util.ArrayList ; 49 import java.util.Enumeration ; 50 import java.io.BufferedInputStream ; 51 import java.io.FileInputStream ; 52 import java.io.IOException ; 53 import java.io.InputStream ; 54 import java.security.InvalidKeyException ; 55 import java.security.NoSuchAlgorithmException ; 56 import java.security.NoSuchProviderException ; 57 import java.security.Principal ; 58 import java.security.PublicKey ; 59 import java.security.cert.Certificate ; 60 import java.security.KeyStore ; 61 import java.security.SignatureException ; 62 import java.security.GeneralSecurityException ; 63 import java.security.cert.CertificateException ; 64 import java.security.cert.CertificateExpiredException ; 65 import java.security.cert.CertificateFactory ; 66 import java.security.cert.CertificateNotYetValidException ; 67 import java.security.cert.X509Certificate ; 68 import java.util.StringTokenizer ; 69 70 import org.apache.log4j.Logger; 71 import org.dspace.core.LogManager; 72 import org.dspace.core.ConfigurationManager; 73 import org.dspace.core.Context; 74 import org.dspace.eperson.EPerson; 75 import org.dspace.eperson.AuthenticationMethod; 76 import org.dspace.authorize.AuthorizeException; 77 78 110 public class X509Authentication 111 implements AuthenticationMethod 112 { 113 114 115 private static Logger log = Logger.getLogger(X509Authentication.class); 116 117 118 private static PublicKey caPublicKey = null; 119 120 121 private static KeyStore caCertKeyStore = null; 122 123 128 static 129 { 130 String keystorePath = ConfigurationManager.getProperty("authentication.x509.keystore.path"); 131 String keystorePassword = ConfigurationManager.getProperty("authentication.x509.keystore.password"); 132 String caCertPath = ConfigurationManager.getProperty("authentication.x509.ca.cert"); 133 134 if (caCertPath == null) 136 caCertPath = ConfigurationManager.getProperty("webui.cert.ca"); 137 138 if (keystorePath != null) 140 { 141 if (keystorePassword == null) 142 keystorePassword = ""; 143 try { 144 KeyStore ks = KeyStore.getInstance("JKS"); 145 ks.load(new FileInputStream (keystorePath), 146 keystorePassword.toCharArray()); 147 caCertKeyStore = ks; 148 } 149 catch (IOException e) 150 { 151 log.error("X509Authentication: Failed to load CA keystore, file="+ 152 keystorePath+", error="+e.toString()); 153 } 154 catch (GeneralSecurityException e) 155 { 156 log.error("X509Authentication: Failed to extract CA keystore, file="+ 157 keystorePath+", error="+e.toString()); 158 } 159 } 160 161 if (caCertPath != null) 163 { 164 try 165 { 166 InputStream is = new BufferedInputStream (new FileInputStream (caCertPath)); 167 X509Certificate cert = (X509Certificate ) CertificateFactory 168 .getInstance("X.509").generateCertificate(is); 169 if (cert != null) 170 caPublicKey = cert.getPublicKey(); 171 } 172 catch (IOException e) 173 { 174 log.error("X509Authentication: Failed to load CA cert, file="+ 175 caCertPath+", error="+e.toString()); 176 } 177 catch (CertificateException e) 178 { 179 log.error("X509Authentication: Failed to extract CA cert, file="+ 180 caCertPath+", error="+e.toString()); 181 } 182 } 183 } 184 185 197 private static String getEmail(X509Certificate certificate) 198 throws SQLException 199 { 200 Principal principal = certificate.getSubjectDN(); 201 202 if (principal == null) 203 return null; 204 205 String dn = principal.getName(); 206 if (dn == null) 207 return null; 208 209 StringTokenizer tokenizer = new StringTokenizer (dn, ","); 210 String token = null; 211 while (tokenizer.hasMoreTokens()) 212 { 213 int len = "emailaddress=".length(); 214 215 token = (String ) tokenizer.nextToken(); 216 217 if (token.toLowerCase().startsWith("emailaddress=")) 218 { 219 if (token.length() <= len) 221 return null; 222 223 return token.substring(len).toLowerCase(); 224 } 225 } 226 227 return null; 228 } 229 230 241 private static boolean isValid(Context context, 242 X509Certificate certificate) 243 { 244 if (certificate == null) 245 return false; 246 247 try 249 { 250 certificate.checkValidity(); 251 } 252 catch (CertificateException e) 253 { 254 log.info(LogManager.getHeader(context, "authentication", 255 "X.509 Certificate is EXPIRED or PREMATURE: "+e.toString())); 256 return false; 257 } 258 259 if (caPublicKey != null) 261 { 262 try 263 { 264 certificate.verify(caPublicKey); 265 return true; 266 } 267 catch (GeneralSecurityException e) 268 { 269 log.info(LogManager.getHeader(context, "authentication", 270 "X.509 Certificate FAILED SIGNATURE check: "+e.toString())); 271 } 272 } 273 274 if (caCertKeyStore != null) 276 { 277 try 278 { 279 Enumeration ke = caCertKeyStore.aliases(); 280 281 while (ke.hasMoreElements()) 282 { 283 String alias = (String )ke.nextElement(); 284 if (caCertKeyStore.isCertificateEntry(alias)) 285 { 286 Certificate ca = caCertKeyStore.getCertificate(alias); 287 try { 288 certificate.verify(ca.getPublicKey()); 289 return true; 290 } 291 catch (CertificateException ce) 292 { 293 } 294 } 295 } 296 log.info(LogManager.getHeader(context, "authentication", 297 "Keystore method FAILED SIGNATURE check on client cert.")); 298 } 299 catch (GeneralSecurityException e) 300 { 301 log.info(LogManager.getHeader(context, "authentication", 302 "X.509 Certificate FAILED SIGNATURE check: "+e.toString())); 303 } 304 305 } 306 return false; 307 } 308 309 315 public boolean canSelfRegister(Context context, 316 HttpServletRequest request, 317 String username) 318 throws SQLException 319 { 320 return ConfigurationManager 321 .getBooleanProperty("authentication.x509.autoregister"); 322 } 323 324 327 public void initEPerson(Context context, HttpServletRequest request, 328 EPerson eperson) 329 throws SQLException 330 { 331 } 332 333 336 public boolean allowSetPassword(Context context, 337 HttpServletRequest request, 338 String username) 339 throws SQLException 340 { 341 return false; 342 } 343 344 347 public boolean isImplicit() 348 { 349 return true; 350 } 351 352 355 public int[] getSpecialGroups(Context context, HttpServletRequest request) 356 { 357 return new int[0]; 358 } 359 360 380 public int authenticate(Context context, 381 String username, 382 String password, 383 String realm, 384 HttpServletRequest request) 385 throws SQLException 386 { 387 X509Certificate [] certs = null; 389 if (request != null) 390 certs = (X509Certificate []) request 391 .getAttribute("javax.servlet.request.X509Certificate"); 392 393 if ((certs == null) || (certs.length == 0)) 394 return BAD_ARGS; 395 else 396 { 397 try 399 { 400 if (!isValid(context, certs[0])) 401 { 402 log.warn(LogManager.getHeader(context, "authenticate", 403 "type=x509certificate, status=BAD_CREDENTIALS (not valid)")); 404 return BAD_CREDENTIALS; 405 } 406 407 String email = getEmail(certs[0]); 409 EPerson eperson = null; 410 if (email != null) 411 eperson = EPerson.findByEmail(context, email); 412 if (eperson == null) 413 { 414 if (email != null && canSelfRegister(context, request, null)) 416 { 417 log.info(LogManager.getHeader(context, 419 "autoregister", "from=x.509, email=" + email)); 420 421 context.setIgnoreAuthorization(true); 423 eperson = EPerson.create(context); 424 eperson.setEmail(email); 425 eperson.setCanLogIn(true); 426 AuthenticationManager.initEPerson(context, 427 request, eperson); 428 eperson.update(); 429 context.commit(); 430 context.setIgnoreAuthorization(false); 431 context.setCurrentUser(eperson); 432 return SUCCESS; 433 } 434 else 435 { 436 log.warn(LogManager.getHeader(context, "authenticate", 438 "type=cert_but_no_record, cannot auto-register")); 439 return NO_SUCH_USER; 440 } 441 } 442 443 else if (!eperson.canLogIn()) 445 { 446 log.warn(LogManager.getHeader(context, "authenticate", 447 "type=x509certificate, email="+email+", canLogIn=false, rejecting.")); 448 return BAD_ARGS; 449 } 450 451 else 452 { 453 log.info(LogManager.getHeader(context, "login", 454 "type=x509certificate")); 455 context.setCurrentUser(eperson); 456 return SUCCESS; 457 } 458 } 459 catch (AuthorizeException ce) 460 { 461 log.warn(LogManager.getHeader(context, "authorize_exception", 462 ""), ce); 463 } 464 465 return BAD_ARGS; 466 } 467 } 468 469 483 public String loginPageURL(Context context, 484 HttpServletRequest request, 485 HttpServletResponse response) 486 { 487 return null; 488 } 489 490 498 public String loginPageTitle(Context context) 499 { 500 return null; 501 } 502 } 503 | Popular Tags |