You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by el...@apache.org on 2008/07/10 13:22:52 UTC

svn commit: r675519 - in /directory: apacheds/trunk/core-integ/src/test/java/org/apache/directory/server/core/jndi/ apacheds/trunk/core/src/main/java/org/apache/directory/server/core/normalization/ shared/trunk/ldap/src/main/java/org/apache/directory/s...

Author: elecharny
Date: Thu Jul 10 04:22:50 2008
New Revision: 675519

URL: http://svn.apache.org/viewvc?rev=675519&view=rev
Log:
Fix for DIRSERVER-1196 (escaped chars in a filter are not un-escaped) 

Modified:
    directory/apacheds/trunk/core-integ/src/test/java/org/apache/directory/server/core/jndi/SearchIT.java
    directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/normalization/NormalizingVisitor.java
    directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/util/StringTools.java

Modified: directory/apacheds/trunk/core-integ/src/test/java/org/apache/directory/server/core/jndi/SearchIT.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core-integ/src/test/java/org/apache/directory/server/core/jndi/SearchIT.java?rev=675519&r1=675518&r2=675519&view=diff
==============================================================================
--- directory/apacheds/trunk/core-integ/src/test/java/org/apache/directory/server/core/jndi/SearchIT.java (original)
+++ directory/apacheds/trunk/core-integ/src/test/java/org/apache/directory/server/core/jndi/SearchIT.java Thu Jul 10 04:22:50 2008
@@ -1213,6 +1213,56 @@
         assertFalse( results.contains( "cn=testGroup4,ou=groups,ou=system" ) );
         assertTrue( results.contains( "cn=testGroup5,ou=groups,ou=system" ) );
     }
