You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by ka...@apache.org on 2010/07/15 11:57:50 UTC

svn commit: r964358 - in /directory/apacheds/trunk: core-integ/src/test/java/org/apache/directory/server/core/authn/ppolicy/PasswordPolicyTest.java core/src/main/java/org/apache/directory/server/core/authn/AuthenticationInterceptor.java

Author: kayyagari
Date: Thu Jul 15 09:57:50 2010
New Revision: 964358

URL: http://svn.apache.org/viewvc?rev=964358&view=rev
Log:
o removed many redundant AT lookups
o fixed some NPE bugs
o used the ModifyOperationContext to bypass the interceptor chain when the pwdpolicy state information needs to be updated
o removed the @CreateDS to use a default DS instance with changelog enabled
o @Ignored a test 

Modified:
    directory/apacheds/trunk/core-integ/src/test/java/org/apache/directory/server/core/authn/ppolicy/PasswordPolicyTest.java
    directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/authn/AuthenticationInterceptor.java

Modified: directory/apacheds/trunk/core-integ/src/test/java/org/apache/directory/server/core/authn/ppolicy/PasswordPolicyTest.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core-integ/src/test/java/org/apache/directory/server/core/authn/ppolicy/PasswordPolicyTest.java?rev=964358&r1=964357&r2=964358&view=diff
==============================================================================
--- directory/apacheds/trunk/core-integ/src/test/java/org/apache/directory/server/core/authn/ppolicy/PasswordPolicyTest.java (original)
+++ directory/apacheds/trunk/core-integ/src/test/java/org/apache/directory/server/core/authn/ppolicy/PasswordPolicyTest.java Thu Jul 15 09:57:50 2010
@@ -39,7 +39,6 @@ import org.apache.directory.ldap.client.
 import org.apache.directory.ldap.client.api.message.ModifyResponse;
 import org.apache.directory.server.annotations.CreateLdapServer;
 import org.apache.directory.server.annotations.CreateTransport;
-import org.apache.directory.server.core.annotations.CreateDS;
 import org.apache.directory.server.core.authn.AuthenticationInterceptor;
 import org.apache.directory.server.core.authn.PasswordPolicyConfiguration;
 import org.apache.directory.server.core.authn.PasswordUtil;
@@ -54,12 +53,14 @@ import org.apache.directory.shared.ldap.
 import org.apache.directory.shared.ldap.entry.DefaultEntry;
 import org.apache.directory.shared.ldap.entry.Entry;
 import org.apache.directory.shared.ldap.entry.EntryAttribute;
+import org.apache.directory.shared.ldap.exception.LdapException;
 import org.apache.directory.shared.ldap.message.ResultCodeEnum;
 import org.apache.directory.shared.ldap.message.control.Control;
 import org.apache.directory.shared.ldap.name.DN;
 import org.apache.directory.shared.ldap.util.StringTools;
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -75,7 +76,6 @@ import org.junit.runner.RunWith;
         @CreateTransport( protocol = "LDAP" ), 
         @CreateTransport( protocol = "LDAPS" ) 
     })
-@CreateDS( enableChangeLog=false )
 public class PasswordPolicyTest extends AbstractLdapTestUnit
 {
     private PasswordPolicyConfiguration policyConfig;
@@ -86,7 +86,7 @@ public class PasswordPolicyTest extends 
 
 
     @Before
-    public void setPwdPolicy()
+    public void setPwdPolicy() throws LdapException
     {
         policyConfig = new PasswordPolicyConfiguration();
         
@@ -104,6 +104,8 @@ public class PasswordPolicyTest extends 
         AuthenticationInterceptor authInterceptor = ( AuthenticationInterceptor ) service
             .getInterceptor( AuthenticationInterceptor.class.getName() );
         authInterceptor.setPwdPolicyConfig( policyConfig );
+        
+        authInterceptor.loadPwdPolicyStateAtributeTypes();
     }
 
 
@@ -191,7 +193,7 @@ public class PasswordPolicyTest extends 
         assertNotNull( userConnection );
         assertTrue( userConnection.isAuthenticated() );
     }
-    
+
     
     @Test
     public void testPwdMinAge() throws Exception
