Ce contenu n'est pas disponible dans la langue sélectionnée.
Chapter 201. LDAP Component
Available as of Camel version 1.5
The ldap component allows you to perform searches in LDAP servers using filters as the message payload.
This component uses standard JNDI (javax.naming package) to access the server.
Maven users will need to add the following dependency to their pom.xml for this component:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-ldap</artifactId>
<version>x.x.x</version>
<!-- use the same version as your Camel core version -->
</dependency>
201.1. URI format Copier lienLien copié sur presse-papiers!
ldap:ldapServerBean[?options]
The ldapServerBean portion of the URI refers to a DirContext bean in the registry. The LDAP component only supports producer endpoints, which means that an ldap URI cannot appear in the from at the start of a route.
You can append query options to the URI in the following format, ?option=value&option=value&…
201.2. Options Copier lienLien copié sur presse-papiers!
The LDAP component has no options.
The LDAP endpoint is configured using URI syntax:
ldap:dirContextName
with the following path and query parameters:
201.2.1. Path Parameters (1 parameters): Copier lienLien copié sur presse-papiers!
| Name | Description | Default | Type |
|---|---|---|---|
| dirContextName | Required Name of either a javax.naming.directory.DirContext, or java.util.Hashtable, or Map bean to lookup in the registry. If the bean is either a Hashtable or Map then a new javax.naming.directory.DirContext instance is created for each use. If the bean is a javax.naming.directory.DirContext then the bean is used as given. The latter may not be possible in all situations where the javax.naming.directory.DirContext must not be shared, and in those situations it can be better to use java.util.Hashtable or Map instead. | String |
201.2.2. Query Parameters (5 parameters): Copier lienLien copié sur presse-papiers!
| Name | Description | Default | Type |
|---|---|---|---|
| base (producer) | The base DN for searches. | ou=system | String |
| pageSize (producer) | When specified the ldap module uses paging to retrieve all results (most LDAP Servers throw an exception when trying to retrieve more than 1000 entries in one query). To be able to use this a LdapContext (subclass of DirContext) has to be passed in as ldapServerBean (otherwise an exception is thrown) | Integer | |
| returnedAttributes (producer) | Comma-separated list of attributes that should be set in each entry of the result | String | |
| scope (producer) | Specifies how deeply to search the tree of entries, starting at the base DN. | subtree | String |
| synchronous (advanced) | Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported). | false | boolean |
201.3. Result Copier lienLien copié sur presse-papiers!
The result is returned in the Out body as a ArrayList<javax.naming.directory.SearchResult> object.
201.4. DirContext Copier lienLien copié sur presse-papiers!
The URI, ldap:ldapserver, references a Spring bean with the ID, ldapserver. The ldapserver bean may be defined as follows:
<bean id="ldapserver" class="javax.naming.directory.InitialDirContext" scope="prototype">
<constructor-arg>
<props>
<prop key="java.naming.factory.initial">com.sun.jndi.ldap.LdapCtxFactory</prop>
<prop key="java.naming.provider.url">ldap://localhost:10389</prop>
<prop key="java.naming.security.authentication">none</prop>
</props>
</constructor-arg>
</bean>
The preceding example declares a regular Sun based LDAP DirContext that connects anonymously to a locally hosted LDAP server.
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.
201.5. Samples Copier lienLien copié sur presse-papiers!
Following on from the Spring 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.
ProducerTemplate<Exchange> template = exchange
.getContext().createProducerTemplate();
Collection<?> results = (Collection<?>) (template
.sendBody(
"ldap:ldapserver?base=ou=mygroup,ou=groups,ou=system",
"(member=uid=huntc,ou=users,ou=system)"));
if (results.size() > 0) {
// Extract what we need from the device's profile
Iterator<?> resultIter = results.iterator();
SearchResult searchResult = (SearchResult) resultIter
.next();
Attributes attributes = searchResult
.getAttributes();
Attribute deviceCNAttr = attributes.get("cn");
String deviceCN = (String) deviceCNAttr.get();
...
If no specific filter is required - for example, you just need to look up a single entry - specify a wildcard filter expression. For example, if the LDAP entry has a Common Name, use a filter expression like:
(cn=*)
201.5.1. Binding using credentials Copier lienLien copié sur presse-papiers!
A Camel end user donated this sample code he used to bind to the ldap server using credentials.
Properties props = new Properties();
props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
props.setProperty(Context.PROVIDER_URL, "ldap://localhost:389");
props.setProperty(Context.URL_PKG_PREFIXES, "com.sun.jndi.url");
props.setProperty(Context.REFERRAL, "ignore");
props.setProperty(Context.SECURITY_AUTHENTICATION, "simple");
props.setProperty(Context.SECURITY_PRINCIPAL, "cn=Manager");
props.setProperty(Context.SECURITY_CREDENTIALS, "secret");
SimpleRegistry reg = new SimpleRegistry();
reg.put("myldap", new InitialLdapContext(props, null));
CamelContext context = new DefaultCamelContext(reg);
context.addRoutes(
new RouteBuilder() {
public void configure() throws Exception {
from("direct:start").to("ldap:myldap?base=ou=test");
}
}
);
context.start();
ProducerTemplate template = context.createProducerTemplate();
Endpoint endpoint = context.getEndpoint("direct:start");
Exchange exchange = endpoint.createExchange();
exchange.getIn().setBody("(uid=test)");
Exchange out = template.send(endpoint, exchange);
Collection<SearchResult> data = out.getOut().getBody(Collection.class);
assert data != null;
assert !data.isEmpty();
System.out.println(out.getOut().getBody());
context.stop();
201.6. Configuring SSL Copier lienLien copié sur presse-papiers!
All required is to create a custom socket factory and reference it in the InitialDirContext bean - see below sample.
SSL Configuration
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd">
<sslContextParameters xmlns="http://camel.apache.org/schema/blueprint"
id="sslContextParameters">
<keyManagers
keyPassword="{{keystore.pwd}}">
<keyStore
resource="{{keystore.url}}"
password="{{keystore.pwd}}"/>
</keyManagers>
</sslContextParameters>
<bean id="customSocketFactory" class="zotix.co.util.CustomSocketFactory">
<argument ref="sslContextParameters" />
</bean>
<bean id="ldapserver" class="javax.naming.directory.InitialDirContext" scope="prototype">
<argument>
<props>
<prop key="java.naming.factory.initial" value="com.sun.jndi.ldap.LdapCtxFactory"/>
<prop key="java.naming.provider.url" value="ldaps://lab.zotix.co:636"/>
<prop key="java.naming.security.protocol" value="ssl"/>
<prop key="java.naming.security.authentication" value="simple" />
<prop key="java.naming.security.principal" value="cn=Manager,dc=example,dc=com"/>
<prop key="java.naming.security.credentials" value="passw0rd"/>
<prop key="java.naming.ldap.factory.socket"
value="zotix.co.util.CustomSocketFactory"/>
</props>
</argument>
</bean>
</blueprint>
Custom Socket Factory
import org.apache.camel.util.jsse.SSLContextParameters;
import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.security.KeyStore;
/**
* The CustomSocketFactory. Loads the KeyStore and creates an instance of SSLSocketFactory
*/
public class CustomSocketFactory extends SSLSocketFactory {
private static SSLSocketFactory socketFactory;
/**
* Called by the getDefault() method.
*/
public CustomSocketFactory() {
}
/**
* Called by Blueprint DI to initialise an instance of SocketFactory
*
* @param sslContextParameters
*/
public CustomSocketFactory(SSLContextParameters sslContextParameters) {
try {
KeyStore keyStore = sslContextParameters.getKeyManagers().getKeyStore().createKeyStore();
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(keyStore);
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, tmf.getTrustManagers(), null);
socketFactory = ctx.getSocketFactory();
} catch (Exception ex) {
ex.printStackTrace(System.err); /* handle exception */
}
}
/**
* Getter for the SocketFactory
*
* @return
*/
public static SocketFactory getDefault() {
return new CustomSocketFactory();
}
@Override
public String[] getDefaultCipherSuites() {
return socketFactory.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return socketFactory.getSupportedCipherSuites();
}
@Override
public Socket createSocket(Socket socket, String string, int i, boolean bln) throws IOException {
return socketFactory.createSocket(socket, string, i, bln);
}
@Override
public Socket createSocket(String string, int i) throws IOException {
return socketFactory.createSocket(string, i);
}
@Override
public Socket createSocket(String string, int i, InetAddress ia, int i1) throws IOException {
return socketFactory.createSocket(string, i, ia, i1);
}
@Override
public Socket createSocket(InetAddress ia, int i) throws IOException {
return socketFactory.createSocket(ia, i);
}
@Override
public Socket createSocket(InetAddress ia, int i, InetAddress ia1, int i1) throws IOException {
return socketFactory.createSocket(ia, i, ia1, i1);
}
}
201.7. See Also Copier lienLien copié sur presse-papiers!
- Configuring Camel
- Component
- Endpoint
- Getting Started
201.8. LevelDB Copier lienLien copié sur presse-papiers!
Available as of Camel 2.10
Leveldb is a very lightweight and embedable key value database. It allows together with Camel to provide persistent support for various Camel features such as Aggregator.
Current features it provides:
- LevelDBAggregationRepository
201.8.1. Using LevelDBAggregationRepository Copier lienLien copié sur presse-papiers!
LevelDBAggregationRepository is an AggregationRepository which on the fly persists the aggregated messages. This ensures that you will not loose messages, as the default aggregator will use an in memory only AggregationRepository.
It has the following options:
| Option | Type | Description |
|---|---|---|
|
| String |
A mandatory repository name. Allows you to use a shared |
|
| String | Filename for the persistent storage. If no file exists on startup a new file is created. |
|
| LevelDBFile |
Use an existing configured |
|
| boolean | Camel 2.12: Whether or not the LevelDBFile should sync on write or not. Default is false. By sync on write ensures that its always waiting for all writes to be spooled to disk and thus will not loose updates. See LevelDB docs for more details about async vs sync writes. |
|
| boolean |
Whether the get operation should return the old existing Exchange if any existed. By default this option is |
|
| boolean |
Whether or not recovery is enabled. This option is by default |
|
| long | If recovery is enabled then a background task is run every x’th time to scan for failed exchanges to recover and resubmit. By default this interval is 5000 millis. |
|
| int |
Allows you to limit the maximum number of redelivery attempts for a recovered exchange. If enabled then the Exchange will be moved to the dead letter channel if all redelivery attempts failed. By default this option is disabled. If this option is used then the |
|
| String |
An endpoint uri for a Dead Letter Channel where exhausted recovered Exchanges will be moved. If this option is used then the |
The repositoryName option must be provided. Then either the persistentFileName or the levelDBFile must be provided.
201.8.2. What is preserved when persisting Copier lienLien copié sur presse-papiers!
LevelDBAggregationRepository will only preserve any Serializable compatible message body data types. Message headers must be primitive / string / numbers / etc. If a data type is not such a type its dropped and a WARN is logged. And it only persists the Message body and the Message headers. The Exchange properties are not persisted.
201.8.3. Recovery Copier lienLien copié sur presse-papiers!
The LevelDBAggregationRepository will by default recover any failed Exchange. It does this by having a background tasks that scans for failed Exchanges in the persistent store. You can use the checkInterval option to set how often this task runs. The recovery works as transactional which ensures that Camel will try to recover and redeliver the failed Exchange. Any Exchange which was found to be recovered will be restored from the persistent store and resubmitted and send out again.
The following headers is set when an Exchange is being recovered/redelivered:
| Header | Type | Description |
|---|---|---|
|
| Boolean | Is set to true to indicate the Exchange is being redelivered. |
|
| Integer | The redelivery attempt, starting from 1. |
Only when an Exchange has been successfully processed it will be marked as complete which happens when the confirm method is invoked on the AggregationRepository. This means if the same Exchange fails again it will be kept retried until it success.
You can use option maximumRedeliveries to limit the maximum number of redelivery attempts for a given recovered Exchange. You must also set the deadLetterUri option so Camel knows where to send the Exchange when the maximumRedeliveries was hit.
You can see some examples in the unit tests of camel-leveldb, for example this test.
201.8.3.1. Using LevelDBAggregationRepository in Java DSL Copier lienLien copié sur presse-papiers!
In this example we want to persist aggregated messages in the target/data/leveldb.dat file.
201.8.3.2. Using LevelDBAggregationRepository in Spring XML Copier lienLien copié sur presse-papiers!
The same example but using Spring XML instead:
201.8.4. Dependencies Copier lienLien copié sur presse-papiers!
To use LevelDB in your camel routes you need to add the a dependency on camel-leveldb.
If you use maven you could just add the following to your pom.xml, substituting the version number for the latest & greatest release (see the download page for the latest versions).
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-leveldb</artifactId>
<version>2.10.0</version>
</dependency>
201.8.5. See Also Copier lienLien copié sur presse-papiers!
- Configuring Camel
- Component
- Endpoint
- Getting Started
- Aggregator
- HawtDB
- Components