+    
+    
+    @Test
+    public void testSearchWithEscapedCharsInFilter() throws NamingException
+    {
+        // Create an entry with special chars in the description attribute
+        LdapContext sysRoot = getSystemContext( service );
+        // Create entry cn=Sid Vicious, ou=system
+        Attributes vicious = new AttributesImpl();
+        Attribute ocls = new AttributeImpl( "objectClass" );
+        ocls.add( "top" );
+        ocls.add( "person" );
+        vicious.put( ocls );
+        vicious.put( "cn", "Sid Vicious" );
+        vicious.put( "sn", "Vicious" );
+        vicious.put(  "description", "(sex pistols)" );
+        DirContext ctx = sysRoot.createSubcontext( "cn=Sid Vicious", vicious );
+        assertNotNull( ctx );
+
+        ctx = ( DirContext ) sysRoot.lookup( "cn=Sid Vicious" );
+        assertNotNull( ctx );
+        
+        Attributes attributes = ctx.getAttributes( "" );
+        
+        assertEquals( "(sex pistols)", attributes.get( "description" ).get() );
+
+        // Now, search for the description
+        SearchControls controls = new SearchControls();
+        controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
+        controls.setDerefLinkFlag( false );
+        controls.setReturningAttributes( new String[] { "*" } );
+        sysRoot.addToEnvironment( JndiPropertyConstants.JNDI_LDAP_DAP_DEREF_ALIASES,
+                AliasDerefMode.NEVER_DEREF_ALIASES.getJndiValue() );
+        HashMap<String, Attributes> map = new HashMap<String, Attributes>();
+
+        NamingEnumeration<SearchResult> list = sysRoot.search( "", "(description=\\28sex pistols\\29)", controls );
+        
+        while ( list.hasMore() )
+        {
+            SearchResult result = list.next();
+            map.put( result.getName(), result.getAttributes() );
+        }
+
+        assertEquals( "Expected number of results returned was incorrect!", 1, map.size() );
+
+        Attributes attrs = map.get( "cn=Sid Vicious,ou=system" );
+
+        assertNotNull( attrs.get( "objectClass" ) );
+        assertNotNull( attrs.get( "cn" ) );
+    }
 
 
     /**

Modified: directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/normalization/NormalizingVisitor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/normalization/NormalizingVisitor.java?rev=675519&r1=675518&r2=675519&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/normalization/NormalizingVisitor.java (original)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/normalization/NormalizingVisitor.java Thu Jul 10 04:22:50 2008
@@ -23,6 +23,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import javax.naming.InvalidNameException;
 import javax.naming.NamingException;
 
 import org.apache.directory.server.schema.registries.Registries;
@@ -41,6 +42,7 @@
 import org.apache.directory.shared.ldap.filter.SubstringNode;
 import org.apache.directory.shared.ldap.name.NameComponentNormalizer;
 import org.apache.directory.shared.ldap.schema.AttributeType;
+import org.apache.directory.shared.ldap.util.ByteBuffer;
 import org.apache.directory.shared.ldap.util.StringTools;
 
 import org.slf4j.Logger;
@@ -77,6 +79,30 @@
 
 
     /**
+     * Chars which need to be escaped in a filter
+     * '\0' | '(' | ')' | '*' | '\'
+     */
+    private static final boolean[] FILTER_CHAR =
+        { 
+            true,  false, false, false, false, false, false, false, // 00 -> 07 NULL
+            false, false, false, false, false, false, false, false, // 08 -> 0F
+            false, false, false, false, false, false, false, false, // 10 -> 17
+            false, false, false, false, false, false, false, false, // 18 -> 1F
+            false, false, false, false, false, false, false, false, // 20 -> 27
+            true,  true,  true,  false, false, false, false, false, // 28 -> 2F '(', ')', '*'
+            false, false, false, false, false, false, false, false, // 30 -> 37
+            false, false, false, false, false, false, false, false, // 38 -> 3F 
+            false, false, false, false, false, false, false, false, // 40 -> 47
+            false, false, false, false, false, false, false, false, // 48 -> 4F
+            false, false, false, false, false, false, false, false, // 50 -> 57
+            false, false, false, false, true,  false, false, false, // 58 -> 5F '\'
+            false, false, false, false, false, false, false, false, // 60 -> 67
+            false, false, false, false, false, false, false, false, // 68 -> 6F
+            false, false, false, false, false, false, false, false, // 70 -> 77
+            false, false, false, false, false, false, false, false  // 78 -> 7F
+        };
+
+    /**
      * 
      * Creates a new instance of NormalizingVisitor.
      *
@@ -91,6 +117,118 @@
 
 
     /**
+     * Check if the given char is a filter escaped char
+     * &lt;filterEscapedChars&gt; ::= '\0' | '(' | ')' | '*' | '\'
+     *
+     * @param c the char we want to test
+     * @return true if the char is a pair char only
+     */
+    public static boolean isFilterChar( char c )
+    {
+        return ( ( ( c | 0x7F ) == 0x7F ) && FILTER_CHAR[c & 0x7f] );
+    }
+
+    /**
+     * Decodes sequences of escaped hex within an attribute's value into 
+     * a UTF-8 String.  The hex is decoded inline and the complete decoded
+     * String is returned.
+     * 
+     * @param str the string containing hex escapes
+     * @return the decoded string
+     */
+    private static final String decodeEscapedHex( String str ) throws InvalidNameException
+    {
+        // create buffer and add everything before start of scan
+        StringBuffer buf = new StringBuffer();
+        ByteBuffer bb = new ByteBuffer();
+        boolean escaped = false;
+        
+        // start scanning until we find an escaped series of bytes
+        for ( int ii = 0; ii < str.length(); ii++ )
+        {
+            char c = str.charAt( ii );
+            
+            if ( c == '\\' )
+            {
+                // we have the start of a hex escape sequence
+                if ( StringTools.isHex( str, ii+1 ) && StringTools.isHex ( str, ii+2 ) )
+                {
+                    bb.clear();
+                    int advancedBy = StringTools.collectEscapedHexBytes( bb, str, ii );
+                    ii+=advancedBy-1;
+                    buf.append( StringTools.utf8ToString( bb.buffer(), bb.position() ) );
+                    escaped = false;
+                    continue;
+                }
+                else if ( !escaped )
+                {
+                    // It may be an escaped char ( '\0', '(', ')', '*', '\' )
+                    escaped = true;
+                    continue;
+                }
+            }
+
+            
+            if ( escaped )
+            {
+                if ( isFilterChar( c ) )
+                {
+                    // It is an escaped char ( '\0', '(', ')', '*', '\' )
+                    // Stores it into the buffer without the '\'
+                    escaped = false;
+                    buf.append( c );
+                    continue;
+                }
+                else
+                {
+                    throw new InvalidNameException( "The value must contain valid escaped characters." );
+                }
+            }
+            else
+            {
+                buf.append( str.charAt( ii ) );
+            }
+        }
+
+        if ( escaped )
+        {
+            // We should not have a '\' at the end of the string
+            throw new InvalidNameException( "The value must not ends with a '\\'." );
+        }
+
+        return buf.toString();
+    }
+
+
+    /**
+     * Un escape the escaped chars in the value
+     */
+    private void unescapeValue( Value<?> value )
+    {
+        if ( !value.isBinary() )
+        {
+            String valStr = (String)value.getNormalizedValue();
+            
+            if ( StringTools.isEmpty( valStr ) )
+            {
+                return;
+            }
+            
+            try
+            {
+                String newStr= decodeEscapedHex( valStr );
+                ((ClientStringValue)value).set( newStr );
+                return;
+            }
+            catch ( InvalidNameException ine )
+            {
+                value.set( null );
+                return;
+            }
+        }
+    }
+
+    /**
      * A private method used to normalize a value
      * 
      * @param attribute The attribute's ID
@@ -111,11 +249,15 @@
                 {
                     normalized = new ClientStringValue( ( String ) ncn.normalizeByName( attribute, StringTools
                         .utf8ToString( ( byte[] ) value.get() ) ) );
+                    
+                    unescapeValue( normalized );
                 }
                 else
                 {
                     normalized = new ClientStringValue( ( String ) ncn.normalizeByName( attribute, ( String ) value
                         .get() ) );
+                    
+                    unescapeValue( normalized );
                 }
             }
             else

Modified: directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/util/StringTools.java
URL: http://svn.apache.org/viewvc/directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/util/StringTools.java?rev=675519&r1=675518&r2=675519&view=diff
==============================================================================
--- directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/util/StringTools.java (original)
+++ directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/util/StringTools.java Thu Jul 10 04:22:50 2008
@@ -3446,7 +3446,17 @@
     }
 
 
-    private static int collectEscapedHexBytes( ByteBuffer bb, String str, int index )
+    /**
+     * Collects an hex sequence from a string, and returns the value
+     * as an integer, after having modified the initial value (the escaped
+     * hex value is transsformed to the byte it represents).
+     *
+     * @param bb the buffer which will contain the unescaped byte
+     * @param str the initial string with ecaped chars 
+     * @param index the position in the string of the escaped data
+     * @return the byte as an integer
+     */
+    public static int collectEscapedHexBytes( ByteBuffer bb, String str, int index )
     {
         int advanceBy = 0;