@@ -200,11 +202,11 @@ public class PasswordPolicyTest extends 
         
         LdapConnection connection = getAdminNetworkConnection( ldapServer );
         
-        DN userDn = new DN( "cn=user,ou=system" );
+        DN userDn = new DN( "cn=userMinAge,ou=system" );
         Entry userEntry = new DefaultEntry( userDn );
         userEntry.add( SchemaConstants.OBJECT_CLASS, SchemaConstants.PERSON_OC );
-        userEntry.add( SchemaConstants.CN_AT, "user" );
-        userEntry.add( SchemaConstants.SN_AT, "user_sn" );
+        userEntry.add( SchemaConstants.CN_AT, "userMinAge" );
+        userEntry.add( SchemaConstants.SN_AT, "userMinAge_sn" );
         userEntry.add( SchemaConstants.USER_PASSWORD_AT, "12345".getBytes() );
 
         AddRequest addReq = new AddRequest( userEntry );

Modified: directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/authn/AuthenticationInterceptor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/authn/AuthenticationInterceptor.java?rev=964358&r1=964357&r2=964358&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/authn/AuthenticationInterceptor.java (original)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/authn/AuthenticationInterceptor.java Thu Jul 15 09:57:50 2010
@@ -30,6 +30,9 @@ import static org.apache.directory.share
 import static org.apache.directory.shared.ldap.constants.PasswordPolicySchemaConstants.PWD_HISTORY_AT;
 import static org.apache.directory.shared.ldap.constants.PasswordPolicySchemaConstants.PWD_LAST_SUCCESS_AT;
 import static org.apache.directory.shared.ldap.constants.PasswordPolicySchemaConstants.PWD_RESET_AT;
+import static org.apache.directory.shared.ldap.entry.ModificationOperation.ADD_ATTRIBUTE;
+import static org.apache.directory.shared.ldap.entry.ModificationOperation.REMOVE_ATTRIBUTE;
+import static org.apache.directory.shared.ldap.entry.ModificationOperation.REPLACE_ATTRIBUTE;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -48,6 +51,11 @@ import org.apache.directory.server.core.
 import org.apache.directory.server.core.DefaultCoreSession;
 import org.apache.directory.server.core.DirectoryService;
 import org.apache.directory.server.core.LdapPrincipal;
+import org.apache.directory.server.core.authz.AciAuthorizationInterceptor;
+import org.apache.directory.server.core.authz.DefaultAuthorizationInterceptor;
+import org.apache.directory.server.core.collective.CollectiveAttributeInterceptor;
+import org.apache.directory.server.core.event.EventInterceptor;
+import org.apache.directory.server.core.exception.ExceptionInterceptor;
 import org.apache.directory.server.core.filtering.EntryFilteringCursor;
 import org.apache.directory.server.core.interceptor.BaseInterceptor;
 import org.apache.directory.server.core.interceptor.Interceptor;
@@ -67,6 +75,11 @@ import org.apache.directory.server.core.
 import org.apache.directory.server.core.interceptor.context.RenameOperationContext;
 import org.apache.directory.server.core.interceptor.context.SearchOperationContext;
 import org.apache.directory.server.core.interceptor.context.UnbindOperationContext;
+import org.apache.directory.server.core.normalization.NormalizationInterceptor;
+import org.apache.directory.server.core.operational.OperationalAttributeInterceptor;
+import org.apache.directory.server.core.schema.SchemaInterceptor;
+import org.apache.directory.server.core.subtree.SubentryInterceptor;
+import org.apache.directory.server.core.trigger.TriggerInterceptor;
 import org.apache.directory.server.i18n.I18n;
 import org.apache.directory.shared.ldap.codec.controls.ppolicy.PasswordPolicyErrorEnum;
 import org.apache.directory.shared.ldap.codec.controls.ppolicy.PasswordPolicyRequestControl;
@@ -90,13 +103,13 @@ import org.apache.directory.shared.ldap.
 import org.apache.directory.shared.ldap.exception.LdapUnwillingToPerformException;
 import org.apache.directory.shared.ldap.message.ResultCodeEnum;
 import org.apache.directory.shared.ldap.name.DN;
