From 080289c5388619b8b5059631c96a4d3b5922b6c1 Mon Sep 17 00:00:00 2001
From: Nicolas Capponi <nicolas.capponi@forgerock.com>
Date: Fri, 07 Nov 2014 16:47:09 +0000
Subject: [PATCH] OPENDJ-1591 CR-5092 Re-implement UserPasswordEqualityMatchingRule to be  compatible with SDK matching rules and schema

---
 opendj3-server-dev/src/server/org/opends/server/schema/UserPasswordEqualityMatchingRule.java |  220 ++++++++++++++++++++++++++----------------------------
 1 files changed, 106 insertions(+), 114 deletions(-)

diff --git a/opendj3-server-dev/src/server/org/opends/server/schema/UserPasswordEqualityMatchingRule.java b/opendj3-server-dev/src/server/org/opends/server/schema/UserPasswordEqualityMatchingRule.java
index 2af5146..de7e7c2 100644
--- a/opendj3-server-dev/src/server/org/opends/server/schema/UserPasswordEqualityMatchingRule.java
+++ b/opendj3-server-dev/src/server/org/opends/server/schema/UserPasswordEqualityMatchingRule.java
@@ -26,102 +26,46 @@
  */
 package org.opends.server.schema;
 
-
-
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
 
 import org.forgerock.i18n.slf4j.LocalizedLogger;
+import org.forgerock.opendj.ldap.Assertion;
 import org.forgerock.opendj.ldap.ByteSequence;
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.ConditionResult;
 import org.forgerock.opendj.ldap.DecodeException;
-import org.opends.server.api.EqualityMatchingRule;
+import org.forgerock.opendj.ldap.schema.MatchingRuleImpl;
+import org.forgerock.opendj.ldap.schema.Schema;
+import org.forgerock.opendj.ldap.spi.IndexQueryFactory;
+import org.forgerock.opendj.ldap.spi.Indexer;
+import org.forgerock.opendj.ldap.spi.IndexingOptions;
 import org.opends.server.api.PasswordStorageScheme;
-import org.opends.server.core.DirectoryServer;
 
-import static org.opends.server.schema.SchemaConstants.*;
-
-
+import static org.forgerock.opendj.ldap.Assertion.*;
+import static org.opends.server.core.DirectoryServer.*;
 
 /**
- * This class implements the userPasswordMatch matching rule, which can be used
+ * Implementation of the userPasswordMatch matching rule, which can be used
  * to determine whether a clear-text value matches an encoded password.
+ * <p>
+ * This matching rule serves a similar purpose to the equivalent
+ * AuthPasswordEqualityMatchingRule defined in RFC 3112 (http://tools.ietf.org/html/rfc3112).
  */
