KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > jguard > ext > authentication > loginmodules > CRLLoginModule


1 /*
2 jGuard is a security framework based on top of jaas (java authentication and authorization security).
3 it is written for web applications, to resolve simply, access control problems.
4
5 http://sourceforge.net/projects/jguard/
6
7 Copyright (C) 2004 Charles GAY
8
9 This library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Lesser General Public
11 License as published by the Free Software Foundation; either
12 version 2.1 of the License, or (at your option) any later version.
13
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public
20 License along with this library; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
23
24 jGuard project home page:
25 http://sourceforge.net/projects/jguard/
26
27 */

28 package net.sf.jguard.ext.authentication.loginmodules;
29
30 import java.io.BufferedInputStream JavaDoc;
31 import java.io.DataInputStream JavaDoc;
32 import java.io.FileInputStream JavaDoc;
33 import java.io.FileNotFoundException JavaDoc;
34 import java.io.IOException JavaDoc;
35 import java.io.InputStream JavaDoc;
36 import java.net.MalformedURLException JavaDoc;
37 import java.net.URL JavaDoc;
38 import java.net.URLConnection JavaDoc;
39 import java.security.InvalidAlgorithmParameterException JavaDoc;
40 import java.security.NoSuchAlgorithmException JavaDoc;
41 import java.security.Provider JavaDoc;
42 import java.security.PublicKey JavaDoc;
43 import java.security.Security JavaDoc;
44 import java.security.cert.CRL JavaDoc;
45 import java.security.cert.CRLException JavaDoc;
46 import java.security.cert.CertPath JavaDoc;
47 import java.security.cert.CertPathValidator JavaDoc;
48 import java.security.cert.CertPathValidatorException JavaDoc;
49 import java.security.cert.CertStore JavaDoc;
50 import java.security.cert.CertStoreParameters JavaDoc;
51 import java.security.cert.CertificateException JavaDoc;
52 import java.security.cert.CertificateFactory JavaDoc;
53 import java.security.cert.CollectionCertStoreParameters JavaDoc;
54 import java.security.cert.LDAPCertStoreParameters JavaDoc;
55 import java.security.cert.PKIXCertPathValidatorResult JavaDoc;
56 import java.security.cert.PKIXParameters JavaDoc;
57 import java.security.cert.PolicyNode JavaDoc;
58 import java.security.cert.TrustAnchor JavaDoc;
59 import java.security.cert.X509Certificate JavaDoc;
60 import java.util.ArrayList JavaDoc;
61 import java.util.Arrays JavaDoc;
62 import java.util.Collection JavaDoc;
63 import java.util.Date JavaDoc;
64 import java.util.List JavaDoc;
65 import java.util.Map JavaDoc;
66 import java.util.Set JavaDoc;
67 import java.util.logging.Level JavaDoc;
68 import java.util.logging.Logger JavaDoc;
69
70 import javax.security.auth.Subject JavaDoc;
71 import javax.security.auth.callback.Callback JavaDoc;
72 import javax.security.auth.callback.CallbackHandler JavaDoc;
73 import javax.security.auth.callback.UnsupportedCallbackException JavaDoc;
74 import javax.security.auth.login.FailedLoginException JavaDoc;
75 import javax.security.auth.login.LoginException JavaDoc;
76 import javax.security.auth.spi.LoginModule JavaDoc;
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 /**
86  * validate certificates: validate their certPath and checks if
87  * some of them are revoked against CRL(Certificate Revocation list).
88  * @author <a HREF="mailto:diabolo512@users.sourceforge.net ">Charles Gay</a>
89  *
90  */