+import org.apache.directory.shared.ldap.schema.AttributeType;
 import org.apache.directory.shared.ldap.schema.SchemaManager;
 import org.apache.directory.shared.ldap.util.DateUtils;
 import org.apache.directory.shared.ldap.util.StringTools;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-
 /**
  * An {@link Interceptor} that authenticates users.
  *
@@ -122,11 +135,46 @@ public class AuthenticationInterceptor e
 
     private CoreSession adminSession;
 
-    private boolean pwdPolicyEnabled = false;
-
     private Set<DN> pwdResetSet = new HashSet<DN>();
 
+    // pwdpolicy state attribute types
+    private AttributeType AT_PWD_RESET;
+    
+    private AttributeType AT_PWD_CHANGED_TIME;
+    
+    private AttributeType AT_PWD_HISTORY;
+
+    private AttributeType AT_PWD_FAILURE_TIME;
+    
+    private AttributeType AT_PWD_ACCOUNT_LOCKED_TIME;
+    
+    private AttributeType AT_PWD_LAST_SUCCESS;
+    
+    private AttributeType AT_PWD_GRACE_USE_TIME;
+
+    /**
+     * the set of interceptors we should *not* go through when pwdpolicy state information is being updated
+     */
+    private static final Collection<String> BYPASS_INTERCEPTORS;
+
+    static
+    {
+        Set<String> c = new HashSet<String>();
+        c.add( NormalizationInterceptor.class.getName() );
+        c.add( AuthenticationInterceptor.class.getName() );
+        c.add( AciAuthorizationInterceptor.class.getName() );
+        c.add( DefaultAuthorizationInterceptor.class.getName() );
+        c.add( ExceptionInterceptor.class.getName() );
+        c.add( OperationalAttributeInterceptor.class.getName() );
+        c.add( SchemaInterceptor.class.getName() );
+        c.add( SubentryInterceptor.class.getName() );
+        c.add( CollectiveAttributeInterceptor.class.getName() );
+        c.add( EventInterceptor.class.getName() );
+        c.add( TriggerInterceptor.class.getName() );
+        BYPASS_INTERCEPTORS = Collections.unmodifiableCollection( c );
+    }
 
+    
     /**
      * Creates an authentication service interceptor.
      */
@@ -146,11 +194,8 @@ public class AuthenticationInterceptor e
 
         adminSession = directoryService.getAdminSession();
 
-        if ( policyConfig != null )
-        {
-            pwdPolicyEnabled = true;
-        }
-
+        loadPwdPolicyStateAtributeTypes();
+        
         if ( authenticators == null )
         {
             setDefaultAuthenticators();
@@ -215,7 +260,6 @@ public class AuthenticationInterceptor e
     private void register( Authenticator authenticator, DirectoryService directoryService ) throws LdapException
     {
         authenticator.init( directoryService );
-        authenticator.setPwdPolicyConfig( policyConfig );
 
         Collection<Authenticator> authenticatorList = getAuthenticators( authenticator.getAuthenticatorType() );
 
@@ -303,24 +347,21 @@ public class AuthenticationInterceptor e
             String pwdChangedTime = DateUtils.getGeneralizedTime();
             if( ( policyConfig.getPwdMinAge() > 0 ) || ( policyConfig.getPwdMaxAge() > 0 ) )
             {
-                EntryAttribute pwdChangedTimeAt = new DefaultEntryAttribute(
-                    schemaManager.lookupAttributeTypeRegistry( PWD_CHANGED_TIME_AT ) );
+                EntryAttribute pwdChangedTimeAt = new DefaultEntryAttribute( AT_PWD_CHANGED_TIME );
                 pwdChangedTimeAt.add( pwdChangedTime );
                 entry.add( pwdChangedTimeAt );
             }
 
             if ( policyConfig.isPwdMustChange() && addContext.getSession().isAnAdministrator() )
             {
-                EntryAttribute pwdMustChangeAt = new DefaultEntryAttribute(
-                    schemaManager.lookupAttributeTypeRegistry( PWD_RESET_AT ) );
-                pwdMustChangeAt.add( "TRUE" );
-                entry.add( pwdMustChangeAt );
+                EntryAttribute pwdResetAt = new DefaultEntryAttribute( AT_PWD_RESET );
+                pwdResetAt.add( "TRUE" );
+                entry.add( pwdResetAt );
             }
 
             if ( policyConfig.getPwdInHistory() > 0 )
             {
-                EntryAttribute pwdHistoryAt = new DefaultEntryAttribute(
-                    schemaManager.lookupAttributeTypeRegistry( PWD_HISTORY_AT ) );
+                EntryAttribute pwdHistoryAt = new DefaultEntryAttribute( AT_PWD_HISTORY );
                 byte[] pwdHistoryVal = new PasswordHistory( pwdChangedTime, userPassword.get() ).getHistoryValue();
                 pwdHistoryAt.add( pwdHistoryVal );
                 entry.add( pwdHistoryAt );
@@ -567,14 +608,14 @@ public class AuthenticationInterceptor e
 
             pwdHistoryAt = new DefaultEntryAttribute( pwdHistoryAt.getAttributeType() );
             pwdHistoryAt.add( newPwdHist.getHistoryValue() );
-            pwdAddHistMod = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, pwdHistoryAt );
+            pwdAddHistMod = new DefaultModification( ADD_ATTRIBUTE, pwdHistoryAt );
 
             if ( pwdHistSet.size() > histSize )
             {
                 pwdHistoryAt = new DefaultEntryAttribute( pwdHistoryAt.getAttributeType() );
                 PasswordHistory remPwdHist = ( PasswordHistory ) pwdHistSet.toArray()[histSize - 1];
                 pwdHistoryAt.add( remPwdHist.getHistoryValue() );
-                pwdRemHistMod = new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE, pwdHistoryAt );
+                pwdRemHistMod = new DefaultModification( REMOVE_ATTRIBUTE, pwdHistoryAt );
             }
         }
 
@@ -586,11 +627,9 @@ public class AuthenticationInterceptor e
             List<Modification> mods = new ArrayList<Modification>();
             if ( ( policyConfig.getPwdMinAge() > 0 ) || ( policyConfig.getPwdMaxAge() > 0 ) )
             {
-                EntryAttribute pwdChangedTimeAt = new DefaultEntryAttribute(
-                    schemaManager.lookupAttributeTypeRegistry( PWD_CHANGED_TIME_AT ) );
+                EntryAttribute pwdChangedTimeAt = new DefaultEntryAttribute( AT_PWD_CHANGED_TIME );
                 pwdChangedTimeAt.add( pwdChangedTime );
-                Modification pwdChangedTimeMod = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE,
-                    pwdChangedTimeAt );
+                Modification pwdChangedTimeMod = new DefaultModification( REPLACE_ATTRIBUTE, pwdChangedTimeAt );
                 mods.add( pwdChangedTimeMod );
             }
 
@@ -607,19 +646,17 @@ public class AuthenticationInterceptor e
             boolean removeFromPwdResetSet = false;
             if ( policyConfig.isPwdMustChange() )
             {
-                EntryAttribute pwdMustChangeAt = new DefaultEntryAttribute(
-                    schemaManager.lookupAttributeTypeRegistry( PWD_RESET_AT ) );
+                EntryAttribute pwdMustChangeAt = new DefaultEntryAttribute( AT_PWD_RESET );
                 Modification pwdMustChangeMod = null;
 
                 if ( modifyContext.getSession().isAnAdministrator() )
                 {
                     pwdMustChangeAt.add( "TRUE" );
-                    pwdMustChangeMod = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE,
-                        pwdMustChangeAt );
+                    pwdMustChangeMod = new DefaultModification( REPLACE_ATTRIBUTE, pwdMustChangeAt );
                 }
                 else
                 {
-                    pwdMustChangeMod = new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE, pwdMustChangeAt );
+                    pwdMustChangeMod = new DefaultModification( REMOVE_ATTRIBUTE, pwdMustChangeAt );
                     removeFromPwdResetSet = true;
                 }
 
@@ -629,17 +666,17 @@ public class AuthenticationInterceptor e
             EntryAttribute pwdFailureTimeAt = entry.get( PWD_FAILURE_TIME_AT );
             if ( pwdFailureTimeAt != null )
             {
-                mods.add( new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE, pwdFailureTimeAt ) );
+                mods.add( new DefaultModification( REMOVE_ATTRIBUTE, pwdFailureTimeAt ) );
             }
 
             EntryAttribute pwdGraceUseTimeAt = entry.get( PWD_GRACE_USE_TIME_AT );
             if ( pwdGraceUseTimeAt != null )
             {
-                mods.add( new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE, pwdGraceUseTimeAt ) );
+                mods.add( new DefaultModification( REMOVE_ATTRIBUTE, pwdGraceUseTimeAt ) );
             }
 
