You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by lu...@apache.org on 2014/01/24 21:10:49 UTC

svn commit: r1561139 - in /directory/apacheds/trunk: interceptors/authn/src/main/java/org/apache/directory/server/core/authn/ protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/extended/ server-integ/src/test/java/org/apache/director...

Author: lucastheisen
Date: Fri Jan 24 20:10:49 2014
New Revision: 1561139

URL: http://svn.apache.org/r1561139
Log:
DIRSERVER-1928: PasswordPolicy should be ignored from Admin session

Modified:
    directory/apacheds/trunk/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AuthenticationInterceptor.java
    directory/apacheds/trunk/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/extended/PwdModifyHandler.java
    directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/operations/extended/PwdModifyIT.java
    directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/ppolicy/PasswordPolicyIT.java

Modified: directory/apacheds/trunk/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AuthenticationInterceptor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AuthenticationInterceptor.java?rev=1561139&r1=1561138&r2=1561139&view=diff
==============================================================================
--- directory/apacheds/trunk/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AuthenticationInterceptor.java (original)
+++ directory/apacheds/trunk/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AuthenticationInterceptor.java Fri Jan 24 20:10:49 2014
@@ -358,7 +358,7 @@ public class AuthenticationInterceptor e
 
             try
             {
-                check( entry, userPassword.getValue(), policyConfig );
+                check( addContext, entry, userPassword.getValue(), policyConfig );
             }
             catch ( PasswordPolicyException e )
             {
@@ -917,7 +917,7 @@ public class AuthenticationInterceptor e
 
             if ( pwdModDetails.isAddOrReplace() )
             {
-                if ( isPwdTooYoung( entry, policyConfig ) )
+                if ( isPwdTooYoung( modifyContext, entry, policyConfig ) )
                 {
                     if ( isPPolicyReqCtrlPresent )
                     {
@@ -936,7 +936,7 @@ public class AuthenticationInterceptor e
 
                 try
                 {
-                    check( entry, newPassword, policyConfig );
+                    check( modifyContext, entry, newPassword, policyConfig );
                 }
                 catch ( PasswordPolicyException e )
                 {
@@ -1252,9 +1252,15 @@ public class AuthenticationInterceptor e
 
 
     // ---------- private methods ----------------
-    private void check( Entry entry, byte[] password, PasswordPolicyConfiguration policyConfig )
+    private void check( OperationContext operationContext, Entry entry, 
+        byte[] password, PasswordPolicyConfiguration policyConfig )
         throws LdapException
     {
+        // https://issues.apache.org/jira/browse/DIRSERVER-1928
+        if ( operationContext.getSession().isAnAdministrator() ) 
+        {
+            return;    
+        }
         final CheckQualityEnum qualityVal = policyConfig.getPwdCheckQuality();
 
         if ( qualityVal == CheckQualityEnum.NO_CHECK )
@@ -1363,9 +1369,15 @@ public class AuthenticationInterceptor e
      * @return true if the password is young, false otherwise
      * @throws LdapException
      */
-    private boolean isPwdTooYoung( Entry userEntry, PasswordPolicyConfiguration policyConfig ) throws LdapException
+    private boolean isPwdTooYoung( OperationContext operationContext, 
+        Entry userEntry, PasswordPolicyConfiguration policyConfig ) throws LdapException
     {
-        if ( policyConfig.getPwdMinAge() == 0 )
+       // https://issues.apache.org/jira/browse/DIRSERVER-1928
+       if ( operationContext.getSession().isAnAdministrator() ) 
+       {
+           return false;    
+       }
+       if ( policyConfig.getPwdMinAge() == 0 )
         {
             return false;
         }

Modified: directory/apacheds/trunk/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/extended/PwdModifyHandler.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/extended/PwdModifyHandler.java?rev=1561139&r1=1561138&r2=1561139&view=diff
==============================================================================
--- directory/apacheds/trunk/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/extended/PwdModifyHandler.java (original)
+++ directory/apacheds/trunk/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/extended/PwdModifyHandler.java Fri Jan 24 20:10:49 2014
@@ -235,10 +235,9 @@ public class PwdModifyHandler implements
         PwdModifyRequest req )
     {
         DirectoryService service = requestor.getLdapServer().getDirectoryService();
-        CoreSession adminSession = service.getAdminSession();
 
         // Try to update the userPassword
-        ModifyOperationContext modifyContext = new ModifyOperationContext( adminSession );
+        ModifyOperationContext modifyContext = new ModifyOperationContext( requestor.getCoreSession() );
         modifyContext.setDn( principalDn );
 
         Control ppolicyControl = req.getControl( PasswordPolicy.OID );
@@ -416,7 +415,8 @@ public class PwdModifyHandler implements
 
             // Ok, we were able to bind using the userIdentity and the password. Let's
             // modify the password now
-            ModifyOperationContext modifyContext = new ModifyOperationContext( adminSession );
+            ModifyOperationContext modifyContext = new ModifyOperationContext( 
+                service.getSession( userDn, oldPassword ) );
             modifyContext.setDn( userDn );
             List<Modification> modifications = new ArrayList<Modification>();
             Modification modification = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE,

Modified: directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/operations/extended/PwdModifyIT.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/operations/extended/PwdModifyIT.java?rev=1561139&r1=1561138&r2=1561139&view=diff
==============================================================================
--- directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/operations/extended/PwdModifyIT.java (original)
+++ directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/operations/extended/PwdModifyIT.java Fri Jan 24 20:10:49 2014
@@ -24,9 +24,11 @@ import static org.apache.directory.serve
 import static org.apache.directory.server.core.integ.IntegrationUtils.getAnonymousNetworkConnection;
 import static org.apache.directory.server.core.integ.IntegrationUtils.getNetworkConnectionAs;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 
+
 import org.apache.directory.api.ldap.codec.api.LdapApiService;
 import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
 import org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicy;
@@ -35,6 +37,7 @@ import org.apache.directory.api.ldap.ext
 import org.apache.directory.api.ldap.extras.controls.ppolicy_impl.PasswordPolicyDecorator;
 import org.apache.directory.api.ldap.extras.extended.PwdModifyRequestImpl;
 import org.apache.directory.api.ldap.extras.extended.PwdModifyResponse;
+import org.apache.directory.api.ldap.model.entry.Attribute;
 import org.apache.directory.api.ldap.model.entry.DefaultEntry;
 import org.apache.directory.api.ldap.model.entry.Entry;
 import org.apache.directory.api.ldap.model.exception.LdapAuthenticationException;
@@ -147,6 +150,21 @@ public class PwdModifyIT extends Abstrac
             }
         }
     }
+    
+    
+    private void safeCloseConnections( LdapConnection... connections ) 
+    {
+        for ( LdapConnection connection : connections ) {
+            if ( connection != null ) {
+                try {
+                    connection.close();
+                }
+                catch ( Exception e ) {
+                    // may wanna log a message or something
+                }
+            }
+        }
+    }
 
 
     /**
@@ -402,7 +420,64 @@ public class PwdModifyIT extends Abstrac
         adminConnection.close();
     }
 
-
+    
+    /**
+     * Modify an existing user password with an admin account
+     */
+    @Test
+    public void testModifyPasswordTooSoon() throws Exception
+    {
+        LdapConnection adminConnection = null;
+        LdapConnection userConnection = null;
+        int minAge = policyConfig.getPwdMinAge();
+        try {
+            policyConfig.setPwdMinAge( 1000 );
+    
+            adminConnection = getAdminNetworkConnection( getLdapServer() );
+            addUser( adminConnection, "User7", "secret7" );
+            Entry userEntry = adminConnection.lookup( "cn=User7,ou=system", "*", "+" );
+            Attribute attribute = userEntry.get( "pwdHistory" );
+            assertEquals( 1, attribute.size() );
+    
+            PwdModifyRequestImpl pwdModifyRequest = null;
+            PwdModifyResponse pwdModifyResponse = null;
+    
+            // Fail modify user with user account
+            try {
+                userConnection = getNetworkConnectionAs( getLdapServer(), "cn=User7,ou=system", "secret7" );
+                pwdModifyRequest = new PwdModifyRequestImpl();
+                pwdModifyRequest.setUserIdentity( Strings.getBytesUtf8( "cn=User7,ou=system" ) );
+                pwdModifyRequest.setNewPassword( Strings.getBytesUtf8( "secret4Bis" ) );
+                pwdModifyResponse = (PwdModifyResponse)userConnection.extended( pwdModifyRequest );
+                assertNotEquals( ResultCodeEnum.SUCCESS, pwdModifyResponse.getLdapResult().getResultCode() );
+            }
+            finally {
+                safeCloseConnections( userConnection );
+            }
+    
+            // Modify the user with the admin account
+            pwdModifyRequest = new PwdModifyRequestImpl();
+            pwdModifyRequest.setUserIdentity( Strings.getBytesUtf8( "cn=User7,ou=system" ) );
+            pwdModifyRequest.setNewPassword( Strings.getBytesUtf8( "secret4Bis" ) );
+            pwdModifyResponse = (PwdModifyResponse)adminConnection.extended( pwdModifyRequest );
+            assertEquals( ResultCodeEnum.SUCCESS, pwdModifyResponse.getLdapResult().getResultCode() );
+            userEntry = adminConnection.lookup( "cn=User7,ou=system", "*", "+" );
+            attribute = userEntry.get( "pwdHistory" );
+            assertEquals( 2, attribute.size() );
+    
+            // Now try to bind with the new password
+            userConnection = getNetworkConnectionAs( ldapServer, "cn=User7,ou=system", "secret4Bis" );
+            Entry entry = userConnection.lookup( "cn=User7,ou=system" );
+       
+            assertNotNull( entry );
+        }
+        finally {
+            policyConfig.setPwdMinAge( minAge );
+            safeCloseConnections( userConnection, adminConnection );
+        }
+    }
+    
+    
     /**
      * Attempt to modify an existing user password and fail.  Then process the
      * password policy control from the response.

Modified: directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/ppolicy/PasswordPolicyIT.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/ppolicy/PasswordPolicyIT.java?rev=1561139&r1=1561138&r2=1561139&view=diff
==============================================================================
--- directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/ppolicy/PasswordPolicyIT.java (original)
+++ directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/ppolicy/PasswordPolicyIT.java Fri Jan 24 20:10:49 2014
@@ -37,8 +37,10 @@ import static org.junit.Assert.assertNul
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import org.apache.directory.api.ldap.codec.api.LdapApiService;
-import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
+
+import java.nio.charset.Charset;
+
+
 import org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicy;
 import org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicyErrorEnum;
 import org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicyImpl;
@@ -103,14 +105,13 @@ import org.junit.runner.RunWith;
 @CreateDS(enableChangeLog = false, name = "PasswordPolicyTest")
 public class PasswordPolicyIT extends AbstractLdapTestUnit
 {
-    private PasswordPolicyConfiguration policyConfig;
-
-    private static final LdapApiService codec = LdapApiServiceFactory.getSingleton();
-
     private static final PasswordPolicy PP_REQ_CTRL =
         new PasswordPolicyImpl();
 
 
+    private PasswordPolicyConfiguration policyConfig;
+
+
     /**
      * Set a default PaswordPolicy configuration
      */
@@ -187,6 +188,38 @@ public class PasswordPolicyIT extends Ab
 
 
     /**
+     * Changes the password of the user in the users own context from the 
+     * old value to the new value.
+     * 
+     * @param userDn
+     * @param oldPassword
+     * @param newPassword
+     * @return The ModifyResponse from the attempt
+     * @throws Exception If unable to obtain the connection with the 
+     * provided user an oldPassword.
+     */
+    private ModifyResponse changePassword( Dn userDn, String oldPassword, byte[] newPassword ) throws Exception 
+    {
+        LdapConnection userConnection = null;
+        try {
+            userConnection = getNetworkConnectionAs( ldapServer, userDn.toString(), oldPassword );
+            ModifyRequest modifyRequest = new ModifyRequestImpl();
+            modifyRequest.setName( userDn );
+            modifyRequest.replace( "userPassword", newPassword );
+            return userConnection.modify( modifyRequest );
+        }
+        finally {
+            userConnection.close();
+        }
+    }
+    
+    private ModifyResponse changePassword( Dn userDn, String oldPassword, String newPassword ) throws Exception 
+    {
+        return changePassword( userDn, oldPassword, newPassword.getBytes( Charset.forName( "UTF-8" ) ) );
+    }
+
+
+    /**
      * Check we can bind a user with a given password
      */
     private void checkBindSuccess( Dn userDn, String password ) throws Exception
@@ -204,18 +237,23 @@ public class PasswordPolicyIT extends Ab
      */
     private void checkBindFailure( Dn userDn, String password ) throws Exception
     {
+        LdapConnection userConnection = null;
         try
         {
-            LdapConnection userConnection = getNetworkConnectionAs( getLdapServer(), userDn.getName(), password );
+            userConnection = getNetworkConnectionAs( getLdapServer(), userDn.getName(), password );
             assertNull( userConnection );
-            assertFalse( userConnection.isAuthenticated() );
-
-            userConnection.close();
         }
         catch ( LdapException le )
         {
             // Expected
         }
+        finally 
+        {
+            if ( userConnection != null ) 
+            {
+                userConnection.close();
+            }
+        }
     }
 
 
@@ -242,7 +280,12 @@ public class PasswordPolicyIT extends Ab
     /**
      * Test that we can't inject a hashed password when the ChekcQuality is CHECK_REJECT,
      * and that we can when the CheckQuality is CHECK_ACCEPT
+     * 
+     * Ignored because if an admin can avoid password policy anyway, and add's are 
+     * performed by an admin, then this case would not get caught.  If there is a case
+     * where a user adds another user then we should put that case here.
      */
+    @Ignore
     @Test
     public void testAddUserWithHashedPwd() throws Exception
     {
@@ -287,6 +330,30 @@ public class PasswordPolicyIT extends Ab
         adminConnection.close();
     }
 
+    
+    @Test
+    public void testModifyUserWithHashedPwd() throws Exception
+    {
+        Dn userDn = new Dn( "cn=hashedpwdm,ou=system" );
+        LdapConnection adminConnection = getAdminNetworkConnection( getLdapServer() );
+        Entry userEntry = new DefaultEntry(
+            userDn.toString(),
+            "ObjectClass: top",
+            "ObjectClass: person",
+            "cn: hashedpwdm",
+            "sn: hashedpwdm_sn",
+            "userPassword", "set4now" );
+        adminConnection.add( userEntry );
+    
+        byte[] password = PasswordUtil.createStoragePassword( "12345", LdapSecurityConstants.HASH_METHOD_CRYPT );
+        assertEquals( ResultCodeEnum.CONSTRAINT_VIOLATION,
+            changePassword( userDn, "set4now", password ).getLdapResult().getResultCode() );
+        
+        checkBindFailure( userDn, "12345" );
+    
+        adminConnection.close();
+    }
+
 
     @Test
     public void testPwdLockoutForever() throws Exception
@@ -385,32 +452,21 @@ public class PasswordPolicyIT extends Ab
             "cn: userMinAge",
             "sn: userMinAge_sn",
             "userPassword: 12345" );
-
         adminConnection.add( userEntry );
-        Modification modification = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, "userPassword",
-            "123456" );
 
         // We should not be able to modify the password : it's too recent
-        try
-        {
-            adminConnection.modify( userDn, modification );
-            fail();
-        }
-        catch ( LdapException LdapInvalidAttributeValueException )
-        {
-            // Expected
-        }
+        assertEquals( ResultCodeEnum.CONSTRAINT_VIOLATION,
+            changePassword( userDn, "12345", "123456" ).getLdapResult().getResultCode() );
 
         // Wait for the pwdMinAge delay to be over
         Thread.sleep( 5000 );
 
         // Now, we should be able to modify the password
-        adminConnection.modify( userDn, modification );
+        assertEquals( ResultCodeEnum.SUCCESS,
+            changePassword( userDn, "12345", "123456" ).getLdapResult().getResultCode() );
+
+        checkBindSuccess( userDn, "123456" );
 
-        LdapConnection userConnection = getNetworkConnectionAs( getLdapServer(), userDn.getName(), "123456" );
-        assertNotNull( userConnection );
-        assertTrue( userConnection.isAuthenticated() );
-        userConnection.close();
         adminConnection.close();
     }
 
@@ -504,40 +560,25 @@ public class PasswordPolicyIT extends Ab
             "ObjectClass: person",
             "cn: userLen",
             "sn: userLen_sn",
-            "userPassword: 1234" );
+            "userPassword: set4now" );
+        adminConnection.add( userEntry );
 
         // Try with a password below the minLength
