directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From fel...@apache.org
Subject svn commit: r985874 - in /directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide: ./ images/
Date Mon, 16 Aug 2010 11:19:50 GMT
Author: felixk
Date: Mon Aug 16 11:19:50 2010
New Revision: 985874

URL: http://svn.apache.org/viewvc?rev=985874&view=rev
Log:
Start with advanced-user-guide

Added:
    directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/chapter-extending-the-server.xml
  (with props)
    directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/helloWorldEntryEditor.png
  (with props)
    directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/helloWorldLDAPBrowser.png
  (with props)
    directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/helloWorld_UML.png
  (with props)
    directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/passwordHashInterceptor_UML.png
  (with props)
    directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/passwordHashInterceptor_entryEditor.png
  (with props)
    directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/passwordHashInterceptor_modificationLog.png
  (with props)
    directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/passwordHashInterceptor_passwordEditor.png
  (with props)
Modified:
    directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/book.xml

Modified: directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/book.xml
URL: http://svn.apache.org/viewvc/directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/book.xml?rev=985874&r1=985873&r2=985874&view=diff
==============================================================================
--- directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/book.xml (original)
+++ directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/book.xml Mon Aug 16 11:19:50
2010
@@ -74,7 +74,8 @@ under the License.</literallayout>
     href="chapter-embedding-apacheds.xml" />
   <xi:include
     href="chapter-protocol-providers.xml" />
-
+  <xi:include
+    href="chapter-extending-the-server.xml" />
   <xi:include
     href="chapter-partitioning-replication.xml" />
   <xi:include

Added: directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/chapter-extending-the-server.xml
URL: http://svn.apache.org/viewvc/directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/chapter-extending-the-server.xml?rev=985874&view=auto
==============================================================================
--- directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/chapter-extending-the-server.xml
(added)
+++ directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/chapter-extending-the-server.xml
Mon Aug 16 11:19:50 2010
@@ -0,0 +1,942 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license
agreements. See the NOTICE file 
+  distributed with this work for additional information regarding copyright ownership. The
ASF licenses this file to you under 
+  the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance
with the License. You may 
+  obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required
by applicable law or agreed to 
+  in writing, software distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF 
+  ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under 
+  the License. -->
+<chapter
+  version="5.0"
+  xmlns="http://docbook.org/ns/docbook"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:xi="http://www.w3.org/2001/XInclude"
+  xmlns:ns5="http://www.w3.org/2000/svg"
+  xmlns:ns4="http://www.w3.org/1998/Math/MathML"
+  xmlns:ns3="http://www.w3.org/1999/xhtml"
+  xml:lang="en">
+  <title>Extending the server</title>
+  <important>
+    <para>Work in progress</para>
+  </important>
+  <section
+    id="How to write a simple custom partition for ApacheDS">
+    <title>How to write a simple custom partition for ApacheDS</title>
+    <important>
+      <title>Be Careful</title>
+      <para>Work in progress. Any feedback highly appreciated!</para>
+    </important>
+    <tip>
+      <title>ApacheDS 1.5.5</title>
+      <para>This site was updated for ApacheDS 1.5.5.</para>
+    </tip>
+    <para>On the mailing list, people ask regularly on how to write a custom partition.
If you simply plan to add
+      another suffix to ApacheDS (besides dc=example,dc=com, for instance) in order to store
data, it is not necessary
+      to write any code. You can simply add some lines to the configuration. The following
is for developers who plan to
+      implement another storage mechanism than the provided default.</para>
+    <itemizedlist>
+      <listitem>
+        <xref
+          linkend="What exactly is a partition?" />
+      </listitem>
+      <listitem>
+        <xref
+          linkend="Hello world. A minimal partition" />
+        <itemizedlist
+          mark="opencircle">
+          <listitem>
+            <xref
+              linkend="The sources Hello world" />
+          </listitem>
+          <listitem>
+            <xref
+              linkend="Implementing the class HelloWorldPartition Hello world" />
+          </listitem>
+          <listitem>
+            <xref
+              linkend="Using the partition Hello world" />
+          </listitem>
+          <listitem>
+            <xref
+              linkend="Verification Hello world" />
+          </listitem>
+        </itemizedlist>
+      </listitem>
+      <listitem>
+        <xref
+          linkend="To be continued" />
+      </listitem>
+    </itemizedlist>
+    <section
+      id="What exactly is a partition?">
+      <title>What exactly is a partition?</title>
+      <para>
+        Within ApacheDS, a partition is a physically distinct store for a subset of the entries
contained within the
+        server. A partition can be implemented using any storage mechanism or can even be
backed in memory. The default
+        storage mechanism for a partition is
+        <link
+          xlink:href="http://jdbm.sourceforge.net/">JDBM</link>
+        .
+      </para>
+      <para>
+        Implementing your own partition is basically implementing the
+        <emphasis>Partition</emphasis>
+        interface from the
+        <emphasis>org.apache.directory.server.core.partition</emphasis>
+        package. Please note that this is not an easy task. Nevertheless I
+        try to give you a starting point with some
+        simple examples.
+      </para>
+    </section>
+    <section
+      id="Hello world. A minimal partition">
+      <title>Hello world. A minimal partition</title>
+      <para>
+        Let's start with a minimal partition, the
+        <link
+          xlink:href="http://en.wikipedia.org/wiki/Hello_world_program">hello world</link>
+        . Minimal means here, that it is possible to add it to ApacheDS and see it with an
LDAP browser. The partition
+        ...
+      </para>
+      <itemizedlist>
+        <listitem>
+          <para>
+            correctly implements the
+            <emphasis>Partition</emphasis>
+            interface
+          </para>
+        </listitem>
+        <listitem>
+          <para>is pluggable in the server (embedded and declarative in the configuration)</para>
+        </listitem>
+        <listitem>
+          <para>
+            is visible for clients like
+            <emphasis>ldapsearch</emphasis>
+            or Apache Directory Studio
+          </para>
+        </listitem>
+        <listitem>
+          <para>contains one entry, which contains the famous "hello, world" message
in an attribute value</para>
+        </listitem>
+        <listitem>
+          <para>does not support any modification operations like delete, add etc.</para>
+        </listitem>
+        <listitem>
+          <para>does not take account of filters in search requests, ...</para>
+        </listitem>
+      </itemizedlist>
+      <section
+        id="The sources Hello world">
+        <title>The sources</title>
+        <para>
+          Currently, the sources are checked in here
+          <itemizedlist>
+            <listitem>
+              <para>
+                <link
+                  xlink:href="http://svn.apache.org/repos/asf/directory/sandbox/szoerner/helloWorldPartition">http://svn.apache.org/repos/asf/directory/sandbox/szoerner/helloWorldPartition</link>
+              </para>
+            </listitem>
+          </itemizedlist>
+        </para>
+        <para>In order to build it, simply check it out and type "mvn install".</para>
+      </section>
+      <section
+        id="Implementing the class HelloWorldPartition Hello world">
+        <title>Implementing the class HelloWorldPartition</title>
+        <para>The following UML class diagram depicts the structure of the little example.</para>
+        <figure
+          id="Hello World UML figure">
+          <title>Hello World UML</title>
+          <mediaobject>
+            <imageobject>
+              <imagedata
+                fileref="images/helloWorld_UML.png" />
+            </imageobject>
+          </mediaobject>
+        </figure>
+        <para>
+          In order to be a partition, class
+          <emphasis>HelloWorldPartition</emphasis>
+          implements the corresponding interface from
+          <emphasis>org.apache.directory.server.core.partition</emphasis>
+          . It has an association to it's only entry (which will hold the
+          "hello, world" method). This entry is created
+          in the
+          <emphasis>init</emphasis>
+          life cycle method of the partition, which looks like
+          this:
+        </para>
+        <programlisting><![CDATA[
+...
+public void init(DirectoryService core) throws Exception {
+                        
+  // Create LDAP DN
+  suffixDn = new LdapDN(suffix);
+  suffixDn.normalize(core.getRegistries().getAttributeTypeRegistry().getNormalizerMapping());
+  Rdn rdn = suffixDn.getRdn();
+        
+  // Create the only entry in this partition
+  ServerEntry entry = new DefaultServerEntry(core
+          .getRegistries(), this.suffixDn);
+  entry.put(SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC,
+                SchemaConstants.ORGANIZATIONAL_UNIT_OC);        
+  entry.put(SchemaConstants.OU_AT, rdn.getUpValue().toString());
+  entry.put("description", "hello, world", "a minimal partition");
+        
+  this.helloEntry = entry;
+}
+...
+        ]]></programlisting>
+        <para>
+          We assume that the suffix starts with "ou=" in order to create an entry of object
class organizational
+          unit. If
+          someone tries to set a suffix which starts with another attribute for the RDN,
the
+          <emphasis>setSuffix</emphasis>
+          will
+          throw an exception.
+        </para>
+        <para>
+          The
+          <emphasis>Partition</emphasis>
+          interface requires to implement many methods for all the operations a partition
should
+          support (adding,
+          deleting, modifying entries ...). Due to the fact, that this is a read only partition,
the
+          implementation in
+          our case is minimalistic. Here is the
+          <emphasis>delete</emphasis>
+          method as an example.
+        </para>
+        <programlisting><![CDATA[
+...
+public void delete(DeleteOperationContext opContext)
+        throws LdapOperationNotSupportedException {
+    throw new LdapOperationNotSupportedException(
+            MODIFICATION_NOT_ALLOWED_MSG, ResultCodeEnum.UNWILLING_TO_PERFORM);
+}
+...
+        ]]></programlisting>
+        <para>Although this example should be minimal, some methods need more attention.
At least if we want to see the
+          partitiion in an LDAP and not only in the error logs ...</para>
+        <para>
+          The important methods are
+          <emphasis>hasEntry</emphasis>
+          ,
+          <emphasis>lookup</emphasis>
+          and
+          <emphasis>search</emphasis>
+          . The following code is the search method. Please
+          note that it ignores search scopes other than
+          <emphasis>BASE</emphasis>
+          and search filters completely in order to have simple code.
+        </para>
+        <programlisting><![CDATA[
+public EntryFilteringCursor search(SearchOperationContext ctx)
+        throws Exception {
+
+    if (ctx.getDn().equals(this.suffixDn)) {
+        switch (ctx.getScope()) {
+        case OBJECT:
+            // return a result with the only entry we have
+            return new BaseEntryFilteringCursor(
+                    new SingletonCursor<ServerEntry>(this.helloEntry), ctx);
+        }
+    }
+
+    // return an empty result
+    return new BaseEntryFilteringCursor(new EmptyCursor<ServerEntry>(), ctx);
+}
+        ]]></programlisting>
+        <para>
+          For the other methods, take a look in the
+          <link
+            xlink:href="http://svn.apache.org/repos/asf/directory/sandbox/szoerner/helloWorldPartition/src/main/java/org/apache/directory/samples/partition/hello/HelloWorldPartition.java">source
code</link>
+          .
+        </para>
+      </section>
+      <section
+        id="Using the partition Hello world">
+        <title>Using the partition</title>
+        <section
+          id="Embedded mode Using the partition Hello world">
+          <title>Embedded mode</title>
+          <programlisting><![CDATA[
+package org.apache.directory.samples.partition.hello;
+
+import org.apache.directory.server.core.DefaultDirectoryService;
+import org.apache.directory.server.core.DirectoryService;
+import org.apache.directory.server.ldap.LdapServer;
+import org.apache.directory.server.protocol.shared.transport.TcpTransport;
+
+/**
+ * Starts the server with the HelloWorld partition.
+ */
+public class Main {
+
+    public static void main(String[] args) throws Exception {
+
+        DirectoryService directoryService = new DefaultDirectoryService();
+        directoryService.setShutdownHookEnabled(true);
+
+        LdapServer ldapServer = new LdapServer();
+        ldapServer.setDirectoryService(directoryService);
+        ldapServer.setAllowAnonymousAccess(true);
+
+        TcpTransport ldapTransport = new TcpTransport(10389);
+        ldapServer.setTransports(ldapTransport);
+
+        HelloWorldPartition helloPartition = new HelloWorldPartition();
+        helloPartition.setSuffix("ou=helloWorld");
+        helloPartition.init(directoryService);
+
+        directoryService.addPartition(helloPartition);
+
+        directoryService.startup();
+        ldapServer.start();
+    }
+}
+        ]]></programlisting>
+        </section>
+        <section
+          id="Adding it to a server.xml file Using the partition Hello world">
+          <title>Adding it to a server.xml file</title>
+          <para>
+            In order to use the partition in a standard installation of ApacheDS, simply
add it to the
+            <emphasis>server.xml</emphasis>
+            configuration. Provide a "native" Spring bean like this.
+          </para>
+          <programlisting>
+            <emphasis
+              role="bold">server.xml</emphasis><![CDATA[
+<spring:beans xmlns:spring="http://xbean.apache.org/schemas/spring/1.0" 
+              xmlns:s="http://www.springframework.org/schema/beans"
+              xmlns="http://apacheds.org/config/1.0">
+
+  ...
+   <defaultDirectoryService ...>
+     ...
+     <partitions>
+     ...
+      <s:bean 
+          id="helloPartition" 
+          class="org.apache.directory.samples.partition.hello.HelloWorldPartition">
+        <s:property name="suffix" value="ou=helloWorld" />
+      </s:bean>
+    </partitions>
+   ...
+  </defaultDirectoryService>
+...
+          ]]></programlisting>
+          <para>
+            Note that the class
+            <emphasis>HelloWorldPartition</emphasis>
+            has to be in the class path of the server. Without, starting the
+            server leads to a
+            <emphasis>ClassNotFoundException</emphasis>
+            .
+            You can copy the jar file which results from the build to the
+            lib/ext directory.
+          </para>
+        </section>
+      </section>
+      <section
+        id="Verification Hello world">
+        <title>Verification</title>
+        <para>
+          After adding the HelloWorldPartition to the directory service like above (embedded
or via configuration in
+          <emphasis>server.xml</emphasis>
+          ), you can browse it with an LDAP browser like the one from Apache Directory Studio.
Here are some
+          screen
+          shots.
+        </para>
+        <figure
+          id="Hello World LDAP Browser figure">
+          <title>Hello World LDAP Browser</title>
+          <mediaobject>
+            <imageobject>
+              <imagedata
+                fileref="images/helloWorldLDAPBrowser.png" />
+            </imageobject>
+          </mediaobject>
+        </figure>
+        <figure
+          id="Hello World Entry Editor figure">
+          <title>Hello World Entry Editor</title>
+          <mediaobject>
+            <imageobject>
+              <imagedata
+                fileref="images/helloWorldEntryEditor.png" />
+            </imageobject>
+          </mediaobject>
+        </figure>
+        <para>Of course using a command line tool works as well ...</para>
+        <screen><![CDATA[
+$ ldapsearch -h localhost -p 10389 -D "uid=admin,ou=system" -w secret \\
+    -b "" -s base "(objectclass=*)" namingContexts
+version: 1
+dn:
+namingContexts: ou=system
+namingContexts: ou=helloWorld
+namingContexts: ou=schema
+$
+$ ldapsearch -h localhost -p 10389 -D "uid=admin,ou=system" -w secret \\
+    -b "ou=helloWorld" -s base "(objectclass=*)"
+
+version: 1
+dn: ou=helloWorld
+objectClass: organizationalUnit
+objectClass: top
+description: hello, world
+description: a minimal partition
+ou: helloWorld
+$
+        ]]></screen>
+      </section>
+    </section>
+    <section
+      id="To be continued">
+      <title>To be continued</title>
+      <para>We plan to add more sophistic examples on this topic in the near feature.
Stay tuned on the mailing lists.
+      </para>
+      <para>
+        Here is an older example on the topic:<?lienbreak?>
+        <link
+          xlink:href="http://svn.apache.org/viewvc/directory/sandbox/akarasulu/custom-partition">http://svn.apache.org/viewvc/directory/sandbox/akarasulu/custom-partition</link>
+      </para>
+      <para>It is outdated, but may still inspire you.</para>
+    </section>
+  </section>
+  <section
+    id="Implementing a simple custom Interceptor">
+    <title>Implementing a simple custom Interceptor</title>
+    <tip>
+      <title>ApacheDS 1.5.5</title>
+      <para>This site was updated for ApacheDS 1.5.5.</para>
+    </tip>
+    <para>The following is for developers who plan to implement their own interceptors
in order to extend or modify the
+      functionality of Apache Directory Server. It contains a simple example as a starting
point.</para>
+    <itemizedlist>
+      <listitem>
+        <xref
+          linkend="What exactly is an interceptor?" />
+      </listitem>
+      <listitem>
+        <xref
+          linkend="Password hash. A simple interceptor" />
+        <itemizedlist
+          mark="opencircle">
+          <listitem>
+            <xref
+              linkend="The sources Password hash" />
+          </listitem>
+          <listitem>
+            <xref
+              linkend="Implementing the class PasswordHashInterceptor Password hash" />
+          </listitem>
+          <listitem>
+            <xref
+              linkend="Using the interceptor Password hash" />
+          </listitem>
+          <listitem>
+            <xref
+              linkend="Verification Password hash" />
+          </listitem>
+          <listitem>
+            <xref
+              linkend="Limitations of the example Password hash" />
+          </listitem>
+        </itemizedlist>
+      </listitem>
+      <listitem>
+        <xref
+          linkend="Further reading Implementing a simple custom Interceptor" />
+      </listitem>
+    </itemizedlist>
+    <section
+      id="What exactly is an interceptor?">
+      <title>What exactly is an interceptor?</title>
+      <para>
+        An interceptor filters method calls performed on on the
+        <emphasis>DefaultPartitionNexus</emphasis>
+        just like Servlet filters do. The ApacheDS configuration contains a chain of filters
performing several tasks.
+        In order to illustrate this, here is the list of interceptors from the default server
configuration of ApacheDS
+        1.5.5
+      </para>
+      <itemizedlist>
+        <listitem>
+          <para>org.apache.directory.server.core.normalization.NormalizationInterceptor</para>
+        </listitem>
+        <listitem>
+          <para>org.apache.directory.server.core.authn.AuthenticationInterceptor</para>
+        </listitem>
+        <listitem>
+          <para>org.apache.directory.server.core.referral.ReferralInterceptor</para>
+        </listitem>
+        <listitem>
+          <para>org.apache.directory.server.core.authz.AciAuthorizationInterceptor</para>
+        </listitem>
+        <listitem>
+          <para>org.apache.directory.server.core.authz.DefaultAuthorizationInterceptor</para>
+        </listitem>
+        <listitem>
+          <para>org.apache.directory.server.core.exception.ExceptionInterceptor</para>
+        </listitem>
+        <listitem>
+          <para>org.apache.directory.server.core.changelog.ChangeLogInterceptor</para>
+        </listitem>
+        <listitem>
+          <para>org.apache.directory.server.core.operational.OperationalAttributeInterceptor</para>
+        </listitem>
+        <listitem>
+          <para>org.apache.directory.server.core.schema.SchemaInterceptor</para>
+        </listitem>
+        <listitem>
+          <para>org.apache.directory.server.core.subtree.SubentryInterceptor</para>
+        </listitem>
+        <listitem>
+          <para>org.apache.directory.server.core.collective.CollectiveAttributeInterceptor</para>
+        </listitem>
+        <listitem>
+          <para>org.apache.directory.server.core.event.EventInterceptor</para>
+        </listitem>
+        <listitem>
+          <para>org.apache.directory.server.core.trigger.TriggerInterceptor</para>
+        </listitem>
+        <listitem>
+          <para>org.apache.directory.server.core.journal.JournalInterceptor</para>
+        </listitem>
+      </itemizedlist>
+      <para>
+        Interceptors should usually pass the control of current invocation to the next interceptor
by calling an
+        appropriate method on
+        <emphasis>NextInterceptor</emphasis>
+        . The flow control is returned when the next interceptor's filter method
+        returns. You can therefore implement
+        pre-, post-, around- invocation handler by how you place the statement.
+      </para>
+      <para>Interceptors are a powerful way to extend and modify the server behavior.
But be warned. A mistakenly
+        written interceptor may lead to a dis-functional or corrupt server. </para>
+    </section>
+    <section
+      id="Password hash. A simple interceptor">
+      <title>Password hash. A simple interceptor</title>
+      <para>In order to demonstrate how to write an interceptor, here is a simple but
realistic example. The following
+        requirement should be fulfilled by an interceptor.</para>
+      <itemizedlist>
+        <listitem>
+          <para>No user password should be stored in the directory in clear text.</para>
+        </listitem>
+      </itemizedlist>
+      <para>To be more concrete:</para>
+      <itemizedlist>
+        <listitem>
+          <para>
+            If a userpassword is set by an LDAP client in plain text, a
+            <link
+              xlink:href="http://en.wikipedia.org/wiki/Cryptographic_hash_function">message
digest algorithm</link>
+            should be applied to the value, and the one-way encrypted value should be stored
+          </para>
+        </listitem>
+        <listitem>
+          <para>the algorithm should be applied if new entries are created or existing
entries are modified (hence
+            modify and add operations will be intercepted)</para>
+        </listitem>
+        <listitem>
+          <para>If the value given by the client is already provided in hashed form,
nothing happens, and the given
+            value is stored in the directory without modification</para>
+        </listitem>
+      </itemizedlist>
+      <section
+        id="The sources Password hash">
+        <title>The sources</title>
+        <para>Currently, the sources are checked in here</para>
+        <itemizedlist>
+          <listitem>
+            <para>
+              <link
+                xlink:href="http://svn.apache.org/repos/asf/directory/sandbox/szoerner/passwordHashInterceptor">http://svn.apache.org/repos/asf/directory/sandbox/szoerner/passwordHashInterceptor</link>
+            </para>
+          </listitem>
+        </itemizedlist>
+        <para>In order to build it, simply check it out and type "mvn install".</para>
+      </section>
+      <section
+        id="Implementing the class PasswordHashInterceptor Password hash">
+        <title>Implementing the class PasswordHashInterceptor</title>
+        <para>The following UML class diagram depicts the structure of the little example.
Classes in white are given by
+          Apache Directory Server as extension points. The two gray classes comprise the
example interceptor.</para>
+        <figure
+          id="PasswordHash Interceptor UML figure">
+          <title>PasswordHash Interceptor UML</title>
+          <mediaobject>
+            <imageobject>
+              <imagedata
+                fileref="images/passwordHashInterceptor_UML.png" />
+            </imageobject>
+          </mediaobject>
+        </figure>
+        <para>
+          The class
+          <emphasis>HashTools</emphasis>
+          contains two simple methods w.r.t. hashing.
+          <emphasis>isAlreadyHashed</emphasis>
+          detects whether a value
+          has already been hashed with a known message digest algorithm.
+          <emphasis>applyHashAlgorithm</emphasis>
+          applies a hash algorithm to
+          a sequence of bytes. See the source code and the unit tests of this class for
+          details, it has not that much to
+          do with the interceptor stuff.
+        </para>
+        <para>
+          The central class is
+          <emphasis>PasswordHashInterceptor</emphasis>
+          . Every interceptor has to implement the
+          <emphasis>Interceptor</emphasis>
+          interface
+          from package
+          <emphasis>org.apache.directory.server.core.interceptor</emphasis>
+          .
+          <emphasis>PasswordHashInterceptor</emphasis>
+          does so by extended the
+          convenience class
+          <emphasis>BaseInterceptor</emphasis>
+          from the same package.
+        </para>
+        <para>
+          The property
+          <emphasis>hashAlgorithm</emphasis>
+          allows to configure the alhorithm used for hashing the passwords. It defaults
+          to
+          <link
+            xlink:href="http://en.wikipedia.org/wiki/MD5">MD5 (Message-Digest algorithm
5)</link>
+          . The property
+          <emphasis>passwordAttributeName</emphasis>
+          allows configuration of the attribute
+          type which stores the user password. Its value will be hashed if needed.
+          The property defaults to
+          "userPassword", which is quite common and used for instance in the
+          <link
+            xlink:href="http://www.ietf.org/rfc/rfc2798.txt">inetOrgPerson</link>
+          object class.
+        </para>
+        <para>
+          The most interesting methods of the class are
+          <emphasis>add</emphasis>
+          and
+          <emphasis>modify</emphasis>
+          . They intercept the requests ans modify the
+          attribute values, if needed. See below the complete source code of
+          the class.
+        </para>
+        <programlisting><![CDATA[
+package org.apache.directory.samples.interceptor.pwdhash;
+
+import static org.apache.directory.samples.interceptor.pwdhash.HashTools.applyHashAlgorithm;
+import static org.apache.directory.samples.interceptor.pwdhash.HashTools.isAlreadyHashed;
+
+import java.util.List;
+
+import org.apache.directory.server.core.entry.ClonedServerEntry;
+import org.apache.directory.server.core.interceptor.BaseInterceptor;
+import org.apache.directory.server.core.interceptor.NextInterceptor;
+import org.apache.directory.server.core.interceptor.context.AddOperationContext;
+import org.apache.directory.server.core.interceptor.context.ModifyOperationContext;
+import org.apache.directory.shared.ldap.entry.EntryAttribute;
+import org.apache.directory.shared.ldap.entry.Modification;
+import org.apache.directory.shared.ldap.entry.ModificationOperation;
+
+public class PasswordHashInterceptor extends BaseInterceptor {
+
+    private String hashAlgorithm = "MD5";
+
+    private String passwordAttributeName = "userPassword";
+
+    public void setHashAlgorithm(String hashAlgorithm) {
+        this.hashAlgorithm = hashAlgorithm;
+    }
+
+    public void setPasswordAttributeName(String passwordAttributeName) {
+        this.passwordAttributeName = passwordAttributeName;
+    }
+
+    /**
+     * Intercepts the add operation in order to replace plain password values
+     * with hashed ones.
+     */
+    @Override
+    public void add(NextInterceptor next, AddOperationContext opContext)
+            throws Exception {
+
+        ClonedServerEntry entry = opContext.getEntry();
+        EntryAttribute attribute = entry.get(passwordAttributeName);
+        if (attribute != null) {
+            hashPasswordIfNeccessary(attribute);
+        }
+
+        super.add(next, opContext);
+    }
+
+    /**
+     * Intercepts the modify operation in order to replace plain password values
+     * with hashed ones.
+     */
+    @Override
+    public void modify(NextInterceptor next, ModifyOperationContext opContext)
+            throws Exception {
+
+        List<Modification> items = opContext.getModItems();
+        for (Modification modification : items) {
+            ModificationOperation operation = modification.getOperation();
+            if (operation == ModificationOperation.ADD_ATTRIBUTE
+                    || operation == ModificationOperation.REPLACE_ATTRIBUTE) {
+                EntryAttribute attribute = modification.getAttribute();
+                if (attribute.getId().equalsIgnoreCase(passwordAttributeName)) {
+                    hashPasswordIfNeccessary(attribute);
+                }
+            }
+        }
+        super.modify(next, opContext);
+    }
+
+    protected void hashPasswordIfNeccessary(EntryAttribute attribute) {
+        try {
+            byte[] password = attribute.getBytes();
+            if (!isAlreadyHashed(password)) {
+                byte[] hashed = applyHashAlgorithm(hashAlgorithm, password);
+                attribute.clear();
+                attribute.add(hashed);
+            }
+        } catch (Exception e) {
+            throw new RuntimeException("Password hash failed", e);
+        }
+    }
+}
+        ]]></programlisting>
+      </section>
+      <section
+        id="Using the interceptor Password hash">
+        <title>Using the interceptor</title>
+        <para>You may use a custom interceptor both in a standard ApacheDS installation
and in a server started
+          embedded.</para>
+        <section
+          id="Adding it to a standard server installation (server.xml) Using the interceptor">
+          <title>Adding it to a standard server installation (server.xml)</title>
+          <para>
+            In order to get the interceptor installed in a default installation of ApacheDS
1.5.5., just copy the
+            jar-File resulting from the Maven build, which contains the custom classes, to
+            <emphasis>APACHEDS_INSTALLDIR/lib/ext</emphasis>
+            .
+          </para>
+          <para>
+            After that, add the interceptor to the
+            <emphasis>server.xml</emphasis>
+            file in
+            <emphasis>APACHEDS_INSTALLDIR/conf/</emphasis>
+            . Make sure to backup
+            the file before your modifications. Within
+            <emphasis>server.xml</emphasis>
+            find the XML elements which list the interceptors. The
+            easiest way to add a custom interceptor is to add a
+            spring bean (namespace "s"). You mya set configuration
+            properties to the interceptor as well, if it supports
+            some.
+          </para>
+          <para>The following fragment shows the interceptor list with the example
interceptor added just behind
+            normalization. For demonstration purposes, the hash algorithm is set to "MD5"
(which is the default of our
+            interceptor anyway).</para>
+          <programlisting><![CDATA[
+...
+<interceptors>
+  <normalizationInterceptor/>
+  <s:bean class="org.apache.directory.samples.interceptor.pwdhash.PasswordHashInterceptor">

+     <s:property name="hashAlgorithm" value="MD5" /> 
+  </s:bean>
+  <authenticationInterceptor/>
+  <referralInterceptor/>
+  <aciAuthorizationInterceptor/>
+  <defaultAuthorizationInterceptor/>
+  <exceptionInterceptor/>
+  <operationalAttributeInterceptor/>
+  ...
+</interceptors>
+...
+            ]]></programlisting>
+        </section>
+        <section
+          id="Embedded mode Using the interceptor">
+          <title>Embedded mode</title>
+          <para>
+            As an alternative, the following Java code starts an ApacheDS embedded in a main
method. The list of
+            interceptors is complemented with the example interceptor. We insert it exactly
behind the
+            <emphasis>NormalizingInterceptor</emphasis>
+            (the position is a little bit tricky to determine).
+          </para>
+          <programlisting><![CDATA[
+package org.apache.directory.samples.interceptor.pwdhash;
+
+import java.util.List;
+
+import org.apache.directory.server.core.DefaultDirectoryService;
+import org.apache.directory.server.core.DirectoryService;
+import org.apache.directory.server.core.interceptor.Interceptor;
+import org.apache.directory.server.core.normalization.NormalizationInterceptor;
+import org.apache.directory.server.ldap.LdapServer;
+import org.apache.directory.server.protocol.shared.transport.TcpTransport;
+
+/**
+ * Main class which starts an embedded server with the interceptor inserted into
+ * the chain.
+ */
+public class Main {
+
+    public static void main(String[] args) throws Exception {
+
+        DirectoryService directoryService = new DefaultDirectoryService();
+        directoryService.setShutdownHookEnabled(true);
+
+        List<Interceptor> interceptors = directoryService.getInterceptors();
+
+        // Find Normalization interceptor in chain
+        int insertionPosition = -1;
+        for (int pos = 0; pos < interceptors.size(); ++pos) {
+            Interceptor interceptor = interceptors.get(pos);
+            if (interceptor instanceof NormalizationInterceptor) {
+                insertionPosition = pos;
+            }
+        }
+
+        // insert our new interceptor just behind
+        interceptors.add(insertionPosition + 1, new PasswordHashInterceptor());
+        directoryService.setInterceptors(interceptors);
+
+        LdapServer ldapServer = new LdapServer();
+        ldapServer.setDirectoryService(directoryService);
+        ldapServer.setAllowAnonymousAccess(true);
+
+        TcpTransport ldapTransport = new TcpTransport(10389);
+        ldapServer.setTransports(ldapTransport);
+
+        directoryService.startup();
+        ldapServer.start();
+    }
+}
+            ]]></programlisting>
+        </section>
+      </section>
+      <section
+        id="Verification Password hash">
+        <title>Verification</title>
+        <para>Let's check whether our new interceptor does its job! In order to do
so, we use Apache Directory Studio
+          and connect to the server with the interceptor enabled (see above).</para>
+        <para>First we create a new entry with the following data, using "New Entry
..." within Studio.</para>
+        <programlisting><![CDATA[
+dn: cn=Kate Bush,ou=users,ou=system
+objectClass: person
+objectClass: top
+cn: Kate Bush
+sn: Bush
+        ]]></programlisting>
+        <para>
+          Then we add a new attribute
+          <emphasis>userPassword</emphasis>
+          in the entry editor. For the value, a special editor appears:
+        </para>
+        <figure
+          id="PasswordHash Interceptor PasswordEditor figure">
+          <title>PasswordHash Interceptor PasswordEditor</title>
+          <mediaobject>
+            <imageobject>
+              <imagedata
+                fileref="images/passwordHashInterceptor_passwordEditor.png" />
+            </imageobject>
+          </mediaobject>
+        </figure>
+        <para>Select "Plaintext" as the hash method and enter a new password. We selected
"secret" (see screen shot
+          above). After pressing OK, a modify operation is sent to the server, which will
be intercepted by our example
+          class.</para>
+        <figure
+          id="PasswordHash Interceptor ModificationLog figure">
+          <title>PasswordHash Interceptor ModificationLog</title>
+          <mediaobject>
+            <imageobject>
+              <imagedata
+                fileref="images/passwordHashInterceptor_modificationLog.png" />
+            </imageobject>
+          </mediaobject>
+        </figure>
+        <para>
+          After that, the value for
+          <emphasis>userPassword</emphasis>
+          is not "secret", but the MD5 digested value of it.
+        </para>
+        <figure
+          id="PasswordHash Interceptor EntryEditor figure">
+          <title>PasswordHash Interceptor EntryEditor</title>
+          <mediaobject>
+            <imageobject>
+              <imagedata
+                fileref="images/passwordHashInterceptor_entryEditor.png" />
+            </imageobject>
+          </mediaobject>
+        </figure>
+        <para>The user Kate Bush is still capable of authenticating with the password
"secret", because Apache Directory
+          Server supports authentication with passwords hashed with this algorithm. You can
verify this by connecting
+          with Studio and the using "cn=Kate Bush,ou=users,ou=system" as bind DN.</para>
+        <para>
+          Here it is demonstrated with the help of the
+          <emphasis>ldapsearch</emphasis>
+          command line tool. The result also shows that the
+          <emphasis>userPassword</emphasis>
+          value is hashed with MD5.
+        </para>
+        <screen><![CDATA[
+$ ldapsearch -h localhost -p 10389 -D "cn=Kate Bush,ou=users,ou=system" \\
+    -w secret  -b "ou=users,ou=system" -s one "(objectClass=*)"
+version: 1
+dn: cn=Kate Bush,ou=users,ou=system
+objectClass: person
+objectClass: top
+cn: Kate Bush
+sn: Bush
+userPassword: {MD5}Xr4ilOzQ4PCOq3aQ0qbuaQ==
+$
+        ]]></screen>
+      </section>
+      <section
+        id="Limitations of the example Password hash">
+        <title>Limitations of the example</title>
+        <para>This example is intended as a demonstration, on how to write your custom
interceptor. Don't consider it
+          bullet proof. It has not been tested under production conditions, etc.</para>
+        <para>At least the following limitation should be mentioned</para>
+        <itemizedlist>
+          <listitem>
+            <para>The default hash algorithm MD5 is considered weak.</para>
+          </listitem>
+          <listitem>
+            <para>Exception handling is poor. E.g. if someone configures an unsupported
hash algorithm, the interceptor
+              fails to create an appropriate LDAP error.</para>
+          </listitem>
+          <listitem>
+            <para>If a multivalued password attribute is used, the interceptor will
simply ignore that fact (does not
+              apply to userPassword as of RFC 2256).</para>
+          </listitem>
+        </itemizedlist>
+      </section>
+    </section>
+    <section
+      id="Further reading Implementing a simple custom Interceptor">
+      <title>Further reading</title>
+      <para>
+        Learn more about interceptors in
+        <xref
+          linkend="Interceptors" />
+        , check out the source code of some implementations of the
+        <emphasis>Interceptor</emphasis>
+        interface, and/or read the javadoc
+        comments.
+      </para>
+    </section>
+  </section>
+</chapter>
\ No newline at end of file

Propchange: directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/chapter-extending-the-server.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/chapter-extending-the-server.xml
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/helloWorldEntryEditor.png
URL: http://svn.apache.org/viewvc/directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/helloWorldEntryEditor.png?rev=985874&view=auto
==============================================================================
Binary file - no diff available.

Propchange: directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/helloWorldEntryEditor.png
------------------------------------------------------------------------------
    svn:mime-type = image/png

Added: directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/helloWorldLDAPBrowser.png
URL: http://svn.apache.org/viewvc/directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/helloWorldLDAPBrowser.png?rev=985874&view=auto
==============================================================================
Binary file - no diff available.

Propchange: directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/helloWorldLDAPBrowser.png
------------------------------------------------------------------------------
    svn:mime-type = image/png

Added: directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/helloWorld_UML.png
URL: http://svn.apache.org/viewvc/directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/helloWorld_UML.png?rev=985874&view=auto
==============================================================================
Binary file - no diff available.

Propchange: directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/helloWorld_UML.png
------------------------------------------------------------------------------
    svn:mime-type = image/png

Added: directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/passwordHashInterceptor_UML.png
URL: http://svn.apache.org/viewvc/directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/passwordHashInterceptor_UML.png?rev=985874&view=auto
==============================================================================
Binary file - no diff available.