91 public class CRLLoginModule extends CertificateLoginModule implements LoginModule JavaDoc {
92
93     private static final String JavaDoc COLLECTION = "Collection";
94     private static final String JavaDoc LDAP = "LDAP";
95     private static final String JavaDoc PKIX = "PKIX";
96     private static final String JavaDoc X_509 = "X.509";
97
98     /** Logger for this class */
99     private static final Logger JavaDoc logger = Logger.getLogger(CRLLoginModule.class.getName());
100     private Set JavaDoc trustAnchors = null;
101     private String JavaDoc trustedCaCertsDirPath = null;
102     private CertPath JavaDoc certPath = null;
103     private boolean debug = false;
104     private Provider JavaDoc securityProvider = null;
105     private String JavaDoc certStoreType =CRLLoginModule.LDAP;
106     private String JavaDoc ldapServerName ="localhost";
107     private int ldapServerPort =389;
108     private CallbackHandler JavaDoc callbackHandler;
109     private Map JavaDoc sharedState;
110     private String JavaDoc fileCrlPath = null;
111     private String JavaDoc 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 JavaDoc sigProvider=null;
118     private static boolean SecurityProviderInitialized = false;
119     
120
121     /**
122      * @param subj
123      * @param cbkHandler
124      * @param state
125      * @param options
126      * @see javax.security.auth.spi.LoginModule#initialize(javax.security.auth.Subject, javax.security.auth.callback.CallbackHandler, java.util.Map, java.util.Map)
127      */

128     public void initialize(Subject JavaDoc subj, CallbackHandler JavaDoc cbkHandler, Map JavaDoc state,Map JavaDoc 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 JavaDoc)options.get(CoreConstants.DEBUG)!=null){
138               debug= Boolean.valueOf((String JavaDoc)options.get(CoreConstants.DEBUG)).booleanValue();
139         }
140
141         if((String JavaDoc)options.get(SecurityConstants.CERT_PATH_ANY_POLICY_INHIBITED)!=null){
142             anyPolicyInhibited = Boolean.valueOf((String JavaDoc)options.get(SecurityConstants.CERT_PATH_ANY_POLICY_INHIBITED)).booleanValue();
143         }
144
145         if((String JavaDoc)options.get(SecurityConstants.CERT_PATH_EXPLICIT_POLICY_REQUIRED)!=null){
146             explicitPolicyRequired = Boolean.valueOf((String JavaDoc)options.get(SecurityConstants.CERT_PATH_EXPLICIT_POLICY_REQUIRED)).booleanValue();
147         }
148
149         if((String JavaDoc)options.get(SecurityConstants.CERT_PATH_POLICY_MAPPING_INHIBITED)!=null){
150             policyMappingInhibited = Boolean.valueOf((String JavaDoc)options.get(SecurityConstants.CERT_PATH_POLICY_MAPPING_INHIBITED)).booleanValue();
151         }
152
153         if((String JavaDoc)options.get(SecurityConstants.CERT_PATH_POLICY_QUALIFIERS_REJECTED)!=null){
154             policyQualifierRejected = Boolean.valueOf((String JavaDoc)options.get(SecurityConstants.CERT_PATH_POLICY_QUALIFIERS_REJECTED)).booleanValue();
155         }
156
157         if((String JavaDoc)options.get(SecurityConstants.CERT_PATH_REVOCATION_ENABLED)!=null){
158             revocationEnabled = Boolean.valueOf((String JavaDoc)options.get(SecurityConstants.CERT_PATH_REVOCATION_ENABLED)).booleanValue();
159         }
160
161         if((String JavaDoc)options.get(SecurityConstants.CERT_PATH_SIG_PROVIDER)!=null){
162             sigProvider =(String JavaDoc)options.get(SecurityConstants.CERT_PATH_SIG_PROVIDER);
163         }
164
165         if((String JavaDoc)options.get(SecurityConstants.CERT_PATH_CRL_PATH)!=null){
166              fileCrlPath =(String JavaDoc)options.get(SecurityConstants.CERT_PATH_CRL_PATH);
167         }
168
169         if((String JavaDoc)options.get(SecurityConstants.CERT_PATH_CRL_PATH)!=null){
170              urlCrlPath =(String JavaDoc)options.get(SecurityConstants.CERT_PATH_URL_CRL_PATH);
171         }
172
173         if((String JavaDoc)options.get(SecurityConstants.TRUSTED_CA_CERTIFICATES_DIRECTORY_PATH)!=null){
174             trustedCaCertsDirPath= (String JavaDoc)options.get(SecurityConstants.TRUSTED_CA_CERTIFICATES_DIRECTORY_PATH);
175         }
176         trustAnchors = CertUtils.getTrustedAnchorsFromDirectory(trustedCaCertsDirPath);
177         if((String JavaDoc)options.get(SecurityConstants.SECURITY_PROVIDER)!=null){
178             String JavaDoc securityProviderClassName = (String JavaDoc)options.get(SecurityConstants.SECURITY_PROVIDER);
179             try {
180                 Class JavaDoc securityProviderClass = this.getClass().getClassLoader().loadClass(securityProviderClassName);
181                 securityProvider = (Provider JavaDoc) securityProviderClass.newInstance();
182
183             } catch (ClassNotFoundException JavaDoc e) {
184                 logger.severe(e.getMessage());
185             } catch (InstantiationException JavaDoc e) {
186                 logger.severe(e.getMessage());
187             } catch (IllegalAccessException JavaDoc e) {
188                 logger.severe(e.getMessage());
189             }
190         }else{
191             securityProvider = new BouncyCastleProvider();
192         }
193
194         if((String JavaDoc)options.get(SecurityConstants.CERT_PATH_CERTSTORE_TYPE)!=null){
195               certStoreType = (String JavaDoc)options.get(SecurityConstants.CERT_PATH_CERTSTORE_TYPE);
196         }
197
198         if((String JavaDoc)options.get(SecurityConstants.CERT_PATH_LDAP_SERVER_NAME)!=null){
199             ldapServerName = (String JavaDoc)options.get(SecurityConstants.CERT_PATH_LDAP_SERVER_NAME);
200         }
201
202         if((String JavaDoc)options.get(SecurityConstants.CERT_PATH_LDAP_SERVER_PORT)!=null){
203             ldapServerPort = Integer.parseInt((String JavaDoc)options.get(SecurityConstants.CERT_PATH_LDAP_SERVER_PORT));
204         }
205     }
206
207     /**
208      *
209      * @see javax.security.auth.spi.LoginModule#login()
210      */