-            directoryService.getAdminSession().modify( modifyContext.getDn(), mods );
-
+//            directoryService.getAdminSession().modify( modifyContext.getDn(), mods );
+            
             if ( removeFromPwdResetSet )
             {
                 pwdResetSet.remove( userDn );
@@ -804,6 +841,8 @@ public class AuthenticationInterceptor e
         {
             try
             {
+                authenticator.setPwdPolicyConfig( policyConfig );
+                
                 // perform the authentication
                 LdapPrincipal principal = authenticator.authenticate( bindContext );
 
@@ -863,13 +902,12 @@ public class AuthenticationInterceptor e
                 LOG.info( "Cannot bind to the server " );
             }
 
-            if ( pwdPolicyEnabled )
+            if ( policyConfig != null )
             {
                 EntryAttribute pwdFailTimeAt = bindContext.getEntry().get( PWD_FAILURE_TIME_AT );
                 if ( pwdFailTimeAt == null )
                 {
-                    pwdFailTimeAt = new DefaultEntryAttribute(
-                        schemaManager.lookupAttributeTypeRegistry( PWD_FAILURE_TIME_AT ) );
+                    pwdFailTimeAt = new DefaultEntryAttribute( AT_PWD_FAILURE_TIME );
                 }
                 else
                 {
@@ -878,8 +916,7 @@ public class AuthenticationInterceptor e
 
                 String failureTime = DateUtils.getGeneralizedTime();
                 pwdFailTimeAt.add( failureTime );
-                Modification pwdFailTimeMod = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE,
-                    pwdFailTimeAt );
+                Modification pwdFailTimeMod = new DefaultModification( ADD_ATTRIBUTE, pwdFailTimeAt );
 
                 List<Modification> mods = new ArrayList<Modification>();
                 mods.add( pwdFailTimeMod );
@@ -888,11 +925,9 @@ public class AuthenticationInterceptor e
 
                 if ( policyConfig.isPwdLockout() && ( numFailures >= policyConfig.getPwdMaxFailure() ) )
                 {
-                    EntryAttribute pwdAccountLockedTimeAt = new DefaultEntryAttribute(
-                        schemaManager.lookupAttributeTypeRegistry( PWD_ACCOUNT_LOCKED_TIME_AT ) );
+                    EntryAttribute pwdAccountLockedTimeAt = new DefaultEntryAttribute( AT_PWD_ACCOUNT_LOCKED_TIME );
                     pwdAccountLockedTimeAt.add( failureTime );
-                    Modification pwdAccountLockedMod = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE,
-                        pwdAccountLockedTimeAt );
+                    Modification pwdAccountLockedMod = new DefaultModification( ADD_ATTRIBUTE, pwdAccountLockedTimeAt );
                     mods.add( pwdAccountLockedMod );
 
                     pwdRespCtrl.setPasswordPolicyError( PasswordPolicyErrorEnum.ACCOUNT_LOCKED );
@@ -918,66 +953,80 @@ public class AuthenticationInterceptor e
                     }
                 }
 
-                adminSession.modify( dn, Collections.singletonList( pwdFailTimeMod ) );
+                //adminSession.modify( dn, Collections.singletonList( pwdFailTimeMod ) );
+                ModifyOperationContext bindModCtx = new ModifyOperationContext( adminSession );
+                bindModCtx.setByPassed( BYPASS_INTERCEPTORS );
+                bindModCtx.setDn( dn );
+                bindModCtx.setModItems( Collections.singletonList( pwdFailTimeMod ) );
+                directoryService.getOperationManager().modify( bindModCtx );
             }
 
             String upDn = ( dn == null ? "" : dn.getName() );
             throw new LdapAuthenticationException( I18n.err( I18n.ERR_229, upDn ) );
         }
