-
1. Re: SSL Certificates Dynamic Loading
rgurzhiy Nov 14, 2008 8:02 AM (in response to vishal_badha)Hy.
I faced the same problem. Have you solve it? -
2. Re: SSL Certificates Dynamic Loading
rgurzhiy Nov 17, 2008 4:45 AM (in response to vishal_badha)Hello.
I found some information, but it still not work.
Anyway...
I use JBoss Portal 2.7.0 (with JBoss AS 4.2.3)
I have configured my security to use jboss implementation.
This is my ssl connector from [path-to-jboss-default]/deploy/jboss-web.deployer/server.xml<Connector port="443" address="${jboss.bind.address}" protocol="HTTP/1.1" SSLEnabled="true" maxThreads="100" strategy="ms" maxHttpHeaderSize="8192" emptySessionPath="true" scheme="https" secure="true" clientAuth="true" securityDomain="java:/jaas/portal-ssl" SSLImplementation="org.jboss.net.ssl.JBossImplementation" sslProtocol="TLS"> <Factory className="org.apache.catalina.net.SSLServerSocketFactory" /> </Connector>
this is my new JbossSecurityDomain from [path-to-jboss-default]/conf/jboss-service.xml<mbean code="org.jboss.security.plugins.JaasSecurityDomain" name="jboss.security:service=JaasSecurityDomain,domain=portal-ssl"> <depends>jboss.security:service=JaasSecurityManager</depends> <constructor> <arg type="java.lang.String" value="portal-ssl" /> </constructor> <attribute name="ManagerServiceName">jboss.security:service=JaasSecurityManager</attribute> <attribute name="KeyStoreURL">D:/server.keystore</attribute> <attribute name="KeyStorePass">server</attribute> <attribute name="TrustStoreURL">D:/trusted.keystore</attribute> <attribute name="TrustStorePass">trusted</attribute> </mbean>
So, my security uses keystores from this mbean.
after that I inserted in my code, that updates keystoresObjectName jaasMgr = new ObjectName("jboss.security:service=JaasSecurityDomain,domain=portal-ssl"); Object[] params = {}; String[] signature = {}; MBeanServer server = (MBeanServer) MBeanServerFactory.findMBeanServer(null).get(0); server.invoke(jaasMgr, "reloadKeyAndTrustStore", params, signature);
I don't know, what reloadKeyAndTrustStore mbean method do, but I suppose, that it reloads cached keystores.
Well, result is - keystores does not reload if I invoke reloadKeyAndTrustStore either from my code or from jmx-console. Changes does not apply until restart jboss.
Can anybody help me with my configuration? -
3. Re: SSL Certificates Dynamic Loading
rgurzhiy Nov 17, 2008 4:04 PM (in response to vishal_badha)Hello again.
After some debug and source code research, I found solution. It is not so beautiful and seems to be workaround, but it works. Well, I hope it would be useful not only for me.
What have I found.
JaasSecurityDomain realy updates keystores, but only in itself. Ssl JBossImplementation in server.xml used only to create and return JBossSocketFactory. Factory gets SecurityDomain by JNDI to init and create socket. But... There is so called SSLContext, that takes care about keystore usage and ssl-handshakes, and it uses SecurityDomain only in initialisation. So, after socket building SSLContext use cached keystores.
Well, my solution.
I wrote custom implementation of 3 classes
org.jboss.net.ssl.JBossReloadableImplementationpackage org.jboss.net.ssl; import org.apache.tomcat.util.net.ServerSocketFactory; public class JBossReloadableImplementation extends JBossImplementation { public JBossReloadableImplementation() throws ClassNotFoundException { super(); } public String getImplementationName() { return "JBossReloadable"; } public ServerSocketFactory getServerSocketFactory() { return new JBossReloadableSocketFactory(); } }
as I said, it used only to provide new JBossReloadableSocketFactory
org.jboss.security.plugins.JaasSecurityDomainReloadablepackage org.jboss.security.plugins; import javax.security.auth.callback.CallbackHandler; import org.jboss.net.ssl.JBossReloadableSocketFactory; public class JaasSecurityDomainReloadable extends JaasSecurityDomain { public JaasSecurityDomainReloadable() { super(); } public JaasSecurityDomainReloadable(String securityDomain) { super(securityDomain); } public JaasSecurityDomainReloadable(String securityDomain, CallbackHandler handler){ super(securityDomain, handler); } @Override public void reloadKeyAndTrustStore() throws Exception { super.reloadKeyAndTrustStore(); //if keystores reloaded successfully, reload them in socket factory socketFactory.reload(); } //Socket factory, where we want to reload keystores private JBossReloadableSocketFactory socketFactory; public void setSocketFactory(JBossReloadableSocketFactory socketFactory) { this.socketFactory = socketFactory; } }
in this class I added method setSocketFactory to post SocketFactory to SecurityDomain, and changed method reloadKeyAndTrustStore. Now it executes SessionFactories method reload() to reload keystores in SSLContext.
org.jboss.net.ssl.JBossReloadableSocketFactorypackage org.jboss.net.ssl; import java.io.IOException; import java.net.InetAddress; import java.net.ServerSocket; import java.security.KeyManagementException; import java.security.SecureRandom; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; import org.jboss.security.SecurityDomain; import org.jboss.security.plugins.JaasSecurityDomainReloadable; public class JBossReloadableSocketFactory extends JBossSocketFactory { @Override public void setSecurityDomainName(String jndiName) throws NamingException, IOException { super.setSecurityDomainName(jndiName); //We can'n get parents securityDomain, cause it's private. Get it from JNDI. InitialContext iniCtx = new InitialContext(); SecurityDomain securityDomain = (SecurityDomain) iniCtx.lookup(jndiName); //If we use reloadable domain, set socket factory (when mbeans reloadKeyAndTrustStore method invokes, we reload keystores in factory) if (securityDomain instanceof JaasSecurityDomainReloadable) { ((JaasSecurityDomainReloadable) securityDomain).setSocketFactory(this); } } //Changed init() method from JSSESocketFactory (we can't override cause it is default) static String defaultProtocol = "TLS"; static String defaultKeystoreType = "JKS"; private SSLContext context = null; void initSsl() throws IOException { try { String clientAuthStr = (String) attributes.get("clientauth"); if("true".equalsIgnoreCase(clientAuthStr) || "yes".equalsIgnoreCase(clientAuthStr)) { requireClientAuth = true; } else if("want".equalsIgnoreCase(clientAuthStr)) { wantClientAuth = true; } String protocol = (String) attributes.get("protocol"); if (protocol == null) { protocol = defaultProtocol; } String algorithm = (String) attributes.get("algorithm"); if (algorithm == null) { algorithm = KeyManagerFactory.getDefaultAlgorithm();; } String keystoreType = (String) attributes.get("keystoreType"); if (keystoreType == null) { keystoreType = defaultKeystoreType; } String trustAlgorithm = (String)attributes.get("truststoreAlgorithm"); if( trustAlgorithm == null ) { trustAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); } //Changes - we use only one SSLContext. If it is not null use old (just load new keystores in init method) if (context==null) context = SSLContext.getInstance(protocol); context.init(getKeyManagers(keystoreType, algorithm, (String) attributes.get("keyAlias")), getTrustManagers(keystoreType, trustAlgorithm), new SecureRandom()); sslProxy = context.getServerSocketFactory(); String requestedCiphers = (String)attributes.get("ciphers"); enabledCiphers = getEnabledCiphers(requestedCiphers, sslProxy.getSupportedCipherSuites()); //Set initialized = true to avoid execution of init() method from JSSESocketFactory initialized = true; } catch(Exception e) { if( e instanceof IOException ) throw (IOException)e; throw new IOException (e.getMessage()); } } public void reload() throws KeyManagementException, Exception { initSsl(); } //Updated methods createSocket (use initSsl() instead of init()) @Override public ServerSocket createSocket(int port) throws IOException { if(!initialized) initSsl(); return super.createSocket(port); } @Override public ServerSocket createSocket(int port, int backlog) throws IOException { if(!initialized) initSsl(); return super.createSocket(port, backlog); } @Override public ServerSocket createSocket(int port, int backlog, InetAddress ifAddress) throws IOException { if(!initialized) initSsl(); return super.createSocket(port, backlog, ifAddress); } }
here I created methods initSsl() and reload(), overrode 3 createSocket methods (to use my initSsl instead of default init) and remembered SSLContext, using by our sockets (to update keystores in it)
I have packed these classes in jar and put it to my [path-to-jboss-default]/deploy/jboss-web.deployer (JBoss AS 4.2.3).
Now configuration:
SSL connector in [path-to-jboss-default]/deploy/jboss-web.deployer/server.xml<Connector port="443" address="${jboss.bind.address}" protocol="HTTP/1.1" SSLEnabled="true" maxThreads="100" strategy="ms" maxHttpHeaderSize="8192" emptySessionPath="true" scheme="https" secure="true" clientAuth="true" securityDomain="java:/jaas/portal-ssl" SSLImplementation="org.jboss.net.ssl.JBossReloadableImplementation" sslProtocol="TLS" />
SecurityDomain mbean in [path-to-jboss-default]/deploy/jboss-web.deployer/META-INF/jboss-service.xml<mbean code="org.jboss.security.plugins.JaasSecurityDomainReloadable" name="jboss.security:service=JaasSecurityDomain,domain=portal-ssl"> <depends>jboss.security:service=JaasSecurityManager</depends> <constructor> <arg type="java.lang.String" value="portal-ssl" /> </constructor> <attribute name="ManagerServiceName">jboss.security:service=JaasSecurityManager</attribute> <attribute name="KeyStoreURL">D:/server.keystore</attribute> <attribute name="KeyStorePass">server</attribute> <attribute name="TrustStoreURL">D:/trusted.keystore</attribute> <attribute name="TrustStorePass">trusted</attribute> </mbean>
And finally, I use mbeans reloadKeyAndTrustStore method invocation from previous post. You may also invoke this method from jmx-console.
Hope this post will help someone )))