-class UserPasswordEqualityMatchingRule
-       extends EqualityMatchingRule
+class UserPasswordEqualityMatchingRule implements MatchingRuleImpl
 {
   private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
 
-
-
-  /**
-   * Creates a new instance of this userPasswordMatch matching rule.
-   */
-  public UserPasswordEqualityMatchingRule()
-  {
-    super();
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public Collection<String> getNames()
-  {
-    return Collections.singleton(EMR_USER_PASSWORD_NAME);
-  }
-
-
-  /**
-   * Retrieves the OID for this matching rule.
-   *
-   * @return  The OID for this matching rule.
-   */
-  @Override
-  public String getOID()
-  {
-    return EMR_USER_PASSWORD_OID;
-  }
-
-
-
-  /**
-   * Retrieves the description for this matching rule.
-   *
-   * @return  The description for this matching rule, or <CODE>null</CODE> if
-   *          there is none.
-   */
-  @Override
-  public String getDescription()
-  {
-    // There is no standard description for this matching rule.
-    return EMR_USER_PASSWORD_DESCRIPTION;
-  }
-
-
-
-  /**
-   * Retrieves the OID of the syntax with which this matching rule is
-   * associated.
-   *
-   * @return  The OID of the syntax with which this matching rule is associated.
-   */
-  @Override
-  public String getSyntaxOID()
-  {
-    return SYNTAX_USER_PASSWORD_OID;
-  }
-
-
+  private static final String EQUALITY_ID = "equality";
 
   /**
    * Retrieves the normalized form of the provided value, which is best suited
    * for efficiently performing matching operations on that value.
    *
-   * @param  value  The value to be normalized.
+   * @param schema The schema.
+   * @param value  The value to be normalized.
    *
    * @return  The normalized version of the provided value.
    *
@@ -129,13 +73,93 @@
    *                              the associated attribute syntax.
    */
   @Override
-  public ByteString normalizeAttributeValue(ByteSequence value)
+  public ByteString normalizeAttributeValue(Schema schema, ByteSequence value)
          throws DecodeException
   {
     // We will not alter the value in any way
     return value.toByteString();
   }
 
+  private final Collection<? extends Indexer> indexers = Collections.singleton(new Indexer()
+  {
+    @Override
+    public void createKeys(Schema schema, ByteSequence value, IndexingOptions options, Collection<ByteString> keys)
+        throws DecodeException
+    {
+      keys.add(normalizeAttributeValue(schema, value));
+    }
+
+    @Override
+    public String getIndexID()
+    {
+      return EQUALITY_ID;
+    }
+  });
+
+  /** {@inheritDoc} */
+  @Override
+  public Comparator<ByteSequence> comparator(Schema schema)
+  {
+    return ByteSequence.COMPARATOR;
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public Assertion getAssertion(final Schema schema, final ByteSequence assertionValue) throws DecodeException
+  {
+    return new Assertion()
+    {
+      final ByteString normalizedAssertionValue = normalizeAttributeValue(schema, assertionValue);
+
+      @Override
+      public ConditionResult matches(final ByteSequence normalizedAttributeValue)
+      {
+        return valuesMatch(normalizedAttributeValue, normalizedAssertionValue);
+      }
+
+      @Override
+      public <T> T createIndexQuery(IndexQueryFactory<T> factory) throws DecodeException
+      {
+        return factory.createExactMatchQuery(EQUALITY_ID, normalizedAssertionValue);
+      }
+    };
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public Assertion getSubstringAssertion(Schema schema, ByteSequence subInitial,
+      List<? extends ByteSequence> subAnyElements, ByteSequence subFinal) throws DecodeException
+  {
+    return UNDEFINED_ASSERTION;
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public Assertion getGreaterOrEqualAssertion(Schema schema, ByteSequence value) throws DecodeException
+  {
+    return UNDEFINED_ASSERTION;
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public Assertion getLessOrEqualAssertion(Schema schema, ByteSequence value) throws DecodeException
+  {
+    return UNDEFINED_ASSERTION;
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public boolean isIndexingSupported()
+  {
+    return indexers.isEmpty();
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public Collection<? extends Indexer> getIndexers()
+  {
+    return indexers;
+  }
 
   /**
    * Indicates whether the provided attribute value should be considered a match
@@ -152,30 +176,24 @@
    *          match for the provided assertion value, or <CODE>false</CODE> if
    *          not.
    */
-  @Override
-  public ConditionResult valuesMatch(ByteSequence attributeValue,
-                                     ByteSequence assertionValue)
+  private ConditionResult valuesMatch(ByteSequence attributeValue, ByteSequence assertionValue)
   {
     // We must be able to decode the attribute value using the user password
     // syntax.
     String[] userPWComponents;
     try
     {
-      userPWComponents =
-           UserPasswordSyntax.decodeUserPassword(attributeValue.toString());
+      userPWComponents = UserPasswordSyntax.decodeUserPassword(attributeValue.toString());
     }
     catch (Exception e)
     {
       logger.traceException(e);
-
       return ConditionResult.FALSE;
     }
 
-
-    // The first element of the array will be the scheme.  Make sure that we
-    // support the requested scheme.
-    PasswordStorageScheme storageScheme =
-         DirectoryServer.getPasswordStorageScheme(userPWComponents[0]);
+    // The first element of the array will be the scheme.
+    // Make sure that we support the requested scheme.
+    PasswordStorageScheme<?> storageScheme =  getPasswordStorageScheme(userPWComponents[0]);
     if (storageScheme == null)
     {
       // It's not a scheme that we can support.
@@ -183,34 +201,8 @@
     }
 
     // We support the scheme, so make the determination.
-    return ConditionResult.valueOf(storageScheme.passwordMatches(
-        assertionValue, ByteString.valueOf(userPWComponents[1])));
-  }
-
-
-
-  /**
-   * Generates a hash code for the provided attribute value.  This version of
-   * the method will simply create a hash code from the normalized form of the
-   * attribute value.  For matching rules explicitly designed to work in cases
-   * where byte-for-byte comparisons of normalized values is not sufficient for
-   * determining equality (e.g., if the associated attribute syntax is based on
-   * hashed or encrypted values), then this method must be overridden to provide
-   * an appropriate implementation for that case.
-   *
-   * @param  attributeValue  The attribute value for which to generate the hash
-   *                         code.
-   *
-   * @return  The hash code generated for the provided attribute value.
-   */
-  @Override
-  public int generateHashCode(ByteSequence attributeValue)
-  {
-    // Because of the variable encoding that may be used, we have no way of
-    // comparing two user password values by hash code and therefore we'll
-    // always return the same value so that the valuesMatch method will be
-    // invoked to make the determination.
-    return 1;
+    return ConditionResult.valueOf(
+        storageScheme.passwordMatches(assertionValue, ByteString.valueOf(userPWComponents[1])));
   }
 }
 

--
Gitblit v1.10.0