Hi Alex,

On 19 avr. 2011, at 16:02, Alex Karasulu wrote:

Please revert putting this into the core-api: this functionality should be loaded when needed as an extra rather than a core function of the server.

I'm afraid, at the moment, there's no easy way to avoid putting it there and having the dependency on the extras jar. We lack, in the server, the same kind of support for extras you built in Shared. 

Plus the dependency on the extras OSGi bundle should not be formed it will create several classloader issues. 

We should move forward with OSGi in the server to make these optional features loadable.

I guess that's what Emmanuel is currently experimenting and why he started the "OSGi perspective, plus a few other things..." thread on the ML.
Being half-way on our OSGI-fication of ApacheDS is starting to cause some issues.
Yesterday, we came to the same conclusion, that we should move the server to OSGI bundle as soon as possible.

Regards,
Pierre-Arnaud

Thanks,
Alex

On Tue, Apr 19, 2011 at 4:33 PM, <kayyagari@apache.org> wrote:
Author: kayyagari
Date: Tue Apr 19 13:33:54 2011
New Revision: 1095083

URL: http://svn.apache.org/viewvc?rev=1095083&view=rev
Log:
o created an interface for validating password quality and added an implementation
o updated the authenticator and policy config to use the validator
o added dependency on shared-ldap-extras-codec (required to resolve PasswordPolicyErrorEnum)

Added:
   directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/ppolicy/DefaultPasswordValidator.java
   directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/ppolicy/PasswordValidator.java
Modified:
   directory/apacheds/trunk/core-api/pom.xml
   directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/ppolicy/PasswordPolicyConfiguration.java
   directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/authn/AuthenticationInterceptor.java

Modified: directory/apacheds/trunk/core-api/pom.xml
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core-api/pom.xml?rev=1095083&r1=1095082&r2=1095083&view=diff
==============================================================================
--- directory/apacheds/trunk/core-api/pom.xml (original)
+++ directory/apacheds/trunk/core-api/pom.xml Tue Apr 19 13:33:54 2011
@@ -117,6 +117,12 @@
       <groupId>net.sf.ehcache</groupId>
       <artifactId>ehcache-core</artifactId>
   </dependency>
+
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-extras-codec</artifactId>
+      <scope>provided</scope>
+    </dependency>

  </dependencies>


Added: directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/ppolicy/DefaultPasswordValidator.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/ppolicy/DefaultPasswordValidator.java?rev=1095083&view=auto
==============================================================================
--- directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/ppolicy/DefaultPasswordValidator.java (added)
+++ directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/ppolicy/DefaultPasswordValidator.java Tue Apr 19 13:33:54 2011
@@ -0,0 +1,88 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.server.core.ppolicy;
+
+
+import static org.apache.directory.shared.ldap.extras.controls.ppolicy.PasswordPolicyErrorEnum.INSUFFICIENT_PASSWORD_QUALITY;
+
+
+/**
+ * The default password validator.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DefaultPasswordValidator implements PasswordValidator
+{
+
+    /** the default validator's instance */
+    public final static DefaultPasswordValidator INSTANCE = new DefaultPasswordValidator();
+
+
+    /**
+     * Creates a new instance of DefaultPasswordValidator.
+     */
+    public DefaultPasswordValidator()
+    {
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void validate( String password, String entryRdnVal ) throws PasswordPolicyException
+    {
+        checkUsernameSubstring( password, entryRdnVal );
+        //TODO add more checks
+    }
+
+
+    /**
+     * The password does not contain three letter (or more) tokens from the user's account name.
+     *
+     * If the account name is less than three characters long, this check is not performed
+     * because the rate at which passwords would be rejected is too high. For each token that is
+     * three or more characters long, that token is searched for in the password; if it is present,
+     * the password change is rejected. For example, the name "First M. Last" would be split into
+     * three tokens: "First", "M", and "Last". Because the second token is only one character long,
+     * it would be ignored. Therefore, this user could not have a password that included either
+     * "first" or "last" as a substring anywhere in the password. All of these checks are
+     * case-insensitive.
+     */
+    private void checkUsernameSubstring( String password, String username ) throws PasswordPolicyException
+    {
+        if ( username == null || username.trim().length() == 0 )
+        {
+            return;
+        }
+
+        String[] tokens = username.split( "[^a-zA-Z]" );
+
+        for ( int ii = 0; ii < tokens.length; ii++ )
+        {
+            if ( password.matches( "(?i).*" + tokens[ii] + ".*" ) )
+            {
+                throw new PasswordPolicyException( "Password shouldn't contain parts of the username",
+                    INSUFFICIENT_PASSWORD_QUALITY );
+            }
+        }
+    }
+
+}

Modified: directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/ppolicy/PasswordPolicyConfiguration.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/ppolicy/PasswordPolicyConfiguration.java?rev=1095083&r1=1095082&r2=1095083&view=diff
==============================================================================
--- directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/ppolicy/PasswordPolicyConfiguration.java (original)
+++ directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/ppolicy/PasswordPolicyConfiguration.java Tue Apr 19 13:33:54 2011
@@ -151,6 +151,9 @@ public class PasswordPolicyConfiguration
     */
    private int pwdMaxIdle = 0;

