LDAP-258: Updated documentation to reflect DistinguishedName deprecation.
This commit is contained in:
@@ -141,94 +141,121 @@ filter.and(new EqualsFilter("objectclass", "person"));
|
||||
filter.and(new WhitespaceWildcardsFilter("cn", cn));</programlisting>
|
||||
</example>
|
||||
|
||||
<para>
|
||||
<note>
|
||||
In addition to simplifying building of complex search filters,
|
||||
the <literal>Filter</literal> 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.
|
||||
</note>
|
||||
<para>
|
||||
<note>
|
||||
In addition to simplifying building of complex search filters,
|
||||
the <literal>Filter</literal> 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.
|
||||
</note>
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>Building Dynamic Distinguished Names</title>
|
||||
<title>Dynamically Building Distinguished Names</title>
|
||||
<para>
|
||||
The standard Java implementation of Distinguished Name, <ulink
|
||||
url="http://docs.oracle.com/javase/6/docs/api/javax/naming/ldap/LdapName.html">LdapName</ulink>,
|
||||
performs very well when it comes to parsing of Distinguished Names. However, in practical use
|
||||
this implementation has a number of shortcomings:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
The <literal>LdapName</literal> implementation is mutable, which is badly suited for an object
|
||||
representing identity.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Despite its mutable nature, the API for dynamically building or modifying Distinguished Names using
|
||||
<literal>LdapName</literal> is cumbersome. Extracting values of indexed or (particularly)
|
||||
named components is also a little bit awkward.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Many of the operations on <literal>LdapName</literal> throw checked Exceptions, requiring unnecessary
|
||||
try-catch statements for situations where the error is typically fatal and cannot be repaired in
|
||||
a meaningful manner.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>The standard <ulink
|
||||
url="http://download.oracle.com/javase/1.5.0/docs/api/javax/naming/Name.html">Name</ulink>
|
||||
interface represents a generic name, which is basically an ordered
|
||||
sequence of components. The <literal>Name</literal> interface also
|
||||
provides operations on that sequence; e.g., <literal>add</literal> or
|
||||
<literal>remove</literal>. LdapTemplate provides an implementation of the
|
||||
<literal>Name</literal> interface: <literal>DistinguishedName</literal>.
|
||||
Using this class will greatly simplify building distinguished names,
|
||||
especially considering the sometimes complex rules regarding escapings and
|
||||
encodings. As with the <literal>Filter</literal> classes this helps preventing
|
||||
potentially malicious data being injected into your LDAP operations.
|
||||
</para>
|
||||
<para>
|
||||
The following example illustrates how
|
||||
<literal>DistinguishedName</literal> can be used to dynamically construct
|
||||
a distinguished name:</para>
|
||||
|
||||
<example>
|
||||
<title>Building a distinguished name dynamically</title>
|
||||
|
||||
<programlisting>package com.example.dao;
|
||||
|
||||
import org.springframework.ldap.core.support.DistinguishedName;
|
||||
To simplify working with Distinguished Names, Spring LDAP provides an <literal>LdapNameBuilder</literal>, as
|
||||
well as a number of utility methods in <literal>LdapUtils</literal> that helps working with
|
||||
<literal>LdapName</literal>.
|
||||
</para>
|
||||
<para>
|
||||
Below are a couple of examples of how these utilities can simplify handling of distinguished names.
|
||||
<example>
|
||||
<title>Dynamically building an LdapName using LdapNameBuilder</title>
|
||||
<programlisting>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) {
|
||||
<emphasis role="bold"> DistinguishedName dn = new DistinguishedName(BASE_DN);
|
||||
dn.add("c", p.getCountry());
|
||||
dn.add("ou", p.getCompany());
|
||||
dn.add("cn", p.getFullname());
|
||||
</emphasis> return dn;
|
||||
}
|
||||
}</programlisting>
|
||||
</example>
|
||||
public static final String BASE_DN = "dc=example,dc=com";
|
||||
...
|
||||
protected Name buildDn(Person p) {
|
||||
<emphasis role="bold"> return LdapNameBuilder.newInstance(BASE_DN)
|
||||
.add("c", p.getCountry())
|
||||
.add("ou", p.getCompany())
|
||||
.add("cn", p.getFullname())
|
||||
.build();
|
||||
</emphasis>
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
Assuming that a Person has the following attributes:
|
||||
</para>
|
||||
<informaltable>
|
||||
<tgroup cols="2">
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><literal>country</literal></entry>
|
||||
<entry>Sweden</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>company</literal></entry>
|
||||
<entry>Some Company</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>fullname</literal></entry>
|
||||
<entry>Some Person</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
|
||||
<para>Assuming that a Person has the following attributes:</para>
|
||||
<para>The code above would then result in the following distinguished
|
||||
name:</para>
|
||||
|
||||
<informaltable>
|
||||
<tgroup cols="2">
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><literal>country</literal></entry>
|
||||
<para><programlisting>cn=Some Person, ou=Some Company, c=Sweden, dc=example, dc=com</programlisting></para>
|
||||
<para>
|
||||
<example>
|
||||
<title>Extracting values from a distinguished name using LdapUtils</title>
|
||||
<programlisting>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(<emphasis>LdapUtils.getStringValue(dn, "c")</emphasis>);
|
||||
person.setCompany(<emphasis>LdapUtils.getStringValue(dn, "ou")</emphasis>);
|
||||
person.setFullname(<emphasis>LdapUtils.getStringValue(dn, "cn")</emphasis>);
|
||||
// Populate rest of person object using attributes.
|
||||
|
||||
<entry>Sweden</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>company</literal></entry>
|
||||
|
||||
<entry>Some Company</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>fullname</literal></entry>
|
||||
|
||||
<entry>Some Person</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
|
||||
<para>The code above would then result in the following distinguished
|
||||
name:</para>
|
||||
|
||||
<para><programlisting>cn=Some Person, ou=Some Company, c=Sweden, dc=example, dc=com</programlisting></para>
|
||||
|
||||
<para>In Java 5, there is an implementation of the Name interface: <ulink
|
||||
url="http://download.oracle.com/javase/1.5.0/docs/api/javax/naming/ldap/LdapName.html">LdapName</ulink>.
|
||||
If you are in the Java 5 world, you might as well use
|
||||
<literal>LdapName</literal>. However, you may still use
|
||||
<literal>DistinguishedName</literal> if you so wish.</para>
|
||||
return person;
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
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, <literal>DistinguishedName</literal>. 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 <literal>LdapName</literal> along with the utilities described above instead.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="basic-binding-unbinding">
|
||||
|
||||
@@ -282,23 +282,23 @@
|
||||
<para>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
|
||||
<literal>BaseLdapPathAware</literal> interface. Secondly, a <literal>BaseLdapPathBeanPostProcessor</literal>
|
||||
<literal>BaseLdapNameAware</literal> interface. Secondly, a <literal>BaseLdapPathBeanPostProcessor</literal>
|
||||
needs to be defined in the application context</para>
|
||||
<example>
|
||||
<title>Implementing <literal>BaseLdapPathAware</literal></title>
|
||||
|
||||
<title>Implementing <literal>BaseLdapNameAware</literal></title>
|
||||
<programlisting>package com.example.service;
|
||||
|
||||
public class PersonService implements PersonService, <emphasis role="bold">BaseLdapPathAware</emphasis> {
|
||||
public class PersonService implements PersonService, <emphasis role="bold">BaseLdapNameAware</emphasis> {
|
||||
...
|
||||
<emphasis role="bold">private DistinguishedName basePath;
|
||||
<emphasis role="bold">private LdapName basePath;
|
||||
|
||||
public void setBaseLdapPath(DistinguishedName basePath) {
|
||||
public void setBaseLdapPath(LdapName basePath) {
|
||||
this.basePath = basePath;
|
||||
}</emphasis>
|
||||
...
|
||||
private DistinguishedName getFullPersonDn(Person person) {
|
||||
return new DistinguishedName(<emphasis role="bold">basePath</emphasis>).append(person.getDn());
|
||||
private LdapName getFullPersonDn(Person person) {
|
||||
return LdapNameBuilder.newInstance(<emphasis role="bold">basePath</emphasis>)
|
||||
.append(person.getDn())
|
||||
.build();
|
||||
}
|
||||
...
|
||||
}</programlisting>
|
||||
@@ -321,6 +321,7 @@ public class PersonService implements PersonService, <emphasis role="bold">BaseL
|
||||
<para>The default behaviour of the <literal>BaseLdapPathBeanPostProcessor</literal> is to use the base path of the single
|
||||
defined <literal>BaseLdapPathSource</literal> (<literal>AbstractContextSource</literal> )in the <literal>ApplicationContext</literal>.
|
||||
If more than one <literal>BaseLdapPathSource</literal> is defined, you will need to specify which one to use with the
|
||||
<literal>baseLdapPathSourceName</literal> property.</para>
|
||||
<literal>baseLdapPathSourceName</literal> property.
|
||||
</para>
|
||||
</sect1>
|
||||
</chapter>
|
||||
|
||||
@@ -59,31 +59,31 @@ public class PersonDaoImpl implements PersonDao {
|
||||
<para>The above code shows that it is possible to retrieve the attributes
|
||||
directly by name, without having to go through the
|
||||
<literal>Attributes</literal> and <literal>BasicAttribute</literal>
|
||||
classes. This is particularly useful when working with multi-value attributes. Extracting values from
|
||||
multi-value attributes normally requires looping through a <literal>NamingEnumeration</literal> of
|
||||
attribute values returned from the <literal>Attributes</literal> implementation. The
|
||||
<literal>DirContextAdapter</literal> can do this for you, using the <literal>getStringAttributes()</literal>
|
||||
classes. This is particularly useful when working with multi-value attributes. Extracting values from
|
||||
multi-value attributes normally requires looping through a <literal>NamingEnumeration</literal> of
|
||||
attribute values returned from the <literal>Attributes</literal> implementation. The
|
||||
<literal>DirContextAdapter</literal> can do this for you, using the <literal>getStringAttributes()</literal>
|
||||
or <literal>getObjectAttributes()</literal> methods:</para>
|
||||
<example>
|
||||
<title>Getting multi-value attribute values using <literal>getStringAttributes()</literal></title>
|
||||
|
||||
<programlisting>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
|
||||
<emphasis role="bold">p.setRoleNames(context.getStringAttributes("roleNames"));</emphasis>
|
||||
return p;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
|
||||
<sect2>
|
||||
<title>The AbstractContextMapper</title>
|
||||
<example>
|
||||
<title>Getting multi-value attribute values using <literal>getStringAttributes()</literal></title>
|
||||
|
||||
<programlisting>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
|
||||
<emphasis role="bold">p.setRoleNames(context.getStringAttributes("roleNames"));</emphasis>
|
||||
return p;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
|
||||
<sect2>
|
||||
<title>The AbstractContextMapper</title>
|
||||
<para>Spring LDAP provides an abstract base implementation of <literal>ContextMapper</literal>,
|
||||
<literal>AbstractContextMapper</literal>. This automatically takes care of the casting of the supplied
|
||||
<literal>Object</literal> parameter to <literal>DirContexOperations</literal>.
|
||||
@@ -104,13 +104,13 @@ public class PersonDaoImpl implements PersonDao {
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
</sect2>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>Binding and Modifying Using DirContextAdapter</title>
|
||||
|
||||
<para>While very useful when extracting attribute values, <literal>DirContextAdapter</literal> is even more
|
||||
<para>While very useful when extracting attribute values, <literal>DirContextAdapter</literal> is even more
|
||||
powerful for hiding attribute details when binding and modifying data.</para>
|
||||
|
||||
<sect2>
|
||||
@@ -141,14 +141,14 @@ public class PersonDaoImpl implements PersonDao {
|
||||
}</programlisting>
|
||||
</example>
|
||||
|
||||
<para>Note that we use the <literal>DirContextAdapter</literal> instance
|
||||
as the second parameter to bind, which should be a <literal>Context</literal>.
|
||||
<para>Note that we use the <literal>DirContextAdapter</literal> instance
|
||||
as the second parameter to bind, which should be a <literal>Context</literal>.
|
||||
The third parameter is <literal>null</literal>, since we're not using any
|
||||
<literal>Attributes</literal>.</para>
|
||||
<para>Also note the use of the <literal>setAttributeValues()</literal> method when setting the
|
||||
<literal>objectclass</literal> attribute values. The <literal>objectclass</literal> 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 <literal>setAttributeValues()</literal> mehtod you can
|
||||
<literal>Attributes</literal>.</para>
|
||||
<para>Also note the use of the <literal>setAttributeValues()</literal> method when setting the
|
||||
<literal>objectclass</literal> attribute values. The <literal>objectclass</literal> 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 <literal>setAttributeValues()</literal> mehtod you can
|
||||
have <literal>DirContextAdapter</literal> handle that work for you.</para>
|
||||
</sect2>
|
||||
|
||||
@@ -157,11 +157,11 @@ public class PersonDaoImpl implements PersonDao {
|
||||
|
||||
<para>The code for a <literal>rebind</literal> would be pretty much
|
||||
identical to <xref linkend="example-binding-contextmapper" />, except
|
||||
that the method called would be <literal>rebind</literal>. As we saw in
|
||||
<xref linkend="modify-modifyAttributes"/> a more correct approach would be to
|
||||
build a <literal>ModificationItem</literal> 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 <literal>rebind</literal>. As we saw in
|
||||
<xref linkend="modify-modifyAttributes"/> a more correct approach would be to
|
||||
build a <literal>ModificationItem</literal> 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 <literal>DirContextAdapter</literal> can help you with; the
|
||||
<literal>DirContextAdapter</literal> 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 {
|
||||
<emphasis role="bold">ldapTemplate.modifyAttributes(context);</emphasis>
|
||||
}
|
||||
}</programlisting>
|
||||
</example>
|
||||
<para>When no mapper is passed to a <literal>ldapTemplate.lookup()</literal> operation,
|
||||
the result will be a <literal>DirContextAdapter</literal> instance.
|
||||
While the <literal>lookup</literal> method returns an <literal>Object</literal>, the convenience
|
||||
method <literal>lookupContext</literal> method automatically casts the return value to
|
||||
</example>
|
||||
<para>When no mapper is passed to a <literal>ldapTemplate.lookup()</literal> operation,
|
||||
the result will be a <literal>DirContextAdapter</literal> instance.
|
||||
While the <literal>lookup</literal> method returns an <literal>Object</literal>, the convenience
|
||||
method <literal>lookupContext</literal> method automatically casts the return value to
|
||||
a <literal>DirContextOperations</literal> (the interface that <literal>DirContextAdapter</literal> implements.</para>
|
||||
<para>The observant reader will see that we have duplicated code in the
|
||||
<literal>create</literal> and <literal>update</literal> methods. This
|
||||
@@ -241,18 +241,17 @@ public class PersonDaoImpl implements PersonDao {
|
||||
<title>A complete PersonDao class</title>
|
||||
|
||||
<programlisting>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) {
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
<para><token>LdapAttribute</token> objects represent options as a
|
||||
<token>Set<String></token>. The DN support added to the
|
||||
<token>LdapAttributes</token> object employs the
|
||||
<token>org.springframework.ldap.core.DistinguishedName</token> class. </para>
|
||||
<token>javax.naming.ldap.LdapName</token> class. </para>
|
||||
</section>
|
||||
|
||||
<section id="ldif-parsing-parser">
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
<para><programlisting>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();
|
||||
|
||||
Reference in New Issue
Block a user