Commit f3c3d13e authored by Guus der Kinderen's avatar Guus der Kinderen

OF-946: Jetty SslContextFactory instantion should not be duplicated.

SSLConfig can now be used to get a consistently configured Jetty SSL configuration.
parent 938c0f26
...@@ -148,23 +148,10 @@ public class AdminConsolePlugin implements Plugin { ...@@ -148,23 +148,10 @@ public class AdminConsolePlugin implements Plugin {
Log.warn("Admin console: Using RSA certificates but they are not valid for the hosted domain"); Log.warn("Admin console: Using RSA certificates but they are not valid for the hosted domain");
} }
final TrustStoreConfig trustStoreConfig = SSLConfig.getInstance().getTrustStoreConfig( Purpose.WEBADMIN ); final SslContextFactory sslContextFactory = SSLConfig.getSslContextFactory( Purpose.WEBADMIN );
final SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setTrustStorePath( trustStoreConfig.getCanonicalPath() );
sslContextFactory.setTrustStorePassword( trustStoreConfig.getPassword() );
sslContextFactory.setTrustStoreType( trustStoreConfig.getType() );
sslContextFactory.setKeyStorePath( identityStoreConfig.getCanonicalPath() );
sslContextFactory.setKeyStorePassword( identityStoreConfig.getPassword() );
sslContextFactory.setKeyStoreType( identityStoreConfig.getType() );
sslContextFactory.addExcludeProtocols( "SSLv3" );
sslContextFactory.setNeedClientAuth( false );
sslContextFactory.setWantClientAuth( false );
final ServerConnector httpsConnector; final ServerConnector httpsConnector;
if ("npn".equals(JiveGlobals.getXMLProperty("spdy.protocol", ""))) if ("npn".equals(JiveGlobals.getXMLProperty("spdy.protocol", ""))) {
{
httpsConnector = new HTTPSPDYServerConnector(adminServer, sslContextFactory); httpsConnector = new HTTPSPDYServerConnector(adminServer, sslContextFactory);
} else { } else {
......
...@@ -64,6 +64,7 @@ import org.jivesoftware.openfire.XMPPServer; ...@@ -64,6 +64,7 @@ import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.keystore.IdentityStoreConfig; import org.jivesoftware.openfire.keystore.IdentityStoreConfig;
import org.jivesoftware.openfire.keystore.Purpose; import org.jivesoftware.openfire.keystore.Purpose;
import org.jivesoftware.openfire.keystore.CertificateStoreConfig; import org.jivesoftware.openfire.keystore.CertificateStoreConfig;
import org.jivesoftware.openfire.keystore.TrustStoreConfig;
import org.jivesoftware.openfire.net.SSLConfig; import org.jivesoftware.openfire.net.SSLConfig;
import org.jivesoftware.openfire.session.ConnectionSettings; import org.jivesoftware.openfire.session.ConnectionSettings;
import org.jivesoftware.util.CertificateEventListener; import org.jivesoftware.util.CertificateEventListener;
...@@ -259,38 +260,15 @@ public final class HttpBindManager { ...@@ -259,38 +260,15 @@ public final class HttpBindManager {
"the hosted domain"); "the hosted domain");
} }
final TrustStoreConfig trustStoreConfig = SSLConfig.getInstance().getTrustStoreConfig( Purpose.BOSH_C2S ); final SslContextFactory sslContextFactory = SSLConfig.getSslContextFactory( Purpose.BOSH_C2S );
final SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setTrustStorePath( trustStoreConfig.getCanonicalPath() );
sslContextFactory.setTrustStorePassword( trustStoreConfig.getPassword() );
sslContextFactory.setTrustStoreType( trustStoreConfig.getType() );
sslContextFactory.setKeyStorePath( identityStoreConfig.getCanonicalPath() );
sslContextFactory.setKeyStorePassword( identityStoreConfig.getPassword() );
sslContextFactory.setKeyStoreType( identityStoreConfig.getType() );
sslContextFactory.addExcludeProtocols( "SSLv3" );
// Set policy for checking client certificates
String certPol = JiveGlobals.getProperty(HTTP_BIND_AUTH_PER_CLIENTCERT_POLICY, "disabled");
if(certPol.equals("needed")) {
sslContextFactory.setNeedClientAuth(true);
sslContextFactory.setWantClientAuth(true);
} else if(certPol.equals("wanted")) {
sslContextFactory.setNeedClientAuth(false);
sslContextFactory.setWantClientAuth(true);
} else {
sslContextFactory.setNeedClientAuth(false);
sslContextFactory.setWantClientAuth(false);
}
HttpConfiguration httpsConfig = new HttpConfiguration(); final HttpConfiguration httpsConfig = new HttpConfiguration();
httpsConfig.setSecureScheme("https"); httpsConfig.setSecureScheme("https");
httpsConfig.setSecurePort(securePort); httpsConfig.setSecurePort(securePort);
configureProxiedConnector(httpsConfig); configureProxiedConnector(httpsConfig);
httpsConfig.addCustomizer(new SecureRequestCustomizer()); httpsConfig.addCustomizer(new SecureRequestCustomizer());
ServerConnector sslConnector = null; final ServerConnector sslConnector;
if ("npn".equals(JiveGlobals.getXMLProperty("spdy.protocol", ""))) if ("npn".equals(JiveGlobals.getXMLProperty("spdy.protocol", "")))
{ {
......
...@@ -4,6 +4,7 @@ import org.jivesoftware.util.JiveGlobals; ...@@ -4,6 +4,7 @@ import org.jivesoftware.util.JiveGlobals;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Set;
/** /**
* Potential intended usages (for TLS connectivity). * Potential intended usages (for TLS connectivity).
...@@ -138,7 +139,7 @@ public enum Purpose ...@@ -138,7 +139,7 @@ public enum Purpose
public String getIdentityStoreLocation() throws IOException public String getIdentityStoreLocation() throws IOException
{ {
return canonicalize( getIdentityStoreLocation() ); return canonicalize( getIdentityStoreLocationNonCanonicalized() );
} }
public String getIdentityStoreLocationNonCanonicalized() public String getIdentityStoreLocationNonCanonicalized()
...@@ -158,7 +159,7 @@ public enum Purpose ...@@ -158,7 +159,7 @@ public enum Purpose
public String getTrustStoreLocation() throws IOException public String getTrustStoreLocation() throws IOException
{ {
return canonicalize( getTrustStoreLocation() ); return canonicalize( getTrustStoreLocationNonCanonicalized() );
} }
public String getTrustStoreLocationNonCanonicalized() public String getTrustStoreLocationNonCanonicalized()
...@@ -176,6 +177,67 @@ public enum Purpose ...@@ -176,6 +177,67 @@ public enum Purpose
} }
} }
public String getProtocolsEnabled()
{
final String propertyName = prefix + "protocols.enabled";
final String defaultValue = "TLSv1,TLSv1.1,TLSv1.2";
if ( fallback == null )
{
return JiveGlobals.getProperty( propertyName, defaultValue ).trim();
}
else
{
return JiveGlobals.getProperty( propertyName, fallback.getProtocolsEnabled() ).trim();
}
}
public String getProtocolsDisabled()
{
final String propertyName = prefix + "protocols.disabled";
final String defaultValue = "SSLv1,SSLv2,SSLv2Hello,SSLv3";
if ( fallback == null )
{
return JiveGlobals.getProperty( propertyName, defaultValue ).trim();
}
else
{
return JiveGlobals.getProperty( propertyName, fallback.getProtocolsDisabled() ).trim();
}
}
public String getCipherSuitesEnabled()
{
final String propertyName = prefix + "ciphersuites.enabled";
final String defaultValue = "";
final String result;
if ( fallback == null )
{
return JiveGlobals.getProperty( propertyName, defaultValue );
}
else
{
return JiveGlobals.getProperty( propertyName, fallback.getCipherSuitesEnabled() );
}
}
public String getCipherSuitesDisabled()
{
final String propertyName = prefix + "ciphersuites.disabled";
final String defaultValue = null;
if ( fallback == null )
{
return JiveGlobals.getProperty( propertyName, defaultValue ).trim();
}
else
{
return JiveGlobals.getProperty( propertyName, fallback.getCipherSuitesDisabled() ).trim();
}
}
public static String canonicalize( String path ) throws IOException public static String canonicalize( String path ) throws IOException
{ {
File file = new File( path ); File file = new File( path );
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
package org.jivesoftware.openfire.net; package org.jivesoftware.openfire.net;
import org.apache.mina.filter.ssl.SslFilter; import org.apache.mina.filter.ssl.SslFilter;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.jivesoftware.openfire.Connection; import org.jivesoftware.openfire.Connection;
import org.jivesoftware.openfire.keystore.*; import org.jivesoftware.openfire.keystore.*;
import org.jivesoftware.openfire.session.ConnectionSettings; import org.jivesoftware.openfire.session.ConnectionSettings;
...@@ -406,7 +407,6 @@ public class SSLConfig ...@@ -406,7 +407,6 @@ public class SSLConfig
final SSLContext sslContext = SSLContext.getInstance( purpose.getIdentityStoreType() ); final SSLContext sslContext = SSLContext.getInstance( purpose.getIdentityStoreType() );
sslContext.init( keyManagers, trustManagers, new SecureRandom() ); sslContext.init( keyManagers, trustManagers, new SecureRandom() );
return sslContext; return sslContext;
} }
...@@ -473,12 +473,89 @@ public class SSLConfig ...@@ -473,12 +473,89 @@ public class SSLConfig
final SSLContext sslContext = getSSLContext( purpose ); final SSLContext sslContext = getSSLContext( purpose );
final SSLEngine sslEngine = sslContext.createSSLEngine(); final SSLEngine sslEngine = sslContext.createSSLEngine();
configureProtocols( sslEngine, purpose );
configureCipherSuites( sslEngine, purpose ); // Configure protocol support.
if ( purpose.getProtocolsEnabled() != null && !purpose.getProtocolsEnabled().isEmpty() )
{
// When an explicit list of enabled protocols is defined, use only those.
sslEngine.setEnabledProtocols( purpose.getProtocolsEnabled().split( "," ) );
}
else if ( purpose.getProtocolsDisabled() != null && !purpose.getProtocolsDisabled().isEmpty() )
{
// Otherwise, use all supported protocols (except for the ones that are explicitly disabled).
final List<String> disabled = Arrays.asList( purpose.getProtocolsDisabled() );
final ArrayList<String> supported = new ArrayList<>( );
for ( final String candidate : sslEngine.getSupportedProtocols() ) {
if ( !disabled.contains( candidate ) ) {
supported.add( candidate );
}
}
sslEngine.setEnabledProtocols( supported.toArray( new String[ supported.size()] ) );
}
// Configure cipher suite support.
if ( purpose.getCipherSuitesEnabled() != null && !purpose.getCipherSuitesEnabled().isEmpty() )
{
// When an explicit list of enabled protocols is defined, use only those.
sslEngine.setEnabledCipherSuites( purpose.getCipherSuitesEnabled().split( "," ) );
}
else if ( purpose.getCipherSuitesDisabled() != null && !purpose.getCipherSuitesDisabled().isEmpty() )
{
// Otherwise, use all supported cipher suites (except for the ones that are explicitly disabled).
final List<String> disabled = Arrays.asList( purpose.getCipherSuitesDisabled() );
final ArrayList<String> supported = new ArrayList<>( );
for ( final String candidate : sslEngine.getSupportedCipherSuites() ) {
if ( !disabled.contains( candidate ) ) {
supported.add( candidate );
}
}
sslEngine.setEnabledCipherSuites( supported.toArray( new String[ supported.size() ] ) );
}
// TODO: Set policy for checking client certificates
return sslEngine; return sslEngine;
} }
public static SslContextFactory getSslContextFactory( final Purpose purpose )
{
final SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setTrustStore( SSLConfig.getTrustStore( purpose ) );
sslContextFactory.setKeyStore( SSLConfig.getIdentityStore( purpose ) );
// Configure protocol and cipher suite support.
if ( purpose.getProtocolsEnabled() != null ) {
sslContextFactory.setIncludeProtocols( purpose.getProtocolsEnabled().split( "," ) );
}
if ( purpose.getProtocolsDisabled() != null ) {
sslContextFactory.setExcludeProtocols( purpose.getProtocolsDisabled().split( "," ) );
}
if ( purpose.getCipherSuitesEnabled() != null) {
sslContextFactory.setIncludeCipherSuites( purpose.getCipherSuitesEnabled().split( "," ) );
}
if ( purpose.getCipherSuitesDisabled() != null ) {
sslContextFactory.setExcludeCipherSuites( purpose.getCipherSuitesDisabled().split( "," ) );
}
// TODO: Set policy for checking client certificates
// String certPol = JiveGlobals.getProperty(HTTP_BIND_AUTH_PER_CLIENTCERT_POLICY, "disabled");
// if(certPol.equals("needed")) {
// sslContextFactory.setNeedClientAuth(true);
// sslContextFactory.setWantClientAuth(true);
// } else if(certPol.equals("wanted")) {
// sslContextFactory.setNeedClientAuth(false);
// sslContextFactory.setWantClientAuth(true);
// } else {
// sslContextFactory.setNeedClientAuth(false);
// sslContextFactory.setWantClientAuth(false);
// }
return sslContextFactory;
}
/** /**
* Enables a specific set of protocols in an SSLEngine instance. * Enables a specific set of protocols in an SSLEngine instance.
* *
...@@ -493,7 +570,7 @@ public class SSLConfig ...@@ -493,7 +570,7 @@ public class SSLConfig
* *
* @param sslEngine The instance to configure. Cannot be null. * @param sslEngine The instance to configure. Cannot be null.
* @param purpose The type of configuration to use (used to select the relevent property). Cannot be null. * @param purpose The type of configuration to use (used to select the relevent property). Cannot be null.
*/
private static void configureProtocols( SSLEngine sslEngine, Purpose purpose ) private static void configureProtocols( SSLEngine sslEngine, Purpose purpose )
{ {
// Find configuration, using fallback where applicable. // Find configuration, using fallback where applicable.
...@@ -530,6 +607,7 @@ public class SSLConfig ...@@ -530,6 +607,7 @@ public class SSLConfig
sslEngine.setEnabledProtocols( defaultEnabled.toArray( new String[ defaultEnabled.size()] ) ); sslEngine.setEnabledProtocols( defaultEnabled.toArray( new String[ defaultEnabled.size()] ) );
} }
} }
*/
/** /**
* Enables a specific set of cipher suites in an SSLEngine instance. * Enables a specific set of cipher suites in an SSLEngine instance.
...@@ -545,7 +623,7 @@ public class SSLConfig ...@@ -545,7 +623,7 @@ public class SSLConfig
* *
* @param sslEngine The instance to configure. Cannot be null. * @param sslEngine The instance to configure. Cannot be null.
* @param purpose The type of configuration to use (used to select the relevent property). Cannot be null. * @param purpose The type of configuration to use (used to select the relevent property). Cannot be null.
*/
private static void configureCipherSuites( SSLEngine sslEngine, Purpose purpose ) private static void configureCipherSuites( SSLEngine sslEngine, Purpose purpose )
{ {
String enabledCipherSuites = JiveGlobals.getProperty( purpose.getPrefix() + "enabled.ciphersuites" ); String enabledCipherSuites = JiveGlobals.getProperty( purpose.getPrefix() + "enabled.ciphersuites" );
...@@ -588,6 +666,7 @@ public class SSLConfig ...@@ -588,6 +666,7 @@ public class SSLConfig
sslEngine.setEnabledCipherSuites( defaultEnabled.toArray( new String[ defaultEnabled.size()] ) ); sslEngine.setEnabledCipherSuites( defaultEnabled.toArray( new String[ defaultEnabled.size()] ) );
} }
} }
*/
/** /**
* Creates an Apache MINA SslFilter that is configured to use server mode when handshaking. * Creates an Apache MINA SslFilter that is configured to use server mode when handshaking.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment