From commits-return-20347-apmail-directory-commits-archive=directory.apache.org@directory.apache.org Wed Nov 19 22:10:33 2008 Return-Path: Delivered-To: apmail-directory-commits-archive@www.apache.org Received: (qmail 68194 invoked from network); 19 Nov 2008 22:10:32 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 19 Nov 2008 22:10:32 -0000 Received: (qmail 31311 invoked by uid 500); 19 Nov 2008 22:10:41 -0000 Delivered-To: apmail-directory-commits-archive@directory.apache.org Received: (qmail 31264 invoked by uid 500); 19 Nov 2008 22:10:41 -0000 Mailing-List: contact commits-help@directory.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@directory.apache.org Delivered-To: mailing list commits@directory.apache.org Received: (qmail 31255 invoked by uid 99); 19 Nov 2008 22:10:41 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 19 Nov 2008 14:10:41 -0800 X-ASF-Spam-Status: No, hits=-1994.3 required=10.0 tests=ALL_TRUSTED,HTML_MESSAGE,MIME_HTML_ONLY X-Spam-Check-By: apache.org Received: from [140.211.11.140] (HELO brutus.apache.org) (140.211.11.140) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 19 Nov 2008 22:09:18 +0000 Received: from brutus (localhost [127.0.0.1]) by brutus.apache.org (Postfix) with ESMTP id A3B1D234C296 for ; Wed, 19 Nov 2008 14:10:03 -0800 (PST) Message-ID: <1842459887.1227132603669.JavaMail.www-data@brutus> Date: Wed, 19 Nov 2008 14:10:03 -0800 (PST) From: confluence@apache.org To: commits@directory.apache.org Subject: [CONF] Apache Directory Server v1.5: 1.2. Interceptors (page edited) MIME-Version: 1.0 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable X-Virus-Checked: Checked by ClamAV on apache.org
Page Edited : DIRxSRVx11 : 1.2. Interceptors

1.2. Interceptors has been edited by Emmanuel L=C3=83=C2=A9charny (Nov 19, 2008).

=20

= (View changes)

Content:
<= colgroup>=
3D""= Work in progress

This site is in the process of being reviewed and updated.

What is it?

The mechanism is a means for injecting and isolating orthogonal services= into calls against the nexus. The nexus is the hub used to route calls to = partitions to perform CRUD operations upon entries. By injecting these serv= ices at this level, partition implementators need not duplicate fuctionalit= y. Services such as authentication, authorization, schema checking, normali= zation, operational attribute maintenance and more are introduced using Int= erceptors. By using interceptors, partition implementors need not be concer= ned with these aspects and can focus on raw CRUD operations against their b= acking stores what ever they may be.

How does it work?

Before we talk more about interceptors we must quickly cover the JNDI pr= ovider implementation since it is somewhat related.

JNDI Implementation=

The JNDI implementation is composed of a set of JNDI Context implementat= ions, a ContextFactory implementation and a set of helper classes.

    =09
  • DeadContext
  • =09
  • JavaLdapSupport
  • =09
  • ServerContext
  • =09
  • ServerDirContext
  • =09
  • ServerLdapContext
  • =09
  • AbstractContextFactory
  • =09
  • CoreContextFactory
  • =09
  • ServerDirObjectFactory
  • =09
  • ServerDirStateFactory

Every JNDI Context implementation in the provider holds a dedicated refe= rence to a nexus proxy object. This proxy contains all the operation= s that the nexus contains. The proxy object is at the heart of the m= echanism. We will disuss it more after covering the rest of the JNDI provid= er.

Calls made against JNDI Contexts take relative names as arguments. These= names are relative to the distinguished name of the JNDI Context. Within t= he Context implementations these relative names are transformed into absolu= te distinguished names. The transformed names are used to make calls agains= t the proxy.

Additional processing may occur before or after a call is made by a cont= ext on its proxy to manage JNDI provider specific functions. One such examp= le is the handling of Java objects for serialization and the use of object = and state factories.

The nexus proxy ob= ject

As mentioned above, each Context that is created has a nexus proxy. The = proxy maintains a handle on the context as well.

The primary job of the proxy is to inject Interceptor based services. It= does so by invoking a chain of Interceptors managed by the system. Interce= ptors mirror the methods that are intercepted on the nexus interface. When = an intercepted method is invoked on the proxy, the proxy pushes an Invocati= on object on to the InvocationStack associated with the current executing T= hread. The proxy then calls the same method on a chain of Interceptors. The= results of the call are returned after the InvocationStack is popped.

