-
Notifications
You must be signed in to change notification settings - Fork 484
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Provide an SSLSocketFactoryFactoryBean #547
Comments
Yes, please! Difficult TLS configuration is something that is holding the whole industry back from becoming more secure. People resort to crazy things like modifying the JVM's |
Any interest in providing a pull request? |
The tricky part is to generate the dynamic subclass that implements |
I think I must be missing something. Can you expand on why making it easier for SSL configuraiton you need to generate a dynamic class that implements getDefault()? |
Because java.naming.ldap.factory.socket expects a socket expects a public class CustomSocketFactory extends SocketFactory {
public static SocketFactory getDefault() {
return new CustomSocketFactory();
}
...
} |
This would be very helpful, I'm facing the same issue. |
I started a small project that does this. It requires ByteBuddy and Java 11+ https://github.com/marschall/ssl-socket-factory-factory-bean |
One thing that could be clearer: AbstractTlsDirContextAuthenticationStrategy does LDAP with StartTLS (usually on port 389), the implementation by @marschall does LDAPS (Microsoft proprietary but supported by various LDAP providers) does an initial TLS handshake and usually runs on port 636. |
Neither do all LDAP servers support LDAPS nor LDAP with Start-TLS. However LDAP without TLS is like having a webserver running on plain http. It's okay for development but don't do this in production. I had to write a bunch of custom code to make it work. I would expect spring-ldap to have built-in support for the common scenarios. |
Ldaps Extension DirContextAuthenticationStrategy can work normally in the spring the boot 3.2.
You can customize JndiSocketFactory.
In this mode, the certificate storage path is not specified. |
That does not look particularly thread safe. |
I was also hoping for some easy ssl configuration, after waiting for some time hoping for this feature to implemented I came up with a way to programatically configure the ssl configuration of spring. It required some customization, but it is not that much. I documented it here: My usecase was hot reloading ssl and not Ldap, but I think that would also be easily possible. So I have the feeling that it is already quite easy to customize the ssl configuration. It basically looks like this: import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ServerConfig {
@Bean
public ServletWebServerFactory servletContainer(SSLConnectorCustomizer sslConnectorCustomizer) {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
tomcat.addConnectorCustomizers(sslConnectorCustomizer);
return tomcat;
}
} import nl.altindag.ssl.SSLFactory;
import org.apache.catalina.connector.Connector;
import org.apache.coyote.http11.AbstractHttp11Protocol;
import org.apache.tomcat.util.net.SSLHostConfig;
import org.apache.tomcat.util.net.SSLHostConfigCertificate;
import org.apache.tomcat.util.net.SSLHostConfigCertificate.Type;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SSLConnectorCustomizer implements TomcatConnectorCustomizer {
private final SSLFactory sslFactory;
private final int port;
public SSLConnectorCustomizer(SSLFactory sslFactory, @Value("${server.port}") int port) {
this.sslFactory = sslFactory;
this.port = port;
}
@Override
public void customize(Connector connector) {
connector.setScheme("https");
connector.setSecure(true);
connector.setPort(port);
AbstractHttp11Protocol<?> protocol = (AbstractHttp11Protocol<?>) connector.getProtocolHandler();
protocol.setSSLEnabled(true);
SSLHostConfig sslHostConfig = new SSLHostConfig();
SSLHostConfigCertificate certificate = new SSLHostConfigCertificate(sslHostConfig, Type.UNDEFINED);
certificate.setSslContext(new TomcatSSLContext(sslFactory));
sslHostConfig.addCertificate(certificate);
protocol.addSslHostConfig(sslHostConfig);
}
} import nl.altindag.ssl.SSLFactory;
import org.apache.tomcat.util.net.SSLContext;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSessionContext;
import javax.net.ssl.TrustManager;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
public final class TomcatSSLContext implements SSLContext {
private final SSLFactory sslFactory;
public TomcatSSLContext(SSLFactory sslFactory) {
this.sslFactory = sslFactory;
}
@Override
public void init(KeyManager[] kms, TrustManager[] tms, SecureRandom sr) {
// not needed to initialize as it is already initialized
}
@Override
public void destroy() {
}
@Override
public SSLSessionContext getServerSessionContext() {
return sslFactory.getSslContext().getServerSessionContext();
}
@Override
public SSLEngine createSSLEngine() {
return sslFactory.getSSLEngine();
}
@Override
public SSLServerSocketFactory getServerSocketFactory() {
return sslFactory.getSslServerSocketFactory();
}
@Override
public SSLParameters getSupportedSSLParameters() {
return sslFactory.getSslParameters();
}
@Override
public X509Certificate[] getCertificateChain(String alias) {
return sslFactory.getKeyManager()
.map(keyManager -> keyManager.getCertificateChain(alias))
.orElseThrow();
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return sslFactory.getTrustedCertificates().toArray(new X509Certificate[0]);
}
} import nl.altindag.ssl.SSLFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SSLConfig {
@Bean
public SSLFactory sslFactory(@Value("${ssl.keystore-path}") String keyStorePath,
@Value("${ssl.keystore-password}") char[] keyStorePassword,
@Value("${ssl.truststore-path}") String trustStorePath,
@Value("${ssl.truststore-password}") char[] trustStorePassword,
@Value("${ssl.client-auth}") boolean isClientAuthenticationRequired) {
return SSLFactory.builder()
.withIdentityMaterial(keyStorePath, keyStorePassword)
.withTrustMaterial(trustStorePath, trustStorePassword)
.withNeedClientAuthentication(isClientAuthenticationRequired)
.withDefaultTrustMaterial() // JDK truststore
.withSystemTrustMaterial() // OS truststore
.build();
}
} |
In order to more easily support custom TLS configuration provide an
SSLSocketFactoryFactoryBean
that takesthat then creates an SSLSocketFactory implementation class. This would require dynamically generating an SSLSocketFactory subclass but would offer the most convent interface for clients.
This is a follow up for #494
The text was updated successfully, but these errors were encountered: