1 28 package net.sf.jguard.ext.authentication.loginmodules; 29 30 import java.io.BufferedInputStream ; 31 import java.io.DataInputStream ; 32 import java.io.FileInputStream ; 33 import java.io.FileNotFoundException ; 34 import java.io.IOException ; 35 import java.io.InputStream ; 36 import java.net.MalformedURLException ; 37 import java.net.URL ; 38 import java.net.URLConnection ; 39 import java.security.InvalidAlgorithmParameterException ; 40 import java.security.NoSuchAlgorithmException ; 41 import java.security.Provider ; 42 import java.security.PublicKey ; 43 import java.security.Security ; 44 import java.security.cert.CRL ; 45 import java.security.cert.CRLException ; 46 import java.security.cert.CertPath ; 47 import java.security.cert.CertPathValidator ; 48 import java.security.cert.CertPathValidatorException ; 49 import java.security.cert.CertStore ; 50 import java.security.cert.CertStoreParameters ; 51 import java.security.cert.CertificateException ; 52 import java.security.cert.CertificateFactory ; 53 import java.security.cert.CollectionCertStoreParameters ; 54 import java.security.cert.LDAPCertStoreParameters ; 55 import java.security.cert.PKIXCertPathValidatorResult ; 56 import java.security.cert.PKIXParameters ; 57 import java.security.cert.PolicyNode ; 58 import java.security.cert.TrustAnchor ; 59 import java.security.cert.X509Certificate ; 60 import java.util.ArrayList ; 61 import java.util.Arrays ; 62 import java.util.Collection ; 63 import java.util.Date ; 64 import java.util.List ; 65 import java.util.Map ; 66 import java.util.Set ; 67 import java.util.logging.Level ; 68 import java.util.logging.Logger ; 69 70 import javax.security.auth.Subject ; 71 import javax.security.auth.callback.Callback ; 72 import javax.security.auth.callback.CallbackHandler ; 73 import javax.security.auth.callback.UnsupportedCallbackException ; 74 import javax.security.auth.login.FailedLoginException ; 75 import javax.security.auth.login.LoginException ; 76 import javax.security.auth.spi.LoginModule ; 77 78 import net.sf.jguard.core.CoreConstants; 79 import net.sf.jguard.ext.SecurityConstants; 80 import net.sf.jguard.ext.authentication.callbacks.CertificatesCallback; 81 import net.sf.jguard.ext.authentication.certificates.CertUtils; 82 83 import org.bouncycastle.jce.provider.BouncyCastleProvider; 84 85 91 public class CRLLoginModule extends CertificateLoginModule implements LoginModule { 92 93 private static final String COLLECTION = "Collection"; 94 private static final String LDAP = "LDAP"; 95 private static final String PKIX = "PKIX"; 96 private static final String X_509 = "X.509"; 97 98 99 private static final Logger logger = Logger.getLogger(CRLLoginModule.class.getName()); 100 private Set trustAnchors = null; 101 private String trustedCaCertsDirPath = null; 102 private CertPath certPath = null; 103 private boolean debug = false; 104 private Provider securityProvider = null; 105 private String certStoreType =CRLLoginModule.LDAP; 106 private String ldapServerName ="localhost"; 107 private int ldapServerPort =389; 108 private CallbackHandler callbackHandler; 109 private Map sharedState; 110 private String fileCrlPath = null; 111 private String urlCrlPath = null; 112 private boolean anyPolicyInhibited = false; 113 private boolean explicitPolicyRequired = false; 114 private boolean policyMappingInhibited = false; 115 private boolean policyQualifierRejected = true; 116 private boolean revocationEnabled = true; 117 private String sigProvider=null; 118 private static boolean SecurityProviderInitialized = false; 119 120 121 128 public void initialize(Subject subj, CallbackHandler cbkHandler, Map state,Map options) { 129 this.subject = subj; 130 this.callbackHandler = cbkHandler; 131 this.sharedState = state; 132 133 if(!SecurityProviderInitialized){ 134 SecurityProviderInitialized = initSecurityProvider(); 135 } 136 137 if((String )options.get(CoreConstants.DEBUG)!=null){ 138 debug= Boolean.valueOf((String )options.get(CoreConstants.DEBUG)).booleanValue(); 139 } 140 141 if((String )options.get(SecurityConstants.CERT_PATH_ANY_POLICY_INHIBITED)!=null){ 142 anyPolicyInhibited = Boolean.valueOf((String )options.get(SecurityConstants.CERT_PATH_ANY_POLICY_INHIBITED)).booleanValue(); 143 } 144 145 if((String )options.get(SecurityConstants.CERT_PATH_EXPLICIT_POLICY_REQUIRED)!=null){ 146 explicitPolicyRequired = Boolean.valueOf((String )options.get(SecurityConstants.CERT_PATH_EXPLICIT_POLICY_REQUIRED)).booleanValue(); 147 } 148 149 if((String )options.get(SecurityConstants.CERT_PATH_POLICY_MAPPING_INHIBITED)!=null){ 150 policyMappingInhibited = Boolean.valueOf((String )options.get(SecurityConstants.CERT_PATH_POLICY_MAPPING_INHIBITED)).booleanValue(); 151 } 152 153 if((String )options.get(SecurityConstants.CERT_PATH_POLICY_QUALIFIERS_REJECTED)!=null){ 154 policyQualifierRejected = Boolean.valueOf((String )options.get(SecurityConstants.CERT_PATH_POLICY_QUALIFIERS_REJECTED)).booleanValue(); 155 } 156 157 if((String )options.get(SecurityConstants.CERT_PATH_REVOCATION_ENABLED)!=null){ 158 revocationEnabled = Boolean.valueOf((String )options.get(SecurityConstants.CERT_PATH_REVOCATION_ENABLED)).booleanValue(); 159 } 160 161 if((String )options.get(SecurityConstants.CERT_PATH_SIG_PROVIDER)!=null){ 162 sigProvider =(String )options.get(SecurityConstants.CERT_PATH_SIG_PROVIDER); 163 } 164 165 if((String )options.get(SecurityConstants.CERT_PATH_CRL_PATH)!=null){ 166 fileCrlPath =(String )options.get(SecurityConstants.CERT_PATH_CRL_PATH); 167 } 168 169 if((String )options.get(SecurityConstants.CERT_PATH_CRL_PATH)!=null){ 170 urlCrlPath =(String )options.get(SecurityConstants.CERT_PATH_URL_CRL_PATH); 171 } 172 173 if((String )options.get(SecurityConstants.TRUSTED_CA_CERTIFICATES_DIRECTORY_PATH)!=null){ 174 trustedCaCertsDirPath= (String )options.get(SecurityConstants.TRUSTED_CA_CERTIFICATES_DIRECTORY_PATH); 175 } 176 trustAnchors = CertUtils.getTrustedAnchorsFromDirectory(trustedCaCertsDirPath); 177 if((String )options.get(SecurityConstants.SECURITY_PROVIDER)!=null){ 178 String securityProviderClassName = (String )options.get(SecurityConstants.SECURITY_PROVIDER); 179 try { 180 Class securityProviderClass = this.getClass().getClassLoader().loadClass(securityProviderClassName); 181 securityProvider = (Provider ) securityProviderClass.newInstance(); 182 183 } catch (ClassNotFoundException e) { 184 logger.severe(e.getMessage()); 185 } catch (InstantiationException e) { 186 logger.severe(e.getMessage()); 187 } catch (IllegalAccessException e) { 188 logger.severe(e.getMessage()); 189 } 190 }else{ 191 securityProvider = new BouncyCastleProvider(); 192 } 193 194 if((String )options.get(SecurityConstants.CERT_PATH_CERTSTORE_TYPE)!=null){ 195 certStoreType = (String )options.get(SecurityConstants.CERT_PATH_CERTSTORE_TYPE); 196 } 197 198 if((String )options.get(SecurityConstants.CERT_PATH_LDAP_SERVER_NAME)!=null){ 199 ldapServerName = (String )options.get(SecurityConstants.CERT_PATH_LDAP_SERVER_NAME); 200 } 201 202 if((String )options.get(SecurityConstants.CERT_PATH_LDAP_SERVER_PORT)!=null){ 203 ldapServerPort = Integer.parseInt((String )options.get(SecurityConstants.CERT_PATH_LDAP_SERVER_PORT)); 204 } 205 } 206 207 211 public boolean login() throws LoginException { 212 213 if (callbackHandler == null){ 214 loginOK = false; 215 throw new LoginException ("there is no CallbackHandler to authenticate the user"); 216 } 217 Callback [] callbacks = new Callback [1]; 218 callbacks[0] = new CertificatesCallback(); 219 try { 220 callbackHandler.handle(callbacks); 221 } catch (IOException e1) { 222 e1.printStackTrace(); 223 } catch (UnsupportedCallbackException e1) { 224 e1.printStackTrace(); 225 } 226 certChainToCheck = ((CertificatesCallback)callbacks[0]).getCertificates(); 227 if(certChainToCheck == null){ 228 loginOK = false; 229 throw new FailedLoginException (" there is no certificates to check with the Certificate Revocation List "); 230 } 231 certPath = buildCertPath(certChainToCheck); 232 validateCertPath(certPath); 233 sharedState.put(SecurityConstants.SKIP_PASSWORD_CHECK, "true"); 236 return true; 237 } 238 239 240 245 private CertPath buildCertPath(X509Certificate [] certs){ 246 CertificateFactory certFactory = null; 247 CertPath certPath = null; 248 try { 249 certFactory = CertificateFactory.getInstance(CRLLoginModule.X_509,securityProvider); 250 certPath = certFactory.generateCertPath(Arrays.asList(certs)); 251 } catch (CertificateException e) { 252 e.printStackTrace(); 253 } 254 255 return certPath; 256 } 257 258 259 264 private void validateCertPath(CertPath certPath) throws LoginException { 265 CertPathValidator validator = null; 266 PKIXParameters parameters = null; 267 PKIXCertPathValidatorResult result = null; 268 try { 269 validator = CertPathValidator.getInstance(CRLLoginModule.PKIX,securityProvider); 270 271 } catch (NoSuchAlgorithmException e) { 272 logger.severe(" algorithm PKIX is not present "+securityProvider.getName() 273 +" "+securityProvider.getInfo()+" "+securityProvider.getVersion()); 274 } 275 try { 276 277 parameters = new PKIXParameters (trustAnchors); 278 List certStores = new ArrayList (); 279 CertStore certStore = getCertStore(); 280 certStores.add(certStore); 281 parameters.setCertStores(certStores); 282 parameters.setAnyPolicyInhibited(anyPolicyInhibited); 283 parameters.setDate(new Date ()); 285 parameters.setExplicitPolicyRequired(explicitPolicyRequired); 287 parameters.setPolicyMappingInhibited(policyMappingInhibited); 288 parameters.setPolicyQualifiersRejected(policyQualifierRejected); 289 parameters.setRevocationEnabled(revocationEnabled); 290 if(sigProvider!=null){ 291 parameters.setSigProvider(sigProvider); 292 } 293 result =(PKIXCertPathValidatorResult )validator.validate(certPath,parameters); 297 PolicyNode policyTree = result.getPolicyTree(); 298 PublicKey key = result.getPublicKey(); 299 TrustAnchor anchor = result.getTrustAnchor(); 300 if(debug){ 301 logger.finest("policyTree depth = "+policyTree.getDepth()); 302 logger.finest("policyTree expected policies = "+policyTree.getExpectedPolicies()); 303 logger.finest("policyTree policy qualifiers = "+policyTree.getPolicyQualifiers()); 304 logger.finest("public key= "+key.toString()); 305 logger.finest("TrustAnchor ca name= "+anchor.getCAName()); 306 logger.finest("TrustAnchor ca public key = "+anchor.getCAPublicKey()); 307 logger.finest("TrustAnchor name constraints = "+anchor.getNameConstraints()); 308 logger.finest("TrustAnchor trustedCert = "+anchor.getTrustedCert()); 309 } 310 } catch (InvalidAlgorithmParameterException e) { 311 logger.severe(e.getMessage()); 312 throw new FailedLoginException (e.getMessage()); 313 } catch (CertPathValidatorException e) { 314 logger.severe(e.getMessage()); 315 throw new FailedLoginException (e.getMessage()); 316 } 317 } 318 319 320 325 private CertStore getCertStore() throws LoginException { 326 CertStore certStore = null; 327 328 CertStoreParameters certStoreParams = null; 330 if(certStoreType.equalsIgnoreCase(CRLLoginModule.LDAP)){ 331 certStoreParams = new LDAPCertStoreParameters (ldapServerName,ldapServerPort); 332 }else if(certStoreType.equalsIgnoreCase(CRLLoginModule.COLLECTION)){ 333 Collection crlCollection = getCRLAndCertsCollection(); 334 certStoreParams = new CollectionCertStoreParameters (crlCollection); 335 }else{ 336 throw new LoginException (" invalid 'certStoreType' value : this value should be 'LDAP' or 'Collection' "); 337 } 338 try { 339 certStore = CertStore.getInstance(certStoreType,certStoreParams,securityProvider); 341 342 } catch (NoSuchAlgorithmException e) { 343 throw new LoginException (e.getMessage()); 344 } catch (InvalidAlgorithmParameterException e) { 345 throw new LoginException (e.getMessage()); 346 } 347 348 return certStore; 349 } 350 351 355 private Collection getCRLAndCertsCollection() { 356 Collection crlAndCerts = new ArrayList (); 357 CertificateFactory certFactory = null; 358 try { 359 certFactory = CertificateFactory.getInstance(CRLLoginModule.X_509,securityProvider); 360 } catch (CertificateException e) { 361 logger.log(Level.SEVERE, " X509 certificate factory cannot be retrieved with the securityProvider "+ 362 securityProvider.getName()+" "+securityProvider.getInfo()+ 363 " "+securityProvider.getVersion(),e); 364 } 365 366 if(fileCrlPath!=null){ 367 addCRLFromPath(crlAndCerts, certFactory); 368 } 369 if(urlCrlPath!=null){ 370 addCRLFromURL(crlAndCerts, certFactory); 371 } 372 return crlAndCerts; 373 } 374 375 381 private void addCRLFromPath(Collection crlAndCerts, CertificateFactory certFactory) { 382 383 InputStream stream = null; 384 try { 385 stream = new BufferedInputStream (new FileInputStream (fileCrlPath)); 386 } catch (FileNotFoundException e) { 387 e.printStackTrace(); 388 } 389 try { 390 CRL crl = certFactory.generateCRL(stream); 391 crlAndCerts.add(crl); 392 } catch (CRLException e) { 393 e.printStackTrace(); 394 }finally{ 395 try { 396 stream.close(); 397 } catch (IOException e) { 398 e.printStackTrace(); 399 } 400 } 401 } 402 403 408 private void addCRLFromURL(Collection crlAndCerts, CertificateFactory certFactory) { 409 DataInputStream data = null; 410 try { 411 URL url = new URL (urlCrlPath); 412 URLConnection connection = url.openConnection(); 413 connection.setDoInput(true); 415 connection.setUseCaches(false); 417 data = new DataInputStream (connection.getInputStream()); 418 try { 419 CRL crl = certFactory.generateCRL(data); 420 crlAndCerts.add(crl); 421 } catch (CRLException e) { 422 logger.severe(" CRL cannot be built with the retrieved data "); 423 e.printStackTrace(); 424 } 425 } catch (MalformedURLException e) { 426 logger.log(Level.SEVERE, " bad uri synthax "+urlCrlPath,e); 427 } catch (IOException e) { 428 logger.log(Level.SEVERE, " IOException when we wan to retrieve CRL with data ",e); 429 }finally{ 430 try { 431 data.close(); 432 } catch (IOException e) { 433 logger.log(Level.SEVERE, " IOException when we close the DATAInputStream",e); 434 } 435 } 436 } 437 438 443 protected static boolean initSecurityProvider(){ 444 if(Security.getProvider(BouncyCastleProvider.class.getName())==null){ 445 try{ 446 Security.addProvider(new BouncyCastleProvider()); 447 return true; 448 }catch(SecurityException sex){ 449 logger.severe(" jGuard cannot add dynamically the JCE provider required from \n"); 450 logger.severe(" the BOUNCYCASTLE library .this operation is prevented by the SECURITYMANAGER \n"); 451 logger.severe(" to use this required provider, you must add an entry to your java.security \n"); 452 logger.severe(" properties file (found in $JAVA_HOME/jre/lib/security/java.security, \n"); 453 logger.severe(" where $JAVA_HOME is the location of your JDK/JRE distribution) \n"); 454 logger.severe(" security.provider.<n>=org.bouncycastle.jce.provider.BouncyCastleProvider \n"); 455 logger.severe(" Where <n> is the preference you want the provider at (1 being the most prefered). "); 456 return false; 457 } 458 }else{ 459 return true; 460 } 461 } 462 463 } 464 | Popular Tags |