The InvocationStack is used to track the calls being intercepted. Invoca= tion objects pushed onto the stack track the context making the call to the= proxy, the name of the intercepted call and its arguments. A stack is used= because in the case of Triggers, stored procedures may be invoked which op= erate against the DIT using JNDI. These JNDI calls will also be intercepted= . Their Invocation object will be stacked on top of the Invocation which ra= ised the Trigger. This way identities and context of operations can be trac= ked and used by the Trigger management system to prevent runnaway cascades = or to limit the cascade depth. There are other areas besides just triggers = where this stack will serve a purpose.

The InterceptorChain is a container of Interceptors which has the same o= r analogous methods as do Interceptors. These are for the interceptable met= hods. A call against the chain invokes the first Interceptor which then usu= ally invokes the next interceptor in the chain. An Interceptor need not cal= l the next interceptor however. It can raise an exception before making the= call to the next interceptor or it can completely bypass the rest of the c= hain by just returning before calling the next Interceptor. Interceptors ca= n preprocess the arguments, or perform other tasks before they invoke the n= ext Interceptor. They can also catch exceptions raised by other downstream = interceptors and respond to them to handle errors. Finally they can perform= post processing operations on the results of returned values from downstre= am Interceptors.

One might ask when is the call made against the actual nexus. This happe= ns using a special Interceptor which resides at the end of the chain. It ac= tually makes the call against the nexus and returns the results.

3D""

Interceptors can be seen as Servlet Filters : they can be added, removed= , bypassed either by configuration or, for embeded servers, on the fly.&nbs= p;

 

The folllowing picture describe the Interceptors mechanisms : 

 

3D""Warning

This page needs to be overworked

Op= eration handling within interceptors

Each operation is associated with a method in each interceptors, even if= it does nothing else than calling the next interceptor.

The base idea is to allow pre and post actions to be executed before and= after the call of the next interceptors :

Each interceptor process the pre action, call the next intercepto= r, wait for the response, execute the post action, and returns. We h= ave to implement this chain of interceptors in a way which allows us to add= new interceptors, or new pre or post actions, without having= to modify the existing code or mechanism. 

 

Bind Operation

The Bind  operation call the interceptor chain in the Par= titionNexusProxy class, where we can found a bind method :

public void bi=
nd( LdapDN bindDn, byte[] credentials, L=
ist mechanisms, String saslAuthId, Colle=
ction bypass ) throws NamingException
    {    ...
            this.configuration.getInter=
ceptorChain().bind( bindDn, credentials, mechanisms, saslAuthId );    ...

this will call the first configured interceptor from a chain which is de= clared in the configuration file server.xml. The first interceptor i= s the NormalizationService.

The information which are passed are :

    =09
  • The DN used to bind
  • =09
  • The password (credentials)
  • =09
  • The list of supported mechanisms 
  • =09
  • The SASL authent
    We will often use only the two first elements.

Normalization= interceptor

This interceptor will just normalize the DN used to bind. If the = DN is invalid, an exception will be thrown.

It is the first interceptor in the chain because as we will manupulate t= he DN through all interceptors, it is important that we normalize it= as soon as possible.

The normalized DN will be stored in an special form, usefull for = internal comparizons. This operation can be costly, but as the DN ha= s already been parsed, this is quite efficient.

We can call the next interceptor :

Authenticati= on interceptor

We must check that this bind request is valid, that is the DN and= the associated password are known by the server. We have two cases :

    =09
  1. The user have already been authenticated
  2. =09
  3. This is the first time this user try to bind

 What we call user is the DN of a known entry store= d in the server.

In the first case, we will have to search the password in the backend, a= nd this will be a lookup operation, which will be applied through an= other chain of interceptors.

Let's assume we are in the second case, because if we are in the first c= ase, we will have to ask the backend about the entry which DN is equ= al to the one we received, to get its associated password, thus callaing a = specific chain of interceptors (FINAL_INTERCEPTOR).

The password is compared using the given mechanism (which should be s= imple on a new server), and if it matches, we create a principal= object which will be stored in the connection context for future = usage.

We are done with the bind operation.

 Add opera= tion

An add operation is more complex. What we need to do is to check = if the current user has enough right to add an entry, and that the entry ca= n be added.

A new entry is a composition of three elements :

    =09
  • A partition name
  • =09
  • A path from this partition
  • =09
  • An entry name

For instance, when adding an entry which DN is cn=3Dacme, ou= =3Dusers, ou=3Dsystem , we will have :

    =09
  • Partition =3D "ou=3Dsystem"
  • =09
  • Path =3D "ou=3Dusers, ou=3Dsystem"
  • =09
  • Entry name =3D "cn=3Dacme"
    The two first elements must exist in the base. We can't add an entry in an = not existing partition, and we can't add an entry which path is not existin= g.