You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by se...@apache.org on 2012/11/04 12:53:00 UTC

svn commit: r1405534 - in /directory/shared/trunk/ldap/model/src: main/java/org/apache/directory/shared/ldap/model/filter/ test/java/org/apache/directory/shared/ldap/model/filter/

Author: seelmann
Date: Sun Nov  4 11:52:59 2012
New Revision: 1405534

URL: http://svn.apache.org/viewvc?rev=1405534&view=rev
Log:
Fix for DIRSHARED-143 (Provide helper method to escape characters to be used in LDAP Filter literal)

Added:
    directory/shared/trunk/ldap/model/src/main/java/org/apache/directory/shared/ldap/model/filter/FilterEncoder.java
    directory/shared/trunk/ldap/model/src/test/java/org/apache/directory/shared/ldap/model/filter/FilterEncoderTest.java
Modified:
    directory/shared/trunk/ldap/model/src/main/java/org/apache/directory/shared/ldap/model/filter/AbstractExprNode.java

Modified: directory/shared/trunk/ldap/model/src/main/java/org/apache/directory/shared/ldap/model/filter/AbstractExprNode.java
URL: http://svn.apache.org/viewvc/directory/shared/trunk/ldap/model/src/main/java/org/apache/directory/shared/ldap/model/filter/AbstractExprNode.java?rev=1405534&r1=1405533&r2=1405534&view=diff
==============================================================================
--- directory/shared/trunk/ldap/model/src/main/java/org/apache/directory/shared/ldap/model/filter/AbstractExprNode.java (original)
+++ directory/shared/trunk/ldap/model/src/main/java/org/apache/directory/shared/ldap/model/filter/AbstractExprNode.java Sun Nov  4 11:52:59 2012
@@ -205,51 +205,15 @@ public abstract class AbstractExprNode i
         }
 
         val = ( ( StringValue ) value ).getString();
-
-        for ( int i = 0; i < val.length(); i++ )
+        String encodedVal = FilterEncoder.encodeFilterValue( val );
+        if ( val.equals( encodedVal ) )
         {
-            char ch = val.charAt( i );
-            String replace = null;
-
-            switch ( ch )
-            {
-                case '*':
-                    replace = "\\2A";
-                    break;
-
-                case '(':
-                    replace = "\\28";
-                    break;
-
-                case ')':
-                    replace = "\\29";
-                    break;
-
-                case '\\':
-                    replace = "\\5C";
-                    break;
-
-                case '\0':
-                    replace = "\\00";
-                    break;
-            }
-
-            if ( replace != null )
-            {
-                if ( sb == null )
-                {
-                    sb = new StringBuilder( val.length() * 2 );
-                    sb.append( val.substring( 0, i ) );
-                }
-                sb.append( replace );
-            }
-            else if ( sb != null )
-            {
-                sb.append( ch );
-            }
+            return value;
+        }
+        else
+        {
+            return new StringValue( encodedVal );
         }
-
-        return ( sb == null ? value : new StringValue( sb.toString() ) );
     }
 
 

Added: directory/shared/trunk/ldap/model/src/main/java/org/apache/directory/shared/ldap/model/filter/FilterEncoder.java
URL: http://svn.apache.org/viewvc/directory/shared/trunk/ldap/model/src/main/java/org/apache/directory/shared/ldap/model/filter/FilterEncoder.java?rev=1405534&view=auto
==============================================================================
--- directory/shared/trunk/ldap/model/src/main/java/org/apache/directory/shared/ldap/model/filter/FilterEncoder.java (added)
+++ directory/shared/trunk/ldap/model/src/main/java/org/apache/directory/shared/ldap/model/filter/FilterEncoder.java Sun Nov  4 11:52:59 2012
@@ -0,0 +1,133 @@
+/*
+ *  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.shared.ldap.model.filter;
+
+
+import java.text.Format;
+import java.text.MessageFormat;
+
+
+/**
+ * An encoder for LDAP filters.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class FilterEncoder
+{
+    private static final String[] EMPTY = new String[0];
+
+
+    /**
+     * Formats a filter and handles encoding of special characters in the value arguments using the
+     * &lt;valueencoding&gt; rule as described in <a href="http://www.ietf.org/rfc/rfc4515.txt">RFC 4515</a>.
+     * 
+     * @param filterTemplate the filter with placeholders
+     * @param values the values to encode and substitute
+     * @return the formatted filter with escaped values
+     * @throws IllegalArgumentException if the number of values does not match the number of placeholders in the template
+     */
+    public static String format( String filterTemplate, String[] values ) throws IllegalArgumentException
+    {
+        if ( values == null )
+        {
+            values = EMPTY;
+        }
+
+        MessageFormat mf = new MessageFormat( filterTemplate );
+
+        // check element count and argument count
+        Format[] formats = mf.getFormatsByArgumentIndex();
+        if ( formats.length != values.length )
+        {
+            // TODO: I18n
+            String msg = "Filter template {0} has {1} placeholders but {2} arguments provided.";
+            throw new IllegalArgumentException( MessageFormat.format( msg, filterTemplate, formats.length,
+                values.length ) );
+        }
+
+        // encode arguments
+        for ( int i = 0; i < values.length; i++ )
+        {
+            values[i] = encodeFilterValue( values[i] );
+        }
+
+        // format the filter
+        String format = mf.format( values );
+        return format;
+    }
+
+
+    /**
+     * Handles encoding of special characters in LDAP search filter assertion values using the
+     * &lt;valueencoding&gt; rule as described in <a href="http://www.ietf.org/rfc/rfc4515.txt">RFC 4515</a>.
+     *
+     * @param value Right hand side of "attrId=value" assertion occurring in an LDAP search filter.
+     * @return Escaped version of <code>value</code>
+     */
+    public static String encodeFilterValue( String value )
+    {
+        StringBuilder sb = null;
+
+        for ( int i = 0; i < value.length(); i++ )
+        {
+            char ch = value.charAt( i );
+            String replace = null;
+
+            switch ( ch )
+            {
+                case '*':
+                    replace = "\\2A";
+                    break;
+
+                case '(':
+                    replace = "\\28";
+                    break;
+
+                case ')':
+                    replace = "\\29";
+                    break;
+
+                case '\\':
+                    replace = "\\5C";
+                    break;
+
+                case '\0':
+                    replace = "\\00";
+                    break;
+            }
+
+            if ( replace != null )
+            {
+                if ( sb == null )
+                {
+                    sb = new StringBuilder( value.length() * 2 );
+                    sb.append( value.substring( 0, i ) );
+                }
+                sb.append( replace );
+            }
+            else if ( sb != null )
+            {
+                sb.append( ch );
+            }
+        }
+
+        return ( sb == null ? value : sb.toString() );
+    }
+}