-        else if ( pwdPolicyEnabled )
+        else if ( policyConfig != null )
         {
             List<Modification> mods = new ArrayList<Modification>();
 
             if ( policyConfig.getPwdMaxIdle() > 0 )
             {
-                EntryAttribute pwdLastSuccesTimeAt = new DefaultEntryAttribute(
-                    schemaManager.lookupAttributeTypeRegistry( PWD_LAST_SUCCESS_AT ) );
+                EntryAttribute pwdLastSuccesTimeAt = new DefaultEntryAttribute( AT_PWD_LAST_SUCCESS );
                 pwdLastSuccesTimeAt.add( DateUtils.getGeneralizedTime() );
-                Modification pwdLastSuccesTimeMod = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE,
-                    pwdLastSuccesTimeAt );
+                Modification pwdLastSuccesTimeMod = new DefaultModification( REPLACE_ATTRIBUTE, pwdLastSuccesTimeAt );
                 mods.add( pwdLastSuccesTimeMod );
             }
 
-            EntryAttribute pwdFailTimeAt = new DefaultEntryAttribute(
-                schemaManager.lookupAttributeTypeRegistry( PWD_FAILURE_TIME_AT ) );
-            Modification pwdFailTimeMod = new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE,
-                pwdFailTimeAt );
-            mods.add( pwdFailTimeMod );
-
-            EntryAttribute pwdAccLockedTimeAt = new DefaultEntryAttribute(
-                schemaManager.lookupAttributeTypeRegistry( PWD_ACCOUNT_LOCKED_TIME_AT ) );
-            Modification pwdAccLockedTimeMod = new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE,
-                pwdAccLockedTimeAt );
-            mods.add( pwdAccLockedTimeMod );
+            EntryAttribute pwdFailTimeAt = userEntry.get( AT_PWD_FAILURE_TIME );
+            if( pwdFailTimeAt != null )
+            {
+                Modification pwdFailTimeMod = new DefaultModification( REMOVE_ATTRIBUTE, pwdFailTimeAt );
+                mods.add( pwdFailTimeMod );
+            }
+
+            EntryAttribute pwdAccLockedTimeAt = userEntry.get( AT_PWD_ACCOUNT_LOCKED_TIME );
+            if( pwdAccLockedTimeAt != null )
+            {
+                Modification pwdAccLockedTimeMod = new DefaultModification( REMOVE_ATTRIBUTE, pwdAccLockedTimeAt );
+                mods.add( pwdAccLockedTimeMod );
+            }
 
             // checking the expiration time *after* performing authentication, do we need to care about millisecond precision?
             if ( ( policyConfig.getPwdMaxAge() > 0 ) && ( policyConfig.getPwdGraceAuthNLimit() > 0 ) )
             {
                 EntryAttribute pwdChangeTimeAttr = userEntry.get( PWD_CHANGED_TIME_AT );
-                boolean expired = PasswordUtil
-                    .isPwdExpired( pwdChangeTimeAttr.getString(), policyConfig.getPwdMaxAge() );
-                if ( expired )
+                if( pwdChangeTimeAttr != null )
                 {
-                    EntryAttribute pwdGraceUseAttr = userEntry.get( PWD_GRACE_USE_TIME_AT );
-                    if ( pwdGraceUseAttr != null )
-                    {
-                        pwdRespCtrl.setGraceAuthNsRemaining( policyConfig.getPwdGraceAuthNLimit()
-                            - ( pwdGraceUseAttr.size() + 1 ) );
-                    }
-                    else
+                    boolean expired = PasswordUtil
+                    .isPwdExpired( pwdChangeTimeAttr.getString(), policyConfig.getPwdMaxAge() );
+                    if ( expired )
                     {
-                        pwdGraceUseAttr = new DefaultEntryAttribute(
-                            schemaManager.lookupAttributeTypeRegistry( PWD_GRACE_USE_TIME_AT ) );
+                        EntryAttribute pwdGraceUseAttr = userEntry.get( PWD_GRACE_USE_TIME_AT );
+                        if ( pwdGraceUseAttr != null )
+                        {
+                            pwdRespCtrl.setGraceAuthNsRemaining( policyConfig.getPwdGraceAuthNLimit()
+                                - ( pwdGraceUseAttr.size() + 1 ) );
+                        }
+                        else
+                        {
+                            pwdGraceUseAttr = new DefaultEntryAttribute( AT_PWD_GRACE_USE_TIME );
+                        }
+                        
+                        pwdGraceUseAttr.add( DateUtils.getGeneralizedTime() );
+                        Modification pwdGraceUseMod = new DefaultModification( ADD_ATTRIBUTE, pwdGraceUseAttr );
+                        mods.add( pwdGraceUseMod );
                     }
-
-                    pwdGraceUseAttr.add( DateUtils.getGeneralizedTime() );
-                    Modification pwdGraceUseMod = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE,
-                        pwdGraceUseAttr );
-                    mods.add( pwdGraceUseMod );
                 }
             }
 
