From be2a4753d04b9c7efa0a2e5444c7de73fd1e5ee0 Mon Sep 17 00:00:00 2001
From: Chris Ridd <chris.ridd@forgerock.com>
Date: Wed, 19 Dec 2012 16:14:49 +0000
Subject: [PATCH] Fix OPENDJ-665 Attribute Value Password Validator should implement check-substrings

---
 opends/resource/schema/02-config.ldif                                                                               |    4 +
 opends/src/server/org/opends/server/extensions/AttributeValuePasswordValidator.java                                 |   49 ++++++++++++++++
 opends/src/admin/defn/org/opends/server/admin/std/AttributeValuePasswordValidatorConfiguration.xml                  |   49 ++++++++++++++++
 opends/src/admin/messages/AttributeValuePasswordValidatorCfgDefn.properties                                         |    4 +
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/AttributeValuePasswordValidatorTestCase.java |   36 +++++++++++-
 opends/resource/config/config.ldif                                                                                  |    1 
 6 files changed, 138 insertions(+), 5 deletions(-)

diff --git a/opends/resource/config/config.ldif b/opends/resource/config/config.ldif
index a12e514..f16c7d3 100644
--- a/opends/resource/config/config.ldif
+++ b/opends/resource/config/config.ldif
@@ -1644,6 +1644,7 @@
 ds-cfg-java-class: org.opends.server.extensions.AttributeValuePasswordValidator
 ds-cfg-enabled: true
 ds-cfg-test-reversed-password: true
+ds-cfg-check-substrings: true
 
 dn: cn=Character Set,cn=Password Validators,cn=config
 objectClass: top
diff --git a/opends/resource/schema/02-config.ldif b/opends/resource/schema/02-config.ldif
index 1335ebb..507d0ed 100644
--- a/opends/resource/schema/02-config.ldif
+++ b/opends/resource/schema/02-config.ldif
@@ -4313,7 +4313,9 @@
   SUP ds-cfg-password-validator
   STRUCTURAL
   MUST ds-cfg-test-reversed-password
-  MAY ds-cfg-match-attribute
+  MAY ( ds-cfg-match-attribute $
+        ds-cfg-check-substrings $
+        ds-cfg-min-substring-length )
   X-ORIGIN 'OpenDS Directory Server' )
 objectClasses: ( 1.3.6.1.4.1.26027.1.2.96
   NAME 'ds-cfg-character-set-password-validator'
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/AttributeValuePasswordValidatorConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/AttributeValuePasswordValidatorConfiguration.xml
index ca4c751..658d772 100644
--- a/opends/src/admin/defn/org/opends/server/admin/std/AttributeValuePasswordValidatorConfiguration.xml
+++ b/opends/src/admin/defn/org/opends/server/admin/std/AttributeValuePasswordValidatorConfiguration.xml
@@ -24,6 +24,7 @@
   !
   !
   !      Copyright 2007-2008 Sun Microsystems, Inc.
+  !      Portions Copyright 2012 ForgeRock, AS.
   ! -->
 <adm:managed-object name="attribute-value-password-validator"
   plural-name="attribute-value-password-validators"
@@ -79,6 +80,54 @@
       </ldap:attribute>
     </adm:profile>
   </adm:property>
+  <adm:property name="check-substrings" mandatory="false">
+    <adm:synopsis>
+      Indicates whether this password validator is to match portions of
+      the password string against attribute values.
+    </adm:synopsis>
+    <adm:description>
+      If "false" then only match the entire password against attribute values
+      otherwise ("true") check whether the password contains attribute values. 
+    </adm:description>
+    <adm:default-behavior>
+      <adm:defined>
+        <adm:value>true</adm:value>
+      </adm:defined>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:boolean />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:name>ds-cfg-check-substrings</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="min-substring-length" mandatory="false">
+    <adm:synopsis>
+      Indicates the minimal length of the substring within the password
+      in case substring checking is enabled.
+    </adm:synopsis>
+    <adm:description>
+      If "check-substrings" option is set to true, then this parameter
+      defines the length of the smallest word which should be used for
+      substring matching. Use with caution because values below 3 might
+      disqualify valid passwords.
+    </adm:description>
+    <adm:default-behavior>
+      <adm:defined>
+        <adm:value>5</adm:value>
+      </adm:defined>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:integer />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:name>ds-cfg-min-substring-length</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
   <adm:property name="test-reversed-password" mandatory="true">
     <adm:synopsis>
       Indicates whether this password validator should test the reversed
diff --git a/opends/src/admin/messages/AttributeValuePasswordValidatorCfgDefn.properties b/opends/src/admin/messages/AttributeValuePasswordValidatorCfgDefn.properties
index 3bfdab5..2bf6c95 100644
--- a/opends/src/admin/messages/AttributeValuePasswordValidatorCfgDefn.properties
+++ b/opends/src/admin/messages/AttributeValuePasswordValidatorCfgDefn.properties
@@ -2,8 +2,12 @@
 user-friendly-plural-name=Attribute Value Password Validators
 synopsis=The Attribute Value Password Validator attempts to determine whether a proposed password is acceptable for use by determining whether that password is contained in any attribute within the user's entry.
 description=It can be configured to look in all attributes or in a specified subset of attributes.
+property.check-substrings.synopsis=Indicates whether this password validator is to match portions of the password string against attribute values.
+property.check-substrings.description=If "false" then only match the entire password against attribute values otherwise ("true") check whether the password contains attribute values.
 property.enabled.synopsis=Indicates whether the password validator is enabled for use.
 property.java-class.synopsis=Specifies the fully-qualified name of the Java class that provides the password validator implementation.
 property.match-attribute.synopsis=Specifies the name(s) of the attribute(s) whose values should be checked to determine whether they match the provided password. If no values are provided, then the server checks if the proposed password matches the value of any attribute in the user's entry.
 property.match-attribute.default-behavior.alias.synopsis=All attributes in the user entry will be checked.
+property.min-substring-length.synopsis=Indicates the minimal length of the substring within the password in case substring checking is enabled.
+property.min-substring-length.description=If "check-substrings" option is set to true, then this parameter defines the length of the smallest word which should be used for substring matching. Use with caution because values below 3 might disqualify valid passwords.
 property.test-reversed-password.synopsis=Indicates whether this password validator should test the reversed value of the provided password as well as the order in which it was given.
diff --git a/opends/src/server/org/opends/server/extensions/AttributeValuePasswordValidator.java b/opends/src/server/org/opends/server/extensions/AttributeValuePasswordValidator.java
index 425a289..7f5f852 100644
--- a/opends/src/server/org/opends/server/extensions/AttributeValuePasswordValidator.java
+++ b/opends/src/server/org/opends/server/extensions/AttributeValuePasswordValidator.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2008 Sun Microsystems, Inc.
+ *      Portions Copyright 2012 ForgeRock, AS.
  */
 package org.opends.server.extensions;
 import org.opends.messages.Message;
@@ -96,6 +97,39 @@
 
 
   /**
+   * Search for substrings of the password in an Attribute. The search is
+   * case-insensitive.
+   *
+   * @param password the password
+   * @param minSubstringLength the minimum substring length to check
+   * @param a the attribute to search
+   * @return true if an attribute value matches a substring of the password,
+   * false otherwise.
+   */
+  private boolean containsSubstring(String password, int minSubstringLength,
+      Attribute a)
+  {
+    final int passwordLength = password.length();
+
+    for (int i = 0; i < passwordLength; i++)
+    {
+      for (int j = i + minSubstringLength; j <= passwordLength; j++)
+      {
+        Attribute substring = Attributes.create(a.getAttributeType(),
+            password.substring(i, j));
+        for (AttributeValue val : a)
+        {
+          if (substring.contains(val))
+            return true;
+        }
+      }
+    }
+    return false;
+  }
+
+
+
+  /**
    * {@inheritDoc}
    */
   @Override()
@@ -113,6 +147,17 @@
     String password = newPassword.toString();
     String reversed = new StringBuilder(password).reverse().toString();
 
+    // Check to see if we should verify the whole password or the substrings.
+    int minSubstringLength = password.length();
+    if (config.isCheckSubstrings())
+    {
+      // We apply the minimal substring length only if the provided value
+      // is smaller then the actual password length
+      if (config.getMinSubstringLength() < password.length())
+      {
+        minSubstringLength = config.getMinSubstringLength();
+      }
+    }
 
     // If we should check a specific set of attributes, then do that now.
     // Otherwise, check all user attributes.
@@ -136,7 +181,9 @@
       for (Attribute a : attrList)
       {
         if (a.contains(vf) ||
-            (config.isTestReversedPassword() && a.contains(vr)))
+            (config.isTestReversedPassword() && a.contains(vr)) ||
+            (config.isCheckSubstrings() &&
+                containsSubstring(password, minSubstringLength, a)))
         {
 
           invalidReason.append(ERR_ATTRVALUE_VALIDATOR_PASSWORD_IN_ENTRY.get());
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/AttributeValuePasswordValidatorTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/AttributeValuePasswordValidatorTestCase.java
index 98847b6..ef7c28d 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/AttributeValuePasswordValidatorTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/AttributeValuePasswordValidatorTestCase.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Portions Copyright 2012 ForgeRock, AS.
  */
 package org.opends.server.extensions;
 
@@ -131,7 +132,17 @@
          "ds-cfg-java-class: org.opends.server.extensions." +
               "AttributeValuePasswordValidator",
          "ds-cfg-enabled: true",
-         "ds-cfg-test-reversed-password: false");
+         "ds-cfg-test-reversed-password: false",
+         "",
+         "dn: cn=Attribute Value,cn=Password Validators,cn=config",
+         "objectClass: top",
+         "objectClass: ds-cfg-password-validator",
+         "objectClass: ds-cfg-attribute-value-password-validator",
+         "cn: Attribute Value",
+         "ds-cfg-java-class: org.opends.server.extensions." +
+              "AttributeValuePasswordValidator",
+         "ds-cfg-check-substrings: false",
+         "ds-cfg-enabled: true");
 
     Object[][] array = new Object[entries.size()][1];
     for (int i=0; i < array.length; i++)
@@ -286,7 +297,7 @@
       },
 
       // Default configuration, with a password that matches the reverse of an
-      // existing attribute value with reverwse matching enabled
+      // existing attribute value with reverse matching enabled
       new Object[]
       {
         TestCaseUtils.makeEntry(
@@ -304,7 +315,7 @@
       },
 
       // Default configuration, with a password that matches the reverse of an
-      // existing attribute value with reverwse matching disabled
+      // existing attribute value with reverse matching disabled
       new Object[]
       {
         TestCaseUtils.makeEntry(
@@ -363,6 +374,25 @@
         "test.user",
         true
       },
+
+      // Default configuration, with a password that contains a substring
+      // from one of the attributes in the entry.
+      new Object[]
+      {
+        TestCaseUtils.makeEntry(
+             "dn: cn=Attribute Value,cn=Password Validators,cn=config",
+             "objectClass: top",
+             "objectClass: ds-cfg-password-validator",
+             "objectClass: ds-cfg-attribute-value-password-validator",
+             "cn: Attribute Value",
+             "ds-cfg-java-class: org.opends.server.extensions." +
+                  "AttributeValuePasswordValidator",
+             "ds-cfg-enabled: true",
+             "ds-cfg-check-substrings: true",
+             "ds-cfg-test-reversed-password: true"),
+        "test.user99",
+        false
+      },
     };
   }
 

--
Gitblit v1.10.0