This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push: new af7423533fa Refactored LDAP docs (#11420) af7423533fa is described below commit af7423533fa35ff164c5767150700628b4558c01 Author: Darren Coleman <dcole...@redhat.com> AuthorDate: Sun Sep 17 10:54:15 2023 +0100 Refactored LDAP docs (#11420) Moved Spring-specific content into dedicated tabs, and added a equivalent tabs for Camel Quarkus. --- .../camel-ldap/src/main/docs/ldap-component.adoc | 165 +++++++++++++++++++-- 1 file changed, 155 insertions(+), 10 deletions(-) diff --git a/components/camel-ldap/src/main/docs/ldap-component.adoc b/components/camel-ldap/src/main/docs/ldap-component.adoc index 08faad5fa56..d5bf23823a7 100644 --- a/components/camel-ldap/src/main/docs/ldap-component.adoc +++ b/components/camel-ldap/src/main/docs/ldap-component.adoc @@ -64,9 +64,33 @@ The result is returned to Out body as a `List<javax.naming.directory.SearchResul == DirContext -The URI, `ldap:ldapserver`, references a Spring bean with the ID, +The URI, `ldap:ldapserver`, references a bean with the ID `ldapserver`. The `ldapserver` bean may be defined as follows: +[tabs] +==== +Java (Quarkus):: ++ +[source,java] +---- +public class LdapServerProducer { + + @Produces + @Dependent + @Named("ldapserver") + public DirContext createLdapServer() throws Exception { + Hashtable<String, String> env = new Hashtable<>(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); + env.put(Context.PROVIDER_URL, "ldap://localhost:10389"); + env.put(Context.SECURITY_AUTHENTICATION, "none"); + + return new InitialDirContext(env); + } +} +---- + +XML (Spring):: ++ [source,xml] ----------------------------------------------------------------------------------------- <bean id="ldapserver" class="javax.naming.directory.InitialDirContext" scope="prototype"> @@ -79,18 +103,16 @@ The URI, `ldap:ldapserver`, references a Spring bean with the ID, </constructor-arg> </bean> ----------------------------------------------------------------------------------------- +==== The preceding example declares a regular Sun based LDAP `DirContext` that connects anonymously to a locally hosted LDAP server. [NOTE] ==== -`DirContext` objects are *not* required to support concurrency by -contract. It is therefore important that the directory context is -declared with the setting, `scope="prototype"`, in the `bean` definition -or that the context supports concurrency. In the Spring framework, -`prototype` scoped objects are instantiated each time they are looked -up. +`DirContext` objects are *not* required to support concurrency by contract. It is therefore important to manage the directory context's lifecycle appropriately. In the Spring framework, `prototype` scoped objects are instantiated each time they are looked up to ensure concurrency and avoid sharing the same context between multiple threads. + +For Camel Quarkus applications, you can achieve similar behavior by using the `@Dependent` annotation. When you annotate a component or bean with `@Dependent`, a new instance of the component is created for each injection point or usage, which effectively provides the same concurrency guarantees as Spring's `prototype` scope. This ensures that each part of your application interacts with a separate and isolated `DirContext` instance, preventing unintended thread interference. ==== == Security concerns related to LDAP injection @@ -105,7 +127,7 @@ for information about https://cheatsheetseries.owasp.org/cheatsheets/LDAP_Inject == Samples -Following on from the Spring configuration above, the code sample below +Following on from the configuration above, the code sample below sends an LDAP request to filter search a group for a member. The Common Name is then extracted from the response. @@ -120,7 +142,7 @@ Collection<SearchResult> results = template.requestBody( if (results.size() > 0) { // Extract what we need from the device's profile - Iterator resultIter = results.iterator(); + Iterator<SearchResult> resultIter = results.iterator(); SearchResult searchResult = (SearchResult) resultIter.next(); Attributes attributes = searchResult.getAttributes(); Attribute deviceCNAttr = attributes.get("cn"); @@ -190,6 +212,31 @@ the InitialDirContext bean - see below sample. *SSL Configuration* +[tabs] +==== +Java (Quarkus):: ++ +[source,java] +---- +public class LdapServerProducer { + + @Produces + @Dependent + @Named("ldapserver") + public DirContext createLdapServer() throws Exception { + Hashtable<String, String> env = new Hashtable<>(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); + env.put(Context.PROVIDER_URL, "ldaps://" + InetAddress.getLocalHost().getCanonicalHostName() + ":10636"); + env.put(Context.SECURITY_AUTHENTICATION, "none"); + env.put("java.naming.ldap.factory.socket", CustomSSLSocketFactory.class.getName()); + + return new InitialDirContext(env); + } +} +---- + +XML (Spring):: ++ [source,xml] ---------------------------------------------------------------------------------------------------------------------------------- <?xml version="1.0" encoding="UTF-8"?> @@ -223,9 +270,107 @@ the InitialDirContext bean - see below sample. </bean> </beans> ---------------------------------------------------------------------------------------------------------------------------------- +==== *Custom Socket Factory* +[tabs] +==== +Java (Quarkus):: ++ +[source,java] +---- +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; +import java.security.KeyStore; + +import javax.net.SocketFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManagerFactory; + +import org.eclipse.microprofile.config.ConfigProvider; + +public class CustomSSLSocketFactory extends SSLSocketFactory { + + private SSLSocketFactory delegate; + + public CustomSSLSocketFactory() throws Exception { + String trustStoreFilename = ConfigProvider.getConfig().getValue("ldap.trustStore", String.class); + String trustStorePassword = ConfigProvider.getConfig().getValue("ldap.trustStorePassword", String.class); + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + try (InputStream in = new FileInputStream(trustStoreFilename)) { + keyStore.load(in, trustStorePassword.toCharArray()); + } + TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); + tmf.init(keyStore); + SSLContext ctx = SSLContext.getInstance("TLS"); + ctx.init(null, tmf.getTrustManagers(), null); + delegate = ctx.getSocketFactory(); + } + + public static SocketFactory getDefault() { + try { + return new CustomSSLSocketFactory(); + } catch (Exception ex) { + ex.printStackTrace(); + return null; + } + } + + @Override + public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { + return delegate.createSocket(s, host, port, autoClose); + } + + @Override + public String[] getDefaultCipherSuites() { + return delegate.getDefaultCipherSuites(); + } + + @Override + public String[] getSupportedCipherSuites() { + return delegate.getSupportedCipherSuites(); + } + + @Override + public Socket createSocket(String host, int port) throws IOException, UnknownHostException { + return delegate.createSocket(host, port); + } + + @Override + public Socket createSocket(InetAddress address, int port) throws IOException { + return delegate.createSocket(address, port); + } + + @Override + public Socket createSocket(String host, int port, InetAddress localAddress, int localPort) + throws IOException, UnknownHostException { + return delegate.createSocket(host, port, localAddress, localPort); + } + + @Override + public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) + throws IOException { + return delegate.createSocket(address, port, localAddress, localPort); + } +} +---- ++ +The constructor uses the `ConfigProvider` to read the `ldap.trustStore` and `ldap.trustStorePassword` configuration properties, which could be specified in the `application.properties` file as follows: ++ +[source,properties] +---- +ldap.trustStore=/path/to/truststore.jks +ldap.trustStorePassword=secret +---- + +XML (Spring):: ++ [source,java] ----------------------------------------------------------------------------------------------------- package com.example.ldap; @@ -314,6 +459,6 @@ public class CustomSocketFactory extends SSLSocketFactory { } } ----------------------------------------------------------------------------------------------------- - +==== include::spring-boot:partial$starter.adoc[]