211     public boolean login() throws LoginException JavaDoc {
212
213          if (callbackHandler == null){
214              loginOK = false;
215              throw new LoginException JavaDoc("there is no CallbackHandler to authenticate the user");
216          }
217          Callback JavaDoc[] callbacks = new Callback JavaDoc[1];
218          callbacks[0] = new CertificatesCallback();
219          try {
220             callbackHandler.handle(callbacks);
221         } catch (IOException JavaDoc e1) {
222             e1.printStackTrace();
223         } catch (UnsupportedCallbackException JavaDoc e1) {
224             e1.printStackTrace();
225         }
226          certChainToCheck = ((CertificatesCallback)callbacks[0]).getCertificates();
227         if(certChainToCheck == null){
228             loginOK = false;
229             throw new FailedLoginException JavaDoc(" there is no certificates to check with the Certificate Revocation List ");
230         }
231         certPath = buildCertPath(certChainToCheck);
232         validateCertPath(certPath);
233         //like we've arleady check user credentials present in the certificate
234
//password check must not be done one more time.
235
sharedState.put(SecurityConstants.SKIP_PASSWORD_CHECK, "true");
236         return true;
237     }
238
239     
240     /**
241      * generate certification Path .
242      * @param certs the X509Certificate Array
243      * @return certification path
244      */

245     private CertPath JavaDoc buildCertPath(X509Certificate JavaDoc[] certs){
246         CertificateFactory JavaDoc certFactory = null;
247         CertPath JavaDoc certPath = null;
248         try {
249             certFactory = CertificateFactory.getInstance(CRLLoginModule.X_509,securityProvider);
250             certPath = certFactory.generateCertPath(Arrays.asList(certs));
251         } catch (CertificateException JavaDoc e) {
252             e.printStackTrace();
253         }
254
255         return certPath;
256     }
257
258
259     /**
260      * validate a certPath.
261      * @param certPath
262      * @throws LoginException
263      */

264     private void validateCertPath(CertPath JavaDoc certPath) throws LoginException JavaDoc{
265         CertPathValidator JavaDoc validator = null;
266         PKIXParameters JavaDoc parameters = null;
267         PKIXCertPathValidatorResult JavaDoc result = null;
268         try {
269             validator = CertPathValidator.getInstance(CRLLoginModule.PKIX,securityProvider);
270
271         } catch (NoSuchAlgorithmException JavaDoc e) {
272             logger.severe(" algorithm PKIX is not present "+securityProvider.getName()
273             +" "+securityProvider.getInfo()+" "+securityProvider.getVersion());
274         }
275         try {
276
277                 parameters = new PKIXParameters JavaDoc(trustAnchors);
278                 List JavaDoc certStores = new ArrayList JavaDoc();
279                 CertStore JavaDoc certStore = getCertStore();
280                 certStores.add(certStore);
281                 parameters.setCertStores(certStores);
282                 parameters.setAnyPolicyInhibited(anyPolicyInhibited);
283                 //TODO implement better data handling (more precise)
284
parameters.setDate(new Date JavaDoc());
285                 //TODO howto implements the CRLSelector => with certStore?
286
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                 //TODO define the certSelector
294
//parameters.setTargetCertConstraints(null);
295
//
296
result =(PKIXCertPathValidatorResult JavaDoc)validator.validate(certPath,parameters);
297                 PolicyNode JavaDoc policyTree = result.getPolicyTree();
298                 PublicKey JavaDoc key = result.getPublicKey();
299                 TrustAnchor JavaDoc 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 JavaDoc e) {
311             logger.severe(e.getMessage());
312             throw new FailedLoginException JavaDoc(e.getMessage());
313         } catch (CertPathValidatorException JavaDoc e) {
314             logger.severe(e.getMessage());
315             throw new FailedLoginException JavaDoc(e.getMessage());
316         }
317     }
318
319
320     /**
321      * retrieve the certStore.
322      * @return certStore
323      * @throws LoginException the certStore valueType is invalid
324      */

