1 7 package org.jboss.security.auth.spi; 8 9 import java.security.KeyStore ; 10 import java.security.KeyStoreException ; 11 import java.security.Principal ; 12 import java.security.acl.Group ; 13 import java.security.cert.X509Certificate ; 14 import java.util.Map ; 15 import java.util.Enumeration ; 16 import java.util.ArrayList ; 17 import java.io.IOException ; 18 19 import javax.naming.InitialContext ; 20 import javax.naming.NamingException ; 21 import javax.security.auth.Subject ; 22 import javax.security.auth.callback.Callback ; 23 import javax.security.auth.callback.CallbackHandler ; 24 import javax.security.auth.callback.NameCallback ; 25 import javax.security.auth.callback.UnsupportedCallbackException ; 26 import javax.security.auth.login.FailedLoginException ; 27 import javax.security.auth.login.LoginException ; 28 29 import org.jboss.security.SecurityDomain; 30 import org.jboss.security.auth.callback.ObjectCallback; 31 import org.jboss.security.auth.certs.X509CertificateVerifier; 32 33 48 public class BaseCertLoginModule extends AbstractServerLoginModule 49 { 50 51 private Principal identity; 52 53 private X509Certificate credential; 54 55 private SecurityDomain domain = null; 56 57 private X509CertificateVerifier verifier; 58 59 private boolean trace; 60 61 78 public void initialize(Subject subject, CallbackHandler callbackHandler, 79 Map sharedState, Map options) 80 { 81 super.initialize(subject, callbackHandler, sharedState, options); 82 trace = log.isTraceEnabled(); 83 84 String sd = (String ) options.get("securityDomain"); 86 if (sd == null) 87 sd = "java:/jaas/other"; 88 89 if( trace ) 90 log.trace("securityDomain=" + sd); 91 92 try 93 { 94 Object tempDomain = new InitialContext ().lookup(sd); 95 if (tempDomain instanceof SecurityDomain) 96 { 97 domain = (SecurityDomain) tempDomain; 98 if( trace ) 99 { 100 if (domain != null) 101 log.trace("found domain: " + domain.getClass().getName()); 102 else 103 log.trace("the domain " + sd + " is null!"); 104 } 105 } 106 else 107 { 108 log.error("The domain " + sd + " is not a SecurityDomain. All authentication using this module will fail!"); 109 } 110 } 111 catch (NamingException e) 112 { 113 log.error("Unable to find the securityDomain named: " + sd, e); 114 } 115 116 String option = (String ) options.get("verifier"); 117 if( option != null ) 118 { 119 try 120 { 121 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 122 Class verifierClass = loader.loadClass(option); 123 verifier = (X509CertificateVerifier) verifierClass.newInstance(); 124 } 125 catch(Throwable e) 126 { 127 if( trace ) 128 log.trace("Failed to create X509CertificateVerifier", e); 129 IllegalArgumentException ex = new IllegalArgumentException ("Invalid verifier: "+option); 130 ex.initCause(e); 131 } 132 } 133 134 if( trace ) 135 log.trace("exit: initialize(Subject, CallbackHandler, Map, Map)"); 136 } 137 138 141 public boolean login() throws LoginException 142 { 143 if( trace ) 144 log.trace("enter: login()"); 145 if (super.login() == true) 147 { 148 Object username = sharedState.get("javax.security.auth.login.name"); 150 if( username instanceof Principal ) 151 identity = (Principal ) username; 152 else 153 { 154 String name = username.toString(); 155 try 156 { 157 identity = createIdentity(name); 158 } 159 catch(Exception e) 160 { 161 log.debug("Failed to create principal", e); 162 throw new LoginException ("Failed to create principal: "+ e.getMessage()); 163 } 164 } 165 166 Object password = sharedState.get("javax.security.auth.login.password"); 167 if (password instanceof X509Certificate ) 168 credential = (X509Certificate ) password; 169 else if (password != null) 170 { 171 log.debug("javax.security.auth.login.password is not X509Certificate"); 172 super.loginOk = false; 173 return false; 174 } 175 return true; 176 } 177 178 super.loginOk = false; 179 Object [] info = getAliasAndCert(); 180 String alias = (String ) info[0]; 181 credential = (X509Certificate ) info[1]; 182 183 if (alias == null && credential == null) 184 { 185 identity = unauthenticatedIdentity; 186 super.log.trace("Authenticating as unauthenticatedIdentity=" + identity); 187 } 188 189 if (identity == null) 190 { 191 try 192 { 193 identity = createIdentity(alias); 194 } 195 catch(Exception e) 196 { 197 log.debug("Failed to create identity for alias:"+alias, e); 198 } 199 200 if (!validateCredential(alias, credential)) 201 { 202 log.debug("Bad credential for alias=" + alias); 203 throw new FailedLoginException ("Supplied Credential did not match existing credential for " + alias); 204 } 205 } 206 207 if (getUseFirstPass() == true) 208 { 209 sharedState.put("javax.security.auth.login.name", alias); 211 sharedState.put("javax.security.auth.login.password", credential); 212 } 213 super.loginOk = true; 214 if( trace ) 215 { 216 log.trace("User '" + identity + "' authenticated, loginOk=" + loginOk); 217 log.debug("exit: login()"); 218 } 219 return true; 220 } 221 222 226 public boolean commit() throws LoginException 227 { 228 boolean ok = super.commit(); 229 if( ok == true ) 230 { 231 subject.getPublicCredentials().add(credential); 233 } 234 return ok; 235 } 236 237 241 protected Group [] getRoleSets() throws LoginException 242 { 243 return new Group [0]; 244 } 245 246 protected Principal getIdentity() 247 { 248 return identity; 249 } 250 protected Object getCredentials() 251 { 252 return credential; 253 } 254 protected String getUsername() 255 { 256 String username = null; 257 if (getIdentity() != null) 258 username = getIdentity().getName(); 259 return username; 260 } 261 262 protected Object [] getAliasAndCert() throws LoginException 263 { 264 if( trace ) 265 log.trace("enter: getAliasAndCert()"); 266 Object [] info = { null, null }; 267 if (callbackHandler == null) 269 { 270 throw new LoginException ("Error: no CallbackHandler available to collect authentication information"); 271 } 272 NameCallback nc = new NameCallback ("Alias: "); 273 ObjectCallback oc = new ObjectCallback("Certificate: "); 274 Callback [] callbacks = { nc, oc }; 275 String alias = null; 276 X509Certificate cert = null; 277 X509Certificate [] certChain; 278 try 279 { 280 callbackHandler.handle(callbacks); 281 alias = nc.getName(); 282 Object tmpCert = oc.getCredential(); 283 if (tmpCert != null) 284 { 285 if (tmpCert instanceof X509Certificate ) 286 { 287 cert = (X509Certificate ) tmpCert; 288 if( trace ) 289 log.trace("found cert " + cert.getSerialNumber().toString(16) + ":" + cert.getSubjectDN().getName()); 290 } 291 else if( tmpCert instanceof X509Certificate [] ) 292 { 293 certChain = (X509Certificate []) tmpCert; 294 if( certChain.length > 0 ) 295 cert = certChain[0]; 296 } 297 else 298 { 299 String msg = "Don't know how to obtain X509Certificate from: " 300 +tmpCert.getClass(); 301 log.warn(msg); 302 throw new LoginException (msg); 303 } 304 } 305 } 306 catch (IOException e) 307 { 308 log.debug("Failed to invoke callback", e); 309 throw new LoginException ("Failed to invoke callback: "+e.toString()); 310 } 311 catch (UnsupportedCallbackException uce) 312 { 313 throw new LoginException ("CallbackHandler does not support: " 314 + uce.getCallback()); 315 } 316 317 info[0] = alias; 318 info[1] = cert; 319 if( trace ) 320 log.trace("exit: getAliasAndCert()"); 321 return info; 322 } 323 324 protected boolean validateCredential(String alias, X509Certificate cert) 325 { 326 if( trace ) 327 log.trace("enter: validateCredentail(String, X509Certificate)"); 328 boolean isValid = false; 329 330 KeyStore keyStore = null; 332 KeyStore trustStore = null; 333 if( domain != null ) 334 { 335 keyStore = domain.getKeyStore(); 336 trustStore = domain.getTrustStore(); 337 } 338 if( trustStore == null ) 339 trustStore = keyStore; 340 341 if( verifier != null ) 342 { 343 if( trace ) 345 log.trace("Validating cert using: "+verifier); 346 isValid = verifier.verify(cert, alias, keyStore, trustStore); 347 } 348 else if (keyStore != null && cert != null) 349 { 350 X509Certificate storeCert = null; 352 try 353 { 354 storeCert = (X509Certificate ) keyStore.getCertificate(alias); 355 if( trace ) 356 { 357 StringBuffer buf = new StringBuffer ("\n\tSupplied Credential: "); 358 buf.append(cert.getSerialNumber().toString(16)); 359 buf.append("\n\t\t"); 360 buf.append(cert.getSubjectDN().getName()); 361 buf.append("\n\n\tExisting Credential: "); 362 if( storeCert != null ) 363 { 364 buf.append(storeCert.getSerialNumber().toString(16)); 365 buf.append("\n\t\t"); 366 buf.append(storeCert.getSubjectDN().getName()); 367 buf.append("\n"); 368 } 369 else 370 { 371 ArrayList aliases = new ArrayList (); 372 Enumeration en = keyStore.aliases(); 373 while (en.hasMoreElements()) 374 { 375 aliases.add(en.nextElement()); 376 } 377 buf.append("No match for alias: "+alias+", we have aliases " + aliases); 378 } 379 log.trace(buf.toString()); 380 } 381 } 382 catch (KeyStoreException e) 383 { 384 log.warn("failed to find the certificate for " + alias, e); 385 } 386 if (cert.equals(storeCert)) 388 isValid = true; 389 } 390 else 391 { 392 log.warn("Domain, KeyStore, or cert is null. Unable to validate the certificate."); 393 } 394 395 if( trace ) 396 { 397 log.trace("The supplied certificate " 398 + (isValid ? "matched" : "DID NOT match") 399 + " the certificate in the keystore."); 400 401 log.trace("exit: validateCredentail(String, X509Certificate)"); 402 } 403 return isValid; 404 } 405 406 } 407 | Popular Tags |