-        try
-        {
-            adminConnection.add( userEntry );
-            fail();
-        }
-        catch ( LdapInvalidAttributeValueException liave )
-        {
-            // Expected
-        }
+        assertEquals( ResultCodeEnum.CONSTRAINT_VIOLATION,
+            changePassword( userDn, "set4now", "1234" ).getLdapResult().getResultCode() );
 
         checkBindFailure( userDn, "1234" );
 
         // Try with a password above the maxLength
-        userEntry.put( "userPassword", "12345678" );
-
-        try
-        {
-            adminConnection.add( userEntry );
-            fail();
-        }
-        catch ( LdapInvalidAttributeValueException liave )
-        {
-            // Expected
-        }
+        assertEquals( ResultCodeEnum.CONSTRAINT_VIOLATION,
+            changePassword( userDn, "set4now", "12345678" ).getLdapResult().getResultCode() );
 
         checkBindFailure( userDn, "12345678" );
 
         // And try with a correct password
-        userEntry.put( "userPassword", "123456" );
+        assertEquals( ResultCodeEnum.SUCCESS,
+            changePassword( userDn, "set4now", "123456" ).getLdapResult().getResultCode() );
 
-        adminConnection.add( userEntry );
         checkBindSuccess( userDn, "123456" );
 
         adminConnection.close();