+    /** validator used for checking the quality of password */
+    //TODO to be injected from config
+    private PasswordValidator pwdValidator = DefaultPasswordValidator.INSTANCE;

    public String getPwdAttribute()
    {
@@ -393,6 +396,24 @@ public class PasswordPolicyConfiguration


    /**
+     * @return the pwdValidator
+     */
+    public PasswordValidator getPwdValidator()
+    {
+        return pwdValidator;
+    }
+
+
+    /**
+     * @param pwdValidator the pwdValidator to set
+     */
+    public void setPwdValidator( PasswordValidator pwdValidator )
+    {
+        this.pwdValidator = pwdValidator;
+    }
+
+
+    /**
     * validates the policy configuration and throws a LdapException if there are any errors
     *
     * @throws LdapException if there are any errors in the configuration

Added: directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/ppolicy/PasswordValidator.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/ppolicy/PasswordValidator.java?rev=1095083&view=auto
==============================================================================
--- directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/ppolicy/PasswordValidator.java (added)
+++ directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/ppolicy/PasswordValidator.java Tue Apr 19 13:33:54 2011
@@ -0,0 +1,41 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.server.core.ppolicy;
+
+/**
+ * An interface for implementing password quality verifiers.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface PasswordValidator
+{
+    /**
+     * checks if the given password meets the required quality contraints.<br>
+     * <p>Note: the length based validations are already done before calling this method<br>
+     *       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+     *       so the implementor should concentrate on the content checking.</p>
+     *
+     * @param password the password value
+     * @param entryRdnVal the value of entry's RDN(typically this is the username) e.x 'admin' if the entry's DN is {uid/cn/etc..}=admin,ou=system
+     * @throws PasswordPolicyException if the password doesn't meet the quality contraints
+     */
+    void validate( String password, String entryRdnVal ) throws PasswordPolicyException;
+}

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=1095083&r1=1095082&r2=1095083&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 Tue Apr 19 13:33:54 2011
@@ -95,7 +95,6 @@ import org.apache.directory.shared.ldap.
 import org.apache.directory.shared.ldap.model.entry.Entry;
 import org.apache.directory.shared.ldap.model.entry.Modification;
 import org.apache.directory.shared.ldap.model.entry.ModificationOperation;
-import org.apache.directory.shared.ldap.model.entry.StringValue;
 import org.apache.directory.shared.ldap.model.entry.Value;
 import org.apache.directory.shared.ldap.model.exception.LdapAuthenticationException;
 import org.apache.directory.shared.ldap.model.exception.LdapException;
@@ -357,14 +356,9 @@ public class AuthenticationInterceptor e

            BinaryValue userPassword = ( BinaryValue ) entry.get( SchemaConstants.USER_PASSWORD_AT ).get();

-            if ( entry.get( SchemaConstants.CN_AT ) != null )
-            {
-                StringValue attr = ( StringValue ) entry.get( SchemaConstants.CN_AT ).get();
-                username = attr.getString();
-            }
-
            try
            {
+                username = entry.getDn().getRdn().getUpValue().getString();
                check( username, userPassword.getValue(), policyConfig );
            }
            catch ( PasswordPolicyException e )
@@ -588,16 +582,11 @@ public class AuthenticationInterceptor e
            byte[] newPassword = null;
            if ( ( pwdModDetails != null ) )
            {
-                String userName = null;
-                if ( entry.get( SchemaConstants.CN_AT ) != null )
-                {
-                    StringValue attr = ( StringValue ) entry.get( SchemaConstants.CN_AT ).get();
-                    userName = attr.getString();
-                }
-
                newPassword = pwdModDetails.getNewPwd();
+
                try
                {
+                    String userName = entry.getDn().getRdn().getUpValue().getString();
                    check( userName, newPassword, policyConfig );
                }
                catch ( PasswordPolicyException e )
@@ -1191,9 +1180,11 @@ public class AuthenticationInterceptor e
        }

        String strPassword = Strings.utf8ToString(password);
+
+        // perform the length validation
        validatePasswordLength( strPassword, policyConfig );
-        checkUsernameSubstring( username, strPassword, policyConfig );
-        //        checkPasswordChars( strPassword );
+
+        policyConfig.getPwdValidator().validate( strPassword, username );
    }


@@ -1227,38 +1218,6 @@ public class AuthenticationInterceptor e
    }


-    /**
-     * The password does not contain three letter (or more) tokens from the user's account name.
-     *
-     * If the account name is less than three characters long, this check is not performed
-     * because the rate at which passwords would be rejected is too high. For each token that is
-     * three or more characters long, that token is searched for in the password; if it is present,
-     * the password change is rejected. For example, the name "First M. Last" would be split into
-     * three tokens: "First", "M", and "Last". Because the second token is only one character long,
-     * it would be ignored. Therefore, this user could not have a password that included either
-     * "first" or "last" as a substring anywhere in the password. All of these checks are
-     * case-insensitive.
-     */
-    private void checkUsernameSubstring( String username, String password, PasswordPolicyConfiguration policyConfig ) throws PasswordPolicyException
-    {
-        if ( username == null || username.trim().length() == 0 )
-        {
-            return;
-        }
-
-        String[] tokens = username.split( "[^a-zA-Z]" );
-
-        for ( int ii = 0; ii < tokens.length; ii++ )
-        {
-            if ( password.matches( "(?i).*" + tokens[ii] + ".*" ) )
-            {
-                throw new PasswordPolicyException( "Password shouldn't contain parts of the username",
-                    INSUFFICIENT_PASSWORD_QUALITY );
-            }
-        }
-    }
-
-
    private int getPwdTimeBeforeExpiry( Entry userEntry, PasswordPolicyConfiguration policyConfig ) throws LdapException
    {
        if ( policyConfig.getPwdMaxAge() == 0 )