You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by el...@apache.org on 2011/11/12 19:24:43 UTC

svn commit: r1201297 [5/9] - in /directory/apacheds/branches/apacheds-txns: all/ apache-felix/ core-annotations/ core-api/ core-api/src/main/java/org/apache/directory/server/core/api/ core-api/src/main/java/org/apache/directory/server/core/api/intercep...

Modified: directory/apacheds/branches/apacheds-txns/interceptors/admin/src/main/java/org/apache/directory/server/core/admin/AdministrativePointInterceptor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/interceptors/admin/src/main/java/org/apache/directory/server/core/admin/AdministrativePointInterceptor.java?rev=1201297&r1=1201296&r2=1201297&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/interceptors/admin/src/main/java/org/apache/directory/server/core/admin/AdministrativePointInterceptor.java (original)
+++ directory/apacheds/branches/apacheds-txns/interceptors/admin/src/main/java/org/apache/directory/server/core/admin/AdministrativePointInterceptor.java Sat Nov 12 18:24:38 2011
@@ -34,6 +34,7 @@ import org.apache.directory.server.const
 import org.apache.directory.server.core.shared.DefaultCoreSession;
 import org.apache.directory.server.core.api.CoreSession;
 import org.apache.directory.server.core.api.DirectoryService;
+import org.apache.directory.server.core.api.InterceptorEnum;
 import org.apache.directory.server.core.api.LdapPrincipal;
 import org.apache.directory.server.core.api.administrative.AccessControlAAP;
 import org.apache.directory.server.core.api.administrative.AccessControlAdministrativePoint;
@@ -54,8 +55,6 @@ import org.apache.directory.server.core.
 import org.apache.directory.server.core.api.entry.ClonedServerEntry;
 import org.apache.directory.server.core.api.filtering.EntryFilteringCursor;
 import org.apache.directory.server.core.api.interceptor.BaseInterceptor;
-import org.apache.directory.server.core.api.interceptor.Interceptor;
-import org.apache.directory.server.core.api.interceptor.NextInterceptor;
 import org.apache.directory.server.core.api.interceptor.context.AddOperationContext;
 import org.apache.directory.server.core.api.interceptor.context.DeleteOperationContext;
 import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
@@ -184,6 +183,16 @@ public class AdministrativePointIntercep
     /** A lock to guarantee the AP cache consistency */
     private ReentrantReadWriteLock mutex = new ReentrantReadWriteLock();
 
+
+    /**
+     * Creates a new instance of a AdministrativePointInterceptor.
+     */
+    public AdministrativePointInterceptor()
+    {
+        super( InterceptorEnum.ADMINISTRATIVE_POINT_INTERCEPTOR );
+    }
+
+    
     /**
      * Get a read-lock on the AP cache.
      * No read operation can be done on the AP cache if this
@@ -247,7 +256,7 @@ public class AdministrativePointIntercep
             SubschemaAdministrativePoint ssAap = new SubschemaAAP( dn, uuid );
             directoryService.getSubschemaAPCache().add( dn, ssAap );
 
-            // TODO : Here, we have to update the children, removing any 
+            // TODO : Here, we have to update the children, removing any
             // reference to any other underlying AP
 
             // If it's an AAP, we can get out immediately
@@ -264,8 +273,8 @@ public class AdministrativePointIntercep
                 AccessControlAdministrativePoint sap = new AccessControlSAP( dn, uuid );
                 directoryService.getAccessControlAPCache().add( dn, sap );
 
-                // TODO : Here, we have to update the children, removing any 
-                // reference to any other underlying AccessControl IAP or SAP 
+                // TODO : Here, we have to update the children, removing any
+                // reference to any other underlying AccessControl IAP or SAP
 
                 continue;
             }
@@ -284,9 +293,9 @@ public class AdministrativePointIntercep
                 CollectiveAttributeAdministrativePoint sap = new CollectiveAttributeSAP( dn, uuid );
                 directoryService.getCollectiveAttributeAPCache().add( dn, sap );
 
-                // TODO : Here, we have to update the children, removing any 
-                // reference to any other underlying CollectiveAttribute IAP or SAP 
-                
+                // TODO : Here, we have to update the children, removing any
+                // reference to any other underlying CollectiveAttribute IAP or SAP
+
                 continue;
             }
 
@@ -304,8 +313,8 @@ public class AdministrativePointIntercep
                 SubschemaAdministrativePoint sap = new SubschemaSAP( dn, uuid );
                 directoryService.getSubschemaAPCache().add( dn, sap );
 
-                // TODO : Here, we have to update the children, removing any 
-                // reference to any other underlying Subschema IAP or SAP 
+                // TODO : Here, we have to update the children, removing any
+                // reference to any other underlying Subschema IAP or SAP
 
                 continue;
             }
@@ -316,9 +325,9 @@ public class AdministrativePointIntercep
                 TriggerExecutionAdministrativePoint sap = new TriggerExecutionSAP( dn, uuid );
                 directoryService.getTriggerExecutionAPCache().add( dn, sap );
 
-                // TODO : Here, we have to update the children, removing any 
+                // TODO : Here, we have to update the children, removing any
                 // reference to any other underlying TriggerExecution IAP or SAP
-                
+
                 continue;
             }
 
@@ -360,7 +369,7 @@ public class AdministrativePointIntercep
             // The SS AAP
             SubschemaAdministrativePoint ssAap = new SubschemaAAP( dn, uuid );
             ssapCache.add( dn, ssAap );
-            
+
             // If it's an AAP, we can get out immediately
             return;
         }
@@ -450,7 +459,7 @@ public class AdministrativePointIntercep
 
             // The SS AAP
             ssapCache.remove( dn );
-            
+
             return;
         }
 
@@ -487,7 +496,7 @@ public class AdministrativePointIntercep
         }
     }
 
-    
+
     private AdministrativePoint getParent( AdministrativePoint ap, List<AdministrativePoint> aps,
         AdministrativeRole role, DnNode<List<AdministrativePoint>> currentNode )
     {
@@ -525,7 +534,7 @@ public class AdministrativePointIntercep
 
     /**
      * Find the parent for the given administrative point. If the AP is an AAP, the parent will be the closest
-     * AAP or the closest SAP. If we have a SAP between the added AAP and a AAP, then 
+     * AAP or the closest SAP. If we have a SAP between the added AAP and a AAP, then
      */
     private AdministrativePoint findParent( AdministrativePoint ap, DnNode<List<AdministrativePoint>> currentNode )
     {
@@ -612,7 +621,7 @@ public class AdministrativePointIntercep
             throw new LdapUnwillingToPerformException( message );
         }
 
-        // If we are trying to add an AAP, we have to check that 
+        // If we are trying to add an AAP, we have to check that
         // it's the only role in the AdminPoint AT
         if ( isAutonomousAreaRole( roleStr ) )
         {
@@ -629,7 +638,7 @@ public class AdministrativePointIntercep
                 return;
             }
         }
-        
+
         // Check that we don't have already an AAP in the AdminPoint AT when we try to
         // add a role
         if ( adminPoint.contains( SchemaConstants.AUTONOMOUS_AREA ) )
@@ -667,24 +676,24 @@ public class AdministrativePointIntercep
             throw new LdapUnwillingToPerformException( message );
         }
 
-        // Now we are trying to delete an Administrative point. We have to check that 
+        // Now we are trying to delete an Administrative point. We have to check that
         // we only have one role if the deleted role is an AAP
         if ( isAutonomousAreaRole( roleStr ) )
         {
-            // We know have to check that removing the AAP, we will not 
+            // We know have to check that removing the AAP, we will not
             // left any pending IAP. We should check for the 3 potential IAPs :
             // AccessControl, CollectiveAttribute and TriggerExecution.
             // If the removed AP has a parent, no need to go any further :
             // the children IAPs will depend on this parent.
-            
+
             // Process the ACs
             DnNode<AccessControlAdministrativePoint> acAps = directoryService.getAccessControlAPCache();
-            
+
             if ( !acAps.hasParent( dn ) )
             {
                 // No parent, check for any IAP
                 List<AccessControlAdministrativePoint> children = acAps.getDescendantElements( dn );
-                
+
                 for ( AccessControlAdministrativePoint child : children )
                 {
                     if ( child.isInner() )
@@ -696,15 +705,15 @@ public class AdministrativePointIntercep
                     }
                 }
             }
-            
+
             // Process the CAs
             DnNode<CollectiveAttributeAdministrativePoint> caAps = directoryService.getCollectiveAttributeAPCache();
-            
+
             if ( !acAps.hasParent( dn ) )
             {
                 // No parent, check for any IAP
                 List<CollectiveAttributeAdministrativePoint> children = caAps.getDescendantElements( dn );
-                
+
                 for ( CollectiveAttributeAdministrativePoint child : children )
                 {
                     if ( child.isInner() )
@@ -716,15 +725,15 @@ public class AdministrativePointIntercep
                     }
                 }
             }
-            
+
             // Process the TEs
             DnNode<TriggerExecutionAdministrativePoint> teAps = directoryService.getTriggerExecutionAPCache();
-            
+
             if ( !acAps.hasParent( dn ) )
             {
                 // No parent, check for any IAP
                 List<TriggerExecutionAdministrativePoint> children = teAps.getDescendantElements( dn );
-                
+
                 for ( TriggerExecutionAdministrativePoint child : children )
                 {
                     if ( child.isInner() )
@@ -740,14 +749,6 @@ public class AdministrativePointIntercep
     }
 
 
-    /**
-     * Creates an Administrative service interceptor.
-     */
-    public AdministrativePointInterceptor()
-    {
-    }
-
-
     //-------------------------------------------------------------------------------------------
     // Helper methods
     //-------------------------------------------------------------------------------------------
@@ -783,7 +784,7 @@ public class AdministrativePointIntercep
 
                 entries.add( entry );
             }
-            
+
             results.close();
         }
         catch ( Exception e )
@@ -826,11 +827,10 @@ public class AdministrativePointIntercep
     /**
      * Update The Administrative Points cache, removing the given AdminPoint
      */