Added: directory/shared/trunk/ldap/model/src/test/java/org/apache/directory/shared/ldap/model/filter/FilterEncoderTest.java
URL: http://svn.apache.org/viewvc/directory/shared/trunk/ldap/model/src/test/java/org/apache/directory/shared/ldap/model/filter/FilterEncoderTest.java?rev=1405534&view=auto
==============================================================================
--- directory/shared/trunk/ldap/model/src/test/java/org/apache/directory/shared/ldap/model/filter/FilterEncoderTest.java (added)
+++ directory/shared/trunk/ldap/model/src/test/java/org/apache/directory/shared/ldap/model/filter/FilterEncoderTest.java Sun Nov  4 11:52:59 2012
@@ -0,0 +1,122 @@
+/*
+ *  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.shared.ldap.model.filter;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.apache.directory.shared.ldap.model.filter.FilterEncoder;
+import org.junit.Test;
+
+
+/**
+ * Tests for {@link FilterEncoder}.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class FilterEncoderTest
+{
+
+    private static final String[] ZERO = new String[0];
+    private static final String[] ONE = new String[]
+        { "foo" };
+    private static final String[] TWO = new String[]
+        { "foo", "bar" };
+    private static final String[] SPECIAL_CHARS = new String[]
+        { "(\\*\0)" };
+
+
+    @Test
+    public void testFormatWithNoPlaceholdersAndCorrectArgumentCount()
+    {
+        assertEquals( "(cn=foo)", FilterEncoder.format( "(cn=foo)", null ) );
+        assertEquals( "(cn=foo)", FilterEncoder.format( "(cn=foo)", ZERO ) );
+    }
+
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testFormatWithNoPlaceholdersAndTooManyArguments()
+    {
+        FilterEncoder.format( "(cn=foo)", ONE );
+    }
+
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testFormatWithPlaceholdersAndTooFewArguments()
+    {
+        FilterEncoder.format( "(cn={0})", ZERO );
+    }
+
+
+    @Test
+    public void testFormatWithPlaceholdersAndCorrectArgumentCount()
+    {
+        assertEquals( "(cn=foo)", FilterEncoder.format( "(cn={0})", ONE ) );
+        assertEquals( "(&(cn=foo)(uid=bar))", FilterEncoder.format( "(&(cn={0})(uid={1}))", TWO ) );
+    }
+
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testFormatWithPlaceholdersAndTooManyArguments()
+    {
+        FilterEncoder.format( "(cn={0})", TWO );
+    }
+
+
+    @Test
+    public void testFormatWithPlaceholdersAndSpecialChars()
+    {
+        assertEquals( "(cn=\\28\\5C\\2A\\00\\29)", FilterEncoder.format( "(cn={0})", SPECIAL_CHARS ) );
+    }
+
+
+    @Test
+    public void testExceptionMessage()
+    {
+        try
+        {
+            FilterEncoder.format( "(&(cn={0})(uid={1}))", ONE );
+            fail( "IllegalArgumentException expected" );
+        }
+        catch ( IllegalArgumentException e )
+        {
+            String message = e.getMessage();
+            assertTrue( message.contains( " (&(cn={0})(uid={1})) " ) );
+            assertTrue( message.contains( " 2 " ) );
+            assertTrue( message.contains( " 1 " ) );
+        }
+    }
+
+
+    @Test
+    public void testEncodeFilterValue()
+    {
+        assertEquals( "1234567890", FilterEncoder.encodeFilterValue( "1234567890" ) );
+        assertEquals( "\\28", FilterEncoder.encodeFilterValue( "(" ) );
+        assertEquals( "\\29", FilterEncoder.encodeFilterValue( ")" ) );
+        assertEquals( "\\2A", FilterEncoder.encodeFilterValue( "*" ) );
+        assertEquals( "\\5C", FilterEncoder.encodeFilterValue( "\\" ) );
+        assertEquals( "\\00", FilterEncoder.encodeFilterValue( "\0" ) );
+        assertEquals( "\\28\\2A\\29", FilterEncoder.encodeFilterValue( "(*)" ) );
+    }
+
+}