KickJava   Java API By Example, From Geeks To Geeks.

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


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  version $Name$
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.ByteArrayInputStream JavaDoc;
31 import java.io.ByteArrayOutputStream JavaDoc;
32 import java.io.File JavaDoc;
33 import java.io.FileInputStream JavaDoc;
34 import java.io.FileNotFoundException JavaDoc;
35 import java.io.IOException JavaDoc;
36 import java.io.InputStream JavaDoc;
37 import java.io.OutputStream JavaDoc;
38 import java.net.HttpURLConnection JavaDoc;
39 import java.net.MalformedURLException JavaDoc;
40 import java.net.ProtocolException JavaDoc;
41 import java.net.URL JavaDoc;
42 import java.security.NoSuchProviderException JavaDoc;
43 import java.security.cert.CertificateException JavaDoc;
44 import java.security.cert.CertificateFactory JavaDoc;
45 import java.security.cert.X509Certificate JavaDoc;
46 import java.util.Map JavaDoc;
47 import java.util.logging.Level JavaDoc;
48 import java.util.logging.Logger JavaDoc;
49
50 import javax.security.auth.Subject JavaDoc;
51 import javax.security.auth.callback.Callback JavaDoc;
52 import javax.security.auth.callback.CallbackHandler JavaDoc;
53 import javax.security.auth.callback.UnsupportedCallbackException JavaDoc;
54 import javax.security.auth.login.FailedLoginException JavaDoc;
55 import javax.security.auth.login.LoginException JavaDoc;
56 import javax.security.auth.spi.LoginModule JavaDoc;
57
58 import net.sf.jguard.ext.SecurityConstants;
59 import net.sf.jguard.ext.authentication.callbacks.CertificatesCallback;
60
61 import org.bouncycastle.ocsp.BasicOCSPResp;
62 import org.bouncycastle.ocsp.CertificateID;
63 import org.bouncycastle.ocsp.OCSPException;
64 import org.bouncycastle.ocsp.OCSPReq;
65 import org.bouncycastle.ocsp.OCSPReqGenerator;
66 import org.bouncycastle.ocsp.OCSPResp;
67 import org.bouncycastle.ocsp.SingleResp;
68
69 /**
70  *
71  * Check the revocation status of a public key certificate using <acronym title="Online Certificate Status Protocol">OCSP</acronym>.
72  * this class comes from the EJBCA project. the <a HREF="http://ejbca.sourceforge.net/">EJBCA</a> project is released under the
73  * <a HREF="http://www.gnu.org/copyleft/lesser.html">LGPL</a> licence. licence, like the jGuard project.
74  *
75  * @author <a HREF="mailto:simon.lebettre[at)gmail.com">Simon Lebettre</a>
76  * @author <a HREF="mailto:diabolo512@users.sourceforge.net">Charles Gay</a>
77  *
78  */