-    private void deleteAdminPointCache( Attribute adminPoint, DeleteOperationContext deleteContext )
-        throws LdapException
+    private void deleteAdminPointCache( Attribute adminPoint, DeleteOperationContext deleteContext ) throws LdapException
     {
         Dn dn = deleteContext.getDn();
-        
+
         // Remove the APs in the AP cache
         for ( Value<?> value : adminPoint )
         {
@@ -897,7 +897,7 @@ public class AdministrativePointIntercep
     private boolean isAccessControlInnerRole( String role )
     {
         return role.equalsIgnoreCase( SchemaConstants.ACCESS_CONTROL_INNER_AREA ) ||
-               role.equals( SchemaConstants.ACCESS_CONTROL_INNER_AREA_OID );
+            role.equals( SchemaConstants.ACCESS_CONTROL_INNER_AREA_OID );
     }
 
 
@@ -907,7 +907,7 @@ public class AdministrativePointIntercep
     private boolean isAccessControlSpecificRole( String role )
     {
         return role.equalsIgnoreCase( SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA ) ||
-               role.equals( SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA_OID );
+            role.equals( SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA_OID );
     }
 
 
@@ -917,7 +917,7 @@ public class AdministrativePointIntercep
     private boolean isCollectiveAttributeInnerRole( String role )
     {
         return role.equalsIgnoreCase( SchemaConstants.COLLECTIVE_ATTRIBUTE_INNER_AREA ) ||
-               role.equals( SchemaConstants.COLLECTIVE_ATTRIBUTE_INNER_AREA_OID );
+            role.equals( SchemaConstants.COLLECTIVE_ATTRIBUTE_INNER_AREA_OID );
     }
 
 
@@ -927,7 +927,7 @@ public class AdministrativePointIntercep
     private boolean isCollectiveAttributeSpecificRole( String role )
     {
         return role.equalsIgnoreCase( SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA ) ||
-               role.equals( SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA_OID );
+            role.equals( SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA_OID );
     }
 
 
@@ -937,7 +937,7 @@ public class AdministrativePointIntercep
     private boolean isTriggerExecutionInnerRole( String role )
     {
         return role.equalsIgnoreCase( SchemaConstants.TRIGGER_EXECUTION_INNER_AREA ) ||
-               role.equals( SchemaConstants.TRIGGER_EXECUTION_INNER_AREA_OID );
+            role.equals( SchemaConstants.TRIGGER_EXECUTION_INNER_AREA_OID );
     }
 
 
@@ -947,7 +947,7 @@ public class AdministrativePointIntercep
     private boolean isTriggerExecutionSpecificRole( String role )
     {
         return role.equalsIgnoreCase( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA ) ||
-               role.equals( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA_OID );
+            role.equals( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA_OID );
     }
 
 
@@ -957,7 +957,7 @@ public class AdministrativePointIntercep
     private boolean isSubschemaSpecficRole( String role )
     {
         return role.equalsIgnoreCase( SchemaConstants.SUB_SCHEMA_ADMIN_SPECIFIC_AREA ) ||
-               role.equals( SchemaConstants.SUB_SCHEMA_ADMIN_SPECIFIC_AREA_OID );
+            role.equals( SchemaConstants.SUB_SCHEMA_ADMIN_SPECIFIC_AREA_OID );
     }
 
 
@@ -967,7 +967,7 @@ public class AdministrativePointIntercep
     private boolean isAutonomousAreaRole( String role )
     {
         return role.equalsIgnoreCase( SchemaConstants.AUTONOMOUS_AREA ) ||
-               role.equals( SchemaConstants.AUTONOMOUS_AREA_OID );
+            role.equals( SchemaConstants.AUTONOMOUS_AREA_OID );
     }
 
 
@@ -984,7 +984,7 @@ public class AdministrativePointIntercep
     private boolean hasAccessControlSpecificRole( Attribute adminPoint )
     {
         return adminPoint.contains( SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA ) ||
-               adminPoint.contains( SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA_OID );
+            adminPoint.contains( SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA_OID );
     }
 
 
@@ -997,14 +997,14 @@ public class AdministrativePointIntercep
     private boolean hasCollectiveAttributeSpecificRole( Attribute adminPoint )
     {
         return adminPoint.contains( SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA ) ||
-               adminPoint.contains( SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA_OID );
+            adminPoint.contains( SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA_OID );
     }
 
 
     private boolean hasTriggerExecutionSpecificRole( Attribute adminPoint )
     {
         return adminPoint.contains( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA ) ||
-               adminPoint.contains( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA_OID );
+            adminPoint.contains( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA_OID );
     }
 
 
@@ -1067,16 +1067,15 @@ public class AdministrativePointIntercep
      * Check that the IAPs (if any) have a parent. We will check for each kind or role :
      * AC, CA and TE.
      */
-    private void checkIAPHasParent( String role, Attribute adminPoint, Dn dn )
-        throws LdapUnwillingToPerformException
+    private void checkIAPHasParent( String role, Attribute adminPoint, Dn dn ) throws LdapUnwillingToPerformException
     {
         // Check for the AC role
         if ( isAccessControlInnerRole( role ) )
         {
             DnNode<AccessControlAdministrativePoint> acCache = directoryService.getAccessControlAPCache();
-            
+
             DnNode<AccessControlAdministrativePoint> parent =  acCache.getNode( dn );
-            
+
             if ( parent == null )
             {
                 // We don't have any AC administrativePoint in the tree, this is an error
@@ -1088,9 +1087,9 @@ public class AdministrativePointIntercep
         else if ( isCollectiveAttributeInnerRole( role ) )
         {
             DnNode<CollectiveAttributeAdministrativePoint> caCache = directoryService.getCollectiveAttributeAPCache();
-            
+
             boolean hasAP = caCache.hasParentElement( dn );
-            
+
             if ( !hasAP )
             {
                 // We don't have any AC administrativePoint in the tree, this is an error
@@ -1102,9 +1101,9 @@ public class AdministrativePointIntercep
         else if ( isTriggerExecutionInnerRole( role ) )
         {
             DnNode<TriggerExecutionAdministrativePoint> caCache = directoryService.getTriggerExecutionAPCache();
-            
+
             DnNode<TriggerExecutionAdministrativePoint> parent =  caCache.getNode( dn );
-            
+
             if ( parent == null )
             {
                 // We don't have any AC administrativePoint in the tree, this is an error
@@ -1148,7 +1147,7 @@ public class AdministrativePointIntercep
 
         // get the list of all the AAPs
         List<Entry> administrativePoints = getAdministrativePoints();
-        
+
         lockWrite();
         addAdminPointCache( administrativePoints );
         unlock();
@@ -1181,12 +1180,11 @@ public class AdministrativePointIntercep
      * <ul>
      * <li>If it's an AA, then the added role should be the only one</li>
      * <li>It's not possible to add IA and SA at the same time</li>
-     * 
-     * @param next The next {@link Interceptor} in the chain
      * @param addContext The {@link AddOperationContext} instance
+     * 
      * @throws LdapException If we had some error while processing the Add operation
      */
-    public void add( NextInterceptor next, AddOperationContext addContext ) throws LdapException
+    public void add( AddOperationContext addContext ) throws LdapException
     {
         LOG.debug( ">>> Entering into the Administrative Interceptor, addRequest" );
         Entry entry = addContext.getEntry();
@@ -1198,7 +1196,7 @@ public class AdministrativePointIntercep
         if ( adminPoint == null )
         {
             // Nope, go on.
-            next.add( addContext );
+            next( addContext );
 
             LOG.debug( "Exit from Administrative Interceptor, no AP in the added entry" );
 
@@ -1209,7 +1207,7 @@ public class AdministrativePointIntercep
 
         // Protect the AP caches against concurrent access
         lockWrite();
-        
+
         // Loop on all the added roles to check if they are valid
         for ( Value<?> role : adminPoint )
         {
@@ -1217,7 +1215,7 @@ public class AdministrativePointIntercep
         }
 
         // Ok, we are golden.
-        next.add( addContext );
+        next( addContext );
 
         String apUuid = entry.get( ENTRY_UUID_AT ).getString();
 
@@ -1226,7 +1224,7 @@ public class AdministrativePointIntercep
 
         // Release the APCaches lock
         unlock();
-        
+
         LOG.debug( "Added an Administrative Point at {}", dn );
 
         return;
@@ -1234,11 +1232,11 @@ public class AdministrativePointIntercep
 
 
     /**
-     * We have to check that we can remove the associated AdministrativePoint : <br/> 
+     * We have to check that we can remove the associated AdministrativePoint : <br/>
      * <ul>
      * <li> if we remove an AAP, no descendant IAP should remain orphan</li>
      * <li> If we remove a SAP, no descendant IAP should remain orphan</li>
-     * </ul> 
+     * </ul>
      * {@inheritDoc}
      */
     public void delete( DeleteOperationContext deleteContext ) throws LdapException
@@ -1261,10 +1259,10 @@ public class AdministrativePointIntercep
         }
 
         LOG.debug( "Deletion of an administrative point at {} for the role {}", dn, adminPoint );
-        
+
         // Protect the AP caches against concurrent access
         lockWrite();
-        
+
         // Check that the removed AdministrativeRoles are valid. We don't have to do
         // any other check, as the deleted entry has no children.
         for ( Value<?> role : adminPoint )
@@ -1285,7 +1283,7 @@ public class AdministrativePointIntercep
 
         // Release the APCaches lock
         unlock();
-        
+
         LOG.debug( "Deleted an Administrative Point at {}", dn );
 
         return;
@@ -1303,7 +1301,7 @@ public class AdministrativePointIntercep
      * 
      * {@inheritDoc}
      */
-    public void modify( NextInterceptor next, ModifyOperationContext modifyContext ) throws LdapException
+    public void modify( ModifyOperationContext modifyContext ) throws LdapException
     {
         LOG.debug( ">>> Entering into the Administrative Interceptor, modifyRequest" );
         // We have to check that the modification is acceptable
@@ -1329,7 +1327,7 @@ public class AdministrativePointIntercep
         DnNode<CollectiveAttributeAdministrativePoint> caapCacheCopy = directoryService.getCollectiveAttributeAPCache().clone();
         DnNode<TriggerExecutionAdministrativePoint> teapCacheCopy = directoryService.getTriggerExecutionAPCache().clone();
         DnNode<SubschemaAdministrativePoint> ssapCacheCopy = directoryService.getSubschemaAPCache().clone();
-        
+
         // Loop on the modification to select the AdministrativeRole and process it :
         // we will create a new AT containing all the roles after having applied the modifications
         // on it
@@ -1425,14 +1423,14 @@ public class AdministrativePointIntercep
         // At this point, we have a new AdministrativeRole AT, and we need to get the lists of
         // added roles and removed roles, in order to process them
 
-        next.modify( modifyContext );
+        next( modifyContext );
     }
 
 
     /**
      * {@inheritDoc}
      */
-    public void move( NextInterceptor next, MoveOperationContext moveContext ) throws LdapException
+    public void move( MoveOperationContext moveContext ) throws LdapException
     {
         LOG.debug( ">>> Entering into the Administrative Interceptor, moveRequest" );
         Entry entry = moveContext.getOriginalEntry();
@@ -1443,7 +1441,7 @@ public class AdministrativePointIntercep
         if ( adminPoint == null )
         {
             // Nope, go on.
-            next.move( moveContext );
+            next( moveContext );
 
             LOG.debug( "Exit from Administrative Interceptor" );
 
@@ -1460,8 +1458,7 @@ public class AdministrativePointIntercep
     /**
      * {@inheritDoc}
      */
-    public void moveAndRename( NextInterceptor next, MoveAndRenameOperationContext moveAndRenameContext )
-        throws LdapException
+    public void moveAndRename( MoveAndRenameOperationContext moveAndRenameContext ) throws LdapException
     {
         LOG.debug( ">>> Entering into the Administrative Interceptor, moveAndRenameRequest" );
         Entry entry = moveAndRenameContext.getOriginalEntry();
@@ -1472,7 +1469,7 @@ public class AdministrativePointIntercep
         if ( adminPoint == null )
         {
             // Nope, go on.
-            next.moveAndRename( moveAndRenameContext );
+            next( moveAndRenameContext );
 
             LOG.debug( "Exit from Administrative Interceptor" );
 
@@ -1489,7 +1486,7 @@ public class AdministrativePointIntercep
     /**
      * {@inheritDoc}
      */
-    public void rename( NextInterceptor next, RenameOperationContext renameContext ) throws LdapException
+    public void rename( RenameOperationContext renameContext ) throws LdapException
     {
         LOG.debug( ">>> Entering into the Administrative Interceptor, renameRequest" );
         Entry entry = renameContext.getEntry();
@@ -1500,7 +1497,7 @@ public class AdministrativePointIntercep
         if ( adminPoint == null )
         {
             // Nope, go on.
-            next.rename( renameContext );
+            next( renameContext );
 
             LOG.debug( "Exit from Administrative Interceptor" );
 

Propchange: directory/apacheds/branches/apacheds-txns/interceptors/authn/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Sat Nov 12 18:24:38 2011
@@ -1 +1 @@
-/directory/apacheds/trunk/interceptors/authn:1183435-1200383
+/directory/apacheds/trunk/interceptors/authn:1183435-1201283

Modified: directory/apacheds/branches/apacheds-txns/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AbstractAuthenticator.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AbstractAuthenticator.java?rev=1201297&r1=1201296&r2=1201297&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AbstractAuthenticator.java (original)
+++ directory/apacheds/branches/apacheds-txns/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AbstractAuthenticator.java Sat Nov 12 18:24:38 2011
@@ -6,16 +6,16 @@
  *  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. 
- *  
+ *  under the License.
+ * 
  */
 package org.apache.directory.server.core.authn;
 
@@ -32,6 +32,7 @@ import static org.apache.directory.share
 import java.util.Date;
 
 import org.apache.directory.server.core.api.DirectoryService;
+import org.apache.directory.server.core.api.InterceptorEnum;
 import org.apache.directory.server.core.api.authn.ppolicy.PasswordPolicyConfiguration;
 import org.apache.directory.server.core.api.authn.ppolicy.PasswordPolicyException;
 import org.apache.directory.shared.ldap.model.constants.AuthenticationLevel;
@@ -116,7 +117,7 @@ public abstract class AbstractAuthentica
     /**
      * Calls {@link #doDestroy()} method, and clears default properties
      * (<tt>factoryConfiguration</tt> and <tt>configuration</tt>).
-     * Please put your deinitialization code into {@link #doDestroy()}. 
+     * Please put your deinitialization code into {@link #doDestroy()}.
      */
     public final void destroy()
     {
@@ -157,7 +158,8 @@ public abstract class AbstractAuthentica
             return;
         }
 
-        AuthenticationInterceptor authenticationInterceptor = (AuthenticationInterceptor)directoryService.getInterceptor( AuthenticationInterceptor.class.getSimpleName() );
+        AuthenticationInterceptor authenticationInterceptor = (AuthenticationInterceptor)directoryService.getInterceptor(
+            InterceptorEnum.AUTHENTICATION_INTERCEPTOR.getName() );
         PasswordPolicyConfiguration pPolicyConfig = authenticationInterceptor.getPwdPolicy( userEntry );
         
         // check for locked out account
@@ -203,7 +205,7 @@ public abstract class AbstractAuthentica
             
             if( System.currentTimeMillis() < pwdStartTime.getTime() )
             {
-                throw new PasswordPolicyException( "account is locked, will be activated after " + pwdStartTime, ACCOUNT_LOCKED.getValue() ); 
+                throw new PasswordPolicyException( "account is locked, will be activated after " + pwdStartTime, ACCOUNT_LOCKED.getValue() );
             }
         }
         

Modified: directory/apacheds/branches/apacheds-txns/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AuthenticationInterceptor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AuthenticationInterceptor.java?rev=1201297&r1=1201296&r2=1201297&view=diff
==============================================================================
--- directory/apacheds/branches/apacheds-txns/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AuthenticationInterceptor.java (original)
+++ directory/apacheds/branches/apacheds-txns/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AuthenticationInterceptor.java Sat Nov 12 18:24:38 2011
@@ -43,20 +43,21 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import org.apache.directory.server.core.shared.DefaultCoreSession;
 import org.apache.directory.server.core.api.CoreSession;
 import org.apache.directory.server.core.api.DirectoryService;
+import org.apache.directory.server.core.api.InterceptorEnum;
 import org.apache.directory.server.core.api.LdapPrincipal;
+import org.apache.directory.server.core.api.authn.ppolicy.PasswordPolicyConfiguration;
+import org.apache.directory.server.core.api.authn.ppolicy.PasswordPolicyException;
 import org.apache.directory.server.core.api.filtering.EntryFilteringCursor;
 import org.apache.directory.server.core.api.interceptor.BaseInterceptor;
 import org.apache.directory.server.core.api.interceptor.Interceptor;
-import org.apache.directory.server.core.api.interceptor.NextInterceptor;
 import org.apache.directory.server.core.api.interceptor.context.AddOperationContext;
 import org.apache.directory.server.core.api.interceptor.context.BindOperationContext;
 import org.apache.directory.server.core.api.interceptor.context.CompareOperationContext;
 import org.apache.directory.server.core.api.interceptor.context.DeleteOperationContext;
-import org.apache.directory.server.core.api.interceptor.context.EntryOperationContext;
-import org.apache.directory.server.core.api.interceptor.context.GetRootDSEOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.HasEntryOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.GetRootDseOperationContext;
 import org.apache.directory.server.core.api.interceptor.context.ListOperationContext;
 import org.apache.directory.server.core.api.interceptor.context.LookupOperationContext;
 import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
@@ -66,9 +67,8 @@ import org.apache.directory.server.core.
 import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext;
 import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
 import org.apache.directory.server.core.api.interceptor.context.UnbindOperationContext;
-import org.apache.directory.server.core.api.authn.ppolicy.PasswordPolicyConfiguration;
-import org.apache.directory.server.core.api.authn.ppolicy.PasswordPolicyException;
 import org.apache.directory.server.core.authn.ppolicy.PpolicyConfigContainer;
+import org.apache.directory.server.core.shared.DefaultCoreSession;
 import org.apache.directory.server.i18n.I18n;
 import org.apache.directory.shared.ldap.extras.controls.ppolicy.PasswordPolicy;
 import org.apache.directory.shared.ldap.extras.controls.ppolicy.PasswordPolicyErrorEnum;
@@ -177,6 +177,7 @@ public class AuthenticationInterceptor e
      */
     public AuthenticationInterceptor()
     {
+        super( InterceptorEnum.AUTHENTICATION_INTERCEPTOR );
     }
 
 
@@ -323,7 +324,10 @@ public class AuthenticationInterceptor e
     }
 
 
-    public void add( NextInterceptor next, AddOperationContext addContext ) throws LdapException
+    /**
+     * {@inheritDoc}
+     */
+    public void add( AddOperationContext addContext ) throws LdapException
     {
         if ( IS_DEBUG )
         {
@@ -337,7 +341,7 @@ public class AuthenticationInterceptor e
 
         if ( !directoryService.isPwdPolicyEnabled() )
         {
-            next.add( addContext );
+            next( addContext );
             return;
         }
 
@@ -397,365 +401,305 @@ public class AuthenticationInterceptor e
             }
         }
 
-        next.add( addContext );
-    }
-
-
-    public void delete( DeleteOperationContext deleteContext ) throws LdapException
-    {
-        if ( IS_DEBUG )
-        {
-            LOG.debug( "Operation Context: {}", deleteContext );
-        }
-
-        checkAuthenticated( deleteContext );
-        checkPwdReset( deleteContext );
-        next( deleteContext );
-        invalidateAuthenticatorCaches( deleteContext.getDn() );
+        next( addContext );
     }
 
 
     /**
      * {@inheritDoc}
      */
-    public Entry getRootDSE( GetRootDSEOperationContext getRootDseContext ) throws LdapException
+    public void bind( BindOperationContext bindContext ) throws LdapException
     {
         if ( IS_DEBUG )
         {
-            LOG.debug( "Operation Context: {}", getRootDseContext );
+            LOG.debug( "Operation Context: {}", bindContext );
         }
 
-        checkAuthenticated( getRootDseContext );
-        checkPwdReset( getRootDseContext );
-
-        return next( getRootDseContext );
-    }
+        if ( ( bindContext.getSession() != null ) && ( bindContext.getSession().getEffectivePrincipal() != null ) )
+        {
+            // null out the credentials
+            bindContext.setCredentials( null );
+        }
 
+        // pick the first matching authenticator type
+        AuthenticationLevel level = bindContext.getAuthenticationLevel();
 
-    /**
-     * {@inheritDoc}
-     */
-    public boolean hasEntry( EntryOperationContext hasEntryContext ) throws LdapException
-    {
-        if ( IS_DEBUG )
+        if ( level == AuthenticationLevel.UNAUTHENT )
         {
-            LOG.debug( "Operation Context: {}", hasEntryContext );
+            // This is a case where the Bind request contains a Dn, but no password.
+            // We don't check the Dn, we just return a UnwillingToPerform error
+            // Cf RFC 4513, chap. 5.1.2
+            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, "Cannot Bind for Dn "
+                + bindContext.getDn().getName() );
         }
 
-        checkAuthenticated( hasEntryContext );
-        checkPwdReset( hasEntryContext );
+        Collection<Authenticator> authenticators = getAuthenticators( level );
 
-        return next( hasEntryContext );
-    }
+        if ( authenticators == null )
+        {
+            LOG.debug( "No authenticators found, delegating bind to the nexus." );
 
+            // as a last resort try binding via the nexus
+            next( bindContext );
 
-    /**
-     * {@inheritDoc}
-     */
-    public EntryFilteringCursor list( ListOperationContext listContext ) throws LdapException
-    {
-        if ( IS_DEBUG )
-        {
-            LOG.debug( "Operation Context: {}", listContext );
-        }
+            LOG.debug( "Nexus succeeded on bind operation." );
 
-        checkAuthenticated( listContext );
-        checkPwdReset( listContext );
+            // bind succeeded if we got this far
+            // TODO - authentication level not being set
+            LdapPrincipal principal = new LdapPrincipal( schemaManager, bindContext.getDn(), AuthenticationLevel.SIMPLE );
+            CoreSession session = new DefaultCoreSession( principal, directoryService );
+            bindContext.setSession( session );
 
-        return next( listContext );
-    }
+            // remove creds so there is no security risk
+            bindContext.setCredentials( null );
+            return;
+        }
 
+        boolean isPPolicyReqCtrlPresent = bindContext.hasRequestControl( PasswordPolicy.OID );
+        PasswordPolicyDecorator pwdRespCtrl =
+            new PasswordPolicyDecorator( directoryService.getLdapCodecService(), true );
 
-    public Entry lookup( LookupOperationContext lookupContext ) throws LdapException
-    {
-        if ( IS_DEBUG )
+        boolean authenticated = false;
+        PasswordPolicyException ppe = null;
+
+        // TODO : we should refactor that.
+        // try each authenticator
+        for ( Authenticator authenticator : authenticators )
         {
-            LOG.debug( "Operation Context: {}", lookupContext );
-        }
+            try
+            {
+                // perform the authentication
+                LdapPrincipal principal = authenticator.authenticate( bindContext );
 
-        checkAuthenticated( lookupContext );
-        checkPwdReset( lookupContext );
+                LdapPrincipal clonedPrincipal = ( LdapPrincipal ) ( principal.clone() );
 
-        return next( lookupContext );
-    }
+                // remove creds so there is no security risk
+                bindContext.setCredentials( null );
+                clonedPrincipal.setUserPassword( StringConstants.EMPTY_BYTES );
 
+                // authentication was successful
+                CoreSession session = new DefaultCoreSession( clonedPrincipal, directoryService );
+                bindContext.setSession( session );
 
-    private void invalidateAuthenticatorCaches( Dn principalDn )
-    {
-        for ( AuthenticationLevel authMech : authenticatorsMapByType.keySet() )
-        {
-            Collection<Authenticator> authenticators = getAuthenticators( authMech );
+                authenticated = true;
 
-            // try each authenticator
-            for ( Authenticator authenticator : authenticators )
+                // break out of the loop if the authentication succeeded
+                break;
+            }
+            catch ( PasswordPolicyException e )
             {
-                authenticator.invalidateCache( principalDn );
+                ppe = e;
+                break;
+            }
+            catch ( LdapAuthenticationException e )
+            {
+                // authentication failed, try the next authenticator
+                if ( LOG.isInfoEnabled() )
+                {
+                    LOG.info( "Authenticator {} failed to authenticate: {}", authenticator, bindContext );
+                }
+            }
+            catch ( Exception e )
+            {
+                // Log other exceptions than LdapAuthenticationException
+                if ( LOG.isWarnEnabled() )
+                {
+                    LOG.info( "Unexpected failure for Authenticator {} : {}", authenticator, bindContext );
+                }
             }
         }
-    }
 
-
-    public void modify( NextInterceptor next, ModifyOperationContext modifyContext ) throws LdapException
-    {
-        if ( IS_DEBUG )
+        if ( ppe != null )
         {
-            LOG.debug( "Operation Context: {}", modifyContext );
+            if ( isPPolicyReqCtrlPresent )
+            {
+                pwdRespCtrl.getResponse().setPasswordPolicyError( PasswordPolicyErrorEnum.get( ppe.getErrorCode() ) );
+                bindContext.addResponseControl( pwdRespCtrl );
+            }
+
+            throw ppe;
         }
 
-        checkAuthenticated( modifyContext );
+        Dn dn = bindContext.getDn();
+        Entry userEntry = bindContext.getEntry();
 
+        PasswordPolicyConfiguration policyConfig = getPwdPolicy( userEntry );
 
-        if ( ! directoryService.isPwdPolicyEnabled() )
+        // check if the user entry is null, it will be null
+        // in cases of anonymous bind
+        if ( authenticated && ( userEntry == null ) && directoryService.isAllowAnonymousAccess() )
         {
-            next.modify( modifyContext );
-            invalidateAuthenticatorCaches( modifyContext.getDn() );
             return;
         }
 
-        // handle the case where pwdPolicySubentry AT is about to be deleted in thid modify()
-        PasswordPolicyConfiguration policyConfig = getPwdPolicy( modifyContext.getEntry() );
-
-        boolean isPPolicyReqCtrlPresent = modifyContext.hasRequestControl( PasswordPolicy.OID );
-        Dn userDn = modifyContext.getSession().getAuthenticatedPrincipal().getDn();
-
-        PwdModDetailsHolder pwdModDetails = null;
-
-        pwdModDetails = getPwdModDetails( modifyContext, policyConfig );
-
-        if ( pwdModDetails.isPwdModPresent() )
+        if ( !authenticated )
         {
-            if ( pwdResetSet.contains( userDn ) )
+            if ( LOG.isInfoEnabled() )
             {
-                if ( pwdModDetails.isOtherModExists() )
-                {
-                    if ( isPPolicyReqCtrlPresent )
-                    {
-                        PasswordPolicyDecorator responseControl =
-                            new PasswordPolicyDecorator( directoryService.getLdapCodecService(), true );
-                        responseControl.getResponse().setPasswordPolicyError( PasswordPolicyErrorEnum.CHANGE_AFTER_RESET );
-                        modifyContext.addResponseControl( responseControl );
-                    }
-
-                    throw new LdapNoPermissionException();
-                }
+                LOG.info( "Cannot bind to the server " );
             }
 
-            if ( policyConfig.isPwdSafeModify() )
+            if ( ( policyConfig != null ) && ( userEntry != null ) )
             {
-                if ( pwdModDetails.isAddOrReplace() && !pwdModDetails.isDelete() )
-                {
-                    LOG.debug( "trying to update password attribute without the supplying the old password" );
-
-                    if ( isPPolicyReqCtrlPresent )
-                    {
-                        PasswordPolicyDecorator responseControl =
-                            new PasswordPolicyDecorator( directoryService.getLdapCodecService(), true );
-                        responseControl.getResponse().setPasswordPolicyError( PasswordPolicyErrorEnum.MUST_SUPPLY_OLD_PASSWORD );
-                        modifyContext.addResponseControl( responseControl );
-                    }
+                Attribute pwdFailTimeAt = userEntry.get( PWD_FAILURE_TIME_AT );
 
-                    throw new LdapNoPermissionException();
+                if ( pwdFailTimeAt == null )
+                {
+                    pwdFailTimeAt = new DefaultAttribute( AT_PWD_FAILURE_TIME );
                 }
-            }
-
-            if ( !policyConfig.isPwdAllowUserChange() && !modifyContext.getSession().isAnAdministrator() )
-            {
-                if ( isPPolicyReqCtrlPresent )
+                else
                 {
-                    PasswordPolicyDecorator responseControl =
-                        new PasswordPolicyDecorator( directoryService.getLdapCodecService(), true );
-                    responseControl.getResponse().setPasswordPolicyError( PasswordPolicyErrorEnum.PASSWORD_MOD_NOT_ALLOWED );
-                    modifyContext.addResponseControl( responseControl );
+                    PasswordUtil.purgeFailureTimes( policyConfig, pwdFailTimeAt );
                 }
 
-                throw new LdapNoPermissionException();
-            }
+                String failureTime = DateUtils.getGeneralizedTime();
+                pwdFailTimeAt.add( failureTime );
+                Modification pwdFailTimeMod = new DefaultModification( ADD_ATTRIBUTE, pwdFailTimeAt );
 
-            Entry entry = modifyContext.getEntry();
+                List<Modification> mods = new ArrayList<Modification>();
+                mods.add( pwdFailTimeMod );
 
-            if ( isPwdTooYoung( entry, policyConfig ) )
-            {
-                if ( isPPolicyReqCtrlPresent )
+                int numFailures = pwdFailTimeAt.size();
+
+                if ( policyConfig.isPwdLockout() && ( numFailures >= policyConfig.getPwdMaxFailure() ) )
                 {
-                    PasswordPolicyDecorator responseControl =
-                        new PasswordPolicyDecorator( directoryService.getLdapCodecService(), true );
-                    responseControl.getResponse().setPasswordPolicyError( PasswordPolicyErrorEnum.PASSWORD_TOO_YOUNG );
-                    modifyContext.addResponseControl( responseControl );
-                }
+                    Attribute pwdAccountLockedTimeAt = new DefaultAttribute( AT_PWD_ACCOUNT_LOCKED_TIME );
 
-                throw new LdapOperationException( ResultCodeEnum.CONSTRAINT_VIOLATION,
-                    "password is too young to update" );
-            }
+                    // if zero, lockout permanently, only admin can unlock it
+                    if ( policyConfig.getPwdLockoutDuration() == 0 )
+                    {
+                        pwdAccountLockedTimeAt.add( "000001010000Z" );
+                    }
+                    else
+                    {
+                        pwdAccountLockedTimeAt.add( failureTime );
+                    }
 
-            byte[] newPassword = null;
+                    Modification pwdAccountLockedMod = new DefaultModification( ADD_ATTRIBUTE, pwdAccountLockedTimeAt );
+                    mods.add( pwdAccountLockedMod );
 
-            if ( ( pwdModDetails != null ) )
-            {
-                newPassword = pwdModDetails.getNewPwd();
-
-                try
-                {
-                    String userName = entry.getDn().getRdn().getUpValue().getString();
-                    check( userName, newPassword, policyConfig );
+                    pwdRespCtrl.getResponse().setPasswordPolicyError( PasswordPolicyErrorEnum.ACCOUNT_LOCKED );
                 }
-                catch ( PasswordPolicyException e )
+                else if ( policyConfig.getPwdMinDelay() > 0 )
                 {
-                    if ( isPPolicyReqCtrlPresent )
+                    int numDelay = numFailures * policyConfig.getPwdMinDelay();
+                    int maxDelay = policyConfig.getPwdMaxDelay();
+                    if ( numDelay > maxDelay )
                     {
-                        PasswordPolicyDecorator responseControl =
-                            new PasswordPolicyDecorator( directoryService.getLdapCodecService(), true );
-                        responseControl.getResponse().setPasswordPolicyError( PasswordPolicyErrorEnum.get( e.getErrorCode() ) );
-                        modifyContext.addResponseControl( responseControl );
+                        numDelay = maxDelay;
                     }
 
-                    // throw exception if userPassword quality checks fail
-                    throw new LdapOperationException( ResultCodeEnum.CONSTRAINT_VIOLATION, e.getMessage(), e );
-                }
-            }
-
-            int histSize = policyConfig.getPwdInHistory();
-            Modification pwdRemHistMod = null;
-            Modification pwdAddHistMod = null;
-            String pwdChangedTime = DateUtils.getGeneralizedTime();
-
-            if ( histSize > 0 )
-            {
-                Attribute pwdHistoryAt = entry.get( PWD_HISTORY_AT );
-
-                if ( pwdHistoryAt == null )
-                {
-                    pwdHistoryAt = new DefaultAttribute( AT_PWD_HISTORY );
-                }
-
-                List<PasswordHistory> pwdHistLst = new ArrayList<PasswordHistory>();
-
-                for ( Value<?> value : pwdHistoryAt  )
-                {
-                    PasswordHistory pwdh = new PasswordHistory( Strings.utf8ToString( value.getBytes() ) );
-
-                    boolean matched = Arrays.equals( newPassword, pwdh.getPassword() );
-
-                    if ( matched )
+                    try
                     {
-                        if ( isPPolicyReqCtrlPresent )
-                        {
-                            PasswordPolicyDecorator responseControl =
-                                new PasswordPolicyDecorator( directoryService.getLdapCodecService(), true );
-                            responseControl.getResponse().setPasswordPolicyError( PasswordPolicyErrorEnum.PASSWORD_IN_HISTORY );
-                            modifyContext.addResponseControl( responseControl );
-                        }
-
-                        throw new LdapOperationException( ResultCodeEnum.CONSTRAINT_VIOLATION,
-                            "invalid reuse of password present in password history" );
+                        Thread.sleep( numDelay * 1000 );
+                    }
+                    catch ( InterruptedException e )
+                    {
+                        LOG.warn(
+                            "Interrupted while delaying to send the failed authentication response for the user {}",
+                            dn, e );
                     }
-
-                    pwdHistLst.add( pwdh );
-                }
-
-                if ( pwdHistLst.size() >= histSize )
-                {
-                    // see the javadoc of PasswordHistory
-                    Collections.sort( pwdHistLst );
-
-                    // remove the oldest value
-                    PasswordHistory remPwdHist = ( PasswordHistory ) pwdHistLst.toArray()[histSize - 1];
-                    Attribute tempAt = new DefaultAttribute( AT_PWD_HISTORY );
-                    tempAt.add( remPwdHist.getHistoryValue() );
-                    pwdRemHistMod = new DefaultModification( REMOVE_ATTRIBUTE, tempAt );
                 }
 
-                pwdHistoryAt.clear();
-                PasswordHistory newPwdHist = new PasswordHistory( pwdChangedTime, newPassword );
-                pwdHistoryAt.clear();
-                pwdHistoryAt.add( newPwdHist.getHistoryValue() );
-                pwdAddHistMod = new DefaultModification( ADD_ATTRIBUTE, pwdHistoryAt );
+                //adminSession.modify( dn, Collections.singletonList( pwdFailTimeMod ) );
+                ModifyOperationContext bindModCtx = new ModifyOperationContext( adminSession );
+                bindModCtx.setDn( dn );
+                bindModCtx.setModItems( mods );
+                directoryService.getPartitionNexus().modify( bindModCtx );
             }
 
-            next.modify( modifyContext );
-
-            invalidateAuthenticatorCaches( modifyContext.getDn() );
-
+            String upDn = ( dn == null ? "" : dn.getName() );
+            throw new LdapAuthenticationException( I18n.err( I18n.ERR_229, upDn ) );
+        }
+        else if ( policyConfig != null )
+        {
             List<Modification> mods = new ArrayList<Modification>();
 
-            if ( ( policyConfig.getPwdMinAge() > 0 ) || ( policyConfig.getPwdMaxAge() > 0 ) )
+            if ( policyConfig.getPwdMaxIdle() > 0 )
             {
-                Attribute pwdChangedTimeAt = new DefaultAttribute( AT_PWD_CHANGED_TIME );
-                pwdChangedTimeAt.add( pwdChangedTime );
-                Modification pwdChangedTimeMod = new DefaultModification( REPLACE_ATTRIBUTE, pwdChangedTimeAt );
-                mods.add( pwdChangedTimeMod );
+                Attribute pwdLastSuccesTimeAt = new DefaultAttribute( AT_PWD_LAST_SUCCESS );
+                pwdLastSuccesTimeAt.add( DateUtils.getGeneralizedTime() );
+                Modification pwdLastSuccesTimeMod = new DefaultModification( REPLACE_ATTRIBUTE, pwdLastSuccesTimeAt );
+                mods.add( pwdLastSuccesTimeMod );
             }
 
-            if ( pwdAddHistMod != null )
+            Attribute pwdFailTimeAt = userEntry.get( AT_PWD_FAILURE_TIME );
+
+            if ( pwdFailTimeAt != null )
             {
-                mods.add( pwdAddHistMod );
+                Modification pwdFailTimeMod = new DefaultModification( REMOVE_ATTRIBUTE, pwdFailTimeAt );
+                mods.add( pwdFailTimeMod );
             }
 
-            if ( pwdRemHistMod != null )
+            Attribute pwdAccLockedTimeAt = userEntry.get( AT_PWD_ACCOUNT_LOCKED_TIME );
+
+            if ( pwdAccLockedTimeAt != null )
             {
-                mods.add( pwdRemHistMod );
+                Modification pwdAccLockedTimeMod = new DefaultModification( REMOVE_ATTRIBUTE, pwdAccLockedTimeAt );
+                mods.add( pwdAccLockedTimeMod );
             }
 
-            boolean removeFromPwdResetSet = false;
-
-            if ( policyConfig.isPwdMustChange() )
+            // checking the expiration time *after* performing authentication, do we need to care about millisecond precision?
+            if ( ( policyConfig.getPwdMaxAge() > 0 ) && ( policyConfig.getPwdGraceAuthNLimit() > 0 ) )
             {
-                Attribute pwdMustChangeAt = new DefaultAttribute( AT_PWD_RESET );
-                Modification pwdMustChangeMod = null;
+                Attribute pwdChangeTimeAttr = userEntry.get( PWD_CHANGED_TIME_AT );
 
-                if ( modifyContext.getSession().isAnAdministrator() )
-                {
-                    pwdMustChangeAt.add( "TRUE" );
-                    pwdMustChangeMod = new DefaultModification( REPLACE_ATTRIBUTE, pwdMustChangeAt );
-                }
-                else
+                if ( pwdChangeTimeAttr != null )
                 {
-                    pwdMustChangeMod = new DefaultModification( REMOVE_ATTRIBUTE, pwdMustChangeAt );
-                    removeFromPwdResetSet = true;
-                }
+                    boolean expired = PasswordUtil.isPwdExpired( pwdChangeTimeAttr.getString(),
+                        policyConfig.getPwdMaxAge() );
 
-                mods.add( pwdMustChangeMod );
-            }
+                    if ( expired )
+                    {
+                        Attribute pwdGraceUseAttr = userEntry.get( PWD_GRACE_USE_TIME_AT );
+                        int numGraceAuth = 0;
 
-            Attribute pwdFailureTimeAt = entry.get( PWD_FAILURE_TIME_AT );
+                        if ( pwdGraceUseAttr != null )
+                        {
+                            numGraceAuth = policyConfig.getPwdGraceAuthNLimit() - ( pwdGraceUseAttr.size() + 1 );
+                        }
+                        else
+                        {
+                            pwdGraceUseAttr = new DefaultAttribute( AT_PWD_GRACE_USE_TIME );
+                            numGraceAuth = policyConfig.getPwdGraceAuthNLimit() - 1;
+                        }
 
-            if ( pwdFailureTimeAt != null )
-            {
-                mods.add( new DefaultModification( REMOVE_ATTRIBUTE, pwdFailureTimeAt ) );
-            }
+                        pwdRespCtrl.getResponse().setGraceAuthNsRemaining( numGraceAuth );
 
-            Attribute pwdGraceUseTimeAt = entry.get( PWD_GRACE_USE_TIME_AT );
+                        pwdGraceUseAttr.add( DateUtils.getGeneralizedTime() );
+                        Modification pwdGraceUseMod = new DefaultModification( ADD_ATTRIBUTE, pwdGraceUseAttr );
+                        mods.add( pwdGraceUseMod );
+                    }
+                }
+            }
 
-            if ( pwdGraceUseTimeAt != null )
+            if ( !mods.isEmpty() )
             {
-                mods.add( new DefaultModification( REMOVE_ATTRIBUTE, pwdGraceUseTimeAt ) );
+                //adminSession.modify( dn, mods );
+                ModifyOperationContext bindModCtx = new ModifyOperationContext( adminSession );
+                bindModCtx.setDn( dn );
+                bindModCtx.setModItems( mods );
+                directoryService.getPartitionNexus().modify( bindModCtx );
             }
 
-            directoryService.getAdminSession().modify( modifyContext.getDn(), mods );
-
-            if ( removeFromPwdResetSet )
+            if ( isPPolicyReqCtrlPresent )
             {
-                pwdResetSet.remove( userDn );
-            }
-        }
-        else
-        {
-            next.modify( modifyContext );
-            invalidateAuthenticatorCaches( modifyContext.getDn() );
-        }
-    }
+                int expiryWarnTime = getPwdTimeBeforeExpiry( userEntry, policyConfig );
 
+                if ( expiryWarnTime > 0 )
+                {
+                    pwdRespCtrl.getResponse().setTimeBeforeExpiration( expiryWarnTime );
+                }
 
-    public void rename( NextInterceptor next, RenameOperationContext renameContext ) throws LdapException
-    {
-        if ( IS_DEBUG )
-        {
-            LOG.debug( "Operation Context: {}", renameContext );
-        }
+                if ( isPwdMustReset( userEntry ) )
+                {
+                    pwdRespCtrl.getResponse().setPasswordPolicyError( PasswordPolicyErrorEnum.CHANGE_AFTER_RESET );
+                    pwdResetSet.add( dn );
+                }
 
-        checkAuthenticated( renameContext );
-        checkPwdReset( renameContext );
-        next.rename( renameContext );
-        invalidateAuthenticatorCaches( renameContext.getDn() );
+                bindContext.addResponseControl( pwdRespCtrl );
+            }
+        }
     }
 
 
@@ -778,367 +722,430 @@ public class AuthenticationInterceptor e
     }
 
 
-    public void moveAndRename( NextInterceptor next, MoveAndRenameOperationContext moveAndRenameContext )
-        throws LdapException
-        {
+    /**
+     * {@inheritDoc}
+     */
+    public void delete( DeleteOperationContext deleteContext ) throws LdapException
+    {
         if ( IS_DEBUG )
         {
-            LOG.debug( "Operation Context: {}", moveAndRenameContext );
+            LOG.debug( "Operation Context: {}", deleteContext );
         }
 
-        checkAuthenticated( moveAndRenameContext );
-        checkPwdReset( moveAndRenameContext );
-        next.moveAndRename( moveAndRenameContext );
-        invalidateAuthenticatorCaches( moveAndRenameContext.getDn() );
-        }
+        checkAuthenticated( deleteContext );
+        checkPwdReset( deleteContext );
+        next( deleteContext );
+        invalidateAuthenticatorCaches( deleteContext.getDn() );
+    }
 
 
     /**
      * {@inheritDoc}
      */
-    public void move( NextInterceptor next, MoveOperationContext moveContext ) throws LdapException
+    public Entry getRootDse( GetRootDseOperationContext getRootDseContext ) throws LdapException
     {
         if ( IS_DEBUG )
         {
-            LOG.debug( "Operation Context: {}", moveContext );
+            LOG.debug( "Operation Context: {}", getRootDseContext );
         }
 
-        checkAuthenticated( moveContext );
-        checkPwdReset( moveContext );
-        next.move( moveContext );
-        invalidateAuthenticatorCaches( moveContext.getDn() );
+        checkAuthenticated( getRootDseContext );
+        checkPwdReset( getRootDseContext );
+
+        return next( getRootDseContext );
     }
 
 
-    public EntryFilteringCursor search( NextInterceptor next, SearchOperationContext searchContext )
-        throws LdapException
-        {
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasEntry( HasEntryOperationContext hasEntryContext ) throws LdapException
+    {
         if ( IS_DEBUG )
         {
-            LOG.debug( "Operation Context: {}", searchContext );
+            LOG.debug( "Operation Context: {}", hasEntryContext );
         }
 
-        checkAuthenticated( searchContext );
-        checkPwdReset( searchContext );
+        checkAuthenticated( hasEntryContext );
+        checkPwdReset( hasEntryContext );
 
-        return next.search( searchContext );
-        }
+        return next( hasEntryContext );
+    }
 
 
     /**
-     * Check if the current operation has a valid PrincipalDN or not.
-     *
-     * @param operation the operation type
-     * @throws Exception
+     * {@inheritDoc}
      */
-    private void checkAuthenticated( OperationContext operation ) throws LdapException
+    public EntryFilteringCursor list( ListOperationContext listContext ) throws LdapException
     {
-        if ( operation.getSession().isAnonymous() && !directoryService.isAllowAnonymousAccess()
-            && !operation.getDn().isEmpty() )
+        if ( IS_DEBUG )
         {
-            String msg = I18n.err( I18n.ERR_5, operation.getName() );
-            LOG.error( msg );
-            throw new LdapNoPermissionException( msg );
+            LOG.debug( "Operation Context: {}", listContext );
         }
+
+        checkAuthenticated( listContext );
+        checkPwdReset( listContext );
+
+        return next( listContext );
     }
 
 
-    public void bind( BindOperationContext bindContext ) throws LdapException
+    /**
+     * {@inheritDoc}
+     */
+    public Entry lookup( LookupOperationContext lookupContext ) throws LdapException
     {
         if ( IS_DEBUG )
         {
-            LOG.debug( "Operation Context: {}", bindContext );
+            LOG.debug( "Operation Context: {}", lookupContext );
         }
 
-        if ( ( bindContext.getSession() != null ) && ( bindContext.getSession().getEffectivePrincipal() != null ) )
-        {
-            // null out the credentials
-            bindContext.setCredentials( null );
-        }
+        checkAuthenticated( lookupContext );
+        checkPwdReset( lookupContext );
 
-        // pick the first matching authenticator type
-        AuthenticationLevel level = bindContext.getAuthenticationLevel();
+        return next( lookupContext );
+    }
 
-        if ( level == AuthenticationLevel.UNAUTHENT )
+
+    private void invalidateAuthenticatorCaches( Dn principalDn )
+    {
+        for ( AuthenticationLevel authMech : authenticatorsMapByType.keySet() )
         {
-            // This is a case where the Bind request contains a Dn, but no password.
-            // We don't check the Dn, we just return a UnwillingToPerform error
-            // Cf RFC 4513, chap. 5.1.2
-            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, "Cannot Bind for Dn "
-                + bindContext.getDn().getName() );
+            Collection<Authenticator> authenticators = getAuthenticators( authMech );
+
+            // try each authenticator
+            for ( Authenticator authenticator : authenticators )
+            {
+                authenticator.invalidateCache( principalDn );
+            }
         }
+    }
 
-        Collection<Authenticator> authenticators = getAuthenticators( level );
 
-        if ( authenticators == null )
+    /**
+     * {@inheritDoc}
+     */
+    public void modify( ModifyOperationContext modifyContext ) throws LdapException
+    {
+        if ( IS_DEBUG )
         {
-            LOG.debug( "No authenticators found, delegating bind to the nexus." );
-
-            // as a last resort try binding via the nexus
-            next( bindContext );
+            LOG.debug( "Operation Context: {}", modifyContext );
+        }
 
-            LOG.debug( "Nexus succeeded on bind operation." );
+        checkAuthenticated( modifyContext );
 
-            // bind succeeded if we got this far
-            // TODO - authentication level not being set
-            LdapPrincipal principal = new LdapPrincipal( schemaManager, bindContext.getDn(), AuthenticationLevel.SIMPLE );
-            CoreSession session = new DefaultCoreSession( principal, directoryService );
-            bindContext.setSession( session );
 
-            // remove creds so there is no security risk
-            bindContext.setCredentials( null );
+        if ( ! directoryService.isPwdPolicyEnabled() )
+        {
+            next( modifyContext );
+            invalidateAuthenticatorCaches( modifyContext.getDn() );
             return;
         }
 
-        boolean isPPolicyReqCtrlPresent = bindContext.hasRequestControl( PasswordPolicy.OID );
-        PasswordPolicyDecorator pwdRespCtrl =
-            new PasswordPolicyDecorator( directoryService.getLdapCodecService(), true );
+        // handle the case where pwdPolicySubentry AT is about to be deleted in thid modify()
+        PasswordPolicyConfiguration policyConfig = getPwdPolicy( modifyContext.getEntry() );
 
-        boolean authenticated = false;
-        PasswordPolicyException ppe = null;
+        boolean isPPolicyReqCtrlPresent = modifyContext.hasRequestControl( PasswordPolicy.OID );
+        Dn userDn = modifyContext.getSession().getAuthenticatedPrincipal().getDn();
 
-        // TODO : we should refactor that.
-        // try each authenticator
-        for ( Authenticator authenticator : authenticators )
+        PwdModDetailsHolder pwdModDetails = null;
+
+        pwdModDetails = getPwdModDetails( modifyContext, policyConfig );
+
+        if ( pwdModDetails.isPwdModPresent() )
         {
-            try
+            if ( pwdResetSet.contains( userDn ) )
             {
-                // perform the authentication
-                LdapPrincipal principal = authenticator.authenticate( bindContext );
-
-                LdapPrincipal clonedPrincipal = ( LdapPrincipal ) ( principal.clone() );
+                if ( pwdModDetails.isOtherModExists() )
+                {
+                    if ( isPPolicyReqCtrlPresent )
+                    {
+                        PasswordPolicyDecorator responseControl =
+                            new PasswordPolicyDecorator( directoryService.getLdapCodecService(), true );
+                        responseControl.getResponse().setPasswordPolicyError( PasswordPolicyErrorEnum.CHANGE_AFTER_RESET );
+                        modifyContext.addResponseControl( responseControl );
+                    }
 
-                // remove creds so there is no security risk
-                bindContext.setCredentials( null );
-                clonedPrincipal.setUserPassword( StringConstants.EMPTY_BYTES );
+                    throw new LdapNoPermissionException();
+                }
+            }
 
-                // authentication was successful
-                CoreSession session = new DefaultCoreSession( clonedPrincipal, directoryService );
-                bindContext.setSession( session );
+            if ( policyConfig.isPwdSafeModify() )
+            {
+                if ( pwdModDetails.isAddOrReplace() && !pwdModDetails.isDelete() )
+                {
+                    LOG.debug( "trying to update password attribute without the supplying the old password" );
 
-                authenticated = true;
+                    if ( isPPolicyReqCtrlPresent )
+                    {
+                        PasswordPolicyDecorator responseControl =
+                            new PasswordPolicyDecorator( directoryService.getLdapCodecService(), true );
+                        responseControl.getResponse().setPasswordPolicyError( PasswordPolicyErrorEnum.MUST_SUPPLY_OLD_PASSWORD );
+                        modifyContext.addResponseControl( responseControl );
+                    }
 
-                // break out of the loop if the authentication succeeded
-                break;
+                    throw new LdapNoPermissionException();
+                }
             }
-            catch ( PasswordPolicyException e )
+
+            if ( !policyConfig.isPwdAllowUserChange() && !modifyContext.getSession().isAnAdministrator() )
             {
-                ppe = e;
-                break;
+                if ( isPPolicyReqCtrlPresent )
+                {
+                    PasswordPolicyDecorator responseControl =
+                        new PasswordPolicyDecorator( directoryService.getLdapCodecService(), true );
+                    responseControl.getResponse().setPasswordPolicyError( PasswordPolicyErrorEnum.PASSWORD_MOD_NOT_ALLOWED );
+                    modifyContext.addResponseControl( responseControl );
+                }
+
+                throw new LdapNoPermissionException();
             }
-            catch ( LdapAuthenticationException e )
+
+            Entry entry = modifyContext.getEntry();
+
+            if ( isPwdTooYoung( entry, policyConfig ) )
             {
-                // authentication failed, try the next authenticator
-                if ( LOG.isInfoEnabled() )
+                if ( isPPolicyReqCtrlPresent )
                 {
-                    LOG.info( "Authenticator {} failed to authenticate: {}", authenticator, bindContext );
+                    PasswordPolicyDecorator responseControl =
+                        new PasswordPolicyDecorator( directoryService.getLdapCodecService(), true );
+                    responseControl.getResponse().setPasswordPolicyError( PasswordPolicyErrorEnum.PASSWORD_TOO_YOUNG );
+                    modifyContext.addResponseControl( responseControl );
                 }
+
+                throw new LdapOperationException( ResultCodeEnum.CONSTRAINT_VIOLATION,
+                    "password is too young to update" );
             }
-            catch ( Exception e )
+
+            byte[] newPassword = null;
+
+            if ( ( pwdModDetails != null ) )
             {
-                // Log other exceptions than LdapAuthenticationException
-                if ( LOG.isWarnEnabled() )
+                newPassword = pwdModDetails.getNewPwd();
+
+                try
                 {
-                    LOG.info( "Unexpected failure for Authenticator {} : {}", authenticator, bindContext );
+                    String userName = entry.getDn().getRdn().getUpValue().getString();
+                    check( userName, newPassword, policyConfig );
+                }
+                catch ( PasswordPolicyException e )
+                {
+                    if ( isPPolicyReqCtrlPresent )
+                    {
+                        PasswordPolicyDecorator responseControl =
+                            new PasswordPolicyDecorator( directoryService.getLdapCodecService(), true );
+                        responseControl.getResponse().setPasswordPolicyError( PasswordPolicyErrorEnum.get( e.getErrorCode() ) );
+                        modifyContext.addResponseControl( responseControl );
+                    }
+
+                    // throw exception if userPassword quality checks fail
+                    throw new LdapOperationException( ResultCodeEnum.CONSTRAINT_VIOLATION, e.getMessage(), e );
                 }
             }
-        }
 
-        if ( ppe != null )
-        {
-            if ( isPPolicyReqCtrlPresent )
+            int histSize = policyConfig.getPwdInHistory();
+            Modification pwdRemHistMod = null;
+            Modification pwdAddHistMod = null;
+            String pwdChangedTime = DateUtils.getGeneralizedTime();
+
+            if ( histSize > 0 )
             {
-                pwdRespCtrl.getResponse().setPasswordPolicyError( PasswordPolicyErrorEnum.get( ppe.getErrorCode() ) );
-                bindContext.addResponseControl( pwdRespCtrl );
+                Attribute pwdHistoryAt = entry.get( PWD_HISTORY_AT );
+
+                if ( pwdHistoryAt == null )
+                {
+                    pwdHistoryAt = new DefaultAttribute( AT_PWD_HISTORY );
+                }
+
+                List<PasswordHistory> pwdHistLst = new ArrayList<PasswordHistory>();
+
+                for ( Value<?> value : pwdHistoryAt  )
+                {
+                    PasswordHistory pwdh = new PasswordHistory( Strings.utf8ToString( value.getBytes() ) );
+
+                    boolean matched = Arrays.equals( newPassword, pwdh.getPassword() );
+
+                    if ( matched )
+                    {
+                        if ( isPPolicyReqCtrlPresent )
+                        {
+                            PasswordPolicyDecorator responseControl =
+                                new PasswordPolicyDecorator( directoryService.getLdapCodecService(), true );
+                            responseControl.getResponse().setPasswordPolicyError( PasswordPolicyErrorEnum.PASSWORD_IN_HISTORY );
+                            modifyContext.addResponseControl( responseControl );
+                        }
+
+                        throw new LdapOperationException( ResultCodeEnum.CONSTRAINT_VIOLATION,
+                            "invalid reuse of password present in password history" );
+                    }
+
+                    pwdHistLst.add( pwdh );
+                }
+
+                if ( pwdHistLst.size() >= histSize )
+                {
+                    // see the javadoc of PasswordHistory
+                    Collections.sort( pwdHistLst );
+
+                    // remove the oldest value
+                    PasswordHistory remPwdHist = ( PasswordHistory ) pwdHistLst.toArray()[histSize - 1];
+                    Attribute tempAt = new DefaultAttribute( AT_PWD_HISTORY );
+                    tempAt.add( remPwdHist.getHistoryValue() );
+                    pwdRemHistMod = new DefaultModification( REMOVE_ATTRIBUTE, tempAt );
+                }
+
+                pwdHistoryAt.clear();
+                PasswordHistory newPwdHist = new PasswordHistory( pwdChangedTime, newPassword );
+                pwdHistoryAt.clear();
+                pwdHistoryAt.add( newPwdHist.getHistoryValue() );
+                pwdAddHistMod = new DefaultModification( ADD_ATTRIBUTE, pwdHistoryAt );
             }
 
-            throw ppe;
-        }
-
-        Dn dn = bindContext.getDn();
-        Entry userEntry = bindContext.getEntry();
+            next( modifyContext );
 
-        PasswordPolicyConfiguration policyConfig = getPwdPolicy( userEntry );
+            invalidateAuthenticatorCaches( modifyContext.getDn() );
 
-        // check if the user entry is null, it will be null
-        // in cases of anonymous bind
-        if ( authenticated && ( userEntry == null ) && directoryService.isAllowAnonymousAccess() )
-        {
-            return;
-        }
+            List<Modification> mods = new ArrayList<Modification>();
 
-        if ( !authenticated )
-        {
-            if ( LOG.isInfoEnabled() )
+            if ( ( policyConfig.getPwdMinAge() > 0 ) || ( policyConfig.getPwdMaxAge() > 0 ) )
             {
-                LOG.info( "Cannot bind to the server " );
+                Attribute pwdChangedTimeAt = new DefaultAttribute( AT_PWD_CHANGED_TIME );
+                pwdChangedTimeAt.add( pwdChangedTime );
+                Modification pwdChangedTimeMod = new DefaultModification( REPLACE_ATTRIBUTE, pwdChangedTimeAt );
+                mods.add( pwdChangedTimeMod );
             }
 
-            if ( ( policyConfig != null ) && ( userEntry != null ) )
+            if ( pwdAddHistMod != null )
             {
-                Attribute pwdFailTimeAt = userEntry.get( PWD_FAILURE_TIME_AT );
-
-                if ( pwdFailTimeAt == null )
-                {
-                    pwdFailTimeAt = new DefaultAttribute( AT_PWD_FAILURE_TIME );
-                }
-                else
-                {
-                    PasswordUtil.purgeFailureTimes( policyConfig, pwdFailTimeAt );
-                }
+                mods.add( pwdAddHistMod );
+            }
 
-                String failureTime = DateUtils.getGeneralizedTime();
-                pwdFailTimeAt.add( failureTime );
-                Modification pwdFailTimeMod = new DefaultModification( ADD_ATTRIBUTE, pwdFailTimeAt );
+            if ( pwdRemHistMod != null )
+            {
+                mods.add( pwdRemHistMod );
+            }
 
-                List<Modification> mods = new ArrayList<Modification>();
-                mods.add( pwdFailTimeMod );
+            boolean removeFromPwdResetSet = false;
 
-                int numFailures = pwdFailTimeAt.size();
+            if ( policyConfig.isPwdMustChange() )
+            {
+                Attribute pwdMustChangeAt = new DefaultAttribute( AT_PWD_RESET );
+                Modification pwdMustChangeMod = null;
 
-                if ( policyConfig.isPwdLockout() && ( numFailures >= policyConfig.getPwdMaxFailure() ) )
+                if ( modifyContext.getSession().isAnAdministrator() )
                 {
-                    Attribute pwdAccountLockedTimeAt = new DefaultAttribute( AT_PWD_ACCOUNT_LOCKED_TIME );
-
-                    // if zero, lockout permanently, only admin can unlock it
-                    if ( policyConfig.getPwdLockoutDuration() == 0 )
-                    {
-                        pwdAccountLockedTimeAt.add( "000001010000Z" );
-                    }
-                    else
-                    {
-                        pwdAccountLockedTimeAt.add( failureTime );
-                    }
-
-                    Modification pwdAccountLockedMod = new DefaultModification( ADD_ATTRIBUTE, pwdAccountLockedTimeAt );
-                    mods.add( pwdAccountLockedMod );
-
-                    pwdRespCtrl.getResponse().setPasswordPolicyError( PasswordPolicyErrorEnum.ACCOUNT_LOCKED );
+                    pwdMustChangeAt.add( "TRUE" );
+                    pwdMustChangeMod = new DefaultModification( REPLACE_ATTRIBUTE, pwdMustChangeAt );
                 }
-                else if ( policyConfig.getPwdMinDelay() > 0 )
+                else
                 {
-                    int numDelay = numFailures * policyConfig.getPwdMinDelay();
-                    int maxDelay = policyConfig.getPwdMaxDelay();
-                    if ( numDelay > maxDelay )
-                    {
-                        numDelay = maxDelay;
-                    }
-
-                    try
-                    {
-                        Thread.sleep( numDelay * 1000 );
-                    }
-                    catch ( InterruptedException e )
-                    {
-                        LOG.warn(
-                            "Interrupted while delaying to send the failed authentication response for the user {}",
-                            dn, e );
-                    }
+                    pwdMustChangeMod = new DefaultModification( REMOVE_ATTRIBUTE, pwdMustChangeAt );
+                    removeFromPwdResetSet = true;
                 }
 
-                //adminSession.modify( dn, Collections.singletonList( pwdFailTimeMod ) );
-                ModifyOperationContext bindModCtx = new ModifyOperationContext( adminSession );
-                bindModCtx.setDn( dn );
-                bindModCtx.setModItems( mods );
-                directoryService.getPartitionNexus().modify( bindModCtx );
+                mods.add( pwdMustChangeMod );
             }
 
-            String upDn = ( dn == null ? "" : dn.getName() );
-            throw new LdapAuthenticationException( I18n.err( I18n.ERR_229, upDn ) );
-        }
-        else if ( policyConfig != null )
-        {
-            List<Modification> mods = new ArrayList<Modification>();
+            Attribute pwdFailureTimeAt = entry.get( PWD_FAILURE_TIME_AT );
 
-            if ( policyConfig.getPwdMaxIdle() > 0 )
+            if ( pwdFailureTimeAt != null )
             {
-                Attribute pwdLastSuccesTimeAt = new DefaultAttribute( AT_PWD_LAST_SUCCESS );
-                pwdLastSuccesTimeAt.add( DateUtils.getGeneralizedTime() );
-                Modification pwdLastSuccesTimeMod = new DefaultModification( REPLACE_ATTRIBUTE, pwdLastSuccesTimeAt );
-                mods.add( pwdLastSuccesTimeMod );
+                mods.add( new DefaultModification( REMOVE_ATTRIBUTE, pwdFailureTimeAt ) );
             }
 
-            Attribute pwdFailTimeAt = userEntry.get( AT_PWD_FAILURE_TIME );
+            Attribute pwdGraceUseTimeAt = entry.get( PWD_GRACE_USE_TIME_AT );
 
-            if ( pwdFailTimeAt != null )
+            if ( pwdGraceUseTimeAt != null )
             {
-                Modification pwdFailTimeMod = new DefaultModification( REMOVE_ATTRIBUTE, pwdFailTimeAt );
-                mods.add( pwdFailTimeMod );
+                mods.add( new DefaultModification( REMOVE_ATTRIBUTE, pwdGraceUseTimeAt ) );
             }
 
-            Attribute pwdAccLockedTimeAt = userEntry.get( AT_PWD_ACCOUNT_LOCKED_TIME );
+            directoryService.getAdminSession().modify( modifyContext.getDn(), mods );
 
-            if ( pwdAccLockedTimeAt != null )
+            if ( removeFromPwdResetSet )
             {
-                Modification pwdAccLockedTimeMod = new DefaultModification( REMOVE_ATTRIBUTE, pwdAccLockedTimeAt );
-                mods.add( pwdAccLockedTimeMod );
+                pwdResetSet.remove( userDn );
             }
+        }
+        else
+        {
+            next( modifyContext );
+            invalidateAuthenticatorCaches( modifyContext.getDn() );
+        }
+    }
 
-            // checking the expiration time *after* performing authentication, do we need to care about millisecond precision?
-            if ( ( policyConfig.getPwdMaxAge() > 0 ) && ( policyConfig.getPwdGraceAuthNLimit() > 0 ) )
-            {
-                Attribute pwdChangeTimeAttr = userEntry.get( PWD_CHANGED_TIME_AT );
 
-                if ( pwdChangeTimeAttr != null )
-                {
-                    boolean expired = PasswordUtil.isPwdExpired( pwdChangeTimeAttr.getString(),
-                        policyConfig.getPwdMaxAge() );
+    /**
+     * {@inheritDoc}
+     */
+    public void move( MoveOperationContext moveContext ) throws LdapException
+    {
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Operation Context: {}", moveContext );
+        }
 
-                    if ( expired )
-                    {
-                        Attribute pwdGraceUseAttr = userEntry.get( PWD_GRACE_USE_TIME_AT );
-                        int numGraceAuth = 0;
+        checkAuthenticated( moveContext );
+        checkPwdReset( moveContext );
+        next( moveContext );
+        invalidateAuthenticatorCaches( moveContext.getDn() );
+    }
 
-                        if ( pwdGraceUseAttr != null )
-                        {
-                            numGraceAuth = policyConfig.getPwdGraceAuthNLimit() - ( pwdGraceUseAttr.size() + 1 );
-                        }
-                        else
-                        {
-                            pwdGraceUseAttr = new DefaultAttribute( AT_PWD_GRACE_USE_TIME );
-                            numGraceAuth = policyConfig.getPwdGraceAuthNLimit() - 1;
-                        }
 
-                        pwdRespCtrl.getResponse().setGraceAuthNsRemaining( numGraceAuth );
+    /**
+     * {@inheritDoc}
+     */
+    public void moveAndRename( MoveAndRenameOperationContext moveAndRenameContext ) throws LdapException
+    {
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Operation Context: {}", moveAndRenameContext );
+        }
 
-                        pwdGraceUseAttr.add( DateUtils.getGeneralizedTime() );
-                        Modification pwdGraceUseMod = new DefaultModification( ADD_ATTRIBUTE, pwdGraceUseAttr );
-                        mods.add( pwdGraceUseMod );
-                    }
-                }
-            }
+        checkAuthenticated( moveAndRenameContext );
+        checkPwdReset( moveAndRenameContext );
+        next( moveAndRenameContext );
+        invalidateAuthenticatorCaches( moveAndRenameContext.getDn() );
+    }
 
-            if ( !mods.isEmpty() )
-            {
-                //adminSession.modify( dn, mods );
-                ModifyOperationContext bindModCtx = new ModifyOperationContext( adminSession );
-                bindModCtx.setDn( dn );
-                bindModCtx.setModItems( mods );
-                directoryService.getPartitionNexus().modify( bindModCtx );
-            }
 
-            if ( isPPolicyReqCtrlPresent )
-            {
-                int expiryWarnTime = getPwdTimeBeforeExpiry( userEntry, policyConfig );
+    /**
+     * {@inheritDoc}
+     */
+    public void rename( RenameOperationContext renameContext ) throws LdapException
+    {
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Operation Context: {}", renameContext );
+        }
 
-                if ( expiryWarnTime > 0 )
-                {
-                    pwdRespCtrl.getResponse().setTimeBeforeExpiration( expiryWarnTime );
-                }
+        checkAuthenticated( renameContext );
+        checkPwdReset( renameContext );
+        next( renameContext );
+        invalidateAuthenticatorCaches( renameContext.getDn() );
+    }
 
-                if ( isPwdMustReset( userEntry ) )
-                {
-                    pwdRespCtrl.getResponse().setPasswordPolicyError( PasswordPolicyErrorEnum.CHANGE_AFTER_RESET );
-                    pwdResetSet.add( dn );
-                }
 
-                bindContext.addResponseControl( pwdRespCtrl );
-            }
+    /**
+     * {@inheritDoc}
+     */
+    public EntryFilteringCursor search( SearchOperationContext searchContext ) throws LdapException
+    {
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Operation Context: {}", searchContext );
         }
+
+        checkAuthenticated( searchContext );
+        checkPwdReset( searchContext );
+
+        return next( searchContext );
     }
 
 
-    @Override
+    /**
+     * {@inheritDoc}
+     */
     public void unbind( UnbindOperationContext unbindContext ) throws LdapException
     {
         next( unbindContext );
@@ -1154,6 +1161,24 @@ public class AuthenticationInterceptor e
 
 
     /**
+     * Check if the current operation has a valid PrincipalDN or not.
+     *
+     * @param operation the operation type
+     * @throws Exception
+     */
+    private void checkAuthenticated( OperationContext operation ) throws LdapException
+    {
+        if ( operation.getSession().isAnonymous() && !directoryService.isAllowAnonymousAccess()
+            && !operation.getDn().isEmpty() )
+        {
+            String msg = I18n.err( I18n.ERR_5, operation.getName() );
+            LOG.error( msg );
+            throw new LdapNoPermissionException( msg );
+        }
+    }
+
+
+    /**
      * Initialize the PasswordPolicy attributeTypes
      * 
      * @throws LdapException If the initialization failed
@@ -1187,7 +1212,6 @@ public class AuthenticationInterceptor e
 
 
     // ---------- private methods ----------------
-
     private void check( String username, byte[] password, PasswordPolicyConfiguration policyConfig ) throws LdapException
     {
         final int qualityVal = policyConfig.getPwdCheckQuality();

Propchange: directory/apacheds/branches/apacheds-txns/interceptors/authz/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Sat Nov 12 18:24:38 2011
@@ -1 +1 @@
-/directory/apacheds/trunk/interceptors/authz:1183435-1200383
+/directory/apacheds/trunk/interceptors/authz:1183435-1201283