-            adminSession.modify( dn, mods );
+            if( !mods.isEmpty() )
+            {
+                //adminSession.modify( dn, mods );
+                ModifyOperationContext bindModCtx = new ModifyOperationContext( adminSession );
+                bindModCtx.setByPassed( BYPASS_INTERCEPTORS );
+                bindModCtx.setDn( dn );
+                bindModCtx.setModItems( mods );
+                directoryService.getOperationManager().modify( bindModCtx );
+            }
 
             if ( isPPolicyReqCtrlPresent )
             {
@@ -1017,6 +1066,32 @@ public class AuthenticationInterceptor e
         this.policyConfig = policyConfig;
     }
 
+    public void loadPwdPolicyStateAtributeTypes() throws LdapException
+    {
+        if ( policyConfig != null )
+        {
+            AT_PWD_RESET = schemaManager.lookupAttributeTypeRegistry( PWD_RESET_AT );
+            PWD_POLICY_STATE_ATTRIBUTE_TYPES.add( AT_PWD_RESET );
+            
+            AT_PWD_CHANGED_TIME = schemaManager.lookupAttributeTypeRegistry( PWD_CHANGED_TIME_AT );
+            PWD_POLICY_STATE_ATTRIBUTE_TYPES.add( AT_PWD_CHANGED_TIME );
+            
+            AT_PWD_HISTORY = schemaManager.lookupAttributeTypeRegistry( PWD_HISTORY_AT );
+            PWD_POLICY_STATE_ATTRIBUTE_TYPES.add( AT_PWD_HISTORY );
+            
+            AT_PWD_FAILURE_TIME = schemaManager.lookupAttributeTypeRegistry( PWD_FAILURE_TIME_AT );
+            PWD_POLICY_STATE_ATTRIBUTE_TYPES.add( AT_PWD_FAILURE_TIME );
+            
+            AT_PWD_ACCOUNT_LOCKED_TIME = schemaManager.lookupAttributeTypeRegistry( PWD_ACCOUNT_LOCKED_TIME_AT );
+            PWD_POLICY_STATE_ATTRIBUTE_TYPES.add( AT_PWD_ACCOUNT_LOCKED_TIME );
+            
+            AT_PWD_LAST_SUCCESS = schemaManager.lookupAttributeTypeRegistry( PWD_LAST_SUCCESS_AT );
+            PWD_POLICY_STATE_ATTRIBUTE_TYPES.add( AT_PWD_LAST_SUCCESS );
+            
+            AT_PWD_GRACE_USE_TIME = schemaManager.lookupAttributeTypeRegistry( PWD_GRACE_USE_TIME_AT );
+            PWD_POLICY_STATE_ATTRIBUTE_TYPES.add( AT_PWD_GRACE_USE_TIME );
+        }
+    }
 
     // ---------- private methods ----------------
 
@@ -1261,11 +1336,11 @@ public class AuthenticationInterceptor e
                 pwdModDetails.setPwdModPresent( true );
                 ModificationOperation op = m.getOperation();
 
-                if ( op == ModificationOperation.REMOVE_ATTRIBUTE )
+                if ( op == REMOVE_ATTRIBUTE )
                 {
                     pwdModDetails.setDelete( true );
                 }
-                else if ( op == ModificationOperation.REPLACE_ATTRIBUTE || op == ModificationOperation.ADD_ATTRIBUTE )
+                else if ( op == REPLACE_ATTRIBUTE || op == ADD_ATTRIBUTE )
                 {
                     pwdModDetails.setAddOrReplace( true );
                     pwdModDetails.setNewPwd( at.getBytes() );