From fc8a31e4f08e0d183d36ed74b1435155cd9cbf9c Mon Sep 17 00:00:00 2001 From: Rob Winch Date: Wed, 23 Oct 2013 10:54:48 -0500 Subject: [PATCH] LDAP-270: Convert Spring LDAP doc to asciidoc --- build.gradle | 32 +- src/asciidoc/Guardfile | 12 + src/asciidoc/faq.adoc | 13 + src/asciidoc/index.adoc | 2228 ++++++++++++++++++++ src/docbkx/advancedqueries.xml | 135 -- src/docbkx/basic.xml | 407 ---- src/docbkx/configuration.xml | 587 ------ src/docbkx/contextprocessor.xml | 206 -- src/docbkx/dirobjectfactory.xml | 348 --- src/docbkx/executors.xml | 148 -- src/docbkx/images/NamingException.png | Bin 64786 -> 0 bytes src/docbkx/images/banner4.jpg | Bin 83374 -> 0 bytes src/docbkx/images/bannerR.gif | Bin 7949 -> 0 bytes src/docbkx/images/logo.png | Bin 23834 -> 0 bytes src/docbkx/images/package-dependencies.png | Bin 25936 -> 0 bytes src/docbkx/images/s2_box_logo.png | Bin 6877 -> 0 bytes src/docbkx/images/xdev-spring_logo.jpg | Bin 37376 -> 0 bytes src/docbkx/index.xml | 56 - src/docbkx/ldif-parsing.xml | 168 -- src/docbkx/odm.xml | 300 --- src/docbkx/overview.xml | 299 --- src/docbkx/pooling.xml | 518 ----- src/docbkx/preface.xml | 32 - src/docbkx/repositories.xml | 58 - src/docbkx/resources/xsl/fopdf.xsl | 426 ---- src/docbkx/resources/xsl/html.xsl | 91 - src/docbkx/resources/xsl/html_chunk.xsl | 208 -- src/docbkx/simple.xml | 38 - src/docbkx/transactions.xml | 241 --- src/docbkx/user-authentication.xml | 165 -- src/docbkx/utilities.xml | 24 - src/site/fml/faq.fml | 108 - 32 files changed, 2278 insertions(+), 4570 deletions(-) create mode 100644 src/asciidoc/Guardfile create mode 100644 src/asciidoc/faq.adoc create mode 100644 src/asciidoc/index.adoc delete mode 100644 src/docbkx/advancedqueries.xml delete mode 100644 src/docbkx/basic.xml delete mode 100644 src/docbkx/configuration.xml delete mode 100644 src/docbkx/contextprocessor.xml delete mode 100644 src/docbkx/dirobjectfactory.xml delete mode 100644 src/docbkx/executors.xml delete mode 100644 src/docbkx/images/NamingException.png delete mode 100644 src/docbkx/images/banner4.jpg delete mode 100644 src/docbkx/images/bannerR.gif delete mode 100644 src/docbkx/images/logo.png delete mode 100644 src/docbkx/images/package-dependencies.png delete mode 100644 src/docbkx/images/s2_box_logo.png delete mode 100644 src/docbkx/images/xdev-spring_logo.jpg delete mode 100644 src/docbkx/index.xml delete mode 100644 src/docbkx/ldif-parsing.xml delete mode 100644 src/docbkx/odm.xml delete mode 100644 src/docbkx/overview.xml delete mode 100644 src/docbkx/pooling.xml delete mode 100644 src/docbkx/preface.xml delete mode 100644 src/docbkx/repositories.xml delete mode 100644 src/docbkx/resources/xsl/fopdf.xsl delete mode 100644 src/docbkx/resources/xsl/html.xsl delete mode 100644 src/docbkx/resources/xsl/html_chunk.xsl delete mode 100644 src/docbkx/simple.xml delete mode 100644 src/docbkx/transactions.xml delete mode 100644 src/docbkx/user-authentication.xml delete mode 100644 src/docbkx/utilities.xml diff --git a/build.gradle b/build.gradle index 99c3a619..607d009e 100644 --- a/build.gradle +++ b/build.gradle @@ -1,14 +1,15 @@ buildscript { repositories { maven { url "http://repo.springsource.org/plugins-release" } + maven { url "http://dl.bintray.com/content/aalmiray/asciidoctor" } } dependencies { classpath("org.springframework.build.gradle:propdeps-plugin:0.0.3") - classpath("org.springframework.build.gradle:docbook-reference-plugin:0.2.6") + classpath('org.asciidoctor:asciidoctor-gradle-plugin:0.7.0') } } -apply plugin: "docbook-reference" +apply plugin: "asciidoctor" apply plugin: "sonar-runner" ext.GRADLE_SCRIPT_DIR = "${rootProject.projectDir}/gradle" @@ -22,6 +23,7 @@ configure(allprojects) { apply plugin: 'propdeps' apply plugin: 'propdeps-idea' apply plugin: 'propdeps-eclipse' + apply plugin: 'groovy' group = "org.springframework.ldap" @@ -65,9 +67,24 @@ sonarRunner { } } -reference { - sourceDir = file("src/docbkx") - pdfFilename = "spring-ldap-reference.pdf" +asciidoctor { + outputDir = new File("$buildDir/docs") + options = [ + eruby: 'erubis', + attributes: [ + copycss : '', + icons : 'font', + 'source-highlighter': 'prettify', + sectanchors : '', + toc2: '', + idprefix: '', + idseparator: '-', + doctype: 'book', + numbered: '', + 'spring-ldap-version' : project.version, + revnumber : project.version + ] + ] } task api(type: Javadoc) { @@ -88,7 +105,7 @@ task api(type: Javadoc) { classpath = files(coreModules*.javadoc*.classpath) } -task docsZip(type: Zip) { +task docsZip(type: Zip, dependsOn: asciidoctor) { group = "Distribution" baseName = "spring-ldap" classifier = "docs" @@ -103,7 +120,8 @@ task docsZip(type: Zip) { into "apidocs" } - from (reference) { + from (asciidoctor.outputDir) { + include "*.html" into "reference" } } diff --git a/src/asciidoc/Guardfile b/src/asciidoc/Guardfile new file mode 100644 index 00000000..45148959 --- /dev/null +++ b/src/asciidoc/Guardfile @@ -0,0 +1,12 @@ +require 'asciidoctor' +require 'erb' + +guard 'shell' do + watch(/^.*\.adoc$/) {|m| + Asciidoctor.render_file(m[0], :to_dir => "build/", :safe => Asciidoctor::SafeMode::UNSAFE, :attributes=> {'idprefix' => '', 'numbered'=>'', 'idseparator' => '-', 'copycss' => '', 'icons' => 'font', 'source-highlighter' => 'prettify', 'sectanchors' => '', 'doctype' => 'book','toc2' => '', 'spring-ldap-version' => '2.0.0.CI-SNAPSHOT', 'revnumber' => '2.0.0.CI-SNAPSHOT' }) + } +end + +guard 'livereload' do + watch(%r{build/.+\.(css|js|html)$}) +end diff --git a/src/asciidoc/faq.adoc b/src/asciidoc/faq.adoc new file mode 100644 index 00000000..2984036a --- /dev/null +++ b/src/asciidoc/faq.adoc @@ -0,0 +1,13 @@ += Spring LDAP FAQ + +== Operational Attributes + +=== How do I remove an operational attribute using context.removeAttributeValue()? + +The `DirContextAdapter` will only read the visible attributes per default. This is because the operational attributes will only be returned by the server if explicitly asked for, and there is no way for Spring LDAP to know what attributes to ask for. This means that the `DirContextAdapter` will not be populated with the operational attributes, and hence the `removeAttributeValue` will not have any effect (since from the `DirContextAdapter`'s point of view, it wasn't there in the first place). + +There are basically two ways to do this: + +* Use a search or lookup method that takes the attribute names as argument, like `LdapTemplate#lookup(Name, String[], ContextMapper)`. Use a `ContextMapper` implementation that just returns the supplied `DirContextAdapter` in `mapFromContext()`. + +* Use `LdapTemplate#modifyAttributes(Name, ModificationItem[])` directly, manually building the `ModificationItem` array. \ No newline at end of file diff --git a/src/asciidoc/index.adoc b/src/asciidoc/index.adoc new file mode 100644 index 00000000..6dc92744 --- /dev/null +++ b/src/asciidoc/index.adoc @@ -0,0 +1,2228 @@ += Spring LDAP Reference +Mattias Arthursson; Ulrik Sandberg; Eric Dalquist; Keith Barlow; Rob Winch + +Spring LDAP makes it easier to build Spring-based applications that use the Lightweight Directory Access Protocol. + +__Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically.__ + += Preface +The Java Naming and Directory Interface (JNDI) is for LDAP programming what Java Database Connectivity (JDBC) is for SQL programming. There are several similarities between JDBC and JNDI/LDAP (Java LDAP). Despite being two completely different APIs with different pros and cons, they share a number of less flattering characteristics: + +* They require extensive plumbing code, even to perform the simplest of tasks. +* All resources need to be correctly closed, no matter what happens. +* Exception handling is difficult. + + +The above points often lead to massive code duplication in common usages of the APIs. As we all know, code duplication is one of the worst code smells. All in all, it boils down to this: JDBC and LDAP programming in Java are both incredibly dull and repetitive. + +Spring JDBC, a part of the Spring framework, provides excellent utilities for simplifying SQL programming. We need a similar framework for Java LDAP programming. + +== Introduction + +=== Overview +Spring LDAP http://spring.io/spring-ldap is a library for simpler LDAP programming in Java, built on the same principles as the http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/jdbc/core/JdbcTemplate.html[JdbcTemplate] in Spring JDBC. It completely eliminates the need to worry about creating and closing `LdapContext` and looping through `NamingEnumeration`. It also provides a more comprehensive unchecked Exception hierarchy, built on Spring's `DataAccessException`. As a bonus, it also contains classes for dynamically building LDAP queries and DNs (Distinguished Names), LDAP attribute management, and client-side LDAP transaction management. + +Consider, for example, a method that should search some storage for all persons and return their names in a list. Using JDBC, we would create a __connection__ and execute a __query__ using a __statement__. We would then loop over the __result set__ and retrieve the __column__ we want, adding it to a list. In contrast, using Java LDAP, we would create a __context__ and perform a __search__ using a __search filter__. We would then loop over the resulting __naming enumeration__ and retrieve the __attribute__ we want, adding it to a list. + +The traditional way of implementing this person name search method in Java LDAP looks like this, where the code marked as bold actually performs tasks related to the business purpose of the method: + +[source,java] +[subs="verbatim,quotes"] +---- +package com.example.dao; + +public class TraditionalPersonDaoImpl implements PersonDao { + public List getAllPersonNames() { + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); + env.put(Context.PROVIDER_URL, "ldap://localhost:389/dc=example,dc=com"); + + DirContext ctx; + try { + ctx = new InitialDirContext(env); + } catch (NamingException e) { + throw new RuntimeException(e); + } + + LinkedList list = new LinkedList(); + NamingEnumeration results = null; + try { + SearchControls controls = new SearchControls(); + controls.setSearchScope(SearchControls.SUBTREE_SCOPE); + results = ctx.**search**("", **"(objectclass=person)"**, controls); + + while (results.hasMore()) { + SearchResult searchResult = (SearchResult) results.next(); + Attributes attributes = searchResult.getAttributes(); + **Attribute attr = attributes.get("cn"); + String cn = (String) attr.get(); + list.add(cn);** + } + } catch (NameNotFoundException e) { + // The base context was not found. + // Just clean up and exit. + } catch (NamingException e) { + throw new RuntimeException(e); + } finally { + if (results != null) { + try { + results.close(); + } catch (Exception e) { + // Never mind this. + } + } + if (ctx != null) { + try { + ctx.close(); + } catch (Exception e) { + // Never mind this. + } + } + } + **return list;** + } +} +---- + +By using the Spring LDAP classes `AttributesMapper` and `LdapTemplate`, we get the exact same functionality with the following code: + + +[source,java] +[subs="verbatim,quotes"] +---- +package com.example.dao; +import static org.springframework.ldap.query.LdapQueryBuilder.query; + +public class PersonDaoImpl implements PersonDao { + private LdapTemplate ldapTemplate; + + public void setLdapTemplate(LdapTemplate ldapTemplate) { + this.ldapTemplate = ldapTemplate; + } + + public List getAllPersonNames() { + return ldapTemplate.search( + **query().where("objectclass").is("person")**, + new AttributesMapper() { + public Object mapFromAttributes(Attributes attrs) + throws NamingException { + **return attrs.get("cn").get();** + } + }); + } +} +---- + +The amount of boiler-plate code is significantly less than in the traditional example. The `LdapTemplate` version of the search method performs the search, maps the attributes to a string using the given `AttributesMapper`, collects the strings in an internal list, and finally returns the list. + +Note that the `PersonDaoImpl` code simply assumes that it has an `LdapTemplate` instance, rather than looking one up somewhere. It provides a set method for this purpose. There is nothing Spring-specific about this "Inversion of Control". Anyone that can create an instance of `PersonDaoImpl` can also set the `LdapTemplate` on it. However, Spring provides a very flexible and easy way of http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html[achieving this]. The Spring container can be told to wire up an instance of `LdapTemplate` with its required dependencies and inject it into the `PersonDao` instance. This wiring can be defined in various ways, but the most common is through XML: + + +[source,xml] +---- + + + + + + + + + + + + +---- + +[NOTE] +==== +In order to use the custom XML namespace for configuring the Spring LDAP components you need to include references to this namespace in your XML declaration as in the example above. +==== + + +=== Packaging overview +At a minimum, to use Spring LDAP you need: + + +* __spring-ldap-core__ (the Spring LDAP library) + +* __spring-core__ (miscellaneous utility classes used internally by the framework) + +* __spring-beans__ (contains interfaces and classes for manipulating Java beans) + +* __slf4j__ (a simple logging facade, used internally) + +* __commons-lang__ (misc utilities, used internally) + + +In addition to the required dependencies the following optional dependencies are required for certain functionality: + + +* __spring-context__ (If your application is wired up using the Spring Application Context - adds the ability for application objects to obtain resources using a consistent API. Definitely needed if you are planning on using the BaseLdapPathBeanPostProcessor.) + +* __spring-tx__ (If you are planning to use the client side compensating transaction support) + +* __spring-jdbc__ (If you are planning to use the client side compensating transaction support) + +* __commons-pool__ (If you are planning to use the pooling functionality) + +* __spring-batch__ (If you are planning to use the LDIF parsing functionality together with Spring Batch) + + + +=== What's new in Spring LDAP 2.0? +While quite significant modernizations have been made to the Spring LDAP APi in version 2.0, great care has been taken to ensure backward compatibility as far as possible. Code that works with Spring LDAP 1.3.x should with very few exceptions still compile and run using the 2.0 libraries without any modifications whatsoever. + +The exception is a small number of classes that have been moved to new packages in order to make a couple of important refactorings possible. The moved classes are usually not part of the intended public API, and the migration procedure should be very smooth - wherever a Spring LDAP class cannot be found after upgrade, just organize the imports in your IDE. + +You will probably encounter some deprecation warnings though, and there are also a lot of other API improvements. The recommendation for getting as much as possible out of the 2.0 version is to move away from the deprecated classes and methods and migrate to the new, improved API utilities. + +Below is a list of the most important changes in Spring LDAP 2.0. + + +* Java 1.6 is now required when using Spring LDAP. Spring versions starting at 2.0 and up are still supported. +* The central API has been updated with Java 5 features such as generics and varargs. As a consequence, the entire `spring-ldap-tiger` module has been deprecated and users are encouraged to migrate to use the core Spring LDAP classes. The parameterization of the core interfaces will most likely cause lots of compilation warnings, and you are obviously encouraged to take appropriate action to get rid of these warning. +* The ODM (Object-Directory Mapping) functionality has been moved to core and there are new methods in `LdapOperations`/`LdapTemplate` that uses this automatic translation to/from ODM-annotated classes. See <> for more information. +* A custom XML namespace is now provided to simplify configuration of Spring LDAP. See <> for more information. +* Spring Data Repository and QueryDSL support is now included in Spring LDAP. See <> for more information. +* `DistinguishedName` and associated classes have been deprecated in favor of standard Java `LdapName`. See <> for information on how the library helps working with `LdapNames`. +* Fluent LDAP query support has been added. This makes for a more pleasant programming experience when working with LDAP searches in Spring LDAP. See <> and <> for more information about the LDAP query builder support. +* The old `authenticate` methods in `LdapTemplate` have been deprecated in favor of a couple of new `authenticate` methods that work with `LdapQuery` objects and __throw exceptions__ on authentication failure, making it easier for the user to find out what caused an authentication attempt to fail. + + + +=== Support +Spring LDAP 2.0 is supported on Spring 2.0 and later. +The community support forum is located at http://forum.spring.io/forum/spring-projects/data/ldap, and the project web page is http://spring.io/spring-ldap/. + + +== Basic Operations + + +=== Search and Lookup Using AttributesMapperAttributesMapper + +In this example we will use an `AttributesMapper` to easily build a List of all common names of all person objects. + +.AttributesMapper that returns a single attribute +[source,java] +[subs="verbatim,quotes"] +---- +package com.example.dao; +import static org.springframework.ldap.query.LdapQueryBuilder.query; + +public class PersonDaoImpl implements PersonDao { + private LdapTemplate ldapTemplate; + + public void setLdapTemplate(LdapTemplate ldapTemplate) { + this.ldapTemplate = ldapTemplate; + } + + public List getAllPersonNames() { + return ldapTemplate.search( + query().where("objectclass").is("person"), + **new AttributesMapper() { + public String mapFromAttributes(Attributes attrs) + throws NamingException { + return (String) attrs.get("cn").get(); + } + }); + }** +} +---- + +The inline implementation of `AttributesMapper` just gets the desired attribute value from the `Attributes` and returns it. Internally, `LdapTemplate` iterates over all entries found, calling the given `AttributesMapper` for each entry, and collects the results in a list. The list is then returned by the `search` method. + +Note that the `AttributesMapper` implementation could easily be modified to return a full `Person` object: + +.AttributesMapper that returns a Person object +[source,java] +[subs="verbatim,quotes"] +---- +package com.example.dao; +import static org.springframework.ldap.query.LdapQueryBuilder.query; + +public class PersonDaoImpl implements PersonDao { + private LdapTemplate ldapTemplate; + ... + **private class PersonAttributesMapper implements AttributesMapper { + public Person mapFromAttributes(Attributes attrs) throws NamingException { + Person person = new Person(); + person.setFullName((String)attrs.get("cn").get()); + person.setLastName((String)attrs.get("sn").get()); + person.setDescription((String)attrs.get("description").get()); + return person; + } + }** + + public List getAllPersons() { + return ldapTemplate.search(query() + .where("objectclass").is("person"), **new PersonAttributesMapper()**); + } +} +---- + +If you have the distinguished name (`dn`) that identifies an entry, you can retrieve the entry directly, without searching for it. This is called a __lookup__ in Java LDAP. The following example shows how a lookup results in a `Person` object: + +.A lookup resulting in a Person object +[source,java] +---- +package com.example.dao; + +public class PersonDaoImpl implements PersonDao { + private LdapTemplate ldapTemplate; + ... + public Person findPerson(String dn) { + return ldapTemplate.lookup(dn, new PersonAttributesMapper()); + } +} +---- + +This will look up the specified `dn` and pass the found attributes to the supplied `AttributesMapper`, in this case resulting in a `Person` object. + +[[basic-queries]] +=== Building LDAP Queries +LDAP searches involve a number of parameters, e.g. Base LDAP path, search scope, attributes to return, and search filters. + +Spring LDAP provides an `LdapQueryBuilder` with a fluent API for building LDAP Queries. + +Let's say that we want to perform a search starting at the base DN `dc=261consulting,dc=com`, limiting the returned attributes to "cn" and "sn", with the following filter: `(&(objectclass=person)(sn=?))`, where we want the `?` to be replaced with the value of the parameter `lastName`. This is how we do it using the `LdapQueryBuilder`: + +.Building a search filter dynamically +[source,java] +[subs="verbatim,quotes"] +---- +package com.example.dao; +import static org.springframework.ldap.query.LdapQueryBuilder.query; + +public class PersonDaoImpl implements PersonDao { + private LdapTemplate ldapTemplate; + ... + public List getPersonNamesByLastName(String lastName) { + + **LdapQuery query = query() + .base("dc=261consulting,dc=com") + .attributes("cn", "sn") + .where("objectclass").is("person") + .and("sn").is(lastName);** + + return ldapTemplate.search(query, + new AttributesMapper() { + public Object mapFromAttributes(Attributes attrs) + throws NamingException { + return attrs.get("cn").get(); + } + }); + } +} +---- + + +[NOTE] +==== +In addition to simplifying building of complex search parameters, the `LdapQueryBuilder` and its associated classes also provide proper escaping of any unsafe characters in search filters. This prevents "ldap injection", where a user might use such characters to inject unwanted operations into your LDAP operations. +==== + +[NOTE] +==== +There are many overloaded methods in `LdapTemplate` for performing LDAP searches. This is in order to accommodate for as many different use cases and programming style preferences as possible. For the vast majority of use cases the ones that take an `LdapQuery` as input will be the recommended methods to use. +==== + +[NOTE] +==== +The `AttributesMapper` is just one of the available callback interfaces to use when handling search and lookup data. See <> for alternatives. +==== + +For more information on the `LdapQueryBuilder` see <>. + +[[ldap-names]] +=== Dynamically Building Distinguished Names + +The standard Java implementation of Distinguished Name, http://docs.oracle.com/javase/6/docs/api/javax/naming/ldap/LdapName.html[LdapName], performs very well when it comes to parsing of Distinguished Names. However, in practical use this implementation has a number of shortcomings: + +* The `LdapName` implementation is mutable, which is badly suited for an object representing identity. + +* Despite its mutable nature, the API for dynamically building or modifying Distinguished Names using `LdapName` is cumbersome. Extracting values of indexed or (particularly) named components is also a little bit awkward. + +* Many of the operations on `LdapName` throw checked Exceptions, requiring unnecessary try-catch statements for situations where the error is typically fatal and cannot be repaired in a meaningful manner. + + +To simplify working with Distinguished Names, Spring LDAP provides an `LdapNameBuilder`, as well as a number of utility methods in `LdapUtils` that helps working with `LdapName`. + +Below are a couple of examples of how these utilities can simplify handling of distinguished names. + +.Dynamically building an LdapName using LdapNameBuilder +[source,java] +[subs="verbatim,quotes"] +---- +package com.example.dao; +import org.springframework.ldap.support.LdapNameBuilder; +import javax.naming.Name; + +public class PersonDaoImpl implements PersonDao { + public static final String BASE_DN = "dc=example,dc=com"; + + protected Name buildDn(Person p) { + **return LdapNameBuilder.newLdapName(BASE_DN) + .add("c", p.getCountry()) + .add("ou", p.getCompany()) + .add("cn", p.getFullname()) + .build();** + } + ... +---- + +Assuming that a Person has the following attributes: + +|=== +| Attribute Name | Attribute Value + +| `country` +| Sweden + +| `company` +| Some Company + +| `fullname` +| Some Person +|=== + +The code above would then result in the following distinguished name: + +[source] +---- +cn=Some Person, ou=Some Company, c=Sweden, dc=example, dc=com +---- + +.Extracting values from a distinguished name using LdapUtils +[source,java] +[subs="verbatim,quotes"] +---- +package com.example.dao; +import org.springframework.ldap.support.LdapNameBuilder; +import javax.naming.Name; +public class PersonDaoImpl implements PersonDao { +... +protected Person buildPerson(Name dn, Attributes attrs) { + Person person = new Person(); + person.setCountry(**LdapUtils.getStringValue(dn, "c")**); + person.setCompany(**LdapUtils.getStringValue(dn, "ou")**); + person.setFullname(**LdapUtils.getStringValue(dn, "cn")**); + // Populate rest of person object using attributes. + + return person; +} + +---- + +Since Java version \<= 1.4 didn't provide any public Distinguished Name implementation at all, Spring LDAP 1.3.2 and lower provided its own implementation, `DistinguishedName`. This implementation suffered from a couple of shortcomings of its own, and has been deprecated in version 2.0. Users are now recommended to use `LdapName` along with the utilities described above instead. + + +=== Binding and Unbinding + +[[basic-binding-data]] +==== Binding Data +Inserting data in Java LDAP is called binding. In order to do that, a distinguished name that uniquely identifies the new entry is required. The following example shows how data is bound using LdapTemplate: + +.Binding data using Attributes +[source,java] +[subs="verbatim,quotes"] +---- +package com.example.dao; + +public class PersonDaoImpl implements PersonDao { + private LdapTemplate ldapTemplate; + ... + public void create(Person p) { + Name dn = buildDn(p); + **ldapTemplate.bind(dn, null, buildAttributes(p));** + } + + private Attributes buildAttributes(Person p) { + Attributes attrs = new BasicAttributes(); + BasicAttribute ocattr = new BasicAttribute("objectclass"); + ocattr.add("top"); + ocattr.add("person"); + attrs.put(ocattr); + attrs.put("cn", "Some Person"); + attrs.put("sn", "Person"); + return attrs; + } +} +---- + +The Attributes building is--while dull and verbose--sufficient for many purposes. It is, however, possible to simplify the binding operation further, which will be described in <>. + + +==== Unbinding Data +Removing data in Java LDAP is called unbinding. A distinguished name (dn) is required to identify the entry, just as in the binding operation. The following example shows how data is unbound using LdapTemplate: + +.Unbinding data +[source,java] +[subs="verbatim,quotes"] +---- +package com.example.dao; + +public class PersonDaoImpl implements PersonDao { + private LdapTemplate ldapTemplate; + ... + public void delete(Person p) { + Name dn = buildDn(p); + **ldapTemplate.unbind(dn);** + } +} +---- + +=== Modifying +In Java LDAP, data can be modified in two ways: either using __rebind__ or __modifyAttributes__. + + +==== Modifying using rebind +A `rebind` is a very crude way to modify data. It's basically an `unbind` followed by a `bind`. It looks like this: + +.Modifying using rebind +[source,java] +[subs="verbatim,quotes"] +---- +package com.example.dao; + +public class PersonDaoImpl implements PersonDao { + private LdapTemplate ldapTemplate; + ... + public void update(Person p) { + Name dn = buildDn(p); + **ldapTemplate.rebind(dn, null, buildAttributes(p));** + } +} +---- + +==== Modifying using modifyAttributes + +If only the modified attributes should be replaced, there is a method called `modifyAttributes` that takes an array of modifications: + +.Modifying using modifyAttributes +[source,java] +[subs="verbatim,quotes"] +---- +package com.example.dao; + +public class PersonDaoImpl implements PersonDao { + private LdapTemplate ldapTemplate; + ... + public void updateDescription(Person p) { + Name dn = buildDn(p); + Attribute attr = new BasicAttribute("description", p.getDescription()) + ModificationItem item = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, attr); + **ldapTemplate.modifyAttributes(dn, new ModificationItem[] {item});** + } +} +---- + +Building `Attributes` and `ModificationItem` arrays is a lot of work, but as you will see in <>, the update operations can be simplified. + + +=== Sample applications +It is recommended that you review the Spring LDAP sample applications included in the release distribution for best-practice illustrations of the features of this library. + +[[dirobjectfactory]] +== Simpler Attribute Access and Manipulation with DirContextAdapter + + +=== Introduction +A little-known--and probably underestimated--feature of the Java LDAP API is the ability to register a `DirObjectFactory` to automatically create objects from found contexts. One of the reasons why it is seldom used is that you will need an implementation of `DirObjectFactory` that creates instances of a meaningful implementation of `DirContext`. The Spring LDAP library provides the missing pieces: a default implementation of `DirContext` called `DirContextAdapter`, and a corresponding implementation of `DirObjectFactory` called `DefaultDirObjectFactory`. Used together with `DefaultDirObjectFactory`, the `DirContextAdapter` can be a very powerful tool. + + +=== Search and Lookup Using ContextMapper +The `DefaultDirObjectFactory` is registered with the `ContextSource` by default, which means that whenever a context is found in the LDAP tree, its `Attributes` and Distinguished Name (DN) will be used to construct a `DirContextAdapter`. This enables us to use a `ContextMapper` instead of an `AttributesMapper` to transform found values: + +.Searching using a ContextMapper +[source,java] +[subs="verbatim,quotes"] +---- +package com.example.dao; + +public class PersonDaoImpl implements PersonDao { + ... + **private static class PersonContextMapper implements ContextMapper { + public Object mapFromContext(Object ctx) { + DirContextAdapter context = (DirContextAdapter)ctx; + Person p = new Person(); + p.setFullName(context.getStringAttribute("cn")); + p.setLastName(context.getStringAttribute("sn")); + p.setDescription(context.getStringAttribute("description")); + return p; + } + }** + + public Person findByPrimaryKey( + String name, String company, String country) { + Name dn = buildDn(name, company, country); + return ldapTemplate.lookup(dn, **new PersonContextMapper()**); + } +} +---- + +The above code shows that it is possible to retrieve the attributes directly by name, without having to go through the `Attributes` and `BasicAttribute` classes. This is particularly useful when working with multi-value attributes. Extracting values from multi-value attributes normally requires looping through a `NamingEnumeration` of attribute values returned from the `Attributes` implementation. The `DirContextAdapter` can do this for you, using the `getStringAttributes()` or `getObjectAttributes()` methods: + +.Getting multi-value attribute values using getStringAttributes() +[source,java] +[subs="verbatim,quotes"] +---- +private static class PersonContextMapper implements ContextMapper { + public Object mapFromContext(Object ctx) { + DirContextAdapter context = (DirContextAdapter)ctx; + Person p = new Person(); + p.setFullName(context.getStringAttribute("cn")); + p.setLastName(context.getStringAttribute("sn")); + p.setDescription(context.getStringAttribute("description")); + // The roleNames property of Person is an String array + **p.setRoleNames(context.getStringAttributes("roleNames"));** + return p; + } +} +---- + +==== The AbstractContextMapper + +Spring LDAP provides an abstract base implementation of `ContextMapper`, `AbstractContextMapper`. This automatically takes care of the casting of the supplied `Object` parameter to `DirContexOperations`. The `PersonContextMapper` above can thus be re-written as follows: + +.Using an AbstractContextMapper +[source,java] +[subs="verbatim,quotes"] +---- +private static class PersonContextMapper **extends AbstractContextMapper** { + public Object **doMapFromContext**(DirContextOperations ctx) { + Person p = new Person(); + p.setFullName(context.getStringAttribute("cn")); + p.setLastName(context.getStringAttribute("sn")); + p.setDescription(context.getStringAttribute("description")); + return p; + } +} +---- + + + +=== Binding and Modifying Using DirContextAdapter +While very useful when extracting attribute values, `DirContextAdapter` is even more powerful for hiding attribute details when binding and modifying data. + + +==== Binding + +This is an example of an improved implementation of the create DAO method. Compare it with the previous implementation in <>. + + +.Binding using DirContextAdapter +[[example-binding-contextmapper]] +[source,java] +[subs="verbatim,quotes"] +---- +package com.example.dao; + +public class PersonDaoImpl implements PersonDao { + ... + public void create(Person p) { + Name dn = buildDn(p); + DirContextAdapter context = new DirContextAdapter(dn); + + **context.setAttributeValues("objectclass", new String[] {"top", "person"}); + context.setAttributeValue("cn", p.getFullname()); + context.setAttributeValue("sn", p.getLastname()); + context.setAttributeValue("description", p.getDescription());** + + ldapTemplate.bind(context); + } +} +---- + +Note that we use the `DirContextAdapter` instance as the second parameter to bind, which should be a `Context`. The third parameter is `null`, since we're not using any `Attributes`. + +Also note the use of the `setAttributeValues()` method when setting the `objectclass` attribute values. The `objectclass` attribute is multi-value, and similar to the troubles of extracting muti-value attribute data, building multi-value attributes is tedious and verbose work. Using the `setAttributeValues()` mehtod you can have `DirContextAdapter` handle that work for you. + + +==== Modifying + +The code for a `rebind` would be pretty much identical to <>, except that the method called would be `rebind`. As we saw in <> a more correct approach would be to build a `ModificationItem` array containing the actual modifications you want to do. This would require you to determine the actual modifications compared to the data present in the LDAP tree. Again, this is something that `DirContextAdapter` can help you with; the `DirContextAdapter` has the ability to keep track of its modified attributes. The following example takes advantage of this feature: +`DirContextAdapter` + +.Modifying using Binding and modifying using DirContextAdapter +[[modify-modifyAttributes]] +[source,java] +[subs="verbatim,quotes"] +---- +package com.example.dao; + +public class PersonDaoImpl implements PersonDao { + ... + public void update(Person p) { + Name dn = buildDn(p); + **DirContextOperations context = ldapTemplate.lookupContext(dn);** + + context.setAttributeValues("objectclass", new String[] {"top", "person"}); + context.setAttributeValue("cn", p.getFullname()); + context.setAttributeValue("sn", p.getLastname()); + context.setAttributeValue("description", p.getDescription()); + + **ldapTemplate.modifyAttributes(context);** + } +} +---- + +When no mapper is passed to a `ldapTemplate.lookup()` operation, the result will be a `DirContextAdapter` instance. While the `lookup` method returns an `Object`, the convenience method `lookupContext` method automatically casts the return value to a `DirContextOperations` (the interface that `DirContextAdapter` implements. + +The observant reader will see that we have duplicated code in the `create` and `update` methods. This code maps from a domain object to a context. It can be extracted to a separate method: + +.Binding and modifying using DirContextAdapter +[source,java] +[subs="verbatim,quotes"] +---- +package com.example.dao; + +public class PersonDaoImpl implements PersonDao { + private LdapTemplate ldapTemplate; + + ... + public void create(Person p) { + Name dn = buildDn(p); + DirContextAdapter context = new DirContextAdapter(dn); + mapToContext(p, context); + ldapTemplate.bind(context); + } + + public void update(Person p) { + Name dn = buildDn(p); + DirContextOperations context = ldapTemplate.lookupContext(dn); + mapToContext(person, context); + ldapTemplate.modifyAttributes(context); + } + + protected void mapToContext (Person p, DirContextOperations context) { + context.setAttributeValues("objectclass", new String[] {"top", "person"}); + context.setAttributeValue("cn", p.getFullName()); + context.setAttributeValue("sn", p.getLastName()); + context.setAttributeValue("description", p.getDescription()); + } +} +---- + + + +=== A Complete PersonDao Class +To illustrate the power of Spring LDAP, here is a complete Person DAO implementation for LDAP in just 68 lines: + + +[source,java] +[subs="verbatim,quotes"] +---- +package com.example.dao; +import java.util.List; + +import javax.naming.Name; +import javax.naming.NamingException; +import javax.naming.directory.Attributes; +import javax.naming.ldap.LdapName; + +import org.springframework.ldap.core.AttributesMapper; +import org.springframework.ldap.core.ContextMapper; +import org.springframework.ldap.core.LdapTemplate; +import org.springframework.ldap.core.DirContextAdapter; +import org.springframework.ldap.filter.AndFilter; +import org.springframework.ldap.filter.EqualsFilter; +import org.springframework.ldap.filter.WhitespaceWildcardsFilter; + +public class PersonDaoImpl implements PersonDao { + private LdapTemplate ldapTemplate; + + public void setLdapTemplate(LdapTemplate ldapTemplate) { + this.ldapTemplate = ldapTemplate; + } + + public void create(Person person) { + DirContextAdapter context = new DirContextAdapter(buildDn(person)); + mapToContext(person, context); + ldapTemplate.bind(context); + } + + public void update(Person person) { + Name dn = buildDn(person); + DirContextOperations context = ldapTemplate.lookupContext(dn); + mapToContext(person, context); + ldapTemplate.modifyAttributes(context); + } + + public void delete(Person person) { + ldapTemplate.unbind(buildDn(person)); + } + + public Person findByPrimaryKey(String name, String company, String country) { + Name dn = buildDn(name, company, country); + return (Person) ldapTemplate.lookup(dn, getContextMapper()); + } + + public List findByName(String name) { + AndFilter filter = new AndFilter(); + filter.and(new EqualsFilter("objectclass", "person")).and(new WhitespaceWildcardsFilter("cn",name)); + return ldapTemplate.search(LdapUtils.emptyPath(), filter.encode(), getContextMapper()); + } + + public List findAll() { + EqualsFilter filter = new EqualsFilter("objectclass", "person"); + return ldapTemplate.search(LdapUtils.emptyPath(), filter.encode(), getContextMapper()); + } + + protected ContextMapper getContextMapper() { + return new PersonContextMapper(); + } + + protected Name buildDn(Person person) { + return buildDn(person.getFullname(), person.getCompany(), person.getCountry()); + } + + protected Name buildDn(String fullname, String company, String country) { + return LdapNameBuilder.newLdapName() + .add("c", country) + .add("ou", company) + .add("cn", fullname) + .build(); + } + + protected void mapToContext(Person person, DirContextOperations context) { + context.setAttributeValues("objectclass", new String[] {"top", "person"}); + context.setAttributeValue("cn", person.getFullName()); + context.setAttributeValue("sn", person.getLastName()); + context.setAttributeValue("description", person.getDescription()); + } + + private static class PersonContextMapper extends AbstractContextMapper { + public Object doMapFromContext(DirContextOperations context) { + Person person = new Person(); + person.setFullName(context.getStringAttribute("cn")); + person.setLastName(context.getStringAttribute("sn")); + person.setDescription(context.getStringAttribute("description")); + return person; + } + } +} +---- + + +[NOTE] +==== +In several cases the Distinguished Name (DN) of an object is constructed using properties of the object. E.g. in the above example, the country, company and full name of the `Person` are used in the DN, which means that updating any of these properties will actually require moving the entry in the LDAP tree using the `rename()` operation in addition to updating the `Attribute` values. Since this is highly implementation specific this is something you'll need to keep track of yourself - either by disallowing the user to change these properties or performing the `rename()` operation in your `update()` method if needed. + +==== + +[[odm]] +== Object-Directory Mapping (ODM) + + +=== Introduction +Relational mapping frameworks like Hibernate and JPA have offered developers the ability to use annotations to map database tables to Java objects for some time. Spring LDAP project offers a similar ability with respect to directories through the use of a number of methods: in `LdapOperations` + +* ` T findByDn(Name dn, Class clazz)` +* ` T findOne(LdapQuery query, Class clazz)` +* ` List find(LdapQuery query, Class clazz)` +* ` List findAll(Class clazz)` +* ` List findAll(Name base, SearchControls searchControls, Class clazz)` +* ` List findAll(Name base, Filter filter, SearchControls searchControls, Class clazz)` +* `void create(Object entry)` +* `void update(Object entry)` +* `void delete(Object entry)` + + +=== Annotations +Entity classes managed used with the object mapping methods are required to be annotated with annotations from the `org.springframework.ldap.odm.annotations` package. The available annotations are: + + +* `@Entry` - Class level annotation indicating the `objectClass` definitions to which the entity maps.__ (required)__ + +* `@Id` - Indicates the entity DN; the field declaring this attribute must be a derivative of the `javax.naming.Name` class. __(required)__ + +* `@Attribute` - Indicates the mapping of a directory attribute to the object class field. + +* `@DnAttribute` - Indicates the mapping of a dn attribute to the object class field. + +* `@Transient` - Indicates the field is not persistent and should be ignored by the `OdmManager`. + + +The `@Entry` and `@Id` attributes are required to be declared on managed classes.`@Entry` is used to specify which object classes the entity maps to. All object classes for which fields are mapped are required to be declared. Also, in order for a directory entry to be considered a match to the managed entity, all object classes declared by the directory entry must match be declared by in the`@Entry` annotation. For example: let's assume that you have entries in your LDAP tree that have the objectclasses `inetOrgPerson,organizationalPerson,person,top`. If you are only interested in changing the attributes defined in the `person` objectclass, your `@Entry` annotation can be `@Entry(objectClasses = { "person", "top" })`. However, if you want to manage attributes defined in the `inetOrgPerson` objectclass you'll need to use the full monty: `@Entry(objectClasses = { "inetOrgPerson", "organizationalPerson", "person", "top" })`. + +The `@Id` annotation is used to map the distinguished name of the entry to a field. The field must be an instance of `javax.naming.Name`. + +The `@Attribute` annotation is used to map object class fields to entity fields. `@Attribute` is required to declare the name of the object class property to which the field maps and may optionally declare the syntax OID of the LDAP attribute, to guarantee exact matching. `@Attribute` also provides the type declaration which allows you to indicate whether the attribute is regarded as binary based or string based by the LDAP JNDI provider. + +The `@DnAttribute` annotation is used to map object class fields to and from components in the distinguished name of an entry. Fields annotated with`@DnAttribute` will automatically be populated with the appropriate value from the distinguished name when an entry is read from the directory tree. If the `index` attribute of all `@DnAttribute` annotations in a class is specified, the DN will also be calculated when creating and updating entries. For update scenarios, this will also automatically take care of moving entries in the tree if attributes that are part of the distinguished name have changed. + +The `@Transient` annotation is used to indicate the field should be ignored by the object directory mapping and not mapped to an underlying LDAP property. Note that if a `@DnAttribute` is not to be bound to an Attribute, i.e. it is only part of the Distinguished Name and not represented by an object attibute, it must also be annotated with `@Transient`. + +=== Type Conversion + +The object directory mapping relies on the `org.springframework.ldap.odm.typeconversion` package to convert LDAP attributes to Java fields. For simple setups, no particular configuraion is needed for this purpose. However, more complex mapping scenarios require the `ObjectDirectoryMapper` and its associated `ConverterManager` to be explicitly configured on the `LdapTemplate` instance. The default `ConverterManager` implementation uses the following algorithm when parsing objects to convert fields: + +. Try to find and use a `Converter` registered for the `fromClass`, `syntax` and `toClass` and use it. +. If this fails, then if the `toClass``isAssignableFrom` the `fromClass` then just assign it. +. If this fails try to find and use a `Converter` registered for the `fromClass` and the `toClass` ignoring the syntax. +. If this fails then throw a `ConverterException`. + + + +Implementations of the `ConverterManager` interface can be obtained from the `o.s.l.odm.typeconversion.impl.ConvertManagerFactoryBean`. The factory bean requires converter configurations to be declared in the bean configuration. + +The converterConfig property accepts a set of `ConverterConfig` classes, each one defining some conversion logic. A converter config is an instance of `o.s.l.odm.typeconversion.impl.ConverterManagerFactoryBean.ConverterConfig`. The config defines a set of source classes, the set of target classes, and an implementation of the `org.springframework.ldap.odm.typeconversion.impl.Converter` interface which provides the logic to convert from the `fromClass` to the `toClass`. A sample configuration is provided in the following example: + +.Configuring the Converter Manager Factory +[source,xml] +[subs="verbatim,quotes"] +---- + + + + + + + + + java.lang.String + + + + + java.lang.Byte + java.lang.Short + java.lang.Integer + java.lang.Long + java.lang.Float + java.lang.Double + java.lang.Boolean + + + + + + + + java.lang.Byte + java.lang.Short + java.lang.Integer + java.lang.Long + java.lang.Float + java.lang.Double + java.lang.Boolean + + + + + java.lang.String + + + + + + + + + + + + +---- + + + +=== Execution +When all components have been properly configured and annotated, the object mapping methods of `LdapTemplate` can be used as follows: + +.Execution +[source,java] +[subs="verbatim,quotes"] +---- + +@Entry(objectClasses = { "person", "top" }, base="ou=someOu") +public class Person { + @Id + private Name dn; + + @Attribute(name="cn") + @DnAttribute(value="cn", index=1) + private String fullName; + + // No @Attribute annotation means this will be bound to the LDAP attribute + // with the same value + private String description; + + @DnAttribute(value="ou", index=0) + @Transient + private String company; + + @Transient + private String someUnmappedField; + // ...more attributes below +} + + +public class OdmPersonDao { + @Autowired + private LdapTemplate ldapTemplate; + + public Person create(Person person) { + ldapTemplate.create(person); + return person; + } + + public Person findByUid(String uid) { + return ldapTemplate.findOne(query().where("uid").is(uid), Person.class); + } + + public void update(Person person) { + ldapTemplate.update(person); + } + + public void delete(Person person) { + ldapTemplate.delete(person); + } + + public List>Person< findAll() { + return ldapTemplate.findAll(Person.class); + } + + public List>Person< findByLastName(String lastName) { + return ldapTemplate.find(query().where("sn").is(lastName), Person.class); + } +} +---- + + +[[query-builder-advanced]] +== Advanced LDAP Queries + + +=== LDAP Query Builder Parameters + +The `LdapQueryBuilder` and its associated classes is intended to support all parameters that can be supplied to an LDAP search. The following parameters are supported: + +* `base` - specifies the root DN in the LDAP tree where the search should start. +* `searchScope` - specifies how deep into the LDAP tree the search should traverse. +* `attributes` - specifies the attributes to return from the search. Default is all. +* `countLimit` - specifies the maximum number of entries to return from the search. +* `timeLimit` - specifies the maximum time that the search may take. +* Search filter - the conditions that the entries we are looking for must meet. + +An `LdapQueryBuilder` is created with a call to the `query` method of `LdapQueryBuilder`. It's intended as a fluent builder API, where the base parameters are defined first, followed by the filter specification calls. Once filter conditions have been started to be defined with a call to the `where` method of `LdapQueryBuilder`, later attempts to call e.g. `base` will be rejected. The base search parameters are optional, but at least one filter specification call is required. + +.Search for all entries with objectclass person +[source,java] +[subs="verbatim,quotes"] +---- +import static org.springframework.ldap.query.LdapQueryBuilder.query; +... + +List persons = ldapTemplate.search( + query().where("objectclass").is("person"), + new PersonAttributesMapper()); + +---- + + +.Search for all entries with objectclass person and cn=John Doe +[source,java] +[subs="verbatim,quotes"] +---- +import static org.springframework.ldap.query.LdapQueryBuilder.query; +... + +List persons = ldapTemplate.search( + query().where("objectclass").is("person") + .and("cn").is("John Doe"), + new PersonAttributesMapper()); +---- + +.Search for all entries with objectclass person starting at dc=261consulting,dc=com +[source,java] +[subs="verbatim,quotes"] +---- +import static org.springframework.ldap.query.LdapQueryBuilder.query; +... + +List persons = ldapTemplate.search( + query().base("dc=261consulting,dc=com") + .where("objectclass").is("person"), + new PersonAttributesMapper()); +---- + +.Search for all entries with objectclass person starting at dc=261consulting,dc=com, only returning the cn attribute +[source,java] +[subs="verbatim,quotes"] +---- +import static org.springframework.ldap.query.LdapQueryBuilder.query; +... + +List persons = ldapTemplate.search( + query().base("dc=261consulting,dc=com") + .attributes("cn") + .where("objectclass").is("person"), + new PersonAttributesMapper()); + +---- + +[source,java] +[subs="verbatim,quotes"] +---- +import static org.springframework.ldap.query.LdapQueryBuilder.query; +... +List persons = ldapTemplate.search( + query().where("objectclass").is("person"), + .and(query().where("cn").is("Doe").or("cn").is("Doo)); + new PersonAttributesMapper()); +---- + +=== Filter Criteria +The examples above demonstrates simple equals conditions in LDAP filters. The LDAP query builder has support for the following criteria types: + +* `is` - specifies an equals condition (=). +* `gte` - specifies a greater than or equals condition (>=). +* `lte` - specifies a less than or equals condition (<=). +* `like` - specifies a "like" condition where wildcards can be included in the query, e.g. `where("cn").like("J*hn Doe")` will result int the filter `(cn=J*hn Doe)`. +* `whitespaceWildcardsLike` - specifies a condition where all whitespace is replaced with wildcards, e.g. `where("cn").whitespaceWildcardsLike("John Doe")` will result in the filter `(cn=*John*Doe*)`. +* `isPresent` - specifies condition that checks for the presence of an attribute, e.g. `where("cn").isPresent()` will result in the filter `(cn=*)`. +* `not` - specifies that the current condition should be negated, e.g. `where("sn").not().is("Doe)` will result in the filter `(!(sn=Doe))` + + + + +=== Hardcoded Filters +There are occasions when you will want to specify a hardcoded filter as input to an `LdapQuery`. `LdapQueryBuilder` has two methods for this purpose: + +* `filter(String hardcodedFilter)` - uses the specified string as filter. Note that the specified input string will not be touched in any way, meaning that this method is not particularly well suited if you are building filters from user input. +* `filter(String filterFormat, String... params)` - uses the specified string as input to `MessageFormat`, properly encoding the parameters and inserting them at the specified places in the filter string. + +You cannot mix the hardcoded filter methods with the `where` approach described above; it's either one or the other. What this means is that if you specified a filter using `filter()` you will get an exception if you try to call `where` afterwards. + + +== Configuration + + +=== Introduction + +The recommended way of configuring Spring LDAP is using the custom XML configuration namespace. In order to make this available you need to include the Spring LDAP namespace declaration in your bean file, e.g.: + +[source,java] +[subs="verbatim,quotes"] +---- + +---- + +=== ContextSource Configuration + +ContextSource Configuration Attributes +The `ContextSource` is defined using a `` tag. The simplest possible `context-source` declaration requires you to specify a server url, a username, and a password: + +.Simplest possible context-source declaration +[source,java] +[subs="verbatim,quotes"] +---- + + +---- + +This will create an `LdapContextSource` with default values (see below), and the url and authentication information as specified. + The configurable attributes on context-source are as follows (required attributes marked with *): + +.ContextSource Configuration Attributes +[cols="2,3,5"] +|=== +| Attribute | Default | Description + +| `id` +| `contextSource` +| The id of the created bean. + +| `username` +| +| The username (principal) to use when authenticating with the LDAP server. This will usually be the distinguished name of an admin user (e.g.`cn=Administrator`, but may differ depending on server and authentication method. Required if `authentication-source-ref` is not explicitly configured. + +| `password` +| +| The password (credentials) to use when authenticating with the LDAP server. Required if `authentication-source-ref` is not explicitly configured. + +| `url` * +| +| The URL of the LDAP server to use. The URL should be in the format `ldap://myserver.example.com:389`. For SSL access, use the `ldaps` protocol and the appropriate port, e.g. `ldaps://myserver.example.com:636`. If fail-over functionality is desired, more than one URL can be specified, separated using comma (,). + +| `base` +| `LdapUtils.emptyLdapName()` +| The base DN. When this attribute has been configured, all Distinguished Names supplied to and received from LDAP operations will be relative to the specified LDAP path. This can significantly simplify working against the LDAP tree; however there are several occasions when you will need to have access to the base path. For more information on this, please refer to <> + +| `anonymous-read-only` +| `false` +| Defines whether read-only operations will be performed using an anonymous (unauthenticated) context. __Note__ that setting this parameter to `true` together with the compensating transaction support is not supported and will be rejected. + +| `referral` +| `null` +a| Defines the strategy to handle referrals, as described http://docs.oracle.com/javase/jndi/tutorial/ldap/referral/jndi.html[here]. Valid values are: + + +* `ignore` +* `follow` +* `throw` + + + +| `native-pooling` +| `false` +| Specify whether native Java LDAP connection pooling should be used. Consider using Spring LDAP connection pooling instead. See <> for more information. + +| `authentication-source-ref` +| A `SimpleAuthenticationSource` instance. +| Id of the AuthenticationSource instance to use (see below). + +| `authentication-strategy-ref` +| A `SimpleDirContextAuthenticationStrategy` instance. +| Id of the DirContextAuthenticationStrategy instance to use (see below). + +| `base-env-props-ref` +| A `SimpleDirContextAuthenticationStrategy` instance. +| Reference to a Map of custom environment properties that should supplied with the environment sent to the `DirContext` on construction. +|=== + +<> + +==== DirContext Authentication +When `DirContext` instances are created to be used for performing operations on an LDAP server these contexts often need to be authenticated. There are different options for configuring this using Spring LDAP, described in this chapter. + +[NOTE] +==== +This section refers to authenticating contexts in the core functionality of the `ContextSource` - to construct `DirContext` instances for use by `LdapTemplate`. LDAP is commonly used for the sole purpose of user authentication, and the `ContextSource` may be used for that as well. This process is discussed in <>. +==== + +Authenticated contexts are created for both read-only and read-write operations by default. You specify `username` and `password` of the LDAP user to be used for authentication on the `context-source` element. +[NOTE] +==== +If `username` is the dn of an LDAP user, it needs to be the full Distinguished Name (DN) of the user from the root of the LDAP tree, regardless of whether a `base` LDAP path has been specified on the `context-source` element. +==== + +Some LDAP server setups allow anonymous read-only access. If you want to use anonymous Contexts for read-only operations, set the `anonymous-read-only` attribute to `true`. + +===== Custom DirContext Authentication Processing +The default authentication mechanism used in Spring LDAP is `SIMPLE` authentication. This means that the principal (as specified to the `username` attribute) and the credentials (as specified to the `password`) are set in the Hashtable sent to the `DirContext` implementation constructor. + +There are many occasions when this processing is not sufficient. For instance, LDAP Servers are commonly set up to only accept communication on a secure TLS channel; there might be a need to use the particular LDAP Proxy Auth mechanism, etc. + +It is possible to specify an alternative authentication mechanism by supplying a `DirContextAuthenticationStrategy` implementation reference to the `context-source` element using the `authentication-strategy-ref` attribute. + + +====== TLS +Spring LDAP provides two different configuration options for LDAP servers requiring TLS secure channel communication: `DefaultTlsDirContextAuthenticationStrategy` and `ExternalTlsDirContextAuthenticationStrategy`. Both these implementations will negotiate a TLS channel on the target connection, but they differ in the actual authentication mechanism. Whereas the `DefaultTlsDirContextAuthenticationStrategy` will apply SIMPLE authentication on the secure channel (using the specified `userDn` and `password`), the `ExternalDirContextAuthenticationStrategy` will use EXTERNAL SASL authentication, applying a client certificate configured using system properties for authentication. + +Since different LDAP server implementations respond differently to explicit shutdown of the TLS channel (some servers require the connection be shutdown gracefully; others do not support it), the TLS `DirContextAuthenticationStrategy` implementations support specifying the shutdown behavior using the `shutdownTlsGracefully` parameter. If this property is set to `false` (the default), no explicit TLS shutdown will happen; if it is `true`, Spring LDAP will try to shutdown the TLS channel gracefully before closing the target context. + +[NOTE] +==== +When working with TLS connections you need to make sure that the native LDAP Pooling functionality (as specified using the `native-pooling` attribute is turned off. This is particularly important if `shutdownTlsGracefully` is set to `false`. However, since the TLS channel negotiation process is quite expensive, great performance benefits will be gained by using the Spring LDAP Pooling Support, described in <>. +==== + + +===== Custom Principal and Credentials ManagementUsing the +While the user name (i.e. user DN) and password used for creating an authenticated `Context` are statically defined by default - the ones defined in the `context-source` element configuration will be used throughout the lifetime of the `ContextSource` - there are several cases where this is not the desired behaviour. A common scenario is that the principal and credentials of the current user should be used when executing LDAP operations for that user. The default behaviour can be modified by supplying a reference to an `AuthenticationSource` implementation to the `context-source` element using the `authentication-source-ref` element, instead of explicitly specifying the `username` and `password`. The `AuthenticationSource` will be queried by the `ContextSource` for principal and credentials each time an authenticated `Context` is to be created. + +If you are using http://spring.io/spring-security[Spring Security] you can make sure the principal and credentials of the currently logged in user is used at all times by configuring your `ContextSource` with an instance of the `SpringSecurityAuthenticationSource` shipped with Spring Security. + + +.Using the SpringSecurityAuthenticationSource +[source,java] +[subs="verbatim,quotes"] +---- + + +... + +... + +---- + + +NOTE: We don't specify any `username` or `password` to our `context-source` when using an `AuthenticationSource` - these properties are needed only when the default behaviour is used. + +NOTE: When using the `SpringSecurityAuthenticationSource` you need to use Spring Security's `LdapAuthenticationProvider` to authenticate the users against LDAP. + + +==== Native Java LDAP Pooling +The internal Java LDAP provider provides some very basic pooling capabilities. This LDAP connection pooling can be turned on/off using the `pooled` flag on `AbstractContextSource`. The default value is `false` (since release 1.3), i.e. the native Java LDAP pooling will be turned off. The configuration of LDAP connection pooling is managed using `System` properties, so this needs to be handled manually, outside of the Spring Context configuration. Details of the native pooling configuration can be found http://java.sun.com/products/jndi/tutorial/ldap/connect/config.html[here]. + +NOTE: There are several serious deficiencies in the built-in LDAP connection pooling, which is why Spring LDAP provides a more sophisticated approach to LDAP connection pooling, described in <>. If pooling functionality is required, this is the recommended approach. + +NOTE: Regardless of the pooling configuration, the `ContextSource#getContext(String principal, String credentials)` method will always explicitly __not__ use native Java LDAP Pooling, in order for reset passwords to take effect as soon as possible. + +==== Advanced ContextSource Configuration + + +===== Custom DirContext Environment Properties +In some cases the user might want to specify additional environment setup properties in addition to the ones directly configurable on `context-source`. Such properties should be set in a `Map` and referenced in the `base-env-props-ref` attribute. + + +=== LdapTemplate Configuration +The `LdapTemplate` is defined using a `` tag. The simplest possible `ldap-template` declaration is the simple tag: + +.Simplest possible ldap-template declaration +[source,java] +[subs="verbatim,quotes"] +---- + + +---- + +This will create an `LdapTemplate` instance with the default id, referencing the default `ContextSource`, which is expected to have the id `contextSource` (the default for the `context-source` element). + +The configurable attributes on `ldap-template` are as follows: + +.LdapTemplate Configuration Attributes +[cols="1,1,4a"] +|=== +| Attribute | Default | Description + +| `id` +| `ldapTemplate` +| The id of the created bean. + +| `context-source-ref` +| `contextSource` +| Id of the ContextSource instance to use. + +| `count-limit` +| `0` +| The default count limit for searches. 0 means no limit. + +| `time-limit` +| `0` +| The default time limit for searches in milliseconds. 0 means no limit. + +| `search-scope` +| `SUBTREE` +| The default search scope for searches. Valid values are: + +* `OBJECT` +* `ONELEVEL` +* `SUBTREE` + +| `ignore-name-not-found` +| `false` +| Specifies whether NameNotFoundException should be ignored in searches. Setting this attribute to true will cause errors caused by invalid search base to be silently swallowed. + +| `ignore-partial-result` +| `false` +| Specifies whether PartialResultException should be ignored in searches. Some LDAP servers have problems with referrals; these should normally be followed automatically, but if this doesn't work it will manifest itself with a PartialResultException. Setting this attribute to true presents a work-around to this problem. + +| `odm-ref` +| +| Id of the ObjectDirectoryMapper instance to use. Default is a default-configured DefaultObjectDirectoryMapper. +|=== + + +[[base-context-configuration]] +=== Obtaining a reference to the base LDAP path + +As described above, a base LDAP path may be supplied to the `ContextSource`, specifying the root in the LDAP tree to which all operations will be relative. This means that you will only be working with relative distinguished names throughout your system, which is typically rather handy. There are however some cases in which you will need to have access to the base path in order to be able to construct full DNs, relative to the actual root of the LDAP tree. One example would be when working with LDAP groups (e.g. `groupOfNames` objectclass), in which case each group member attribute value will need to be the full DN of the referenced member. + +For that reason, Spring LDAP has a mechanism by which any Spring controlled bean may be supplied the base path on startup. For beans to be notified of the base path, two things need to be in place: First of all, the bean that wants the base path reference needs to implement the `BaseLdapNameAware` interface. Secondly, a `BaseLdapPathBeanPostProcessor` needs to be defined in the application context + +.Implementing BaseLdapNameAware +[source,java] +[subs="verbatim,quotes"] +---- +package com.example.service; +public class PersonService implements PersonService**, BaseLdapNameAware** { + ... + **private LdapName basePath; + + public void setBaseLdapPath(LdapName basePath) { + this.basePath = basePath; + }** + ... + private LdapName getFullPersonDn(Person person) { + return LdapNameBuilder.newLdapName(**basePath**) + .append(person.getDn()) + .build(); + } + ... +} +---- + +.Specifying a BaseLdapPathBeanPostProcessor in your ApplicationContext +[source,java] +[subs="verbatim,quotes"] +---- + + ... + + ... + **** + +---- + +The default behaviour of the `BaseLdapPathBeanPostProcessor` is to use the base path of the single defined `BaseLdapPathSource` (`AbstractContextSource`)in the `ApplicationContext`. If more than one `BaseLdapPathSource` is defined, you will need to specify which one to use with the `baseLdapPathSourceName` property. + +[[repositories]] +== Spring LDAP Repositories + +=== Overview +Spring LDAP has built-in support for Spring Data repositories. The basic functionality and configuration is described http://docs.spring.io/spring-data/data-commons/docs/1.6.1.RELEASE/reference/html/repositories.html[here]. When working with Spring LDAP repositories, please note the following: + +* Spring LDAP repositories can be enabled using an `` tag in your XML configuration or using an `@EnableLdapRepositories` annotation on a configuration class. +* To include support for `LdapQuery` parameters in automatically generated repositories, have your interface extend `LdapRepository` rather than `CrudRepository`. +* All Spring LDAP repositories must work with entities annotated with the ODM annotations, as described in <>. +* Since all ODM managed classes must have a Distinguished Name as ID, all Spring LDAP repositories must have the ID type parameter set to `javax.naming.Name`. Indeed, the built-in `SpringLdapRepository` only takes one type parameter; the managed entity class, defaulting ID to `javax.naming.Name`. +* Due to specifics of the LDAP protocol, paging and sorting is not supported for Spring LDAP repositories. + +=== QueryDSL support +Basic QueryDSL support is included in Spring LDAP. This support includes the following: + +* An Annotation Processor, `LdapAnnotationProcessor`, for generating QueryDSL classes based on Spring LDAP ODM annotations. See <> for more information on the ODM annotations. +* A Query implementation, `QueryDslLdapQuery`, for building and executing QueryDSL queries in code. +* Spring Data repository support for QueryDSL predicates. `QueryDslPredicateExecutor` includes a number of additional methods with appropriate parameters; extend this interface along with `LdapRepository` to include this support in your repository. + +[[pooling]] +== Pooling Support + +=== Introduction +Pooling LDAP connections helps mitigate the overhead of creating a new LDAP connection for each LDAP interaction. While http://java.sun.com/products/jndi/tutorial/ldap/connect/pool.html[Java LDAP pooling support] exists it is limited in its configuration options and features, such as connection validation and pool maintenance. Spring LDAP provides support for detailed pool configuration on a per-`ContextSource` basis. + +Pooling support is provided by supplying a `` sub-element to the `` element in the application context configuration. Read-only and read-write `DirContext` objects are pooled separately (if `anonymous-read-only` is specified. http://commons.apache.org/pool/index.html[Jakarta Commons-Pool] is used to provide the underlying pool implementation. + + +=== DirContext Validation +Validation of pooled connections is the primary motivation for using a custom pooling library versus the JDK provided LDAP pooling functionality. Validation allows pooled `DirContext` connections to be checked to ensure they are still properly connected and configured when checking them out of the pool, in to the pool or while idle in the pool. + +If connection validation is configured, pooled connections are validated using `DefaultDirContextValidator`. `DefaultDirContextValidator` does a ` DirContext.search(String, String, SearchControls) ` , with an empty name, a filter of `"objectclass=*"` and `SearchControls` set to limit a single result with the only the objectclass attribute and a 500ms timeout. If the returned `NamingEnumeration` has results the `DirContext` passes validation, if no results are returned or an exception is thrown the `DirContext` fails validation. The default settings should work with no configuration changes on most LDAP servers and provide the fastest way to validate the `DirContext`. If customization required this can be done using the validation configuration attributes, described below + +[NOTE] +==== +Connections will be automatically invalidated if they throw an exception that is considered non-transient. E.g. if a `DirContext` instance throws a `javax.naming.CommunicationException`, this will be interpreted as a non-transient error and the instance will be automatically invalidated, without the overhead of an additional testOnReturn operation. The exceptions that are interpreted as non-transient are configured using the `nonTransientExceptions` property of the `PoolingContextSource`. +==== + + +=== Pool Configuration +The following attributes are available on the `` element for configuration of the DirContext pool: + +[cols="1,1,4a"] +.Pooling Configuration Attributes +|=== +| Attribute | Default | Description + +| `max-active` +| `8` +| The maximum number of active connections of each type (read-only\|read-write) that can be allocated from this pool at the same time, or non-positive for no limit. + +| `max-total` +| `-1` +| The overall maximum number of active connections (for all types) that can be allocated from this pool at the same time, or non-positive for no limit. + +| `max-idle` +| `8` +| The maximum number of active connections of each type (read-only\|read-write) that can remain idle in the pool, without extra ones being released, or non-positive for no limit. + +| `min-idle` +| `0` +| The minimum number of active connections of each type (read-only\|read-write) that can remain idle in the pool, without extra ones being created, or zero to create none. + +| `max-wait` +| `-1` +| The maximum number of milliseconds that the pool will wait (when there are no available connections) for a connection to be returned before throwing an exception, or non-positive to wait indefinitely. + +| `when-exhausted` +| `BLOCK` +| Specifies the behaviour when the pool is exhausted. + +* The `FAIL` option will throw a ` NoSuchElementException ` when the pool is exhausted. + +* The `BLOCK` option will wait until a new object is available. If `max-wait` is positive a ` NoSuchElementException ` is thrown if no new object is available after the `max-wait` time expires. + +* The `GROW` option will create and return a new object (essentially making `max-active` meaningless). + + +| `test-on-borrow` +| `false` +| The indication of whether objects will be validated before being borrowed from the pool. If the object fails to validate, it will be dropped from the pool, and an attempt to borrow another will be made. + +| `test-on-return` +| `false` +| The indication of whether objects will be validated before being returned to the pool. + +| `test-while-idle` +| `false` +| The indication of whether objects will be validated by the idle object evictor (if any). If an object fails to validate, it will be dropped from the pool. + +| `eviction-run-interval-millis` +| `-1` +| The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no idle object evictor thread will be run. + +| `tests-per-eviction-run` +| `3` +| The number of objects to examine during each run of the idle object evictor thread (if any). + +| `min-evictable-time-millis` +| `1000 * 60 * 30` +| The minimum amount of time an object may sit idle in the pool before it is eligible for eviction by the idle object evictor (if any). + +| `validation-query-base` +| `LdapUtils.emptyName()` +| The search base to be used when validating connections. Only used if `test-on-borrow`, `test-on-return`, or `test-while-idle` is specified + +| `validation-query-filter` +| `objectclass=*` +| The search filter to be used when validating connections. Only used if `test-on-borrow`, `test-on-return`, or `test-while-idle` is specified + +| `validation-query-search-controls-ref` +| `null`; default search control settings are described above. +| Id of a SearchControls instance to be used when validating connections. Only used if `test-on-borrow`, `test-on-return`, or `test-while-idle` is specified + +| `non-transient-exceptions` +| `javax.naming.CommunicationException` +| Comma-separated list of Exception classes. The listed exceptions will be considered non-transient with regards to eager invalidation. Should any of the listed exceptions (or subclasses of them) be thrown by a call to a pooled `DirContext` instance, that object will be automatically invalidated without any additional testOnReturn operation. +|=== + + + +=== Configuration +Configuring pooling should look very familiar if you're used to Jakarta Commons-Pool or Commons-DBCP. You will first create a normal `ContextSource` then wrap it in a `PoolingContextSource` . + +[source,xml] +[subs="verbatim,quotes"] +---- + + ... + + + + ... + +---- + +In a real world example you would probably configure the pool options and enable connection validation; the above serves as an example to demonstrate the general idea. + +==== Validation Configuration +Adding validation and a few pool configuration tweaks to the above example is straight forward. Inject a `DirContextValidator` and set when validation should occur and the pool is ready to go. + +[source,xml] +[subs="verbatim,quotes"] +---- + + ... + + + + ... + +---- + +The above example will test each `DirContext` before it is passed to the client application and test `DirContext`s that have been sitting idle in the pool. + + +=== Known Issues + + +==== Custom Authentication +The `PoolingContextSource` assumes that all `DirContext` objects retrieved from `ContextSource.getReadOnlyContext()` will have the same environment and likewise that all `DirContext` objects retrieved from `ContextSource.getReadWriteContext()` will have the same environment. This means that wrapping a `LdapContextSource` configured with an `AuthenticationSource` in a `PoolingContextSource` will not function as expected. The pool would be populated using the credentials of the first user and unless new connections were needed subsequent context requests would not be filled for the user specified by the `AuthenticationSource` for the requesting thread. + + +== Adding Missing Overloaded API Methods + + +=== Implementing Custom Search Methods + +While `LdapTemplate` contains several overloaded versions of the most common operations in `DirContext`, we have not provided an alternative for each and every method signature, mostly because there are so many of them. We have, however, provided a means to call whichever `DirContext` method you want and still get the benefits that LdapTemplate provides. + +Let's say that you want to call the following `DirContext` method: + +[source,java] +[subs="verbatim,quotes"] +---- +NamingEnumeration search(Name name, String filterExpr, Object[] filterArgs, SearchControls ctls) +---- + +There is no corresponding overloaded method in LdapTemplate. The way to solve this is to use a custom `SearchExecutor` implementation: + + +[source,java] +[subs="verbatim,quotes"] +---- +public interface SearchExecutor { + public NamingEnumeration executeSearch(DirContext ctx) throws NamingException; +} +---- + +In your custom executor, you have access to a `DirContext` object, which you use to call the method you want. You then provide a handler that is responsible for mapping attributes and collecting the results. You can for example use one of the available implementations of `CollectingNameClassPairCallbackHandler`, which will collect the mapped results in an internal list. In order to actually execute the search, you call the `search` method in LdapTemplate that takes an executor and a handler as arguments. Finally, you return whatever your handler has collected. + +.A custom search method using SearchExecutor and AttributesMapper +[source,java] +[subs="verbatim,quotes"] +---- +package com.example.dao; + +public class PersonDaoImpl implements PersonDao { + ... + public List search(final Name base, final String filter, final String[] params, + final SearchControls ctls) { + **SearchExecutor executor = new SearchExecutor() { + public NamingEnumeration executeSearch(DirContext ctx) { + return ctx.search(base, filter, params, ctls); + } + };** + + CollectingNameClassPairCallbackHandler handler = + new AttributesMapperCallbackHandler(new PersonAttributesMapper()); + + ldapTemplate.search(**executor**, handler); + return handler.getList(); + } +} +---- + +If you prefer the `ContextMapper` to the `AttributesMapper`, this is what it would look like: + +.A custom search method using SearchExecutor and ContextMapper +[source,java] +[subs="verbatim,quotes"] +---- +package com.example.dao; + +public class PersonDaoImpl implements PersonDao { + ... + public List search(final Name base, final String filter, final String[] params, + final SearchControls ctls) { + SearchExecutor executor = new SearchExecutor() { + public NamingEnumeration executeSearch(DirContext ctx) { + return ctx.search(base, filter, params, ctls); + } + }; + + CollectingNameClassPairCallbackHandler handler = + **new ContextMapperCallbackHandler(new PersonContextMapper()**); + + ldapTemplate.search(executor, handler); + return handler.getList(); + } +} +---- + + +[NOTE] +==== +When using the `ContextMapperCallbackHandler` you must make sure that you have called `setReturningObjFlag(true)` on your `SearchControls` instance. +==== + + +=== Implementing Other Custom Context Methods + +In the same manner as for custom `search` methods, you can actually execute any method in `DirContext` by using a `ContextExecutor`. + + +[source,java] +[subs="verbatim,quotes"] +---- +public interface ContextExecutor { + public Object executeWithContext(DirContext ctx) throws NamingException; +} +---- + +When implementing a custom `ContextExecutor`, you can choose between using the `executeReadOnly()` or the `executeReadWrite()` method. Let's say that we want to call this method: + + +[source,java] +[subs="verbatim,quotes"] +---- +Object lookupLink(Name name) +---- + +It's available in `DirContext`, but there is no matching method in `LdapTemplate`. It's a lookup method, so it should be read-only. We can implement it like this: + +.A custom DirContext method using ContextExecutor +[source,java] +[subs="verbatim,quotes"] +---- +package com.example.dao; + +public class PersonDaoImpl implements PersonDao { + ... + public Object lookupLink(final Name name) { + ContextExecutor executor = new ContextExecutor() { + public Object executeWithContext(DirContext ctx) { + return ctx.lookupLink(name); + } + }; + + return ldapTemplate.executeReadOnly(executor); + } +} +---- + +In the same manner you can execute a read-write operation using the `executeReadWrite()` method. + + +== Processing the DirContext + + +=== Custom DirContext Pre/Postprocessing +In some situations, one would like to perform operations on the `DirContext` before and after the search operation. The interface that is used for this is called `DirContextProcessor`: + +[source,java] +[subs="verbatim,quotes"] +---- +public interface DirContextProcessor { + public void preProcess(DirContext ctx) throws NamingException; + public void postProcess(DirContext ctx) throws NamingException; +} +---- + +The `LdapTemplate` class has a search method that takes a `DirContextProcessor`: + +[source,java] +[subs="verbatim,quotes"] +---- +public void search(SearchExecutor se, NameClassPairCallbackHandler handler, + DirContextProcessor processor) throws DataAccessException; +---- + +Before the search operation, the `preProcess` method is called on the given `DirContextProcessor` instance. After the search has been executed and the resulting `NamingEnumeration` has been processed, the `postProcess` method is called. This enables a user to perform operations on the `DirContext` to be used in the search, and to check the `DirContext` when the search has been performed. This can be very useful for example when handling request and response controls. + +There are also a few convenience methods for those that don't need a custom `SearchExecutor`: + + +[source,java] +[subs="verbatim,quotes"] +---- +public void search(Name base, String filter, + SearchControls controls, NameClassPairCallbackHandler handler, DirContextProcessor processor) + +public void search(String base, String filter, + SearchControls controls, NameClassPairCallbackHandler handler, DirContextProcessor processor) + +public void search(Name base, String filter, + SearchControls controls, AttributesMapper mapper, DirContextProcessor processor) + +public void search(String base, String filter, + SearchControls controls, AttributesMapper mapper, DirContextProcessor processor) + +public void search(Name base, String filter, + SearchControls controls, ContextMapper mapper, DirContextProcessor processor) + +public void search(String base, String filter, + SearchControls controls, ContextMapper mapper, DirContextProcessor processor) +---- + + +=== Implementing a Request Control DirContextProcessor + +The LDAPv3 protocol uses Controls to send and receive additional data to affect the behavior of predefined operations. In order to simplify the implementation of a request control `DirContextProcessor`, Spring LDAP provides the base class `AbstractRequestControlDirContextProcessor`. This class handles the retrieval of the current request controls from the `LdapContext`, calls a template method for creating a request control, and adds it to the `LdapContext`. All you have to do in the subclass is to implement the template method `createRequestControl`, and of course the `postProcess` method for performing whatever you need to do after the search. + +[source,java] +[subs="verbatim,quotes"] +---- +public abstract class AbstractRequestControlDirContextProcessor implements + DirContextProcessor { + + public void preProcess(DirContext ctx) throws NamingException { + ... + } + + public abstract Control createRequestControl(); +} +---- + +A typical `DirContextProcessor` will be similar to the following: + +.A request control DirContextProcessor implementation +[source,java] +[subs="verbatim,quotes"] +---- +package com.example.control; + +public class MyCoolRequestControl extends AbstractRequestControlDirContextProcessor { + private static final boolean CRITICAL_CONTROL = true; + private MyCoolCookie cookie; + ... + public MyCoolCookie getCookie() { + return cookie; + } + + public Control createRequestControl() { + return new SomeCoolControl(cookie.getCookie(), CRITICAL_CONTROL); + } + + public void postProcess(DirContext ctx) throws NamingException { + LdapContext ldapContext = (LdapContext) ctx; + Control[] responseControls = ldapContext.getResponseControls(); + + for (int i = 0; i < responseControls.length; i++) { + if (responseControls[i] instanceof SomeCoolResponseControl) { + SomeCoolResponseControl control = (SomeCoolResponseControl) responseControls[i]; + this.cookie = new MyCoolCookie(control.getCookie()); + } + } + } +} +---- + + +[NOTE] +==== +Make sure you use `LdapContextSource` when you use Controls. The http://download.oracle.com/javase/1.5.0/docs/api/javax/naming/ldap/Control.html[`Control`] interface is specific for LDAPv3 and requires that `LdapContext` is used instead of `DirContext`. If an `AbstractRequestControlDirContextProcessor` subclass is called with an argument that is not an `LdapContext`, it will throw an `IllegalArgumentException`. +==== + +=== Paged Search Results +Some searches may return large numbers of results. When there is no easy way to filter out a smaller amount, it would be convenient to have the server return only a certain number of results each time it is called. This is known as __paged search results__. Each "page" of the result could then be displayed at the time, with links to the next and previous page. Without this functionality, the client must either manually limit the search result into pages, or retrieve the whole result and then chop it into pages of suitable size. The former would be rather complicated, and the latter would be consuming unnecessary amounts of memory. + +Some LDAP servers have support for the `PagedResultsControl`, which requests that the results of a search operation are returned by the LDAP server in pages of a specified size. The user controls the rate at which the pages are returned, simply by the rate at which the searches are called. However, the user must keep track of a __cookie__ between the calls. The server uses this cookie to keep track of where it left off the previous time it was called with a paged results request. + +Spring LDAP provides support for paged results by leveraging the concept for pre- and postprocessing of an `LdapContext` that was discussed in the previous sections. It does so using the class `PagedResultsDirContextProcessor`. The `PagedResultsDirContextProcessor` class creates a `PagedResultsControl` with the requested page size and adds it to the `LdapContext`. After the search, it gets the `PagedResultsResponseControl` and retrieves the paged results cookie, which is needed to keep the context between consecutive paged results requests. + +Below is an example of how the paged search results functionality may be used: +`PagedResultsDirContextProcessor` + +.Paged results using PagedResultsDirContextProcessor +[source,java] +[subs="verbatim,quotes"] +---- + +public List getAllPersonNames() { + final SearchControls searchControls = new SearchControls(); + searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); + final PagedResultsDirContextProcessor processor = new PagedResultsDirContextProcessor(PAGE_SIZE); + + return SingleContextSource.doWithSingleContext(contextSource, new LdapOperationsCallback>() { + @Override + public List doWithLdapOperations(LdapOperations operations) { + List result = new LinkedList(); + + do { + List oneResult = operations.search( + "ou=People", + "(&(objectclass=person))", + searchControls, + CN_ATTRIBUTES_MAPPER, + processor); + result.addAll(oneResult); + } while(processor.hasMore()); + + return result; + } + }); +} +---- + + +[NOTE] +==== +In order for a paged results cookie to continue being valid, it is imperative that the same underlying connection is used for each paged results call. This can be accomplished using the `SingleContextSource`, as demonstrated in the example. +==== + +== Transaction Support +=== Introduction +Programmers used to working with relational databases coming to the LDAP world often express surprise to the fact that there is no notion of transactions. It is not specified in the protocol, and thus no servers support it. Recognizing that this may be a major problem, Spring LDAP provides support for client-side, compensating transactions on LDAP resources. + +LDAP transaction support is provided by `ContextSourceTransactionManager`, a `PlatformTransactionManager` implementation that manages Spring transaction support for LDAP operations. Along with its collaborators it keeps track of the LDAP operations performed in a transaction, making record of the state before each operation and taking steps to restore the initial state should the transaction need to be rolled back. + +In addition to the actual transaction management, Spring LDAP transaction support also makes sure that the same `DirContext` instance will be used throughout the same transaction, i.e. the `DirContext` will not actually be closed until the transaction is finished, allowing for more efficient resources usage. + +[NOTE] +==== +It is important to note that while the approach used by Spring LDAP to provide transaction support is sufficient for many cases it is by no means "real" transactions in the traditional sense. The server is completely unaware of the transactions, so e.g. if the connection is broken there will be no hope to rollback the transaction. While this should be carefully considered it should also be noted that the alternative will be to operate without any transaction support whatsoever; this is pretty much as good as it gets. +==== + +[NOTE] +==== +The client side transaction support will add some overhead in addition to the work required by the original operations. While this overhead should not be something to worry about in most cases, if your application will not perform several LDAP operations within the same transaction (e.g. a `modifyAttributes` followed by a `rebind`), or if transaction synchronization with a JDBC data source is not required (see below) there will be nothing to gain by using the LDAP transaction support. +==== + +=== Configuration +Configuring Spring LDAP transactions should look very familiar if you're used to configuring Spring transactions. You will annotate your transacted classes with `@Transactional`, create a `TransactionManager` instance and include a `` tag in your bean configuraion. + + +[source,xml] +[subs="verbatim,quotes"] +---- + + + + + + + + + + + + + + +... +---- + +[NOTE] +==== +While this setup will work fine for most simple use cases, some more complex scenarios will require additional configuration; more specifically if you will be creating or deleting subtrees within transactions, you will need to use an alternative `TempEntryRenamingStrategy`, as described in <> below +==== + +In a real world example you would probably apply the transactions on the service object level rather than the DAO level; the above serves as an example to demonstrate the general idea. + +=== JDBC Transaction Integration +A common use case when working against LDAP is that some of the data is stored in the LDAP tree, but other data is stored in a relational database. In this case, transaction support becomes even more important, since the update of the different resources should be synchronized. + +While actual XA transactions is not supported, support is provided to conceptually wrap JDBC and LDAP access within the same transaction by supplying a `data-source-ref` attribute to the `` tag. This will create a `ContextSourceAndDataSourceTransactionManager`, which will then manage the two transactions, virtually as if they were one. When performing a commit, the LDAP part of the operation will always be performed first, allowing both transactions to be rolled back should the LDAP commit fail. The JDBC part of the transaction is managed exactly as in `DataSourceTransactionManager`, except that nested transactions is not supported: + + +[source,java] +[subs="verbatim,quotes"] +---- + + + +---- + +[NOTE] +==== + Once again it should be noted that the provided support is all client side. The wrapped transaction is not an XA transaction. No two-phase as such commit is performed, as the LDAP server will be unable to vote on its outcome. Once again, however, for the majority of cases the supplied support will be sufficient. +==== + +The same thing can be accomplished for Hibernate integration by supplying a `session-factory-ref` attribute to the `` tag. + +[source,java] +[subs="verbatim,quotes"] +---- + + + +---- + +=== LDAP Compensating Transactions Explained +Spring LDAP manages compensating transactions by making record of the state in the LDAP tree before each modifying operation (`bind`, `unbind`, `rebind`, `modifyAttributes`, and `rename`). +This enables the system to perform compensating operations should the transaction need to be rolled back. In many cases the compensating operation is pretty straightforward. E.g. the compensating rollback operation for a `bind` operation will quite obviously be to unbind the entry. Other operations however require a different, more complicated approach because of some particular characteristics of LDAP databases. Specifically, it is not always possible to get the values of all `Attributes` of an entry, making the above strategy insufficient for e.g. an `unbind` operation. +This is why each modifying operation performed within a Spring LDAP managed transaction is internally split up in four distinct operations - a recording operation, a preparation operation, a commit operation, and a rollback operation. The specifics for each LDAP operation is described in the table below: + + +|=== +| LDAP Operation | Recording | Preparation | Commit | Rollback + +| `bind` +| Make record of the DN of the entry to bind. +| Bind the entry. +| No operation. +| Unbind the entry using the recorded DN. + +| `rename` +| Make record of the original and target DN. +| Rename the entry. +| No operation. +| Rename the entry back to its original DN. + +| `unbind` +| Make record of the original DN and calculate a temporary DN. +| Rename the entry to the temporary location. +| Unbind the temporary entry. +| Rename the entry from the temporary location back to its original DN. + +| `rebind` +| Make record of the original DN and the new `Attributes`, and calculate a temporary DN. +| Rename the entry to a temporary location. +| Bind the new `Attributes` at the original DN, and unbind the original entry from its temporary location. +| Rename the entry from the temporary location back to its original DN. + +| `modifyAttributes` +| Make record of the DN of the entry to modify and calculate compensating `ModificationItem`s for the modifications to be done. +| Perform the `modifyAttributes` operation. +| No operation. +| Perform a `modifyAttributes` operation using the calculated compensating `ModificationItem`s. +|=== + +A more detailed description of the internal workings of the Spring LDAP transaction support is available in the javadocs. + + +==== Renaming Strategies +As described in the table above, the transaction management of some operations require the original entry affected by the operation to be temporarily renamed before the actual modification can be made in the commit. The manner in which the temporary DN of the entry is calculated is managed by a `TempEntryRenamingStrategy` specified in a sub-element to the `` declaration in the configuration. Two implementations are supplied with Spring LDAP: + + +* `DefaultTempEntryRenamingStrategy` (the default). Specified using a `` element. Adds a suffix to the least significant part of the entry DN. E.g. for the DN `cn=john doe, ou=users`, this strategy would return the temporary DN `cn=john doe_temp, ou=users`. The suffix is configurable using the `temp-suffix` attribute. + +* `DifferentSubtreeTempEntryRenamingStrategy`. Specified using a `` element. Takes the least significant part of the DN and appends a subtree DN to this. This makes all temporary entries be placed at a specific location in the LDAP tree. The temporary subtree DN is configured using the `subtree-node` attribute. E.g., if `subtree-node` is `ou=tempEntries` and the original DN of the entry is `cn=john doe, ou=users`, the temporary DN will be `cn=john doe, ou=tempEntries`. Note that the configured subtree node needs to be present in the LDAP tree. + + + +[NOTE] +==== +There are some situations where the `DefaultTempEntryRenamingStrategy` will not work. E.g. if your are planning to do recursive deletes you'll need to use `DifferentSubtreeTempEntryRenamingStrategy`. This is because the recursive delete operation actually consists of a depth-first delete of each node in the sub tree individually. Since it is not allowed to rename an entry that has any children, and `DefaultTempEntryRenamingStrategy` would leave each node in the same subtree (with a different name) in stead of actually removing it, this operation would fail. When in doubt, use `DifferentSubtreeTempEntryRenamingStrategy`. +==== + +[[user-authentication]] +== User Authentication using Spring LDAP + + +=== Basic Authentication + +While the core functionality of the `ContextSource` is to provide `DirContext` instances for use by `LdapTemplate`, it may also be used for authenticating users against an LDAP server. The `getContext(principal, credentials)` method of `ContextSource` will do exactly that; construct a `DirContext` instance according to the `ContextSource` configuration, authenticating the context using the supplied principal and credentials. A custom authenticate method could look like this: + + +[source,java] +[subs="verbatim,quotes"] +---- +public boolean authenticate(String userDn, String credentials) { + DirContext ctx = null; + try { + ctx = contextSource.getContext(userDn, credentials); + return true; + } catch (Exception e) { + // Context creation failed - authentication did not succeed + logger.error("Login failed", e); + return false; + } finally { + // It is imperative that the created DirContext instance is always closed + LdapUtils.closeContext(ctx); + } +} +---- + +The userDn supplied to the `authenticate` method needs to be the full DN of the user to authenticate (regardless of the `base` setting on the `ContextSource`). You will typically need to perform an LDAP search based on e.g. the user name to get this DN: + + +[source,java] +[subs="verbatim,quotes"] +---- +private String getDnForUser(String uid) { + List result = ldapTemplate.search(query().where("uid").is(uid), + new AbstractContextMapper() { + protected Object doMapFromContext(DirContextOperations ctx) { + return ctx.getNameInNamespace(); + } + }); + + if(result.size() != 1) { + throw new RuntimeException("User not found or not unique"); + } + + return (String)result.get(0); +} +---- + +There are some drawbacks to this approach. The user is forced to concern herself with the DN of the user, she can only search for the user's uid, and the search always starts at the root of the tree (the empty path). A more flexible method would let the user specify the search base, the search filter, and the credentials. Spring LDAP includes an authenticate method in LdapTemplate that provide this functionality: `boolean authenticate(LdapQuery query, String password);` + +Using this method authentication becomes as simple as this: + +.Authenticating a user using Spring LDAP. +[source,java] +[subs="verbatim,quotes"] +---- +ldapTemplate.authenticate(query().where("uid").is("john.doe"), "secret"); +---- + +[NOTE] +==== +As described in below, some setups may require additional operations to be performed in order for actual authentication to occur. See <> for details. +==== + +[TIP] +==== +Don't write your own custom authenticate methods. Use the ones provided in Spring LDAP 1.3.x. +==== + + +[[operationsOnAuthenticatedContext]] +=== Performing Operations on the Authenticated Context +Some authentication schemes and LDAP servers require some operation to be performed on the created `DirContext` instance for the actual authentication to occur. You should test and make sure how your server setup and authentication schemes behave; failure to do so might result in that users will be admitted into your system regardless of the DN/credentials supplied. This is a naïve implementation of an authenticate method where a hard-coded `lookup` operation is performed on the authenticated context: + + +[source,java] +[subs="verbatim,quotes"] +---- +public boolean authenticate(String userDn, String credentials) { + DirContext ctx = null; + try { + ctx = contextSource.getContext(userDn, credentials); + // Take care here - if a base was specified on the ContextSource + // that needs to be removed from the user DN for the lookup to succeed. + **ctx.lookup(userDn);** + return true; + } catch (Exception e) { + // Context creation failed - authentication did not succeed + logger.error("Login failed", e); + return false; + } finally { + // It is imperative that the created DirContext instance is always closed + LdapUtils.closeContext(ctx); + } +} +---- + +It would be better if the operation could be provided as an implementation of a callback interface, thus not limiting the operation to always be a `lookup`. Spring LDAP includes the callback interface `AuthenticatedLdapEntryContextMapper` and a corresponding `authenticate` method: ` T authenticate(LdapQuery query, String password, AuthenticatedLdapEntryContextMapper mapper);` + +This opens up for any operation to be performed on the authenticated context: + +.Performing an LDAP operation on the authenticated context using Spring LDAP. +[source,java] +[subs="verbatim,quotes"] +---- +AuthenticatedLdapEntryContextMapper mapper = new AuthenticatedLdapEntryContextMapper() { + public DirContextOperations mapWithContext(DirContext ctx, LdapEntryIdentification ldapEntryIdentification) { + try { + return (DirContextOperations) ctx.lookup(ldapEntryIdentification.getRelativeName()); + } + catch (NamingException e) { + throw new RuntimeException("Failed to lookup " + ldapEntryIdentification.getRelativeName(), e); + } + } +}; + +ldapTemplate.authenticate(query().where("uid").is("john.doe"), "secret", mapper); +---- + +=== Obsolete authentication methods +In addition to the `authenticate` methods described above there are a number of deprecated methods that can be used for authentication. While these will work fine, the recommendation is to use the `LdapQuery` methods instead. + + +=== Use Spring Security +While the approach above may be sufficient for simple authentication scenarios, requirements in this area commonly expand rapidly. There is a multitude of aspects that apply, including authentication, authorization, web integration, user context management, etc. If you suspect that the requirements might expand beyond just simple authentication, you should definitely consider using http://spring.io/spring-security[Spring Security] for your security purposes instead. It is a full-blown, mature security framework addressing the above aspects as well as several others. + + +== LDIF Parsing + + +=== Introduction +LDAP Directory Interchange Format (LDIF) files are the standard medium for describing directory data in a flat file format. The most common uses of this format include information transfer and archival. However, the standard also defines a way to describe modifications to stored data in a flat file format. LDIFs of this later type are typically referred to as __changetype__ or __modify__ LDIFs. + +The `org.springframework.ldap.ldif` package provides classes needed to parse LDIF files and deserialize them into tangible objects. The `LdifParser` is the main class of the `org.springframework.ldap.ldif` package and is capable of parsing files that are RFC 2849 compliant. This class reads lines from a resource and assembles them into an `LdapAttributes` object. The `LdifParser` currently ignores __changetype__ LDIF entries as their usefulness in the context of an application has yet to be determined. + + +=== Object Representation +Two classes in the `org.springframework.ldap.core` package provide the means to represent an LDIF in code: + + +* `LdapAttribute` - Extends `javax.naming.directory.BasicAttribute` adding support for LDIF options as defined in RFC2849. + +* `LdapAttributes` - Extends `javax.naming.directory.BasicAttributes` adding specialized support for DNs. + + +`LdapAttribute` objects represent options as a `Set`. The DN support added to the `LdapAttributes` object employs the `javax.naming.ldap.LdapName` class. + + +=== The Parser +The `Parser` interface provides the foundation for operation and employs three supporting policy definitions: + + +* `SeparatorPolicy` - establishes the mechanism by which lines are assembled into attributes. + +* `AttributeValidationPolicy` - ensures that attributes are correctly structured prior to parsing. + +* `Specification` - provides a mechanism by which object structure can be validated after assembly. + + +The default implementations of these interfaces are the `org.springframework.ldap.ldif.parser.LdifParser`, the `org.springframework.ldap.ldif.support.SeparatorPolicy`, and the `org.springframework.ldap.ldif.support.DefaultAttributeValidationPolicy`, and the `org.springframework.ldap.schema.DefaultSchemaSpecification` respectively. Together, these 4 classes parse a resource line by line and translate the data into `LdapAttributes` objects. + +The `SeparatorPolicy` determines how individual lines read from the source file should be interpreted as the LDIF specification allows attributes to span multiple lines. The default policy assess lines in the context of the order in which they were read to determine the nature of the line in consideration. __control__ attributes and __changetype__ records are ignored. + +The `DefaultAttributeValidationPolicy` uses REGEX expressions to ensure each attribute conforms to a valid attribute format according to RFC 2849 once parsed. If an attribute fails validation, an `InvalidAttributeFormatException` is logged and the record is skipped (the parser returns null). + +=== Schema Validation +A mechanism for validating parsed objects against a schema and is available via the `Specification` interface in the `org.springframework.ldap.schema` package. The `DefaultSchemaSpecification` does not do any validation and is available for instances where records are known to be valid and not required to be checked. This option saves the performance penalty that validation imposes. The `BasicSchemaSpecification` applies basic checks such as ensuring DN and object class declarations have been provided. Currently, validation against an actual schema requires implementation of the `Specification` interface. + + +=== Spring Batch Integration +While the `LdifParser` can be employed by any application that requires parsing of LDIF files, Spring offers a batch processing framework that offers many file processing utilities for parsing delimited files such as CSV. The `org.springframework.ldap.ldif.batch` package offers the classes necessary for using the `LdifParser` as a valid configuration option in the Spring Batch framework. +There are 5 classes in this package which offer three basic use cases: + + +* Use Case 1: Read LDIF records from a file and return an `LdapAttributes` object. + +* Use Case 2: Read LDIF records from a file and map records to Java objects (POJOs). + +* Use Case 3: Write LDIF records to a file. + + +The first use case is accomplished with the LdifReader. This class extends Spring Batch's `AbstractItemCountingItemSteamItemReader` and implements its `ResourceAwareItemReaderItemStream`. It fits naturally into the framework and can be used to read `LdapAttributes` objects from a file. + +The `MappingLdifReader` can be used to map LDIF objects directly to any POJO. This class requires an implementation of the `RecordMapper` interface be provided. This implementation should implement the logic for mapping objects to POJOs. + +The `RecordCallbackHandler` can be implemented and provided to either reader. This handler can be used to operate on skipped records. Consult the Spring Batch documentation for more information. + +The last member of this package, the `LdifAggregator`, can be used to write LDIF records to a file. This class simply invokes the `toString()` method of the `LdapAttributes` object. + + +== Utilities + + +=== Incremental Retrieval of Multi-Valued Attributes +When there are a very large number of attribute values (>1500) for a specific attribute, Active Directory will typically refuse to return all these values at once. Instead the attribute values will be returned according to the http://www.watersprings.org/pub/id/draft-kashi-incremental-00.txt[Incremental Retrieval of Multi-valued Properties] method. This requires the calling part to inspect the returned attribute for specific markers and, if necessary, make additional lookup requests until all values are found. + +Spring LDAP's `org.springframework.ldap.core.support.DefaultIncrementalAttributesMapper` helps working with this kind of attributes, as follows: + +[source,java] +[subs="verbatim,quotes"] +---- +Object[] attrNames = new Object[]{"oneAttribute", "anotherAttribute"}; +Attributes attrs = DefaultIncrementalAttributeMapper.lookupAttributes(ldapTemplate, theDn, attrNames); +---- + +This will parse any returned attribute range markers and make repeated requests as necessary until all values for all requested attributes have been retrieved. + +== Java 5 Support + +=== SimpleLdapTemplateUsing + +[NOTE] +==== +As of Spring LDAP 2.0 the core API has full Java 5 support, and `SimpleLdapTemplate` and associated classes are all deprecated. +==== + +As of version 1.3 Spring LDAP includes the spring-ldap-core-tiger.jar distributable, which adds a thin layer of Java 5 functionality on top of Spring LDAP. + +The `SimpleLdapTemplate` class adds search and lookup methods that take a `ParameterizedContextMapper`, adding generics support to these methods. + +`ParametrizedContextMapper` is a typed version of `ContextMapper`, which simplifies working with searches and lookups:`ParameterizedContextMapper` + +.Using ParameterizedContextMapper +[source,java] +[subs="verbatim,quotes"] +---- +public List getAllPersons(){ + return simpleLdapTemplate.search("", "(objectclass=person)", + new **ParameterizedContextMapper**() { + public **Person** mapFromContext(Object ctx) { + DirContextAdapter adapter = (DirContextAdapter) ctx; + Person person = new Person(); + // Fill the domain object with data from the DirContextAdapter + + return person; + } + }; +} +---- \ No newline at end of file diff --git a/src/docbkx/advancedqueries.xml b/src/docbkx/advancedqueries.xml deleted file mode 100644 index 33163341..00000000 --- a/src/docbkx/advancedqueries.xml +++ /dev/null @@ -1,135 +0,0 @@ - - - Advanced LDAP Queries - - - LDAP Query Builder Parameters - - The LdapQueryBuilder and its associated classes is intended to support all parameters - that can be supplied to an LDAP search. The following parameters are supported: - - base - specifies the root DN in the LDAP tree where the search should start. - searchScope - specifies how deep into the LDAP tree the search should traverse. - attributes - specifies the attributes to return from the search. Default is all. - countLimit - specifies the maximum number of entries to return from the search. - timeLimit - specifies the maximum time that the search may take. - Search filter - the conditions that the entries we are looking for must meet. - - - - An LdapQueryBuilder is created with a call to the query method of - LdapQueryBuilder. It's intended as a fluent builder API, where the base parameters are defined first, - followed by the filter specification calls. Once filter conditions have been started to be defined with a call to the - where method of LdapQueryBuilder, later attempts to call e.g. base - will be rejected. The base search parameters are optional, but at least one filter specification call is required. - - - Search for all entries with objectclass person - import static org.springframework.ldap.query.LdapQueryBuilder.query; -... - -List<Person> persons = ldapTemplate.search( - query().where("objectclass").is("person"), - new PersonAttributesMapper()); - - - - Search for all entries with objectclass person and cn=John Doe - import static org.springframework.ldap.query.LdapQueryBuilder.query; -... - -List<Person> persons = ldapTemplate.search( - query().where("objectclass").is("person") - .and("cn").is("John Doe"), - new PersonAttributesMapper()); - - - - Search for all entries with objectclass person starting at <literal>dc=261consulting,dc=com</literal> - import static org.springframework.ldap.query.LdapQueryBuilder.query; -... - -List<Person> persons = ldapTemplate.search( - query().base("dc=261consulting,dc=com") - .where("objectclass").is("person"), - new PersonAttributesMapper()); - - - - Search for all entries with objectclass person starting at <literal>dc=261consulting,dc=com</literal>, - only returning the cn attribute - import static org.springframework.ldap.query.LdapQueryBuilder.query; -... - -List<Person> persons = ldapTemplate.search( - query().base("dc=261consulting,dc=com") - .attributes("cn") - .where("objectclass").is("person"), - new PersonAttributesMapper()); - - - - Search for all entries with objectclass person where sn=Doe or Doo (nested query) - import static org.springframework.ldap.query.LdapQueryBuilder.query; -... -List<Person> persons = ldapTemplate.search( - query().where("objectclass").is("person"), - .and(query().where("cn").is("Doe").or("cn").is("Doo)); - new PersonAttributesMapper()); - - - - - Filter Criteria - - The examples above demonstrates simple equals conditions in LDAP filters. The LDAP query builder has support - for the following criteria types: - - is - specifies an equals condition (=). - gte - specifies a greater than or equals condition (>=). - lte - specifies a less than or equals condition (<=). - - like - specifies a "like" condition where wildcards can be included in the query, - e.g. where("cn").like("J*hn Doe") will result int the filter (cn=J*hn Doe). - - - whitespaceWildcardsLike - specifies a condition where all whitespace is replaced with wildcards, - e.g. where("cn").whitespaceWildcardsLike("John Doe") will result in the filter - (cn=*John*Doe*). - - - isPresent - specifies condition that checks for the presence of an attribute, - e.g. where("cn").isPresent() will result in the filter (cn=*). - - - not - specifies that the current condition should be negated, e.g. - where("sn").not().is("Doe) will result in the filter (!(sn=Doe)) - - - - - - Hardcoded Filters - - There are occasions when you will want to specify a hardcoded filter as input to an LdapQuery. - LdapQueryBuilder has two methods for this purpose: - - - filter(String hardcodedFilter) - uses the specified string as filter. - Note that the specified input string will not be touched in any way, meaning that this method is not - particularly well suited if you are building filters from user input. - - - filter(String filterFormat, String... params) - uses the specified string as input - to MessageFormat, properly encoding the parameters and inserting them at the - specified places in the filter string. - - - - - You cannot mix the hardcoded filter methods with the where approach described above; it's - either one or the other. What this means is that if you specified a filter using filter() - you will get an exception if you try to call where afterwards. - - - \ No newline at end of file diff --git a/src/docbkx/basic.xml b/src/docbkx/basic.xml deleted file mode 100644 index c1d7b0f2..00000000 --- a/src/docbkx/basic.xml +++ /dev/null @@ -1,407 +0,0 @@ - - - Basic Operations - - - Search and Lookup Using AttributesMapper - - In this example we will use an AttributesMapper - to easily build a List of all common names of all person objects. - - - AttributesMapper that returns a single attribute - - package com.example.dao; -import static org.springframework.ldap.query.LdapQueryBuilder.query; - -public class PersonDaoImpl implements PersonDao { - private LdapTemplate ldapTemplate; - - public void setLdapTemplate(LdapTemplate ldapTemplate) { - this.ldapTemplate = ldapTemplate; - } - - public List<String> getAllPersonNames() { - return ldapTemplate.search(query() - .where("objectclass").is("person"), - new AttributesMapper<String>() { - public String mapFromAttributes(Attributes attrs) - throws NamingException { - return (String) attrs.get("cn").get(); - } - }); - } -} - - - The inline implementation of AttributesMapper - just gets the desired attribute value from the - Attributes and returns it. Internally, - LdapTemplate iterates over all entries found, calling - the given AttributesMapper for each entry, and collects - the results in a list. The list is then returned by the - search method. - - Note that the AttributesMapper implementation - could easily be modified to return a full Person - object: - - - AttributesMapper that returns a Person object - - package com.example.dao; -import static org.springframework.ldap.query.LdapQueryBuilder.query; - -public class PersonDaoImpl implements PersonDao { - private LdapTemplate ldapTemplate; - ... - private class PersonAttributesMapper implements AttributesMapper<Person> { - public Person mapFromAttributes(Attributes attrs) throws NamingException { - Person person = new Person(); - person.setFullName((String)attrs.get("cn").get()); - person.setLastName((String)attrs.get("sn").get()); - person.setDescription((String)attrs.get("description").get()); - return person; - } - } - - public List<Person> getAllPersons() { - return ldapTemplate.search(query() - .where("objectclass").is("person"), new PersonAttributesMapper()); - } -} - - - If you have the distinguished name (dn) that - identifies an entry, you can retrieve the entry directly, without - searching for it. This is called a lookup in Java - LDAP. The following example shows how a lookup results in a Person - object: - - - A lookup resulting in a Person object - - package com.example.dao; - -public class PersonDaoImpl implements PersonDao { - private LdapTemplate ldapTemplate; - ... - public Person findPerson(String dn) { - return ldapTemplate.lookup(dn, new PersonAttributesMapper()); - } -} - - - This will look up the specified dn and pass the - found attributes to the supplied AttributesMapper, in - this case resulting in a Person object. - - - - Building LDAP Queries - LDAP searches involve a number of parameters, e.g. Base LDAP path, - search scope, attributes to return, and search filters. - Spring LDAP provides an LdapQueryBuilder with a fluent - API for building LDAP Queries. - Let's say that we want to perform a search starting at the - base DN dc=261consulting,dc=com, limiting the returned attributes to "cn" - and "sn", with the following filter: - (&(objectclass=person)(sn=?)), where we want the - ? to be replaced with the value of the parameter - lastName. This is how we do it using the LdapQueryBuilder: - - - Building a search filter dynamically - - package com.example.dao; -import static org.springframework.ldap.query.LdapQueryBuilder.query; - -public class PersonDaoImpl implements PersonDao { - private LdapTemplate ldapTemplate; - ... - public List getPersonNamesByLastName(String lastName) { - - LdapQuery query = query() - .base("dc=261consulting,dc=com") - .attributes("cn", "sn") - .where("objectclass").is("person") - .and("sn").is(lastName); - - return ldapTemplate.search(query, - new AttributesMapper() { - public Object mapFromAttributes(Attributes attrs) - throws NamingException { - return attrs.get("cn").get(); - } - }); - } -} - - - - In addition to simplifying building of complex search parameters, - the LdapQueryBuilder and its associated classes - also provide proper escaping of any unsafe characters in search filters. - This prevents "ldap injection", where a user might use such - characters to inject unwanted operations into your LDAP operations. - - - There are many overloaded methods in LdapTemplate for - performing LDAP searches. This is in order to accommodate for as many different use cases - and programming style preferences as possible. For the vast majority of use cases the ones that - take an LdapQuery as input will be the recommended methods to use. - - - The AttributesMapper is just one of the available callback interfaces to use - when handling search and lookup data. See for alternatives. - - - - For more information on the LdapQueryBuilder see . - - - - - Dynamically Building Distinguished Names - - The standard Java implementation of Distinguished Name, LdapName, - performs very well when it comes to parsing of Distinguished Names. However, in practical use - this implementation has a number of shortcomings: - - - - The LdapName implementation is mutable, which is badly suited for an object - representing identity. - - - - - Despite its mutable nature, the API for dynamically building or modifying Distinguished Names using - LdapName is cumbersome. Extracting values of indexed or (particularly) - named components is also a little bit awkward. - - - - - Many of the operations on LdapName throw checked Exceptions, requiring unnecessary - try-catch statements for situations where the error is typically fatal and cannot be repaired in - a meaningful manner. - - - - - To simplify working with Distinguished Names, Spring LDAP provides an LdapNameBuilder, as - well as a number of utility methods in LdapUtils that helps working with - LdapName. - - - Below are a couple of examples of how these utilities can simplify handling of distinguished names. - - Dynamically building an LdapName using LdapNameBuilder - package com.example.dao; -import org.springframework.ldap.support.LdapNameBuilder; -import javax.naming.Name; - -public class PersonDaoImpl implements PersonDao { -public static final String BASE_DN = "dc=example,dc=com"; -... -protected Name buildDn(Person p) { - return LdapNameBuilder.newLdapName(BASE_DN) - .add("c", p.getCountry()) - .add("ou", p.getCompany()) - .add("cn", p.getFullname()) - .build(); - -} - - - Assuming that a Person has the following attributes: - - - - - - country - Sweden - - - company - Some Company - - - fullname - Some Person - - - - - - The code above would then result in the following distinguished - name: - - cn=Some Person, ou=Some Company, c=Sweden, dc=example, dc=com - - - Extracting values from a distinguished name using LdapUtils - package com.example.dao; -import org.springframework.ldap.support.LdapNameBuilder; -import javax.naming.Name; -public class PersonDaoImpl implements PersonDao { -... -protected Person buildPerson(Name dn, Attributes attrs) { - Person person = new Person(); - person.setCountry(LdapUtils.getStringValue(dn, "c")); - person.setCompany(LdapUtils.getStringValue(dn, "ou")); - person.setFullname(LdapUtils.getStringValue(dn, "cn")); - // Populate rest of person object using attributes. - - return person; -} - - - Since Java version <=1.4 didn't provide any public Distinguished Name implementation at all, Spring LDAP - 1.3.2 and lower provided its own implementation, DistinguishedName. This implementation - suffered from a couple of shortcomings of its own, and has been deprecated in version 2.0. - Users are now recommended to use LdapName along with the utilities described above instead. - - - - - Binding and Unbinding - - - Binding Data - - Inserting data in Java LDAP is called binding. In order to do - that, a distinguished name that uniquely identifies the new entry is - required. The following example shows how data is bound using - LdapTemplate: - - - Binding data using Attributes - - package com.example.dao; - -public class PersonDaoImpl implements PersonDao { - private LdapTemplate ldapTemplate; - ... - public void create(Person p) { - Name dn = buildDn(p); - ldapTemplate.bind(dn, null, buildAttributes(p)); - } - - private Attributes buildAttributes(Person p) { - Attributes attrs = new BasicAttributes(); - BasicAttribute ocattr = new BasicAttribute("objectclass"); - ocattr.add("top"); - ocattr.add("person"); - attrs.put(ocattr); - attrs.put("cn", "Some Person"); - attrs.put("sn", "Person"); - return attrs; - } -} - - - The Attributes building is--while dull and verbose--sufficient for - many purposes. It is, however, possible to simplify the binding - operation further, which will be described in . - - - - Unbinding Data - - Removing data in Java LDAP is called unbinding. A distinguished - name (dn) is required to identify the entry, just as in the binding - operation. The following example shows how data is unbound using - LdapTemplate: - - - Unbinding data - - package com.example.dao; - -public class PersonDaoImpl implements PersonDao { - private LdapTemplate ldapTemplate; - ... - public void delete(Person p) { - Name dn = buildDn(p); - ldapTemplate.unbind(dn); - } -} - - - - - - Modifying - - In Java LDAP, data can be modified in two ways: either using - rebind or - modifyAttributes. - - - Modifying using <literal>rebind</literal> - - A rebind is a very crude way to modify data. - It's basically an unbind followed by a - bind. It looks like this: - - - Modifying using rebind - - package com.example.dao; - -public class PersonDaoImpl implements PersonDao { - private LdapTemplate ldapTemplate; - ... - public void update(Person p) { - Name dn = buildDn(p); - ldapTemplate.rebind(dn, null, buildAttributes(p)); - } -} - - - - - Modifying using <literal>modifyAttributes</literal> - - If only the modified attributes should be replaced, there is a - method called modifyAttributes that takes an array of - modifications: - - - Modifying using modifyAttributes - - package com.example.dao; - -public class PersonDaoImpl implements PersonDao { - private LdapTemplate ldapTemplate; - ... - public void updateDescription(Person p) { - Name dn = buildDn(p); - Attribute attr = new BasicAttribute("description", p.getDescription()) - ModificationItem item = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, attr); - ldapTemplate.modifyAttributes(dn, new ModificationItem[] {item}); - } -} - - - Building Attributes and - ModificationItem arrays is a lot of work, but as you - will see in , the update operations - can be simplified. - - - - - Sample applications - - It is recommended that you review the Spring LDAP sample - applications included in the release distribution for best-practice - illustrations of the features of this library. - - diff --git a/src/docbkx/configuration.xml b/src/docbkx/configuration.xml deleted file mode 100644 index bf84741b..00000000 --- a/src/docbkx/configuration.xml +++ /dev/null @@ -1,587 +0,0 @@ - - - Configuration - - Introduction - The recommended way of configuring Spring LDAP is using the custom XML configuration namespace. - In order to make this available you need to include the Spring LDAP namespace declaration in your - bean file, e.g.: - - -<beans xmlns="http://www.springframework.org/schema/beans" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns:ldap="http://www.springframework.org/schema/ldap" - xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd - http://www.springframework.org/schema/ldap http://www.springframework.org/schema/ldap/spring-ldap.xsd"> - - - - - - ContextSource Configuration - - - The ContextSource is defined using a <ldap:context-source> - tag. The simplest possible context-source declaration requires you to specify a - server url, a username, and a password: - - Simplest possible context-source declaration - ]]> - - This will create an LdapContextSource with default values (see below), - and the url and authentication information as specified. - - - The configurable attributes on context-source are as follows (required attributes marked with *): - - - ContextSource Configuration Attributes - - - - - - - Attribute - Default - Description - - - - - - id - - - contextSource - - - The id of the created bean. - - - - - username - - - - - The username (principal) to use when authenticating with the LDAP server. - This will usually be the distinguished name of an admin user (e.g. - cn=Administrator, but may differ depending on server - and authentication method. - Required if authentication-source-ref is not explicitly configured. - - - - - password - - - - - The password (credentials) to use when authenticating with the LDAP server. - Required if authentication-source-ref is not explicitly configured. - - - - - url * - - - - - The URL of the LDAP server to use. The URL should be in the format - ldap://myserver.example.com:389. - For SSL access, use the ldaps protocol and the appropriate port, e.g. - ldaps://myserver.example.com:636. If fail-over functionality is desired, - more than one URL can be specified, separated using comma (,). - - - - - base - - - LdapUtils.emptyLdapName() - - - The base DN. When this attribute has been configured, all Distinguished Names supplied to - and received from LDAP operations will be relative to the sepecified LDAP path. - This can significantly simplify working against the LDAP tree; however there are several - occasions when you will need to have access to the base path. - For more information on this, please refer to - - - - - anonymous-read-only - - - false - - - Defines whether read-only operations will be performed using an anonymous (unauthenticated) context. - Note that setting this parameter to true - together with the compensating transaction support is not supported and will be rejected. - - - - - referral - - - null - - - Defines the strategy to handle referrals, as described - here. - Valid values are: - - ignore - follow - throw - - - - - - native-pooling - - - false - - - Specify whether native Java LDAP connection pooling should be used. Consider using - Spring LDAP connection pooling instead. See for more information. - - - - - authentication-source-ref - - - A SimpleAuthenticationSource instance. - - - Id of the AuthenticationSource instance to use (see below). - - - - - authentication-strategy-ref - - - A SimpleDirContextAuthenticationStrategy instance. - - - Id of the DirContextAuthenticationStrategy instance to use (see below). - - - - - base-env-props-ref - - - A SimpleDirContextAuthenticationStrategy instance. - - - Reference to a Map of custom environment properties that should supplied with the environment - sent to the DirContext on construction. - - - - -
- - - DirContext Authentication - - - When DirContext instances are created to be used for performing - operations on an LDAP server these contexts often need to be authenticated. There are - different options for configuring this using Spring LDAP, described in this chapter. - - - - This section refers to authenticating contexts in the core functionality - of the ContextSource - to construct DirContext instances - for use by LdapTemplate. LDAP is commonly used for the sole purpose - of user authentication, and the ContextSource may be used for that as - well. This process is discussed in . - - - - - - Authenticated contexts are created for both read-only and - read-write operations by default. You specify - username and password of the LDAP - user to be used for authentication on the - context-source element. - - - - If username is the dn of an LDAP user, it needs to be the full - Distinguished Name (DN) of the user from the root of the LDAP tree, - regardless of whether a base LDAP path has been specified on - the context-source element. - - - - - Some LDAP server setups allow anonymous read-only access. If you - want to use anonymous Contexts for read-only operations, set the - anonymous-read-only attribute to - true. - - - - Custom DirContext Authentication Processing - - - The default authentication mechanism used in Spring LDAP is SIMPLE authentication. - This means that the principal (as specified to the username attribute) and - the credentials (as specified to the password) are set in - the Hashtable sent to the DirContext implementation constructor. - - - There are many occasions when this processing is not sufficient. For instance, - LDAP Servers are commonly set up to only accept communication on a secure TLS channel; - there might be a need to use the particular LDAP Proxy Auth mechanism, etc. - - - It is possible to specify an alternative authentication mechanism by supplying a - DirContextAuthenticationStrategy implementation reference - to the context-source element using the authentication-strategy-ref - attribute. - - - TLS - - - Spring LDAP provides two different configuration options for LDAP servers requiring TLS secure - channel communication: DefaultTlsDirContextAuthenticationStrategy and - ExternalTlsDirContextAuthenticationStrategy. Both these - implementations will negotiate a TLS channel on the target connection, but they differ in the actual authentication mechanism. - Whereas the DefaultTlsDirContextAuthenticationStrategy will apply SIMPLE authentication - on the secure channel (using the specified userDn and password), - the ExternalDirContextAuthenticationStrategy will use EXTERNAL SASL authentication, - applying a client certificate configured using system properties for authentication. - - - - Since different LDAP server implementations respond differently to explicit shutdown of the - TLS channel (some servers require the connection be shutdown gracefully; others do not support it), - the TLS DirContextAuthenticationStrategy implementations support specifying - the shutdown behavior using the shutdownTlsGracefully parameter. If this - property is set to false (the default), no explicit TLS shutdown will happen; - if it is true, Spring LDAP will try to shutdown the TLS channel gracefully - before closing the target context. - - - - - When working with TLS connections you need to make sure that the native LDAP - Pooling functionality (as specified using the native-pooling attribute - is turned off. This is particularly important if shutdownTlsGracefully - is set to false. However, since the TLS channel negotiation process is - quite expensive, great performance benefits will be gained by using the Spring LDAP - Pooling Support, described in . - - - - - - Custom Principal and Credentials Management - - - While the user name (i.e. user DN) and password used for - creating an authenticated Context are statically defined by - default - the ones defined in the context-source element - configuration will be used throughout the lifetime of the - ContextSource - there are several cases where this is not the desired behaviour. - A common scenario is that the principal and credentials of the current user should be used when - executing LDAP operations for that user. The default behaviour can be - modified by supplying a reference to an AuthenticationSource - implementation to the context-source element using the - authentication-source-ref element, - instead of explicitly specifying the username and - password. The - AuthenticationSource will be queried by the - ContextSource for principal and credentials each - time an authenticated Context is to be - created. - - - - If you are using Spring Security - you can make sure the principal and credentials of the currently logged in user - is used at all times by configuring your ContextSource - with an instance of the SpringSecurityAuthenticationSource - shipped with Spring Security. - - - - Using the <literal>SpringSecurityAuthenticationSource</literal> - - -... - -... -
]]> - - - - - We don't specify any username or - password to our context-source - when using an AuthenticationSource - these - properties are needed only when the default behaviour is - used. - - - - - - When using the SpringSecurityAuthenticationSource - you need to use Spring Security's LdapAuthenticationProvider to authenticate the - users against LDAP. - - - - - - - Native Java LDAP Pooling - The internal Java LDAP provider provides some very basic pooling capabilities. - This LDAP connection pooling can be turned on/off using the - pooled flag on AbstractContextSource. - The default value is false (since release 1.3), i.e. the native - Java LDAP pooling will be turned off. The configuration of LDAP connection pooling is managed using - System properties, so this needs to be handled - manually, outside of the Spring Context configuration. Details of the native pooling configuration - can be found here. - - - There are several serious deficiencies in the built-in LDAP connection pooling, - which is why Spring LDAP provides a more sophisticated approach to LDAP connection pooling, - described in . If pooling functionality is required, this is the - recommended approach. - - Regardless of the pooling configuration, the ContextSource#getContext(String principal, String credentials) - method will always explicitly not use native Java LDAP Pooling, in order for - reset passwords to take effect as soon as possible. - - - - Advanced ContextSource Configuration - - Custom DirContext Environment Properties - - In some cases the user might want to specify additional environment setup properties - in addition to the ones directly configurable on context-source. - Such properties should be set in a Map and referenced in - the base-env-props-ref attribute. - - - - - LdapTemplate Configuration - - The LdapTemplate is defined using a <ldap:ldap-template> - tag. The simplest possible ldap-template declaration is the simple tag: - - Simplest possible ldap-template declaration - ]]> - - This will create an LdapTemplate instance with the default id, referencing the - default ContextSource, which is expected to have the id contextSource - (the default for the context-source element). - - - The configurable attributes on ldap-template are as follows: - - - LdapTemplate Configuration Attributes - - - - - - - Attribute - Default - Description - - - - - - id - - - ldapTemplate - - - The id of the created bean. - - - - - context-source-ref - - - contextSource - - - Id of the ContextSource instance to use. - - - - - count-limit - - - 0 - - - The default count limit for searches. 0 means no limit. - - - - - time-limit - - - 0 - - - The default time limit for searches in milliseconds. 0 means no limit. - - - - - search-scope - - - SUBTREE - - - The default search scope for searches. - Valid values are: - - OBJECT - ONELEVEL - SUBTREE - - - - - - ignore-name-not-found - - - false - - - Specifies whether NameNotFoundException should be ignored in searches. Setting this - attribute to true will cause errors caused by invalid search base to be silently swallowed. - - - - - ignore-partial-result - - - false - - - Specifies whether PartialResultException should be ignored in searches. Some LDAP servers - have problems with referrals; these should normally be followed automatically, but if this - doesn't work it will manifest itself with a PartialResultException. Setting this attribute - to true presents a work-around to this problem. - - - - - odm-ref - - - - - Id of the ObjectDirectoryMapper instance to use. Default is a default-configured DefaultObjectDirectoryMapper. - - - - -
- -
- - - Obtaining a reference to the base LDAP path - - As described above, a base LDAP path may be supplied to the ContextSource, - specifying the root in the LDAP tree to which all operations will be relative. This means that - you will only be working with relative distinguished names throughout your system, which is - typically rather handy. There are however some cases in which you will need to have access - to the base path in order to be able to construct full DNs, relative to the actual root of the LDAP tree. - One example would be when working with LDAP groups (e.g. groupOfNames objectclass), - in which case each group member attribute value will need to be the full DN of the referenced member. - For that reason, Spring LDAP has a mechanism by which any Spring controlled bean may be supplied - the base path on startup. For beans to be notified of the base path, two things need to be in place: - First of all, the bean that wants the base path reference needs to implement the - BaseLdapNameAware interface. Secondly, a BaseLdapPathBeanPostProcessor - needs to be defined in the application context - - - Implementing <literal>BaseLdapNameAware</literal> - package com.example.service; -public class PersonService implements PersonService, BaseLdapNameAware { - ... - private LdapName basePath; - - public void setBaseLdapPath(LdapName basePath) { - this.basePath = basePath; - } - ... - private LdapName getFullPersonDn(Person person) { - return LdapNameBuilder.newLdapName(basePath) - .append(person.getDn()) - .build(); - } - ... -} - - - Specifying a <literal>BaseLdapPathBeanPostProcessor</literal> in your <literal>ApplicationContext</literal> - - <beans> - ... - <ldap:context-source - username="cn=Administrator" - password="secret" - url="ldap://localhost:389" - base="dc=261consulting,dc=com" /> - ... - <bean class="org.springframework.ldap.core.support.BaseLdapPathBeanPostProcessor" /> -</beans> - - - - The default behaviour of the BaseLdapPathBeanPostProcessor is to use the base path of the single - defined BaseLdapPathSource (AbstractContextSource)in the ApplicationContext. - If more than one BaseLdapPathSource is defined, you will need to specify which one to use with the - baseLdapPathSourceName property. - - - diff --git a/src/docbkx/contextprocessor.xml b/src/docbkx/contextprocessor.xml deleted file mode 100644 index 442fe506..00000000 --- a/src/docbkx/contextprocessor.xml +++ /dev/null @@ -1,206 +0,0 @@ - - - Processing the DirContext - - - Custom DirContext Pre/Postprocessing - - In some situations, one would like to perform operations on the - DirContext before and after the search operation. The - interface that is used for this is called - DirContextProcessor: - - - public interface DirContextProcessor { - public void preProcess(DirContext ctx) throws NamingException; - public void postProcess(DirContext ctx) throws NamingException; -} - - - The LdapTemplate class has a search method that - takes a DirContextProcessor: - - - public void search(SearchExecutor se, NameClassPairCallbackHandler handler, - DirContextProcessor processor) throws DataAccessException; - - - Before the search operation, the preProcess - method is called on the given DirContextProcessor - instance. After the search has been executed and the resulting - NamingEnumeration has been processed, the - postProcess method is called. This enables a user to - perform operations on the DirContext to be used in the - search, and to check the DirContext when the search has - been performed. This can be very useful for example when handling request - and response controls. - - There are also a few convenience methods for those that don't need a - custom SearchExecutor: - - - public void search(Name base, String filter, - SearchControls controls, NameClassPairCallbackHandler handler, DirContextProcessor processor) - -public void search(String base, String filter, - SearchControls controls, NameClassPairCallbackHandler handler, DirContextProcessor processor) - -public void search(Name base, String filter, - SearchControls controls, AttributesMapper mapper, DirContextProcessor processor) - -public void search(String base, String filter, - SearchControls controls, AttributesMapper mapper, DirContextProcessor processor) - -public void search(Name base, String filter, - SearchControls controls, ContextMapper mapper, DirContextProcessor processor) - -public void search(String base, String filter, - SearchControls controls, ContextMapper mapper, DirContextProcessor processor) - - - - - Implementing a Request Control DirContextProcessor - - The LDAPv3 protocol uses Controls to send and receive additional - data to affect the behavior of predefined operations. In order to simplify - the implementation of a request control - DirContextProcessor, Spring LDAP provides the base - class AbstractRequestControlDirContextProcessor. This - class handles the retrieval of the current request controls from the - LdapContext, calls a template method for creating a - request control, and adds it to the LdapContext. All - you have to do in the subclass is to implement the template method - createRequestControl, and of course the - postProcess method for performing whatever you need to - do after the search. - - - public abstract class AbstractRequestControlDirContextProcessor implements - DirContextProcessor { - - public void preProcess(DirContext ctx) throws NamingException { - ... - } - - public abstract Control createRequestControl(); -} - - A typical DirContextProcessor will be similar to the following: - - - - A request control DirContextProcessor implementation - - package com.example.control; - -public class MyCoolRequestControl extends AbstractRequestControlDirContextProcessor { - private static final boolean CRITICAL_CONTROL = true; - private MyCoolCookie cookie; - ... - public MyCoolCookie getCookie() { - return cookie; - } - - public Control createRequestControl() { - return new SomeCoolControl(cookie.getCookie(), CRITICAL_CONTROL); - } - - public void postProcess(DirContext ctx) throws NamingException { - LdapContext ldapContext = (LdapContext) ctx; - Control[] responseControls = ldapContext.getResponseControls(); - - for (int i = 0; i < responseControls.length; i++) { - if (responseControls[i] instanceof SomeCoolResponseControl) { - SomeCoolResponseControl control = (SomeCoolResponseControl) responseControls[i]; - this.cookie = new MyCoolCookie(control.getCookie()); - } - } - } -} - - - - Make sure you use LdapContextSource when you - use Controls. The Control - interface is specific for LDAPv3 and requires that - LdapContext is used instead of - DirContext. If an - AbstractRequestControlDirContextProcessor subclass is - called with an argument that is not an LdapContext, - it will throw an IllegalArgumentException. - - - - - Paged Search Results - - Some searches may return large numbers of results. When there is no - easy way to filter out a smaller amount, it would be convenient to have - the server return only a certain number of results each time it is called. - This is known as paged search results. Each "page" of - the result could then be displayed at the time, with links to the next and - previous page. Without this functionality, the client must either manually - limit the search result into pages, or retrieve the whole result and then - chop it into pages of suitable size. The former would be rather - complicated, and the latter would be consuming unnecessary amounts of - memory. - - Some LDAP servers have support for the - PagedResultsControl, which requests that the results of - a search operation are returned by the LDAP server in pages of a specified - size. The user controls the rate at which the pages are returned, simply - by the rate at which the searches are called. However, the user must keep - track of a cookie between the calls. The server uses - this cookie to keep track of where it left off the previous time it was - called with a paged results request. - - Spring LDAP provides support for paged results by leveraging the - concept for pre- and postprocessing of an LdapContext that was discussed - in the previous sections. It does so using the class - PagedResultsDirContextProcessor. The - PagedResultsDirContextProcessor class creates a - PagedResultsControl with the requested page size and - adds it to the LdapContext. After the search, it gets - the PagedResultsResponseControl and retrieves the paged results - cookie, which is needed to keep the context between consecutive paged results requests. - - Below is an example of how the paged search results functionality may - be used: - - - Paged results using <literal>PagedResultsDirContextProcessor</literal> - - -public List<String> getAllPersonNames() { - final SearchControls searchControls = new SearchControls(); - searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); - final PagedResultsDirContextProcessor processor = new PagedResultsDirContextProcessor(PAGE_SIZE); - - return SingleContextSource.doWithSingleContext(contextSource, new LdapOperationsCallback<List<String>>() { - @Override - public List<String> doWithLdapOperations(LdapOperations operations) { - List<String> result = new LinkedList<String>(); - - do { - List<String> oneResult = operations.search( - "ou=People", - "(&(objectclass=person))", - searchControls, - CN_ATTRIBUTES_MAPPER, - processor); - result.addAll(oneResult); - } while(processor.hasMore()); - - return result; - } - }); -} - - - In order for a paged results cookie to continue being valid, it is imperative that the same underlying - connection is used for each paged results call. This can be accomplished using the SingleContextSource, - as demonstrated in the example. - - diff --git a/src/docbkx/dirobjectfactory.xml b/src/docbkx/dirobjectfactory.xml deleted file mode 100644 index c9019fee..00000000 --- a/src/docbkx/dirobjectfactory.xml +++ /dev/null @@ -1,348 +0,0 @@ - - - Simpler Attribute Access and Manipulation with DirContextAdapter - - - Introduction - - A little-known--and probably underestimated--feature of the Java - LDAP API is the ability to register a DirObjectFactory - to automatically create objects from found contexts. One of the reasons - why it is seldom used is that you will need an implementation of - DirObjectFactory that creates instances of a meaningful - implementation of DirContext. The Spring LDAP library - provides the missing pieces: a default implementation of - DirContext called DirContextAdapter, - and a corresponding implementation of DirObjectFactory - called DefaultDirObjectFactory. Used together with - DefaultDirObjectFactory, the - DirContextAdapter can be a very powerful tool. - - - - Search and Lookup Using ContextMapper - - The DefaultDirObjectFactory is registered with - the ContextSource by default, which means that whenever - a context is found in the LDAP tree, its Attributes and - Distinguished Name (DN) will be used to construct a - DirContextAdapter. This enables us to use a - ContextMapper instead of an - AttributesMapper to transform found values: - - - Searching using a ContextMapper - - package com.example.dao; - -public class PersonDaoImpl implements PersonDao { - ... - private static class PersonContextMapper implements ContextMapper { - public Object mapFromContext(Object ctx) { - DirContextAdapter context = (DirContextAdapter)ctx; - Person p = new Person(); - p.setFullName(context.getStringAttribute("cn")); - p.setLastName(context.getStringAttribute("sn")); - p.setDescription(context.getStringAttribute("description")); - return p; - } - } - - public Person findByPrimaryKey( - String name, String company, String country) { - Name dn = buildDn(name, company, country); - return ldapTemplate.lookup(dn, new PersonContextMapper()); - } -} - - - The above code shows that it is possible to retrieve the attributes - directly by name, without having to go through the - Attributes and BasicAttribute - classes. This is particularly useful when working with multi-value attributes. Extracting values from - multi-value attributes normally requires looping through a NamingEnumeration of - attribute values returned from the Attributes implementation. The - DirContextAdapter can do this for you, using the getStringAttributes() - or getObjectAttributes() methods: - - Getting multi-value attribute values using <literal>getStringAttributes()</literal> - - private static class PersonContextMapper implements ContextMapper { - public Object mapFromContext(Object ctx) { - DirContextAdapter context = (DirContextAdapter)ctx; - Person p = new Person(); - p.setFullName(context.getStringAttribute("cn")); - p.setLastName(context.getStringAttribute("sn")); - p.setDescription(context.getStringAttribute("description")); - // The roleNames property of Person is an String array - p.setRoleNames(context.getStringAttributes("roleNames")); - return p; - } -} - - - - - The AbstractContextMapper - Spring LDAP provides an abstract base implementation of ContextMapper, - AbstractContextMapper. This automatically takes care of the casting of the supplied - Object parameter to DirContexOperations. - The PersonContextMapper above can thus be re-written as follows: - - - Using an AbstractContextMapper - - - private static class PersonContextMapper extends AbstractContextMapper { - public Object doMapFromContext(DirContextOperations ctx) { - Person p = new Person(); - p.setFullName(context.getStringAttribute("cn")); - p.setLastName(context.getStringAttribute("sn")); - p.setDescription(context.getStringAttribute("description")); - return p; - } - } - - - - - - - Binding and Modifying Using DirContextAdapter - - While very useful when extracting attribute values, DirContextAdapter is even more - powerful for hiding attribute details when binding and modifying data. - - - Binding - - This is an example of an improved implementation of the create DAO - method. Compare it with the previous implementation in . - - - Binding using <literal>DirContextAdapter</literal> - - package com.example.dao; - -public class PersonDaoImpl implements PersonDao { - ... - public void create(Person p) { - Name dn = buildDn(p); - DirContextAdapter context = new DirContextAdapter(dn); - - context.setAttributeValues("objectclass", new String[] {"top", "person"}); - context.setAttributeValue("cn", p.getFullname()); - context.setAttributeValue("sn", p.getLastname()); - context.setAttributeValue("description", p.getDescription()); - - ldapTemplate.bind(context); - } -} - - - Note that we use the DirContextAdapter instance - as the second parameter to bind, which should be a Context. - The third parameter is null, since we're not using any - Attributes. - Also note the use of the setAttributeValues() method when setting the - objectclass attribute values. The objectclass attribute is - multi-value, and similar to the troubles of extracting muti-value attribute data, building multi-value - attributes is tedious and verbose work. Using the setAttributeValues() mehtod you can - have DirContextAdapter handle that work for you. - - - - Modifying - - The code for a rebind would be pretty much - identical to , except - that the method called would be rebind. As we saw in - a more correct approach would be to - build a ModificationItem array containing the actual - modifications you want to do. This would require you to determine the actual - modifications compared to the data present in the LDAP tree. Again, this - is something that DirContextAdapter can help you with; the - DirContextAdapter has the ability to keep track of - its modified attributes. The following example takes advantage of this - feature: - - - Modifying using <literal>DirContextAdapter</literal> - - package com.example.dao; - -public class PersonDaoImpl implements PersonDao { - ... - public void update(Person p) { - Name dn = buildDn(p); - DirContextOperations context = ldapTemplate.lookupContext(dn); - - context.setAttributeValues("objectclass", new String[] {"top", "person"}); - context.setAttributeValue("cn", p.getFullname()); - context.setAttributeValue("sn", p.getLastname()); - context.setAttributeValue("description", p.getDescription()); - - ldapTemplate.modifyAttributes(context); - } -} - - When no mapper is passed to a ldapTemplate.lookup() operation, - the result will be a DirContextAdapter instance. - While the lookup method returns an Object, the convenience - method lookupContext method automatically casts the return value to - a DirContextOperations (the interface that DirContextAdapter implements. - The observant reader will see that we have duplicated code in the - create and update methods. This - code maps from a domain object to a context. It can be extracted to a - separate method: - - - Binding and modifying using DirContextAdapter - - package com.example.dao; - -public class PersonDaoImpl implements PersonDao { - private LdapTemplate ldapTemplate; - - ... - public void create(Person p) { - Name dn = buildDn(p); - DirContextAdapter context = new DirContextAdapter(dn); - mapToContext(p, context); - ldapTemplate.bind(context); - } - - public void update(Person p) { - Name dn = buildDn(p); - DirContextOperations context = ldapTemplate.lookupContext(dn); - mapToContext(person, context); - ldapTemplate.modifyAttributes(context); - } - - protected void mapToContext (Person p, DirContextOperations context) { - context.setAttributeValues("objectclass", new String[] {"top", "person"}); - context.setAttributeValue("cn", p.getFullName()); - context.setAttributeValue("sn", p.getLastName()); - context.setAttributeValue("description", p.getDescription()); - } -} - - - - - - A Complete PersonDao Class - - To illustrate the power of Spring LDAP, here is a complete Person - DAO implementation for LDAP in just 68 lines: - - - A complete PersonDao class - - package com.example.dao; -import java.util.List; - -import javax.naming.Name; -import javax.naming.NamingException; -import javax.naming.directory.Attributes; -import javax.naming.ldap.LdapName; - -import org.springframework.ldap.core.AttributesMapper; -import org.springframework.ldap.core.ContextMapper; -import org.springframework.ldap.core.LdapTemplate; -import org.springframework.ldap.core.DirContextAdapter; -import org.springframework.ldap.filter.AndFilter; -import org.springframework.ldap.filter.EqualsFilter; -import org.springframework.ldap.filter.WhitespaceWildcardsFilter; - -public class PersonDaoImpl implements PersonDao { - private LdapTemplate ldapTemplate; - - public void setLdapTemplate(LdapTemplate ldapTemplate) { - this.ldapTemplate = ldapTemplate; - } - - public void create(Person person) { - DirContextAdapter context = new DirContextAdapter(buildDn(person)); - mapToContext(person, context); - ldapTemplate.bind(context); - } - - public void update(Person person) { - Name dn = buildDn(person); - DirContextOperations context = ldapTemplate.lookupContext(dn); - mapToContext(person, context); - ldapTemplate.modifyAttributes(context); - } - - public void delete(Person person) { - ldapTemplate.unbind(buildDn(person)); - } - - public Person findByPrimaryKey(String name, String company, String country) { - Name dn = buildDn(name, company, country); - return (Person) ldapTemplate.lookup(dn, getContextMapper()); - } - - public List findByName(String name) { - AndFilter filter = new AndFilter(); - filter.and(new EqualsFilter("objectclass", "person")).and(new WhitespaceWildcardsFilter("cn",name)); - return ldapTemplate.search(LdapUtils.emptyPath(), filter.encode(), getContextMapper()); - } - - public List findAll() { - EqualsFilter filter = new EqualsFilter("objectclass", "person"); - return ldapTemplate.search(LdapUtils.emptyPath(), filter.encode(), getContextMapper()); - } - - protected ContextMapper getContextMapper() { - return new PersonContextMapper(); - } - - protected Name buildDn(Person person) { - return buildDn(person.getFullname(), person.getCompany(), person.getCountry()); - } - - protected Name buildDn(String fullname, String company, String country) { - return LdapNameBuilder.newLdapName() - .add("c", country) - .add("ou", company) - .add("cn", fullname) - .build(); - } - - protected void mapToContext(Person person, DirContextOperations context) { - context.setAttributeValues("objectclass", new String[] {"top", "person"}); - context.setAttributeValue("cn", person.getFullName()); - context.setAttributeValue("sn", person.getLastName()); - context.setAttributeValue("description", person.getDescription()); - } - - private static class PersonContextMapper extends AbstractContextMapper { - public Object doMapFromContext(DirContextOperations context) { - Person person = new Person(); - person.setFullName(context.getStringAttribute("cn")); - person.setLastName(context.getStringAttribute("sn")); - person.setDescription(context.getStringAttribute("description")); - return person; - } - } -} - - - - In several cases the Distinguished Name (DN) of an object is - constructed using properties of the object. E.g. in the above example, - the country, company and full name of the Person are - used in the DN, which means that updating any of these properties will - actually require moving the entry in the LDAP tree using the - rename() operation in addition to updating the - Attribute values. Since this is highly implementation - specific this is something you'll need to keep track of yourself - - either by disallowing the user to change these properties or performing - the rename() operation in your - update() method if needed. - - - \ No newline at end of file diff --git a/src/docbkx/executors.xml b/src/docbkx/executors.xml deleted file mode 100644 index cadc78e8..00000000 --- a/src/docbkx/executors.xml +++ /dev/null @@ -1,148 +0,0 @@ - - - Adding Missing Overloaded API Methods - - - Implementing Custom Search Methods - - While LdapTemplate contains several overloaded - versions of the most common operations in DirContext, - we have not provided an alternative for each and every method signature, - mostly because there are so many of them. We have, however, provided a - means to call whichever DirContext method you want - and still get the benefits that LdapTemplate provides. - - Let's say that you want to call the following DirContext - method: - - NamingEnumeration search(Name name, String filterExpr, Object[] filterArgs, SearchControls ctls) - - There is no corresponding overloaded method in LdapTemplate. The way to solve - this is to use a custom SearchExecutor implementation: - - - public interface SearchExecutor { - public NamingEnumeration executeSearch(DirContext ctx) throws NamingException; -} - - - In your custom executor, you have access to a DirContext - object, which you use to call the method you want. You then provide a handler - that is responsible for mapping attributes and collecting the results. You can - for example use one of the available implementations of - CollectingNameClassPairCallbackHandler, which will collect - the mapped results in an internal list. In order to - actually execute the search, you call the search - method in LdapTemplate that takes an executor and a handler as arguments. Finally, - you return whatever your handler has collected. - - - A custom search method using SearchExecutor and - AttributesMapper - - package com.example.dao; - -public class PersonDaoImpl implements PersonDao { - ... - public List search(final Name base, final String filter, final String[] params, - final SearchControls ctls) { - SearchExecutor executor = new SearchExecutor() { - public NamingEnumeration executeSearch(DirContext ctx) { - return ctx.search(base, filter, params, ctls); - } - }; - - CollectingNameClassPairCallbackHandler handler = - new AttributesMapperCallbackHandler(new PersonAttributesMapper()); - - ldapTemplate.search(executor, handler); - return handler.getList(); - } -} - - - If you prefer the ContextMapper to the - AttributesMapper, this is what it would look - like: - - - A custom search method using SearchExecutor and - ContextMapper - - package com.example.dao; - -public class PersonDaoImpl implements PersonDao { - ... - public List search(final Name base, final String filter, final String[] params, - final SearchControls ctls) { - SearchExecutor executor = new SearchExecutor() { - public NamingEnumeration executeSearch(DirContext ctx) { - return ctx.search(base, filter, params, ctls); - } - }; - - CollectingNameClassPairCallbackHandler handler = - new ContextMapperCallbackHandler(new PersonContextMapper()); - - ldapTemplate.search(executor, handler); - return handler.getList(); - } -} - - - - When using the - ContextMapperCallbackHandler you must - make sure that you have called - setReturningObjFlag(true) on your - SearchControls instance. - - - - - Implementing Other Custom Context Methods - - In the same manner as for custom search methods, - you can actually execute any method in DirContext by - using a ContextExecutor. - - - public interface ContextExecutor { - public Object executeWithContext(DirContext ctx) throws NamingException; -} - - When implementing a custom ContextExecutor, you - can choose between using the executeReadOnly() or the - executeReadWrite() method. Let's say that we want to - call this method: - - - Object lookupLink(Name name) - - It's available in DirContext, but there is no - matching method in LdapTemplate. It's a lookup method, - so it should be read-only. We can implement it like this: - - - A custom DirContext method using ContextExecutor - - package com.example.dao; - -public class PersonDaoImpl implements PersonDao { - ... - public Object lookupLink(final Name name) { - ContextExecutor executor = new ContextExecutor() { - public Object executeWithContext(DirContext ctx) { - return ctx.lookupLink(name); - } - }; - - return ldapTemplate.executeReadOnly(executor); - } -} - - In the same manner you can execute a read-write operation using - the executeReadWrite() method. - - - \ No newline at end of file diff --git a/src/docbkx/images/NamingException.png b/src/docbkx/images/NamingException.png deleted file mode 100644 index 8042b84e0cb8de38b32f00ea8e84810ba8ddbcf7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 64786 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 l&ocQzY?HljSpcAP` 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
- Introduction - - LDAP Directory Interchange Format (LDIF) files are the standard - medium for describing directory data in a flat file format. The most common - uses of this format include information transfer and archival. However, - the standard also defines a way to describe modifications to stored data - in a flat file format. LDIFs of this later type are typically referred to - as changetype or modify LDIFs. - - - The org.springframework.ldap.ldif package provides - classes needed to parse LDIF files and deserialize them into tangible - objects. The LdifParser is the main class of the - org.springframework.ldap.ldif package and is capable of - parsing files that are RFC 2849 compliant. This class reads lines from a - resource and assembles them into an LdapAttributes object. - The LdifParser currently ignores - changetype LDIF entries as their usefulness in the - context of an application has yet to be determined. -
- -
- Object Representation - - Two classes in the org.springframework.ldap.core - package provide the means to represent an LDIF in code: - - - - LdapAttribute - Extends - javax.naming.directory.BasicAttribute adding support - for LDIF options as defined in RFC2849. - - - - LdapAttributes - Extends - javax.naming.directory.BasicAttributes adding - specialized support for DNs. - - - - LdapAttribute objects represent options as a - Set<String>. The DN support added to the - LdapAttributes object employs the - javax.naming.ldap.LdapName class. -
- -
- The Parser - - The Parser interface provides the foundation for - operation and employs three supporting policy definitions: - - - - SeparatorPolicy - establishes the mechanism by - which lines are assembled into attributes. - - - - AttributeValidationPolicy - ensures that - attributes are correctly structured prior to parsing. - - - - Specification - provides a mechanism by which - object structure can be validated after assembly. - - - - The default implementations of these interfaces are the - org.springframework.ldap.ldif.parser.LdifParser, the - org.springframework.ldap.ldif.support.SeparatorPolicy, and - the - org.springframework.ldap.ldif.support.DefaultAttributeValidationPolicy, - and the - org.springframework.ldap.schema.DefaultSchemaSpecification - respectively. Together, these 4 classes parse a resource line by line and - translate the data into LdapAttributes objects. - - The SeparatorPolicy determines how individual - lines read from the source file should be interpreted as the LDIF - specification allows attributes to span multiple lines. The default policy - assess lines in the context of the order in which they were read to - determine the nature of the line in consideration. - control attributes and - changetype records are ignored. - - The DefaultAttributeValidationPolicy uses REGEX - expressions to ensure each attribute conforms to a valid attribute format - according to RFC 2849 once parsed. If an attribute fails validation, an - InvalidAttributeFormatException is logged and the record is - skipped (the parser returns null). -
- -
- Schema Validation - - A mechanism for validating parsed objects against a schema and is - available via the Specification interface in the - org.springframework.ldap.schema package. The - DefaultSchemaSpecification does not do any validation and - is available for instances where records are known to be valid and not - required to be checked. This option saves the performance penalty that - validation imposes. The BasicSchemaSpecification applies - basic checks such as ensuring DN and object class declarations have been - provided. Currently, validation against an actual schema requires - implementation of the Specification interface. -
- -
- Spring Batch Integration - - While the LdifParser can be employed by any - application that requires parsing of LDIF files, Spring offers a batch - processing framework that offers many file processing utilities for - parsing delimited files such as CSV. The - org.springframework.ldap.ldif.batch package offers the - classes necessary for using the LdifParser as a valid - configuration option in the Spring Batch framework. - - There are 5 classes in this package which offer three basic use - cases: - - - - Use Case 1: Read LDIF records from a file and return an - LdapAttributes object. - - - - Use Case 2: Read LDIF records from a file and map records to - Java objects (POJOs). - - - - Use Case 3: Write LDIF records to a file. - - - - The first use case is accomplished with the LdifReader. This class - extends Spring Batch's - AbstractItemCountingItemSteamItemReader and implements its - ResourceAwareItemReaderItemStream. It fits naturally into - the framework and can be used to read LdapAttributes - objects from a file. - - The MappingLdifReader can be used to map LDIF objects - directly to any POJO. This class requires an implementation of the - RecordMapper interface be provided. This implementation - should implement the logic for mapping objects to POJOs. - - The RecordCallbackHandler can be implemented and - provided to either reader. This handler can be used to operate on skipped - records. Consult the Spring Batch documentation for more - information. - - The last member of this package, the LdifAggregator, - can be used to write LDIF records to a file. This class simply invokes the - toString() method of the LdapAttributes - object. -
- diff --git a/src/docbkx/odm.xml b/src/docbkx/odm.xml deleted file mode 100644 index d8524217..00000000 --- a/src/docbkx/odm.xml +++ /dev/null @@ -1,300 +0,0 @@ - - - Object-Directory Mapping (ODM) - - - Introduction - - - Relational mapping frameworks like Hibernate and JPA have offered - developers the ability to use annotations to map database tables to Java - objects for some time. Spring LDAP project offers a similar - ability with respect to directories through the use of a number of methods: - in LdapOperations - - <T> T findByDn(Name dn, Class<T> clazz) - <T> T findOne(LdapQuery query, Class<T> clazz) - <T> List<T> find(LdapQuery query, Class<T> clazz) - <T> List<T> findAll(Class<T> clazz) - <T> List<T> findAll(Name base, SearchControls searchControls, - Class<T> clazz) - <T> List<T> findAll(Name base, Filter filter, SearchControls searchControls, - Class<T> clazz) - void create(Object entry) - void update(Object entry) - void delete(Object entry) - - - - - - Annotations - - Entity classes managed used with the object mapping methods are required - to be annotated with annotations from the - org.springframework.ldap.odm.annotations package. The - available annotations are: - - - - @Entry - Class level annotation indicating the - objectClass definitions to which the entity - maps. (required) - - - - @Id - Indicates the entity DN; the field declaring - this attribute must be a derivative of the - javax.naming.Name class. - (required) - - - - @Attribute - Indicates the mapping of a directory - attribute to the object class field. - - - - @DnAttribute - Indicates the mapping of a dn - attribute to the object class field. - - - - @Transient - Indicates the field is not persistent - and should be ignored by the OdmManager. - - - - - The @Entry and @Id attributes are - required to be declared on managed classes. - @Entry is used to specify which object classes the entity maps to. - All object classes for which fields are mapped are required to be declared. Also, in order for a - directory entry to be considered a match to the managed entity, all object - classes declared by the directory entry must match be declared by in the - @Entry annotation. For example: let's assume that you have entries in - your LDAP tree that have the objectclassesinetOrgPerson,organizationalPerson,person,top. - If you are only interested in changing the attributes defined in the person - objectclass, your @Entry annotation can be - @Entry(objectClasses = { "person", "top" }). However, if you want to manage - attributes defined in the inetOrgPerson objectclass you'll need to use the full - monty: @Entry(objectClasses = { "inetOrgPerson", "organizationalPerson", "person", "top" }). - - - The @Id annotation is used to map the distinguished - name of the entry to a field. The field must be an instance of - javax.naming.Name. - - The @Attribute annotation is used to map object - class fields to entity fields. @Attribute is required to - declare the name of the object class property to which the field maps and - may optionally declare the syntax OID of the LDAP attribute, to guarantee - exact matching. @Attribute also provides the type declaration - which allows you to indicate whether the attribute is regarded as binary - based or string based by the LDAP JNDI provider. - - - The @DnAttribute annotation is used to map object class fields - to and from components in the distinguished name of an entry. Fields annotated with - @DnAttribute - will automatically be populated with the appropriate value from the distinguished name - when an entry is read from the directory tree. If the index attribute - of all @DnAttribute annotations in a class is specified, the DN - will also be calculated when creating and updating entries. For update scenarios, - this will also automatically take care of moving entries in the tree if attributes - that are part of the distinguished name have changed. - - - The @Transient annotation is used to indicate the - field should be ignored by the object directory mapping and not mapped to - an underlying LDAP property. Note that if a @DnAttribute is not to be bound - to an Attribute, i.e. it is only part of the Distinguished Name and not represented by an object attibute, - it must also be annotated with @Transient. - - - - Type Conversion - - The object directory mapping relies on the - org.springframework.ldap.odm.typeconversion package to - convert LDAP attributes to Java fields. For simple setups, no particular configuraion - is needed for this purpose. However, more complex mapping scenarios require the - ObjectDirectoryMapper and its associated ConverterManager - to be explicitly configured on the LdapTemplate instance. - - The default ConverterManager implementation uses the - following algorithm when parsing objects to convert fields: - - Try to find and use a Converter registered for - the fromClass, syntax and - toClass and use it. - - - - If this fails, then if the toClass - isAssignableFrom the - fromClass then just assign it. - - - - If this fails try to find and use a - Converter registered for the - fromClass and the toClass ignoring the - syntax. - - - - If this fails then throw a - ConverterException. - - - - Implementations of the ConverterManager interface can - be obtained from the - o.s.l.odm.typeconversion.impl.ConvertManagerFactoryBean. - The factory bean requires converter configurations to be declared in the - bean configuration. - - The converterConfig property accepts a set of - ConverterConfig classes, each one defining some conversion - logic. A converter config is an instance of - o.s.l.odm.typeconversion.impl.ConverterManagerFactoryBean.ConverterConfig. - The config defines a set of source classes, the set of target classes, and - an implementation of the - org.springframework.ldap.odm.typeconversion.impl.Converter - interface which provides the logic to convert from the - fromClass to the toClass. A sample configuration - is provided in the following example: - - - Configuring the Converter Manager Factory - - -<bean id="fromStringConverter" - class="org.springframework.ldap.odm.typeconversion.impl.converters.FromStringConverter" /> -<bean id="toStringConverter" - class="org.springframework.ldap.odm.typeconversion.impl.converters.ToStringConverter" /> -<bean id="converterManager" - class="org.springframework.ldap.odm.typeconversion.impl.ConverterManagerFactoryBean"> - <property name="converterConfig"> - <set> - <bean class="org.springframework.ldap.odm.\ - typeconversion.impl.ConverterManagerFactoryBean$ConverterConfig"> - <property name="fromClasses"> - <set> - <value>java.lang.String</value> - </set> - </property> - <property name="toClasses"> - <set> - <value>java.lang.Byte</value> - <value>java.lang.Short</value> - <value>java.lang.Integer</value> - <value>java.lang.Long</value> - <value>java.lang.Float</value> - <value>java.lang.Double</value> - <value>java.lang.Boolean</value> - </set> - </property> - <property name="converter" ref="fromStringConverter" /> - </bean> - <bean class="org.springframework.ldap.odm.\ - typeconversion.impl.ConverterManagerFactoryBean$ConverterConfig"> - <property name="fromClasses"> - <set> - <value>java.lang.Byte</value> - <value>java.lang.Short</value> - <value>java.lang.Integer</value> - <value>java.lang.Long</value> - <value>java.lang.Float</value> - <value>java.lang.Double</value> - <value>java.lang.Boolean</value> - </set> - </property> - <property name="toClasses"> - <set> - <value>java.lang.String</value> - </set> - </property> - <property name="converter" ref="toStringConverter" /> - </bean> - </set> - </property> -</bean> - -<ldap:ldap-template id="ldapTemplate" odm-ref="odm" /> -<bean id="odm" class="org.springframework.ldap.odm.impl.DefaultObjectDirectoryMapper"> - <property name="converterManager" ref="converterManager" /> -</bean> - - - - - - - - Execution - - - When all components have been properly configured and annotated, the object mapping - methods of LdapTemplate can be used as follows: - - Execution - - -@Entry(objectClasses = { "person", "top" }, base="ou=someOu") -public class Person { - @Id - private Name dn; - - @Attribute(name="cn") - @DnAttribute(value="cn", index=1) - private String fullName; - - // No @Attribute annotation means this will be bound to the LDAP attribute - // with the same value - private String description; - - @DnAttribute(value="ou", index=0) - @Transient - private String company; - - @Transient - private String someUnmappedField; - // ...more attributes below -} - - -public class OdmPersonDao { - @Autowired - private LdapTemplate ldapTemplate; - - public Person create(Person person) { - ldapTemplate.create(person); - return person; - } - - public Person findByUid(String uid) { - return ldapTemplate.findOne(query().where("uid").is(uid), Person.class); - } - - public void update(Person person) { - ldapTemplate.update(person); - } - - public void delete(Person person) { - ldapTemplate.delete(person); - } - - public List>Person< findAll() { - return ldapTemplate.findAll(Person.class); - } - - public List>Person< findByLastName(String lastName) { - return ldapTemplate.find(query().where("sn").is(lastName), Person.class); - } -} - - - - diff --git a/src/docbkx/overview.xml b/src/docbkx/overview.xml deleted file mode 100644 index 805204fe..00000000 --- a/src/docbkx/overview.xml +++ /dev/null @@ -1,299 +0,0 @@ - - - Introduction - - - Overview - - Spring LDAP (http://www.springframework.org/ldap) - is a library for simpler LDAP programming in Java, built on the same - principles as the JdbcTemplate - in Spring JDBC. It completely eliminates the need to worry about creating - and closing LdapContext and looping through - NamingEnumeration. It also provides a more - comprehensive unchecked Exception hierarchy, built on Spring's - DataAccessException. As a bonus, it also contains - classes for dynamically building LDAP queries and DNs (Distinguished - Names), LDAP attribute management, and client-side LDAP transaction management. - - Consider, for example, a method that should search some storage for - all persons and return their names in a list. Using JDBC, we would create - a connection and execute a query - using a statement. We would then loop over the - result set and retrieve the - column we want, adding it to a list. In contrast, - using Java LDAP, we would create a context and - perform a search using a search - filter. We would then loop over the resulting naming - enumeration and retrieve the attribute we - want, adding it to a list. - - The traditional way of implementing this person name search method - in Java LDAP looks like this, where the code marked as bold actually - performs tasks related to the business purpose of the method: - - - package com.example.dao; - -public class TraditionalPersonDaoImpl implements PersonDao { - public List getAllPersonNames() { - Hashtable env = new Hashtable(); - env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); - env.put(Context.PROVIDER_URL, "ldap://localhost:389/dc=example,dc=com"); - - DirContext ctx; - try { - ctx = new InitialDirContext(env); - } catch (NamingException e) { - throw new RuntimeException(e); - } - - LinkedList list = new LinkedList(); - NamingEnumeration results = null; - try { - SearchControls controls = new SearchControls(); - controls.setSearchScope(SearchControls.SUBTREE_SCOPE); - results = ctx.search("", "(objectclass=person)", controls); - - while (results.hasMore()) { - SearchResult searchResult = (SearchResult) results.next(); - Attributes attributes = searchResult.getAttributes(); - Attribute attr = attributes.get("cn"); - String cn = (String) attr.get(); - list.add(cn); - } - } catch (NameNotFoundException e) { - // The base context was not found. - // Just clean up and exit. - } catch (NamingException e) { - throw new RuntimeException(e); - } finally { - if (results != null) { - try { - results.close(); - } catch (Exception e) { - // Never mind this. - } - } - if (ctx != null) { - try { - ctx.close(); - } catch (Exception e) { - // Never mind this. - } - } - } - return list; - } -} - - - By using the Spring LDAP classes AttributesMapper - and LdapTemplate, we get the exact same functionality - with the following code: - - - package com.example.dao; -import static org.springframework.ldap.query.LdapQueryBuilder.query; - -public class PersonDaoImpl implements PersonDao { - private LdapTemplate ldapTemplate; - - public void setLdapTemplate(LdapTemplate ldapTemplate) { - this.ldapTemplate = ldapTemplate; - } - - public List getAllPersonNames() { - return ldapTemplate.search( - query().where("objectclass").is("person"), - new AttributesMapper() { - public Object mapFromAttributes(Attributes attrs) - throws NamingException { - return attrs.get("cn").get(); - } - }); - } -} - - - The amount of boiler-plate code is significantly less than in the - traditional example. The LdapTemplate version of the - search method performs the search, maps the attributes to a string using - the given AttributesMapper, collects the strings in an - internal list, and finally returns the list. - - Note that the PersonDaoImpl code simply assumes - that it has an LdapTemplate instance, rather than - looking one up somewhere. It provides a set method for this purpose. There - is nothing Spring-specific about this "Inversion of Control". Anyone that - can create an instance of PersonDaoImpl can also set - the LdapTemplate on it. However, Spring provides a very - flexible and easy way of achieving - this. The Spring container can be told to wire up an instance of - LdapTemplate with its required dependencies and inject - it into the PersonDao instance. This wiring can be - defined in various ways, but the most common is through XML: - - - - - - - - - - - - - -]]> - - - In order to use the custom XML namespace for configuring the Spring LDAP components - you need to include references to this namespace in your XML declaration as in the example above. - - - - - Packaging overview - - At a minimum, to use Spring LDAP you need: - - - - spring-ldap-core (the Spring LDAP library) - - - - spring-core (miscellaneous utility classes used internally by - the framework) - - - - spring-beans (contains interfaces and classes for manipulating - Java beans) - - - - slf4j (a simple logging facade, used - internally) - - - - commons-lang (misc utilities, used internally) - - - - - In addition to the required dependencies the following optional dependencies - are required for certain functionality: - - - - spring-context (If your application is wired up using the Spring Application Context - - adds the ability for application objects to obtain resources using a consistent API. Definitely needed if you are - planning on using the BaseLdapPathBeanPostProcessor.) - - - spring-tx (If you are planning to use the client side compensating transaction support) - - - spring-jdbc (If you are planning to use the client side compensating transaction support) - - - commons-pool (If you are planning to use the pooling functionality) - - - spring-batch (If you are planning to use the LDIF parsing functionality together with Spring Batch) - - - - - - - What's new in Spring LDAP 2.0? - - While quite significant modernizations have been made to the Spring LDAP APi in version 2.0, great care has been - taken to ensure backward compatibility as far as possible. - Code that works with Spring LDAP 1.3.x should with very few exceptions still compile and run using the 2.0 libraries - without any modifications whatsoever. - - - The exception is a small number of classes that have been moved to new packages in order to make - a couple of important refactorings possible. The moved classes are usually not part of the intended - public API, and the migration procedure should be very smooth - wherever a Spring LDAP class cannot be found - after upgrade, just organize the imports in your IDE. - - - You will probably encounter some deprecation warnings though, and there are also a lot of other API improvements. - The recommendation for getting as much as possible out of the 2.0 version is to move away from the deprecated - classes and methods and migrate to the new, improved API utilities. - - - Below is a list of the most important changes in Spring LDAP 2.0. - - - - Java 1.6 is now required when using Spring LDAP. Spring versions starting at 2.0 and up are still supported. - - - The central API has been updated with Java 5 features such as generics and varargs. As a consequence, - the entire spring-ldap-tiger module has been deprecated and users are encouraged to migrate - to use the core Spring LDAP classes. The parameterization of the core interfaces will most likely cause - lots of compilation warnings, and you are obviously encouraged to take appropriate action to get rid - of these warning. - - - The ODM (Object-Directory Mapping) functionality has been moved to core and there are new methods - in LdapOperations/LdapTemplate that uses this automatic - translation to/from ODM-annotated classes. See for more information. - - - A custom XML namespace is now provided to simplify configuration of Spring LDAP. - See for more information. - - - Spring Data Repository and QueryDSL support is now included in Spring LDAP. - See for more information. - - - DistinguishedName and associated classes have been deprecated in favor of standard - Java LdapName. See for information on how the library - helps working with LdapNames. - - - Fluent LDAP query support has been added. This makes for a more pleasant programming experience when - working with LDAP searches in Spring LDAP. See and - for more information about the LDAP query builder support. - - - The old authenticate methods in LdapTemplate have been deprecated - in favor of a couple of new authenticate methods that work with - LdapQuery objects and throw exceptions on authentication failure, - making it easier for the user to find out what caused an authentication attempt to fail. - - - - - Support - - Spring LDAP 2.0 is supported on Spring 2.0 and later. - - The community support forum is located at http://forum.spring.io/forum/spring-projects/data/ldap, - and the project web page is http://projects.spring.io/spring-ldap/. - - diff --git a/src/docbkx/pooling.xml b/src/docbkx/pooling.xml deleted file mode 100644 index 6444d8b6..00000000 --- a/src/docbkx/pooling.xml +++ /dev/null @@ -1,518 +0,0 @@ - - - - Pooling Support - - - Introduction - - - Pooling LDAP connections helps mitigate the overhead of - creating a new LDAP connection for each LDAP interaction. - While - - Java LDAP pooling support - - exists it is limited in its configuration options and - features, such as connection validation and pool - maintenance. Spring LDAP provides support for detailed pool - configuration on a per- - ContextSource - basis. - - - - Pooling support is provided by supplying a <ldap:pooling /> sub-element - to the <ldap:context-source /> element in the application context configuration. - Read-only and read-write DirContext objects are pooled separately - (if anonymous-read-only is specified. - - Jakarta Commons-Pool - - is used to provide the underlying pool implementation. - - - - - DirContext Validation - - - Validation of pooled connections is the primary motivation - for using a custom pooling library versus the JDK provided - LDAP pooling functionality. Validation allows pooled - DirContext - connections to be checked to ensure they are still properly - connected and configured when checking them out of the pool, - in to the pool or while idle in the pool. - - - - If connection validation is configured, pooled connections are validated using - DefaultDirContextValidator. - DefaultDirContextValidator - does a - - DirContext.search(String, String, SearchControls) - - , with an empty name, a filter of - "objectclass=*" - and - SearchControls - set to limit a single result with the only the objectclass - attribute and a 500ms timeout. If the returned - NamingEnumeration - has results the - DirContext - passes validation, if no results are returned or an - exception is thrown the - DirContext - fails validation. The default settings - should work with no configuration changes on most LDAP - servers and provide the fastest way to validate the - DirContext. If customization required this can be done using the validation - configuration attributes, described below - - - Connections will be automatically invalidated if they throw an exception that is considered - non-transient. E.g. if a DirContext instance throws a - javax.naming.CommunicationException, this will be interpreted - as a non-transient error and the instance will be automatically invalidated, without the overhead - of an additional testOnReturn operation. The exceptions that are interpreted as non-transient are - configured using the nonTransientExceptions property of the - PoolingContextSource. - - - - - Pool Configuration - - - The following attributes are available on the - <ldap:pooling /> element - for configuration of the DirContext pool: - - - - Pooling Configuration Attributes - - - - - - - - - - Attribute - - Default - - Description - - - - - - - max-active - - - - 8 - - - - The maximum number of active connections of - each type (read-only|read-write) that can be - allocated from this pool at the same time, - or non-positive for no limit. - - - - - - max-total - - - - -1 - - - - The overall maximum number of active - connections (for all types) that can be - allocated from this pool at the same time, - or non-positive for no limit. - - - - - - max-idle - - - - 8 - - - - The maximum number of active connections of - each type (read-only|read-write) that can - remain idle in the pool, without extra ones - being released, or non-positive for no - limit. - - - - - - min-idle - - - - 0 - - - - The minimum number of active connections of - each type (read-only|read-write) that can - remain idle in the pool, without extra ones - being created, or zero to create none. - - - - - - max-wait - - - - -1 - - - - The maximum number of milliseconds that the - pool will wait (when there are no available - connections) for a connection to be returned - before throwing an exception, or - non-positive to wait indefinitely. - - - - - - when-exhausted - - - - BLOCK - - - - Specifies the behaviour when the pool is - exhausted. - - - - The FAIL option will throw a - - NoSuchElementException - - when the pool is exhausted. - - - - - - The BLOCK - option will wait until a new - object is available. If - max-wait - is positive a - - NoSuchElementException - - is thrown if no new object is - available after the - max-wait - time expires. - - - - - - The GROW - option will create and return a - new object (essentially making - max-active - meaningless). - - - - - - - - - test-on-borrow - - - - false - - - - The indication of whether objects will be - validated before being borrowed from the - pool. If the object fails to validate, it - will be dropped from the pool, and an - attempt to borrow another will be made. - - - - - - test-on-return - - - - false - - - - The indication of whether objects will be - validated before being returned to the pool. - - - - - - test-while-idle - - - - false - - - - The indication of whether objects will be - validated by the idle object evictor (if - any). If an object fails to validate, it - will be dropped from the pool. - - - - - - - eviction-run-interval-millis - - - - - -1 - - - - The number of milliseconds to sleep between - runs of the idle object evictor thread. When - non-positive, no idle object evictor thread - will be run. - - - - - - tests-per-eviction-run - - - - 3 - - - - The number of objects to examine during each - run of the idle object evictor thread (if - any). - - - - - - - min-evictable-time-millis - - - - - 1000 * 60 * 30 - - - - The minimum amount of time an object may sit - idle in the pool before it is eligible for - eviction by the idle object evictor (if - any). - - - - - - validation-query-base - - - - - LdapUtils.emptyName() - - - - The search base to be used when validating connections. Only used if - test-on-borrow, test-on-return, - or test-while-idle is specified - - - - - - validation-query-filter - - - - - objectclass=* - - - - The search filter to be used when validating connections. Only used if - test-on-borrow, test-on-return, - or test-while-idle is specified - - - - - - validation-query-search-controls-ref - - - - - null; default search control settings are described above. - - - - Id of a SearchControls instance to be used when validating connections. Only used if - test-on-borrow, test-on-return, - or test-while-idle is specified - - - - - - non-transient-exceptions - - - - - javax.naming.CommunicationException - - - - Comma-separated list of Exception classes. The listed exceptions will be considered - non-transient with regards to eager invalidation. Should any of the listed exceptions - (or subclasses of them) be thrown by a call to a - pooled DirContext instance, that object will be - automatically invalidated without any additional testOnReturn operation. - - - - -
-
- - - Configuration - - - Configuring pooling should look very familiar if you're used - to Jakarta Commons-Pool or Commons-DBCP. You will first - create a normal - ContextSource - then wrap it in a - PoolingContextSource - . - - - ... - - - - ... - -]]> - - In a real world example you would probably configure the - pool options and enable connection validation; the above - serves as an example to demonstrate the general idea. - - - - Validation Configuration - - - Adding validation and a few pool configuration tweaks to - the above example is straight forward. Inject a - DirContextValidator - and set when validation should occur and the pool is - ready to go. - - - ... - - - - ... - -]]> - - The above example will test each - DirContext - before it is passed to the client application and test - DirContexts that have been sitting idle in the pool. - - - - - - Known Issues - - - Custom Authentication - - - The PoolingContextSource assumes that all - DirContext objects retrieved from - ContextSource.getReadOnlyContext() will have - the same environment and likewise that all - DirContext objects retrieved from - ContextSource.getReadWriteContext() will - have the same environment. This means that wrapping a - LdapContextSource configured with an - AuthenticationSource in a - PoolingContextSource will not function - as expected. The pool would be populated using the credentials - of the first user and unless new connections were needed - subsequent context requests would not be filled for the user - specified by the AuthenticationSource for - the requesting thread. - - - -
\ No newline at end of file diff --git a/src/docbkx/preface.xml b/src/docbkx/preface.xml deleted file mode 100644 index b0a97605..00000000 --- a/src/docbkx/preface.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - Preface - - The Java Naming and Directory Interface (JNDI) is for LDAP programming - what Java Database Connectivity (JDBC) is for SQL programming. There are - several similarities between JDBC and JNDI/LDAP (Java LDAP). Despite - being two completely different APIs with different pros and cons, they - share a number of less flattering characteristics: - - - - They require extensive plumbing code, even to perform the simplest of tasks. - - - All resources need to be correctly closed, no matter what happens. - - - Exception handling is difficult. - - - - The above points often lead to massive code duplication in common usages - of the APIs. As we all know, code duplication is one of the worst code smells. - All in all, it boils down to this: JDBC and LDAP programming in Java are both - incredibly dull and repetitive. - - - Spring JDBC, a part of the Spring framework, provides excellent utilities for - simplifying SQL programming. We need a similar framework for Java LDAP programming. - - diff --git a/src/docbkx/repositories.xml b/src/docbkx/repositories.xml deleted file mode 100644 index 33aa5b4d..00000000 --- a/src/docbkx/repositories.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - Spring LDAP Repositories - - - Overview - - Spring LDAP has built-in support for Spring Data repositories. The basic functionality and configuration is described here. - When working with Spring LDAP repositories, please note the following: - - - Spring LDAP repositories can be enabled using an <ldap:repositories> tag in - your XML configuration or using an @EnableLdapRepositories annotation on a - configuration class. - - - To include support for LdapQuery parameters in automatically generated repositories, - have your interface extend LdapRepository rather than CrudRepository. - - - All Spring LDAP repositories must work with entities annotated with the ODM annotations, as described - in . - - - Since all ODM managed classes must have a Distinguished Name as ID, all Spring LDAP repositories must - have the ID type parameter set to javax.naming.Name. Indeed, the built-in - SpringLdapRepository only takes one type parameter; the managed entity class, defaulting - ID to javax.naming.Name. - - - Due to specifics of the LDAP protocol, paging and sorting is not supported for Spring LDAP repositories. - - - - - - QueryDSL support - - Basic QueryDSL support is included in Spring LDAP. This support includes the following: - - - An Annotation Processor, LdapAnnotationProcessor, for generating QueryDSL classes - based on Spring LDAP ODM annotations. See for more information on the ODM annotations. - - - A Query implementation, QueryDslLdapQuery, for building and executing QueryDSL - queries in code. - - - Spring Data repository support for QueryDSL predicates. QueryDslPredicateExecutor - includes a number of additional methods with appropriate parameters; extend this interface along with - LdapRepository to include this support in your repository. - - - - - diff --git a/src/docbkx/resources/xsl/fopdf.xsl b/src/docbkx/resources/xsl/fopdf.xsl deleted file mode 100644 index 4c95d7e1..00000000 --- a/src/docbkx/resources/xsl/fopdf.xsl +++ /dev/null @@ -1,426 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Copyright © 2005-2010 - - - , - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -5em - -5em - - - - - - - - - - - Spring LDAP ( - - ) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1 - 0 - 1 - - 1 - - - - - - - book toc - - - - 2 - - - - - - - - - - 0 - 0 - 0 - - - 5mm - 10mm - 10mm - - 15mm - 10mm - 0mm - - 18mm - 18mm - - - 0pc - - - - - justify - false - - - 11 - 8 - - - 1.4 - - - - - - - 0.8em - - - - - - 17.4cm - - - - 4pt - 4pt - 4pt - 4pt - - - - 0.1pt - 0.1pt - - - - - 1 - - - - - - - - left - bold - - - pt - - - - - - - - - - - - - - - 0.8em - 0.8em - 0.8em - - - pt - - 0.1em - 0.1em - 0.1em - - - 0.6em - 0.6em - 0.6em - - - pt - - 0.1em - 0.1em - 0.1em - - - 0.4em - 0.4em - 0.4em - - - pt - - 0.1em - 0.1em - 0.1em - - - - - bold - - - pt - - false - 0.4em - 0.6em - 0.8em - - - - - - - - - pt - - - - - 1em - 1em - 1em - #444444 - solid - 0.1pt - 0.5em - 0.5em - 0.5em - 0.5em - 0.5em - 0.5em - - - - 1 - - #F0F0F0 - - - - - - 0 - 1 - - - 90 - - - - - '1' - - - - - - - figure after - example before - equation before - table before - procedure before - - - - 1 - - - - 0.8em - 0.8em - 0.8em - 0.1em - 0.1em - 0.1em - - - - - - - - - - - - - - - - - diff --git a/src/docbkx/resources/xsl/html.xsl b/src/docbkx/resources/xsl/html.xsl deleted file mode 100644 index 015b02c9..00000000 --- a/src/docbkx/resources/xsl/html.xsl +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - html.css - - - 1 - 0 - 1 - 0 - - - - - - book toc - - - - 3 - - - - - 1 - - - - - - - 0 - - - 90 - - - - - 0 - - - - - figure after - example before - equation before - table before - procedure before - - - - , - - - - - - - - -
-

Authors

-

- -

-
- -
diff --git a/src/docbkx/resources/xsl/html_chunk.xsl b/src/docbkx/resources/xsl/html_chunk.xsl deleted file mode 100644 index 3a405d8f..00000000 --- a/src/docbkx/resources/xsl/html_chunk.xsl +++ /dev/null @@ -1,208 +0,0 @@ - - - - - - - '5' - '1' - - 1 - 0 - 1 - 0 - - - - book toc - - - 3 - - - 1 - - - - - 1 - 90 - - - - figure after - example before - equation before - table before - procedure before - - - - , - - - - - - - - -
-

Authors

-

- -

-
- - - -
- - - - 1 - - - - - - - - - - - - - - diff --git a/src/docbkx/simple.xml b/src/docbkx/simple.xml deleted file mode 100644 index 788e2bd1..00000000 --- a/src/docbkx/simple.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - Java 5 Support - - - SimpleLdapTemplate - - As of Spring LDAP 2.0 the core API has full Java 5 support, and SimpleLdapTemplate - and associated classes are all deprecated. - - As of version 1.3 Spring LDAP includes the spring-ldap-core-tiger.jar distributable, which adds - a thin layer of Java 5 functionality on top of Spring LDAP. - - The SimpleLdapTemplate class adds search and lookup methods that take a - ParameterizedContextMapper, adding generics support to these methods. - - ParametrizedContextMapper is a typed version of ContextMapper, - which simplifies working with searches and lookups: - - Using <literal>ParameterizedContextMapper</literal> - public List<Person> getAllPersons(){ - return simpleLdapTemplate.search("", "(objectclass=person)", - new ParameterizedContextMapper<Person>() { - public Person mapFromContext(Object ctx) { - DirContextAdapter adapter = (DirContextAdapter) ctx; - Person person = new Person(); - // Fill the domain object with data from the DirContextAdapter - - return person; - } - }; -} - - - - - diff --git a/src/docbkx/transactions.xml b/src/docbkx/transactions.xml deleted file mode 100644 index d32c7748..00000000 --- a/src/docbkx/transactions.xml +++ /dev/null @@ -1,241 +0,0 @@ - - - - Transaction Support - - - Introduction - - Programmers used to working with relational databases coming to the LDAP - world often express surprise to the fact that there is no notion of transactions. - It is not specified in the protocol, and thus no servers support it. - Recognizing that this may be a major problem, Spring LDAP provides support for client-side, - compensating transactions on LDAP resources. - - LDAP transaction support is provided by ContextSourceTransactionManager, a - PlatformTransactionManager implementation that manages Spring transaction - support for LDAP operations. Along with its collaborators it keeps track of the LDAP operations - performed in a transaction, making record of the state before each operation and taking steps to - restore the initial state should the transaction need to be rolled back. - In addition to the actual transaction management, Spring LDAP transaction support also - makes sure that the same DirContext instance will be used throughout the same transaction, - i.e. the DirContext will not actually be closed until the transaction is finished, - allowing for more efficient resources usage. - - It is important to note that while the approach used by Spring LDAP to provide transaction support - is sufficient for many cases it is by no means "real" transactions in the traditional sense. - The server is completely unaware of the transactions, so e.g. if the connection is broken there will - be no hope to rollback the transaction. While this should be carefully considered it should also be noted - that the alternative will be to operate without any transaction support whatsoever; this is pretty much - as good as it gets. - The client side transaction support will add some overhead in addition to the work required - by the original operations. While this overhead should not be something to worry about in most cases, - if your application will not perform several LDAP operations within the same - transaction (e.g. a modifyAttributes followed by a rebind), or - if transaction synchronization with a JDBC data source is not required (see below) there will be nothing to gain - by using the LDAP transaction support. - - - - - Configuration - - Configuring Spring LDAP transactions should look very familiar if you're used to configuring Spring transactions. - You will annotate your transacted classes with @Transactional, create a - TransactionManager instance and include a <tx:annotation-driven> - tag in your bean configuraion. - - -<beans> - ... - <ldap:context-source - url="ldap://localhost:389" - base="dc=example,dc=com" - username="cn=Manager" - password="secret" /> - - <ldap:ldap-template id="ldapTemplate" /> - <ldap:transaction-manager> - <!-- - Note this default configuration will not work for more complex scenarios, see below for more information on RenamingStrategies. - --> - <ldap:default-renaming-strategy /> - </ldap:transaction-manager> - - <!-- - The MyDataAccessObject class is annotated with @Transactional. - --> - <bean id="myDataAccessObject" class="com.example.MyDataAccessObject"> - <property name="ldapTemplate" ref="ldapTemplate" /> - </bean> - - <tx:annotation-driven /> - ... - While this setup will work fine for most simple use cases, some more complex scenarios will - require additional configuration; more specifically if you will be creating or deleting subtrees within - transactions, you will need to use an alternative TempEntryRenamingStrategy, as described - in below - - In a real world example you would probably apply the transactions on the service object level - rather than the DAO level; the above serves as an example to demonstrate the general idea. - - - - JDBC Transaction Integration - - A common use case when working against LDAP is that some of the data is stored in the LDAP tree, but - other data is stored in a relational database. In this case, transaction support becomes even more important, - since the update of the different resources should be synchronized. - - - While actual XA transactions is not supported, support is provided to conceptually wrap JDBC and LDAP - access within the same transaction by supplying a data-source-ref attribute to the - <ldap:transaction-manager> tag. - This will create a ContextSourceAndDataSourceTransactionManager, - which will then manage the two transactions, virtually as if they were one. When performing a commit, - the LDAP part of the operation will always be performed first, allowing both transactions to be rolled - back should the LDAP commit fail. The JDBC part of the transaction is managed exactly as in - DataSourceTransactionManager, except that nested transactions is not supported: - - - <ldap:transaction-manager data-source-ref="dataSource" > - <ldap:default-renaming-strategy /> - <ldap:transaction-manager /> - - - - Once again it should be noted that the provided support is all client side. The wrapped transaction is not - an XA transaction. No two-phase as such commit is performed, as the LDAP server will be unable to vote on its outcome. - Once again, however, for the majority of cases the supplied support will be sufficient. - - - - The same thing can be accomplished for Hibernate integration by supplying a session-factory-ref - attribute to the <ldap:transaction-manager> tag. - - - <ldap:transaction-manager session-factory-ref="dataSource" > - <ldap:default-renaming-strategy /> - <ldap:transaction-manager /> - - - - - - LDAP Compensating Transactions Explained - Spring LDAP manages compensating transactions by making record of the state in the LDAP tree - before each modifying operation (bind, unbind, rebind, - modifyAttributes, and rename). - This enables the system - to perform compensating operations should the transaction need to be rolled back. In many cases the - compensating operation is pretty straightforward. E.g. the compensating rollback operation for a - bind operation will quite obviously be to unbind the entry. Other operations however require - a different, more complicated approach because of some particular characteristics of LDAP databases. Specifically, - it is not always possible to get the values of all Attributes of an entry, making the above - strategy insufficient for e.g. an unbind operation. - This is why each modifying operation performed within a Spring LDAP managed transaction is internally - split up in four distinct operations - a recording operation, a preparation operation, a commit operation, - and a rollback operation. The specifics for each LDAP operation is described in the table below: - - - - - - - - - - LDAP Operation - Recording - Preparation - Commit - Rollback - - - - - bind - Make record of the DN of the entry to bind. - Bind the entry. - No operation. - Unbind the entry using the recorded DN. - - - rename - Make record of the original and target DN. - Rename the entry. - No operation. - Rename the entry back to its original DN. - - - unbind - Make record of the original DN and calculate a temporary DN. - Rename the entry to the temporary location. - Unbind the temporary entry. - Rename the entry from the temporary location back to its original DN. - - - rebind - Make record of the original DN and the new Attributes, and calculate a temporary DN. - Rename the entry to a temporary location. - Bind the new Attributes at the original DN, and unbind the original entry - from its temporary location. - Rename the entry from the temporary location back to its original DN. - - - modifyAttributes - Make record of the DN of the entry to modify and calculate compensating ModificationItems - for the modifications to be done. - Perform the modifyAttributes operation. - No operation. - Perform a modifyAttributes operation using the calculated compensating - ModificationItems. - - - -
- A more detailed description of the internal workings of the Spring LDAP transaction support is available in the - javadocs. - - Renaming Strategies - - As described in the table above, the transaction management of some operations require the original entry affected - by the operation to be temporarily renamed before the actual modification can be made in the commit. - The manner in which the temporary DN of the entry is calculated is managed by a TempEntryRenamingStrategy - specified in a sub-element to the <ldap:transaction-manager > declaration - in the configuration. Two implementations are supplied with Spring LDAP: - - - - - DefaultTempEntryRenamingStrategy (the default). Specified using a - <ldap:default-renaming-strategy /> element. Adds a suffix to the least significant - part of the entry DN. E.g. for the DN cn=john doe, ou=users, this strategy would return the - temporary DN cn=john doe_temp, ou=users. - The suffix is configurable using the temp-suffix attribute. - - - - - DifferentSubtreeTempEntryRenamingStrategy. Specified using a - <ldap:different-subtree-renaming-strategy /> element. - Takes the least significant part of the DN and appends a subtree DN to this. - This makes all temporary entries be placed at a specific location in the LDAP tree. - The temporary subtree DN is configured using the subtree-node attribute. E.g., if - subtree-node is ou=tempEntries and the original DN of the entry is - cn=john doe, ou=users, the temporary DN will be cn=john doe, ou=tempEntries. - Note that the configured subtree node needs to be present in the LDAP tree. - - - - - There are some situations where the DefaultTempEntryRenamingStrategy will not work. E.g. if your are planning - to do recursive deletes you'll need to use DifferentSubtreeTempEntryRenamingStrategy. This is because - the recursive delete operation actually consists of a depth-first delete of each node in the sub tree individually. - Since it is not allowed to rename an entry that has any children, and DefaultTempEntryRenamingStrategy would - leave each node in the same subtree (with a different name) in stead of actually removing it, this operation would fail. - When in doubt, use DifferentSubtreeTempEntryRenamingStrategy. - - -
-
\ No newline at end of file diff --git a/src/docbkx/user-authentication.xml b/src/docbkx/user-authentication.xml deleted file mode 100644 index eae4bbf3..00000000 --- a/src/docbkx/user-authentication.xml +++ /dev/null @@ -1,165 +0,0 @@ - - - User Authentication using Spring LDAP - - - Basic Authentication - - While the core functionality of the ContextSource - is to provide DirContext instances for use by - LdapTemplate, it may also be used for authenticating - users against an LDAP server. The getContext(principal, - credentials) method of ContextSource will do - exactly that; construct a DirContext instance according - to the ContextSource configuration, authenticating the - context using the supplied principal and credentials. A custom - authenticate method could look like this: - - public boolean authenticate(String userDn, String credentials) { - DirContext ctx = null; - try { - ctx = contextSource.getContext(userDn, credentials); - return true; - } catch (Exception e) { - // Context creation failed - authentication did not succeed - logger.error("Login failed", e); - return false; - } finally { - // It is imperative that the created DirContext instance is always closed - LdapUtils.closeContext(ctx); - } -}The userDn supplied to the authenticate - method needs to be the full DN of the user to authenticate (regardless of - the base setting on the - ContextSource). You will typically need to perform an - LDAP search based on e.g. the user name to get this DN: - - private String getDnForUser(String uid) { - List result = ldapTemplate.search(query().where("uid").is(uid), - new AbstractContextMapper() { - protected Object doMapFromContext(DirContextOperations ctx) { - return ctx.getNameInNamespace(); - } - }); - - if(result.size() != 1) { - throw new RuntimeException("User not found or not unique"); - } - - return (String)result.get(0); -}There are some drawbacks to this approach. The user is - forced to concern herself with the DN of the user, she can only search for - the user's uid, and the search always starts at the root of the tree (the - empty path). A more flexible method would let the user specify the search - base, the search filter, and the credentials. Spring LDAP includes an authenticate - method in LdapTemplate that provide this functionality: boolean authenticate(LdapQuery query, String password); - - Using this method authentication becomes as simple as this: - - - Authenticating a user using Spring LDAP. - - ldapTemplate.authenticate(query().where("uid").is("john.doe"), "secret"); - - - As described in below, some setups may require additional operations to be performed - in order for actual authentication to occur. See - for details. - - - Don't write your own custom authenticate methods. Use the ones - provided in Spring LDAP 1.3.x. - - - - - - Performing Operations on the Authenticated Context - - Some authentication schemes and LDAP servers require some operation - to be performed on the created DirContext instance for - the actual authentication to occur. You should test and make sure how your - server setup and authentication schemes behave; failure to do so might - result in that users will be admitted into your system regardless of the - DN/credentials supplied. This is a naïve implementation of an authenticate - method where a hard-coded lookup operation is performed - on the authenticated context: - - public boolean authenticate(String userDn, String credentials) { - DirContext ctx = null; - try { - ctx = contextSource.getContext(userDn, credentials); - // Take care here - if a base was specified on the ContextSource - // that needs to be removed from the user DN for the lookup to succeed. - ctx.lookup(userDn); - return true; - } catch (Exception e) { - // Context creation failed - authentication did not succeed - logger.error("Login failed", e); - return false; - } finally { - // It is imperative that the created DirContext instance is always closed - LdapUtils.closeContext(ctx); - } -} - It would be better if the operation could be provided as an - implementation of a callback interface, thus not limiting the operation to - always be a lookup. Spring LDAP includes the callback interface - AuthenticatedLdapEntryContextMapper and a - corresponding authenticate method: - <T> T authenticate(LdapQuery query, String password, AuthenticatedLdapEntryContextMapper<T> mapper); - - - - - - - - This opens up for any operation to be performed on the authenticated - context: - - - Performing an LDAP operation on the authenticated context using - Spring LDAP. - - AuthenticatedLdapEntryContextMapper<DirContextOperations> mapper = new AuthenticatedLdapEntryContextMapper<DirContextOperations>() { - public DirContextOperations mapWithContext(DirContext ctx, LdapEntryIdentification ldapEntryIdentification) { - try { - return (DirContextOperations) ctx.lookup(ldapEntryIdentification.getRelativeName()); - } - catch (NamingException e) { - throw new RuntimeException("Failed to lookup " + ldapEntryIdentification.getRelativeName(), e); - } - } -}; - -ldapTemplate.authenticate(query().where("uid").is("john.doe"), "secret", mapper); - - - - - Obsolete authentication methods - - - In addition to the authenticate methods described above - there are a number of deprecated methods that can be used for authentication. - While these will work fine, the recommendation is to use the - LdapQuery methods instead. - - - - - Use Spring Security - - While the approach above may be sufficient for simple authentication - scenarios, requirements in this area commonly expand rapidly. There is a - multitude of aspects that apply, including authentication, authorization, - web integration, user context management, etc. If you suspect that the - requirements might expand beyond just simple authentication, you should - definitely consider using Spring - Security for your security purposes instead. It is a full-blown, - mature security framework addressing the above aspects as well as several - others. - - diff --git a/src/docbkx/utilities.xml b/src/docbkx/utilities.xml deleted file mode 100644 index 5fe85dd6..00000000 --- a/src/docbkx/utilities.xml +++ /dev/null @@ -1,24 +0,0 @@ - - Utilities - - Incremental Retrieval of Multi-Valued Attributes - - When there are a very large number of attribute values (>1500) for a specific attribute, - Active Directory will typically refuse to return all these values at once. Instead - the attribute values will be returned according to the - Incremental Retrieval of Multi-valued Properties - method. This requires the calling part to inspect the returned attribute for specific markers and, - if necessary, make additional lookup requests until all values are found. - - - Spring LDAP's org.springframework.ldap.core.support.DefaultIncrementalAttributesMapper - helps working with this kind of attributes, as follows: - -Attributes attrs = DefaultIncrementalAttributeMapper.lookupAttributes(ldapTemplate, theDn, new Object[]{"oneAttribute", "anotherAttribute"}); - - This will parse any returned attribute range markers and make repeated requests as necessary until all values - for all requested attributes have been retrieved. - - - - \ No newline at end of file diff --git a/src/site/fml/faq.fml b/src/site/fml/faq.fml index d5bdc99f..e69de29b 100644 --- a/src/site/fml/faq.fml +++ b/src/site/fml/faq.fml @@ -1,108 +0,0 @@ - - - - Operational Attributes - - How do I remove an operational attribute using context.removeAttributeValue()? - -

- The DirContextAdapter will only read the visible attributes per default. This is because the - operational attributes will only be returned by the server if explicitly asked for, and there - is no way for Spring LDAP to know what attributes to ask for. This means that the DirContextAdapter - will not be populated with the operational attributes, and hence the removeAttributeValue - will not have any effect (since from the DirContextAdapter's point of view, it wasn't there in the - first place). -

-

- There are basically two ways to do this: -

-
    -
  1. Use a search or lookup method that takes the attribute names as argument, like - LdapTemplate#lookup(Name, String[], ContextMapper). Use a ContextMapper - implementation that just returns the supplied DirContextAdapter in mapFromContext(). -
  2. -
  3. Use LdapTemplate#modifyAttributes(Name, ModificationItem[]) directly, manually - building the ModificationItem array. -
  4. -
-
-
-
- -

xIMXTzCz!PWHf;k0AKWz0 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 z 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 ZS8OItGvK?g2SfIM{e>0(*I)Sc{{bz;*^&SN diff --git a/src/docbkx/images/bannerR.gif b/src/docbkx/images/bannerR.gif deleted file mode 100644 index 548ab8848daf59ca783e1a21d131d7af7a71ff68..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7949 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 diff --git a/src/docbkx/images/logo.png b/src/docbkx/images/logo.png deleted file mode 100644 index 31396b8a49cd65687bce18f95777cd610d195c5c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23834 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 VWp_0;V3%|y(-Rg(Wd_&6{|6NOk;?!8 diff --git a/src/docbkx/images/s2_box_logo.png b/src/docbkx/images/s2_box_logo.png deleted file mode 100644 index 8c778a57940f0da55628282e6a77aa5904542c54..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6877 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 diff --git a/src/docbkx/images/xdev-spring_logo.jpg b/src/docbkx/images/xdev-spring_logo.jpg deleted file mode 100644 index 622962ee3c89651ded6aea73c854d7ad44f880f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37376 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 diff --git a/src/docbkx/index.xml b/src/docbkx/index.xml deleted file mode 100644 index 9c4d0e17..00000000 --- a/src/docbkx/index.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - Spring LDAP - Reference Documentation - &version; - - - - Mattias - Hellborg Arthursson - - - Ulrik - Sandberg - - - Eric - Dalquist - - - Keith - Barlow - - - - - - Copies of this document may be made for your own use and - for distribution to others, provided that you do not - charge any fee for such copies and further provided that - each copy contains this Copyright Notice, whether - distributed in print or electronically. - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/docbkx/ldif-parsing.xml b/src/docbkx/ldif-parsing.xml deleted file mode 100644 index cbd79883..00000000 --- a/src/docbkx/ldif-parsing.xml +++ /dev/null @@ -1,168 +0,0 @@ - - - LDIF Parsing - -