325     private CertStore JavaDoc getCertStore() throws LoginException JavaDoc{
326         CertStore JavaDoc certStore = null;
327
328                 //build a certStoreParameters object
329
CertStoreParameters JavaDoc certStoreParams = null;
330                 if(certStoreType.equalsIgnoreCase(CRLLoginModule.LDAP)){
331                     certStoreParams = new LDAPCertStoreParameters JavaDoc(ldapServerName,ldapServerPort);
332                 }else if(certStoreType.equalsIgnoreCase(CRLLoginModule.COLLECTION)){
333                     Collection JavaDoc crlCollection = getCRLAndCertsCollection();
334                     certStoreParams = new CollectionCertStoreParameters JavaDoc(crlCollection);
335                 }else{
336                     throw new LoginException JavaDoc(" invalid 'certStoreType' value : this value should be 'LDAP' or 'Collection' ");
337                 }
338                 try {
339                     //build a CRL certStore
340
certStore = CertStore.getInstance(certStoreType,certStoreParams,securityProvider);
341
342                 } catch (NoSuchAlgorithmException JavaDoc e) {
343                     throw new LoginException JavaDoc(e.getMessage());
344                 } catch (InvalidAlgorithmParameterException JavaDoc e) {
345                     throw new LoginException JavaDoc(e.getMessage());
346                 }
347
348         return certStore;
349     }
350
351     /**
352      * retrieve Certificate Revocation List (CRL) and Certificates.
353      * @return collection of CRL and Certificates
354      */

355     private Collection JavaDoc getCRLAndCertsCollection() {
356         Collection JavaDoc crlAndCerts = new ArrayList JavaDoc();
357         CertificateFactory JavaDoc certFactory = null;
358         try {
359             certFactory = CertificateFactory.getInstance(CRLLoginModule.X_509,securityProvider);
360         } catch (CertificateException JavaDoc 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     /**
376      *
377      * add <b>ONE</b> CRL grabbed from a file path to the 'CRLs and Certs' Collection.
378      * @param crlAndCerts
379      * @param certFactory
380      */

381     private void addCRLFromPath(Collection JavaDoc crlAndCerts, CertificateFactory JavaDoc certFactory) {
382
383             InputStream JavaDoc stream = null;
384             try {
385                 stream = new BufferedInputStream JavaDoc(new FileInputStream JavaDoc(fileCrlPath));
386             } catch (FileNotFoundException JavaDoc e) {
387                 e.printStackTrace();
388             }
389             try {
390                 CRL JavaDoc crl = certFactory.generateCRL(stream);
391                 crlAndCerts.add(crl);
392             } catch (CRLException JavaDoc e) {
393                 e.printStackTrace();
394             }finally{
395                   try {
396                     stream.close();
397                 } catch (IOException JavaDoc e) {
398                     e.printStackTrace();
399                 }
400             }
401     }
402
403     /**
404      * add <b>ONE</b> CRL grabbed from an URL to the 'CRLs and Certs' Collection.
405      * @param crlAndCerts
406      * @param certFactory
407      */

408     private void addCRLFromURL(Collection JavaDoc crlAndCerts, CertificateFactory JavaDoc certFactory) {
409             DataInputStream JavaDoc data = null;
410             try {
411                 URL JavaDoc url = new URL JavaDoc(urlCrlPath);
412                 URLConnection JavaDoc connection = url.openConnection();
413                 //we retrieve content
414
connection.setDoInput(true);
415                 //we do not permit to cache content
416
connection.setUseCaches(false);
417                 data = new DataInputStream JavaDoc(connection.getInputStream());
418                 try {
419                     CRL JavaDoc crl = certFactory.generateCRL(data);
420                     crlAndCerts.add(crl);
421                 } catch (CRLException JavaDoc e) {
422                     logger.severe(" CRL cannot be built with the retrieved data ");
423                     e.printStackTrace();
424                 }
425             } catch (MalformedURLException JavaDoc e) {
426                 logger.log(Level.SEVERE, " bad uri synthax "+urlCrlPath,e);
427             } catch (IOException JavaDoc 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 JavaDoc e) {
433                     logger.log(Level.SEVERE, " IOException when we close the DATAInputStream",e);
434                 }
435             }
436     }
437
438     /**
439      * install BouncyCastleProvider in the secuirty providers
440      * stack of the java platform.
441      * @return true if installation succeed, false otherwise
442      */

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 JavaDoc 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