Propchange: directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/passwordHashInterceptor_UML.png
------------------------------------------------------------------------------
    svn:mime-type = image/png

Added: directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/passwordHashInterceptor_entryEditor.png
URL: http://svn.apache.org/viewvc/directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/passwordHashInterceptor_entryEditor.png?rev=985874&view=auto
==============================================================================
Binary file - no diff available.

Propchange: directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/passwordHashInterceptor_entryEditor.png
------------------------------------------------------------------------------
    svn:mime-type = image/png

Added: directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/passwordHashInterceptor_modificationLog.png
URL: http://svn.apache.org/viewvc/directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/passwordHashInterceptor_modificationLog.png?rev=985874&view=auto
==============================================================================
Binary file - no diff available.

Propchange: directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/passwordHashInterceptor_modificationLog.png
------------------------------------------------------------------------------
    svn:mime-type = image/png

Added: directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/passwordHashInterceptor_passwordEditor.png
URL: http://svn.apache.org/viewvc/directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/passwordHashInterceptor_passwordEditor.png?rev=985874&view=auto
==============================================================================
Binary file - no diff available.

Propchange: directory/sandbox/felixk/apacheds-docs/src/advanced-user-guide/images/passwordHashInterceptor_passwordEditor.png
------------------------------------------------------------------------------
    svn:mime-type = image/png



Mime
View raw message