| 1 28 package net.sf.jguard.ext.authentication.loginmodules; 29 30 import java.io.ByteArrayInputStream ; 31 import java.io.ByteArrayOutputStream ; 32 import java.io.File ; 33 import java.io.FileInputStream ; 34 import java.io.FileNotFoundException ; 35 import java.io.IOException ; 36 import java.io.InputStream ; 37 import java.io.OutputStream ; 38 import java.net.HttpURLConnection ; 39 import java.net.MalformedURLException ; 40 import java.net.ProtocolException ; 41 import java.net.URL ; 42 import java.security.NoSuchProviderException ; 43 import java.security.cert.CertificateException ; 44 import java.security.cert.CertificateFactory ; 45 import java.security.cert.X509Certificate ; 46 import java.util.Map ; 47 import java.util.logging.Level ; 48 import java.util.logging.Logger ; 49 50 import javax.security.auth.Subject ; 51 import javax.security.auth.callback.Callback ; 52 import javax.security.auth.callback.CallbackHandler ; 53 import javax.security.auth.callback.UnsupportedCallbackException ; 54 import javax.security.auth.login.FailedLoginException ; 55 import javax.security.auth.login.LoginException ; 56 import javax.security.auth.spi.LoginModule ; 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 79 public class OCSPLoginModule extends CertificateLoginModule implements LoginModule { 80 81 private static final String X509 = "X509"; 82 private static final String CONTENT_TYPE = "Content-Type"; 83 private static final String APPLICATION_OCSP_REQUEST = "application/ocsp-request"; 84 private static final String POST = "POST"; 85 private static final String BC = "BC"; 86 87 private static final Logger logger = Logger.getLogger(OCSPLoginModule.class.getName()); 88 private Map sharedState; 89 private boolean debug = false; 90 private CallbackHandler callbackHandler; 91 private Map options; 92 93 private URL ocspServerUrl; 94 private X509Certificate issuerCACert; 95 private String issuerCACertLocation; 96 private X509Certificate OcspSignerCert; 97 private String OcspSignerCertLocation; 98 private Object certStatus = null; 99 private static boolean SecurityProviderInitialized = false; 100 101 107 public void initialize(Subject subj, CallbackHandler cbkHandler, Map sState, Map 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 ((String ) options.get(SecurityConstants.OCSP_SERVER_URL)); 119 } catch (MalformedURLException e) { 120 logger.severe("ocspServerUrl=" + ocspServerUrl + " is malformed"); 121 throw new IllegalArgumentException (e.getMessage()); 122 } 123 issuerCACertLocation = (String ) options.get(SecurityConstants.ISSUER_CA_CERT_LOCATION); 124 try { 125 issuerCACert = getCertFromFile(issuerCACertLocation); 126 OcspSignerCertLocation = (String ) options.get(SecurityConstants.OCSP_SIGNER_CERT_LOCATION); 127 OcspSignerCert = getCertFromFile(OcspSignerCertLocation); 128 } catch (CertificateException e) { 129 logger.log(Level.SEVERE, "", e); 130 throw new IllegalArgumentException (e.getMessage()); 131 } 132 133 if (!issuerCACert.equals(OcspSignerCert)) { 134 throw new UnsupportedOperationException ("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 144 public boolean login() throws LoginException { 145 if (callbackHandler == null) { 146 loginOK = false; 147 throw new LoginException ("there is no CallbackHandler to authenticate the user"); 148 } 149 Callback [] callbacks = new Callback [1]; 150 callbacks[0] = new CertificatesCallback(); 151 try { 152 callbackHandler.handle(callbacks); 153 } catch (IOException e1) { 154 logger.log(Level.SEVERE, " IOException when we handle callbacks with callback " + callbackHandler.getClass().getName(), e1); 155 } catch (UnsupportedCallbackException 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 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 (respBytes)); 171 } catch (IOException 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 [] 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 (" 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 191 if (certStatus == null) { 192 continue; 193 } else { 194 loginOK = false; 195 throw new FailedLoginException (" status is not null. 'null' is the success result " + certStatus.toString()); 196 } 197 } 198 199 } catch (OCSPException e) { 200 throw new LoginException (e.getMessage()); 201 } catch (NoSuchProviderException e) { 202 throw new LoginException (e.getMessage()); 203 } 204 sharedState.put(SecurityConstants.SKIP_PASSWORD_CHECK, "true"); 207 return true; 208 209 } 210 211 221 private byte[] getResponseFromHttp(byte[] ocspPackage, URL url) throws IOException { 222 HttpURLConnection con = (HttpURLConnection ) url.openConnection(); 223 224 con.setDoOutput(true); 225 try { 226 con.setRequestMethod(OCSPLoginModule.POST); 227 } catch (ProtocolException e) { 228 throw new IOException (e.getMessage()); 229 } 230 231 con.setRequestProperty(OCSPLoginModule.CONTENT_TYPE, OCSPLoginModule.APPLICATION_OCSP_REQUEST); 232 OutputStream os = null; 233 try{ 234 os = con.getOutputStream(); 235 os.write(ocspPackage); 236 }catch(IOException e){ 237 logger.severe(e.getMessage()); 238 throw e; 239 }finally{ 240 os.close(); 241 } 242 InputStream in = null; 243 byte[] respBytes = null; 244 ByteArrayOutputStream baos = null; 245 try{ 246 baos = new ByteArrayOutputStream (); 247 248 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 272 private byte[] generateOcspRequest(X509Certificate [] certsToCheck) throws OCSPException, IOException { 273 OCSPReqGenerator gen = new OCSPReqGenerator(); 274 for (int i = 0; i < certsToCheck.length; i++) { 275 X509Certificate 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 291 public static X509Certificate getCertFromFile(String path) throws CertificateException { 292 X509Certificate cert = null; 293 294 File certFile = new File (path); 295 if (!certFile.canRead()) { 296 logger.severe(" File " + certFile.toString() + " is unreadable"); 297 throw new CertificateException (" File " + certFile.toString() + " is unreadable"); 298 299 } 300 FileInputStream fis = null; 301 try { 302 fis = new FileInputStream (path); 303 CertificateFactory cf; 304 cf = CertificateFactory.getInstance(OCSPLoginModule.X509); 305 cert = (X509Certificate ) cf.generateCertificate(fis); 306 } catch (FileNotFoundException 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 e) { 312 logger.severe(e.getMessage()); 313 } 314 } 315 316 317 return cert; 318 } 319 320 } 321 | Popular Tags |