79 public class OCSPLoginModule extends CertificateLoginModule implements LoginModule JavaDoc {
80
81     private static final String JavaDoc X509 = "X509";
82     private static final String JavaDoc CONTENT_TYPE = "Content-Type";
83     private static final String JavaDoc APPLICATION_OCSP_REQUEST = "application/ocsp-request";
84     private static final String JavaDoc POST = "POST";
85     private static final String JavaDoc BC = "BC";
86     /** Logger for this class */
87     private static final Logger JavaDoc logger = Logger.getLogger(OCSPLoginModule.class.getName());
88     private Map JavaDoc sharedState;
89     private boolean debug = false;
90     private CallbackHandler JavaDoc callbackHandler;
91     private Map JavaDoc options;
92     
93     private URL JavaDoc ocspServerUrl;
94     private X509Certificate JavaDoc issuerCACert;
95     private String JavaDoc issuerCACertLocation;
96     private X509Certificate JavaDoc OcspSignerCert;
97     private String JavaDoc OcspSignerCertLocation;
98     private Object JavaDoc certStatus = null;
99     private static boolean SecurityProviderInitialized = false;
100
101     /**
102      * initialize the LoginModule with the required issuer, the OCSP server certificates and its adress.
103      *
104      * @see javax.security.auth.spi.LoginModule#initialize(javax.security.auth.Subject,
105      * javax.security.auth.callback.CallbackHandler, java.util.Map, java.util.Map)
106      */

107     public void initialize(Subject JavaDoc subj, CallbackHandler JavaDoc cbkHandler, Map JavaDoc sState, Map JavaDoc opts) {
108         super.subject = subj;
109         this.callbackHandler = cbkHandler;
110         this.sharedState = sState;
111         this.options = opts;
112
113         if (!SecurityProviderInitialized) {
114             SecurityProviderInitialized = CRLLoginModule.initSecurityProvider();
115         }
116
117         try {
118             ocspServerUrl = new URL JavaDoc((String JavaDoc) options.get(SecurityConstants.OCSP_SERVER_URL));
119         } catch (MalformedURLException JavaDoc e) {
120             logger.severe("ocspServerUrl=" + ocspServerUrl + " is malformed");
121             throw new IllegalArgumentException JavaDoc(e.getMessage());
122         }
123         issuerCACertLocation = (String JavaDoc) options.get(SecurityConstants.ISSUER_CA_CERT_LOCATION);
124         try {
125             issuerCACert = getCertFromFile(issuerCACertLocation);
126             OcspSignerCertLocation = (String JavaDoc) options.get(SecurityConstants.OCSP_SIGNER_CERT_LOCATION);
127             OcspSignerCert = getCertFromFile(OcspSignerCertLocation);
128         } catch (CertificateException JavaDoc e) {
129             logger.log(Level.SEVERE, "", e);
130             throw new IllegalArgumentException JavaDoc(e.getMessage());
131         }
132
133         if (!issuerCACert.equals(OcspSignerCert)) {
134             throw new UnsupportedOperationException JavaDoc("Having a CA cert different "
135                     + "from ocspSigner cert is not currently supported," + " the ocsp response is signed by the CA ");
136         }
137
138     }
139
140     /**
141      * verify either user is registered or not.
142      * @see javax.security.auth.spi.LoginModule#login()
143      */

144     public boolean login() throws LoginException JavaDoc {
145         if (callbackHandler == null) {
146             loginOK = false;
147             throw new LoginException JavaDoc("there is no CallbackHandler to authenticate the user");
148         }
149         Callback JavaDoc[] callbacks = new Callback JavaDoc[1];
150         callbacks[0] = new CertificatesCallback();
151         try {
152             callbackHandler.handle(callbacks);
153         } catch (IOException JavaDoc e1) {
154             logger.log(Level.SEVERE, " IOException when we handle callbacks with callback " + callbackHandler.getClass().getName(), e1);
155         } catch (UnsupportedCallbackException JavaDoc e1) {
156             logger.log(Level.SEVERE, " one callback type is not supported ", e1);
157         }
158         certChainToCheck = ((CertificatesCallback) callbacks[0]).getCertificates();
159         if (certChainToCheck == null ||certChainToCheck.length==0) {
160             loginOK = false;
161             //no certificates can be checked so we inactivate this loginmodule
162
return false;
163         }
164         byte[] ocspRequest;
165         try {
166             OCSPResp response = null;
167             try {
168                 ocspRequest = generateOcspRequest(certChainToCheck);
169                 byte[] respBytes = getResponseFromHttp(ocspRequest, ocspServerUrl);
170                 response = new OCSPResp(new ByteArrayInputStream JavaDoc(respBytes));
171             } catch (IOException JavaDoc e) {
172                 logger.log(Level.SEVERE, " IOException when we build the OCSPResponse from HTTP ", e);
173
174             }
175
176             BasicOCSPResp brep = (BasicOCSPResp) response.getResponseObject();
177             X509Certificate JavaDoc[] chain = brep.getCerts(OCSPLoginModule.BC);
178             boolean verify = brep.verify(chain[0].getPublicKey(), OCSPLoginModule.BC);
179
180             if (!verify) {
181                 loginOK = false;
182                 throw new LoginException JavaDoc(" OCSP response is not valid ");
183             }
184
185             SingleResp[] singleResps = brep.getResponses();
186             for (int i = 0; i < singleResps.length; i++) {
187                 SingleResp singleResp = singleResps[i];
188                 certStatus = singleResp.getCertStatus();
189                 // when the status object is null, the response is good (@see org.bouncycastle.ocsp.SingleResp )
190

191                 if (certStatus == null) {
192                     continue;
193                 } else {
194                     loginOK = false;
195                     throw new FailedLoginException JavaDoc(" status is not null. 'null' is the success result " + certStatus.toString());
196                 }
197             }
198
199         } catch (OCSPException e) {
200             throw new LoginException JavaDoc(e.getMessage());
201         } catch (NoSuchProviderException JavaDoc e) {
202             throw new LoginException JavaDoc(e.getMessage());
203         }
204         //like we've arleady check user credentials present in the certificate
205
//password check must not be done one more time.
206
sharedState.put(SecurityConstants.SKIP_PASSWORD_CHECK, "true");
207         return true;
208
209     }
210
211     /**
212      * ask from the OCSP server if the certificate is valid.
213      *
214      * @param ocspPackage
215      * @param url
216      * @return response from the OCSP server.
217      * @throws IOException
218      * @throws IOException
219      * @throws ProtocolException
220      */

221     private byte[] getResponseFromHttp(byte[] ocspPackage, URL JavaDoc url) throws IOException JavaDoc {
222         HttpURLConnection JavaDoc con = (HttpURLConnection JavaDoc) url.openConnection();
223
224         con.setDoOutput(true);
225         try {
226             con.setRequestMethod(OCSPLoginModule.POST);
227         } catch (ProtocolException JavaDoc e) {
228             throw new IOException JavaDoc(e.getMessage());
229         }
230
231         con.setRequestProperty(OCSPLoginModule.CONTENT_TYPE, OCSPLoginModule.APPLICATION_OCSP_REQUEST);
232         OutputStream JavaDoc os = null;
233         try{
234             os = con.getOutputStream();
235             os.write(ocspPackage);
236         }catch(IOException JavaDoc e){
237             logger.severe(e.getMessage());
238             throw e;
239         }finally{
240             os.close();
241         }
242         InputStream JavaDoc in = null;
243         byte[] respBytes = null;
244         ByteArrayOutputStream JavaDoc baos = null;
245         try{
246             baos = new ByteArrayOutputStream JavaDoc();
247
248             // This works for small requests, and OCSP requests are small
249
in = con.getInputStream();
250             int b = in.read();
251             while (b != -1) {
252                 baos.write(b);
253                 b = in.read();
254             }
255             baos.flush();
256         }finally{
257             in.close();
258             con.disconnect();
259         }
260         respBytes = baos.toByteArray();
261         return respBytes;
262
263     }
264
265     /**
266      * generate the OCSP request.
267      * @param certsToCheck
268      * @return byte[] ocsp request
269      * @throws OCSPException
270      * @throws IOException
271      */

272     private byte[] generateOcspRequest(X509Certificate JavaDoc[] certsToCheck) throws OCSPException, IOException JavaDoc {
273         OCSPReqGenerator gen = new OCSPReqGenerator();
274         for (int i = 0; i < certsToCheck.length; i++) {
275             X509Certificate JavaDoc certToCheck = certsToCheck[i];
276             gen.addRequest(new CertificateID(CertificateID.HASH_SHA1, issuerCACert, certToCheck.getSerialNumber()));
277         }
278         OCSPReq req = gen.generate();
279         byte[] ocspRequest = req.getEncoded();
280         return ocspRequest;
281     }
282
283
284     /**
285      * Read a certificate from the specified filepath.
286      *
287      * @param path
288      * @return certificate
289      * @throws CertificateException
290      */

291     public static X509Certificate JavaDoc getCertFromFile(String JavaDoc path) throws CertificateException JavaDoc {
292         X509Certificate JavaDoc cert = null;
293
294         File JavaDoc certFile = new File JavaDoc(path);
295         if (!certFile.canRead()) {
296             logger.severe(" File " + certFile.toString() + " is unreadable");
297             throw new CertificateException JavaDoc(" File " + certFile.toString() + " is unreadable");
298
299         }
300         FileInputStream JavaDoc fis = null;
301         try {
302             fis = new FileInputStream JavaDoc(path);
303             CertificateFactory JavaDoc cf;
304             cf = CertificateFactory.getInstance(OCSPLoginModule.X509);
305             cert = (X509Certificate JavaDoc) cf.generateCertificate(fis);
306         } catch (FileNotFoundException JavaDoc e) {
307             logger.log(Level.SEVERE, "we cannot found the certificate file here:" + path, e);
308         }finally{
309             try {
310                 fis.close();
311             } catch (IOException JavaDoc e) {
312                 logger.severe(e.getMessage());
313             }
314         }
315         
316
317         return cert;
318     }
319
320 }
321
Popular Tags