diff --git a/src/docbkx/basic.xml b/src/docbkx/basic.xml
index fc084687..46201622 100644
--- a/src/docbkx/basic.xml
+++ b/src/docbkx/basic.xml
@@ -141,94 +141,121 @@ filter.and(new EqualsFilter("objectclass", "person"));
filter.and(new WhitespaceWildcardsFilter("cn", cn));
-
-
- In addition to simplifying building of complex search filters,
- the Filter classes also provide proper escaping
- of any unsafe characters. This prevents "ldap injection",
- where a user might use such characters to inject unwanted operations
- into your LDAP operations.
-
+
+
+ In addition to simplifying building of complex search filters,
+ the Filter classes also provide proper escaping
+ of any unsafe characters. This prevents "ldap injection",
+ where a user might use such characters to inject unwanted operations
+ into your LDAP operations.
+
- Building Dynamic Distinguished Names
+ 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.
+
+
+
- The standard Name
- interface represents a generic name, which is basically an ordered
- sequence of components. The Name interface also
- provides operations on that sequence; e.g., add or
- remove. LdapTemplate provides an implementation of the
- Name interface: DistinguishedName.
- Using this class will greatly simplify building distinguished names,
- especially considering the sometimes complex rules regarding escapings and
- encodings. As with the Filter classes this helps preventing
- potentially malicious data being injected into your LDAP operations.
-
-
- The following example illustrates how
- DistinguishedName can be used to dynamically construct
- a distinguished name:
-
-
- Building a distinguished name dynamically
-
- package com.example.dao;
-
-import org.springframework.ldap.core.support.DistinguishedName;
+ 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) {
- DistinguishedName dn = new DistinguishedName(BASE_DN);
- dn.add("c", p.getCountry());
- dn.add("ou", p.getCompany());
- dn.add("cn", p.getFullname());
- return dn;
- }
-}
-
+public static final String BASE_DN = "dc=example,dc=com";
+...
+protected Name buildDn(Person p) {
+ return LdapNameBuilder.newInstance(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
+
+
+
+
- Assuming that a Person has the following attributes:
+ The code above would then result in the following distinguished
+ name:
-
-
-
-
- country
+ 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.
- 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
-
- In Java 5, there is an implementation of the Name interface: LdapName.
- If you are in the Java 5 world, you might as well use
- LdapName. However, you may still use
- DistinguishedName if you so wish.
+ 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 have been deprecated in version 2.0.
+ Users are now recommended to use LdapName along with the utilities described above instead.
+
diff --git a/src/docbkx/configuration.xml b/src/docbkx/configuration.xml
index 528b1f3d..0ec4c83f 100644
--- a/src/docbkx/configuration.xml
+++ b/src/docbkx/configuration.xml
@@ -282,23 +282,23 @@
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
- BaseLdapPathAware interface. Secondly, a BaseLdapPathBeanPostProcessor
+ BaseLdapNameAware interface. Secondly, a BaseLdapPathBeanPostProcessor
needs to be defined in the application context
- Implementing BaseLdapPathAware
-
+ Implementing BaseLdapNameAware
package com.example.service;
-
-public class PersonService implements PersonService, BaseLdapPathAware {
+public class PersonService implements PersonService, BaseLdapNameAware {
...
- private DistinguishedName basePath;
+ private LdapName basePath;
- public void setBaseLdapPath(DistinguishedName basePath) {
+ public void setBaseLdapPath(LdapName basePath) {
this.basePath = basePath;
}
...
- private DistinguishedName getFullPersonDn(Person person) {
- return new DistinguishedName(basePath).append(person.getDn());
+ private LdapName getFullPersonDn(Person person) {
+ return LdapNameBuilder.newInstance(basePath)
+ .append(person.getDn())
+ .build();
}
...
}
@@ -321,6 +321,7 @@ public class PersonService implements PersonService, BaseL
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.
+ baseLdapPathSourceName property.
+
diff --git a/src/docbkx/dirobjectfactory.xml b/src/docbkx/dirobjectfactory.xml
index f3ad6b4c..dadbe03b 100644
--- a/src/docbkx/dirobjectfactory.xml
+++ b/src/docbkx/dirobjectfactory.xml
@@ -59,31 +59,31 @@ public class PersonDaoImpl implements PersonDao {
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()
+ 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()
-
- 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
+
+ Getting multi-value attribute values using getStringAttributes()
+
+ 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.
@@ -104,13 +104,13 @@ public class PersonDaoImpl implements PersonDao {
}
-
+
Binding and Modifying Using DirContextAdapter
- While very useful when extracting attribute values, DirContextAdapter is even more
+ While very useful when extracting attribute values, DirContextAdapter is even more
powerful for hiding attribute details when binding and modifying data.
@@ -141,14 +141,14 @@ public class PersonDaoImpl implements PersonDao {
}
- Note that we use the DirContextAdapter instance
- as the second parameter to bind, which should be a 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
+ 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.
@@ -157,11 +157,11 @@ public class PersonDaoImpl implements PersonDao {
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
+ 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
@@ -186,11 +186,11 @@ public class PersonDaoImpl implements PersonDao {
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
+
+ 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
@@ -241,18 +241,17 @@ public class PersonDaoImpl implements PersonDao {
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.core.support.DistinguishedName;
import org.springframework.ldap.filter.AndFilter;
import org.springframework.ldap.filter.EqualsFilter;
import org.springframework.ldap.filter.WhitespaceWildcardsFilter;
@@ -289,12 +288,12 @@ public class PersonDaoImpl implements PersonDao {
public List findByName(String name) {
AndFilter filter = new AndFilter();
filter.and(new EqualsFilter("objectclass", "person")).and(new WhitespaceWildcardsFilter("cn",name));
- return ldapTemplate.search(DistinguishedName.EMPTY_PATH, filter.encode(), getContextMapper());
+ return ldapTemplate.search(LdapUtils.emptyPath(), filter.encode(), getContextMapper());
}
public List findAll() {
EqualsFilter filter = new EqualsFilter("objectclass", "person");
- return ldapTemplate.search(DistinguishedName.EMPTY_PATH, filter.encode(), getContextMapper());
+ return ldapTemplate.search(LdapUtils.emptyPath(), filter.encode(), getContextMapper());
}
protected ContextMapper getContextMapper() {
@@ -306,11 +305,11 @@ public class PersonDaoImpl implements PersonDao {
}
protected Name buildDn(String fullname, String company, String country) {
- DistinguishedName dn = new DistinguishedName();
- dn.add("c", country);
- dn.add("ou", company);
- dn.add("cn", fullname);
- return dn;
+ return LdapNameBuilder.newInstance()
+ .add("c", country)
+ .add("ou", company)
+ .add("cn", fullname)
+ .build();
}
protected void mapToContext(Person person, DirContextOperations context) {
diff --git a/src/docbkx/ldif-parsing.xml b/src/docbkx/ldif-parsing.xml
index 90262775..cbd79883 100644
--- a/src/docbkx/ldif-parsing.xml
+++ b/src/docbkx/ldif-parsing.xml
@@ -47,7 +47,7 @@
LdapAttribute objects represent options as a
Set<String>. The DN support added to the
LdapAttributes object employs the
- org.springframework.ldap.core.DistinguishedName class.
+ javax.naming.ldap.LdapName class.
diff --git a/src/docbkx/odm.xml b/src/docbkx/odm.xml
index 0ee69dbb..6da56fb8 100644
--- a/src/docbkx/odm.xml
+++ b/src/docbkx/odm.xml
@@ -273,7 +273,7 @@ public class App {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
OdmManager manager = (OdmManager) context.getBean("odmManager");
List<SimplePerson> people = manager.search(SimplePerson.class,
- new DistinguishedName("dc=example,dc=com"), "uid=*", searchControls);
+ LdapUtils.newLdapName("dc=example,dc=com"), "uid=*", searchControls);
log.info("People found: " + people.size());
for (SimplePerson person : people) {
log.info( person );
diff --git a/src/docbkx/user-authentication.xml b/src/docbkx/user-authentication.xml
index 8bbc9c41..a01114f3 100644
--- a/src/docbkx/user-authentication.xml
+++ b/src/docbkx/user-authentication.xml
@@ -36,7 +36,7 @@
private String getDnForUser(String uid) {
Filter f = new EqualsFilter("uid", uid);
- List result = ldapTemplate.search(DistinguishedName.EMPTY_PATH, f.toString(),
+ List result = ldapTemplate.search(LdapUtils.emptyLdapName(), f.toString(),
new AbstractContextMapper() {
protected Object doMapFromContext(DirContextOperations ctx) {
return ctx.getNameInNamespace();