1 17 package org.apache.geronimo.security.keystore; 18 19 import java.io.BufferedOutputStream ; 20 import java.io.File ; 21 import java.io.FileOutputStream ; 22 import java.io.IOException ; 23 import java.io.OutputStream ; 24 import java.math.BigInteger ; 25 import java.net.URI ; 26 import java.net.URISyntaxException ; 27 import java.security.KeyManagementException ; 28 import java.security.KeyStore ; 29 import java.security.KeyStoreException ; 30 import java.security.NoSuchAlgorithmException ; 31 import java.security.NoSuchProviderException ; 32 import java.security.PrivateKey ; 33 import java.security.PublicKey ; 34 import java.security.UnrecoverableKeyException ; 35 import java.security.cert.CertificateException ; 36 import java.security.cert.X509Certificate ; 37 import java.util.ArrayList ; 38 import java.util.Collection ; 39 import java.util.Date ; 40 import java.util.Hashtable ; 41 import java.util.Iterator ; 42 import java.util.List ; 43 import java.util.Vector ; 44 import javax.net.ssl.SSLServerSocketFactory; 45 import javax.net.ssl.SSLSocketFactory; 46 import org.apache.commons.logging.Log; 47 import org.apache.commons.logging.LogFactory; 48 import org.apache.geronimo.gbean.AbstractName; 49 import org.apache.geronimo.gbean.GBeanData; 50 import org.apache.geronimo.gbean.GBeanInfo; 51 import org.apache.geronimo.gbean.GBeanInfoBuilder; 52 import org.apache.geronimo.gbean.GBeanLifecycle; 53 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory; 54 import org.apache.geronimo.kernel.Kernel; 55 import org.apache.geronimo.kernel.config.ConfigurationUtil; 56 import org.apache.geronimo.kernel.config.EditableConfigurationManager; 57 import org.apache.geronimo.kernel.config.InvalidConfigException; 58 import org.apache.geronimo.management.geronimo.KeyIsLocked; 59 import org.apache.geronimo.management.geronimo.KeystoreException; 60 import org.apache.geronimo.management.geronimo.KeystoreInstance; 61 import org.apache.geronimo.management.geronimo.KeystoreIsLocked; 62 import org.apache.geronimo.management.geronimo.KeystoreManager; 63 import org.apache.geronimo.system.serverinfo.ServerInfo; 64 import org.apache.geronimo.util.jce.X509Principal; 65 import org.apache.geronimo.util.jce.X509V1CertificateGenerator; 66 67 73 public class FileKeystoreManager implements KeystoreManager, GBeanLifecycle { 74 private static final Log log = LogFactory.getLog(FileKeystoreManager.class); 75 private File directory; 76 private ServerInfo serverInfo; 77 private URI configuredDir; 78 private Collection keystores; 79 private Kernel kernel; 80 81 public FileKeystoreManager(URI keystoreDir, ServerInfo serverInfo, Collection keystores, Kernel kernel) { 82 configuredDir = keystoreDir; 83 this.serverInfo = serverInfo; 84 this.keystores = keystores; 85 this.kernel = kernel; 86 } 87 88 public void doStart() throws Exception { 89 URI rootURI; 90 if (serverInfo != null) { 91 rootURI = serverInfo.resolve(configuredDir); 92 } else { 93 rootURI = configuredDir; 94 } 95 if (!rootURI.getScheme().equals("file")) { 96 throw new IllegalStateException ("FileKeystoreManager must have a root that's a local directory (not " + rootURI + ")"); 97 } 98 directory = new File (rootURI); 99 if (!directory.exists() || !directory.isDirectory() || !directory.canRead()) { 100 throw new IllegalStateException ("FileKeystoreManager must have a root that's a valid readable directory (not " + directory.getAbsolutePath() + ")"); 101 } 102 log.debug("Keystore directory is " + directory.getAbsolutePath()); 103 } 104 105 public void doStop() throws Exception { 106 } 107 108 public void doFail() { 109 } 110 111 public String [] listKeystoreFiles() { 112 File [] files = directory.listFiles(); 113 List list = new ArrayList (); 114 for (int i = 0; i < files.length; i++) { 115 File file = files[i]; 116 if(file.canRead() && !file.isDirectory()) { 117 list.add(file.getName()); 118 } 119 } 120 return (String []) list.toArray(new String [list.size()]); 121 } 122 123 public KeystoreInstance[] getKeystores() { 124 String [] names = listKeystoreFiles(); 125 KeystoreInstance[] result = new KeystoreInstance[names.length]; 126 for (int i = 0; i < result.length; i++) { 127 result[i] = getKeystore(names[i]); 128 if(result[i] == null) { 129 return null; 130 } 131 } 132 return result; 133 } 134 135 public KeystoreInstance getKeystore(String name) { 136 for (Iterator it = keystores.iterator(); it.hasNext();) { 137 KeystoreInstance instance = (KeystoreInstance) it.next(); 138 if(instance.getKeystoreName().equals(name)) { 139 return instance; 140 } 141 } 142 File test = new File (directory, name); 143 if(!test.exists() || !test.canRead()) { 144 throw new IllegalArgumentException ("Cannot access keystore "+test.getAbsolutePath()+"!"); 145 } 146 AbstractName aName; 147 AbstractName myName = kernel.getAbstractNameFor(this); 148 aName = kernel.getNaming().createSiblingName(myName, name, NameFactory.KEYSTORE_INSTANCE); 149 GBeanData data = new GBeanData(aName, FileKeystoreInstance.getGBeanInfo()); 150 try { 151 String path = configuredDir.toString(); 152 if(!path.endsWith("/")) { 153 path += "/"; 154 } 155 data.setAttribute("keystorePath", new URI (path +name)); 156 } catch (URISyntaxException e) { 157 throw new IllegalStateException ("Can't resolve keystore path: "+e.getMessage()); 158 } 159 data.setReferencePattern("ServerInfo", kernel.getAbstractNameFor(serverInfo)); 160 data.setAttribute("keystoreName", name); 161 EditableConfigurationManager mgr = ConfigurationUtil.getEditableConfigurationManager(kernel); 162 if(mgr != null) { 163 try { 164 mgr.addGBeanToConfiguration(myName.getArtifact(), data, true); 165 return (KeystoreInstance) kernel.getProxyManager().createProxy(aName, KeystoreInstance.class); 166 } catch (InvalidConfigException e) { 167 log.error("Should never happen", e); 168 throw new IllegalStateException ("Unable to add Keystore GBean ("+e.getMessage()+")"); 169 } finally { 170 ConfigurationUtil.releaseConfigurationManager(kernel, mgr); 171 } 172 } else { 173 log.warn("The ConfigurationManager in the kernel does not allow changes at runtime"); 174 return null; 175 } 176 } 177 178 204 public SSLSocketFactory createSSLFactory(String provider, String protocol, String algorithm, String trustStore, ClassLoader loader) throws KeystoreException { 205 return createSSLFactory(provider, protocol, algorithm, null, null, trustStore, loader); 207 } 208 209 236 public SSLSocketFactory createSSLFactory(String provider, String protocol, String algorithm, String keyStore, String keyAlias, String trustStore, ClassLoader loader) throws KeystoreException { 237 KeystoreInstance keyInstance = null; 239 if (keyStore != null) { 240 keyInstance = getKeystore(keyStore); 241 if(keyInstance.isKeystoreLocked()) { 242 throw new KeystoreIsLocked("Keystore '"+keyStore+"' is locked; please use the keystore page in the admin console to unlock it"); 243 } 244 if(keyInstance.isKeyLocked(keyAlias)) { 245 throw new KeystoreIsLocked("Key '"+keyAlias+"' in keystore '"+keyStore+"' is locked; please use the keystore page in the admin console to unlock it"); 246 } 247 } 248 KeystoreInstance trustInstance = trustStore == null ? null : getKeystore(trustStore); 249 if(trustInstance != null && trustInstance.isKeystoreLocked()) { 250 throw new KeystoreIsLocked("Keystore '"+trustStore+"' is locked; please use the keystore page in the admin console to unlock it"); 251 } 252 253 try { 255 Class cls = loader.loadClass("javax.net.ssl.SSLContext"); 256 Object ctx = cls.getMethod("getInstance", new Class [] {String .class}).invoke(null, new Object []{protocol}); 257 Class kmc = loader.loadClass("[Ljavax.net.ssl.KeyManager;"); 258 Class tmc = loader.loadClass("[Ljavax.net.ssl.TrustManager;"); 259 Class src = loader.loadClass("java.security.SecureRandom"); 260 cls.getMethod("init", new Class []{kmc, tmc, src}).invoke(ctx, new Object []{ 261 keyInstance == null ? null : keyInstance.getKeyManager(algorithm, keyAlias, null), 262 trustInstance == null ? null : trustInstance.getTrustManager(algorithm, null), 263 new java.security.SecureRandom ()}); 264 Object result = cls.getMethod("getSocketFactory", new Class [0]).invoke(ctx, new Object [0]); 265 return (SSLSocketFactory) result; 266 } catch (Exception e) { 267 throw new KeystoreException("Unable to create SSL Factory", e); 268 } 269 } 270 271 293 public SSLServerSocketFactory createSSLServerFactory(String provider, String protocol, String algorithm, String keyStore, String keyAlias, String trustStore, ClassLoader loader) throws KeystoreException { 294 KeystoreInstance keyInstance = getKeystore(keyStore); 295 if(keyInstance.isKeystoreLocked()) { 296 throw new KeystoreIsLocked("Keystore '"+keyStore+"' is locked; please use the keystore page in the admin console to unlock it"); 297 } 298 if(keyInstance.isKeyLocked(keyAlias)) { 299 throw new KeystoreIsLocked("Key '"+keyAlias+"' in keystore '"+keyStore+"' is locked; please use the keystore page in the admin console to unlock it"); 300 } 301 KeystoreInstance trustInstance = trustStore == null ? null : getKeystore(trustStore); 302 if(trustInstance != null && trustInstance.isKeystoreLocked()) { 303 throw new KeystoreIsLocked("Keystore '"+trustStore+"' is locked; please use the keystore page in the admin console to unlock it"); 304 } 305 306 try { 308 Class cls = loader.loadClass("javax.net.ssl.SSLContext"); 309 Object ctx = cls.getMethod("getInstance", new Class [] {String .class}).invoke(null, new Object []{protocol}); 310 Class kmc = loader.loadClass("[Ljavax.net.ssl.KeyManager;"); 311 Class tmc = loader.loadClass("[Ljavax.net.ssl.TrustManager;"); 312 Class src = loader.loadClass("java.security.SecureRandom"); 313 cls.getMethod("init", new Class []{kmc, tmc, src}).invoke(ctx, new Object []{keyInstance.getKeyManager(algorithm, keyAlias, null), 314 trustInstance == null ? null : trustInstance.getTrustManager(algorithm, null), 315 new java.security.SecureRandom ()}); 316 Object result = cls.getMethod("getServerSocketFactory", new Class [0]).invoke(ctx, new Object [0]); 317 return (SSLServerSocketFactory) result; 318 } catch (Exception e) { 319 throw new KeystoreException("Unable to create SSL Server Factory", e); 320 } 321 } 322 323 public KeystoreInstance createKeystore(String name, char[] password) throws KeystoreException { 324 File test = new File (directory, name); 325 if(test.exists()) { 326 throw new IllegalArgumentException ("Keystore already exists "+test.getAbsolutePath()+"!"); 327 } 328 try { 329 KeyStore keystore = KeyStore.getInstance(FileKeystoreInstance.JKS); 330 keystore.load(null, password); 331 OutputStream out = new BufferedOutputStream (new FileOutputStream (test)); 332 keystore.store(out, password); 333 out.flush(); 334 out.close(); 335 return getKeystore(name); 336 } catch (KeyStoreException e) { 337 throw new KeystoreException("Unable to create keystore", e); 338 } catch (IOException e) { 339 throw new KeystoreException("Unable to create keystore", e); 340 } catch (NoSuchAlgorithmException e) { 341 throw new KeystoreException("Unable to create keystore", e); 342 } catch (CertificateException e) { 343 throw new KeystoreException("Unable to create keystore", e); 344 } 345 } 346 347 public KeystoreInstance[] getUnlockedKeyStores() { 348 List results = new ArrayList (); 349 for (Iterator it = keystores.iterator(); it.hasNext();) { 350 KeystoreInstance instance = (KeystoreInstance) it.next(); 351 try { 352 if(!instance.isKeystoreLocked() && instance.getUnlockedKeys(null).length > 0) { 353 results.add(instance); 354 } 355 } catch (KeystoreException e) {} 356 } 357 return (KeystoreInstance[]) results.toArray(new KeystoreInstance[results.size()]); 358 } 359 360 public KeystoreInstance[] getUnlockedTrustStores() { 361 List results = new ArrayList (); 362 for (Iterator it = keystores.iterator(); it.hasNext();) { 363 KeystoreInstance instance = (KeystoreInstance) it.next(); 364 try { 365 if(!instance.isKeystoreLocked() && instance.isTrustStore(null)) { 366 results.add(instance); 367 } 368 } catch (KeystoreException e) {} 369 } 370 return (KeystoreInstance[]) results.toArray(new KeystoreInstance[results.size()]); 371 } 372 373 public static final GBeanInfo GBEAN_INFO; 374 375 static { 376 GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(FileKeystoreManager.class); 377 infoFactory.addAttribute("keystoreDir", URI .class, true); 378 infoFactory.addAttribute("kernel", Kernel.class, false); 379 infoFactory.addReference("ServerInfo", ServerInfo.class, "GBean"); 380 infoFactory.addReference("KeystoreInstances", KeystoreInstance.class, NameFactory.KEYSTORE_INSTANCE); 381 infoFactory.addInterface(KeystoreManager.class); 382 infoFactory.setConstructor(new String []{"keystoreDir", "ServerInfo", "KeystoreInstances", "kernel"}); 383 384 GBEAN_INFO = infoFactory.getBeanInfo(); 385 } 386 387 public static GBeanInfo getGBeanInfo() { 388 return GBEAN_INFO; 389 } 390 391 393 public X509Certificate generateCert(PublicKey publicKey, 394 PrivateKey privateKey, String sigalg, int validity, String cn, 395 String ou, String o, String l, String st, String c) 396 throws java.security.SignatureException , 397 java.security.InvalidKeyException { 398 X509V1CertificateGenerator certgen = new X509V1CertificateGenerator(); 399 400 Vector order = new Vector (); 402 Hashtable attrmap = new Hashtable (); 403 404 if (cn != null) { 405 attrmap.put(X509Principal.CN, cn); 406 order.add(X509Principal.CN); 407 } 408 409 if (ou != null) { 410 attrmap.put(X509Principal.OU, ou); 411 order.add(X509Principal.OU); 412 } 413 414 if (o != null) { 415 attrmap.put(X509Principal.O, o); 416 order.add(X509Principal.O); 417 } 418 419 if (l != null) { 420 attrmap.put(X509Principal.L, l); 421 order.add(X509Principal.L); 422 } 423 424 if (st != null) { 425 attrmap.put(X509Principal.ST, st); 426 order.add(X509Principal.ST); 427 } 428 429 if (c != null) { 430 attrmap.put(X509Principal.C, c); 431 order.add(X509Principal.C); 432 } 433 434 X509Principal issuerDN = new X509Principal(order, attrmap); 435 certgen.setIssuerDN(issuerDN); 436 437 long curr = System.currentTimeMillis(); 439 long untill = curr + (long) validity * 24 * 60 * 60 * 1000; 440 441 certgen.setNotBefore(new Date (curr)); 442 certgen.setNotAfter(new Date (untill)); 443 444 certgen.setSubjectDN(issuerDN); 446 447 certgen.setPublicKey(publicKey); 449 450 certgen.setSignatureAlgorithm(sigalg); 452 453 certgen.setSerialNumber(new BigInteger (String.valueOf(curr))); 455 456 return certgen.generateX509Certificate(privateKey); 458 } 459 } 460 | Popular Tags |