1   /*
2    * Copyright (c) 2004 Solarsis Group LLC.
3    *
4    * Licensed under the Open Software License, Version 2.1 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://opensource.org/licenses/osl-2.1.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.apache.ldap.server;
17  
18  import java.util.Hashtable;
19  
20  import javax.naming.NamingEnumeration;
21  import javax.naming.NamingException;
22  import javax.naming.directory.Attribute;
23  import javax.naming.directory.Attributes;
24  import javax.naming.directory.BasicAttribute;
25  import javax.naming.directory.BasicAttributes;
26  import javax.naming.directory.DirContext;
27  import javax.naming.directory.SearchControls;
28  import javax.naming.ldap.InitialLdapContext;
29  import javax.naming.ldap.LdapContext;
30  
31  /***
32   * Tests with compare operations on attributes which use different matching
33   * rules. Created to demonstrate JIRA DIREVE-243 ("Compare operation does not
34   * adhere to some matching rules").
35   * 
36   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
37   * @version $Rev$
38   */
39  public class MatchingRuleCompareTest extends AbstractServerTest
40  {
41      private LdapContext ctx = null;
42  
43      public static final String PERSON_CN = "Tori Amos";
44      public static final String PERSON_SN = "Amos";
45      public static final String PERSON_RDN = "cn=" + PERSON_CN;
46      public static final String PERSON_TELEPHONE = "1234567890abc";
47      public static final String PERSON_PWD = "Secret1!";
48  
49      public static final String GROUP_CN = "Artists";
50      public static final String GROUP_RDN = "cn=" + GROUP_CN;
51  
52      protected Attributes getPersonAttributes(String sn, String cn)
53      {
54          Attributes attributes = new BasicAttributes();
55          Attribute attribute = new BasicAttribute("objectClass");
56          attribute.add("top");
57          attribute.add("person");
58          attributes.put(attribute);
59          attributes.put("cn", cn);
60          attributes.put("sn", sn);
61  
62          return attributes;
63      }
64  
65      protected Attributes getGroupOfNamesAttributes(String cn, String member)
66      {
67          Attributes attributes = new BasicAttributes();
68          Attribute attribute = new BasicAttribute("objectClass");
69          attribute.add("top");
70          attribute.add("groupOfNames");
71          attributes.put(attribute);
72          attributes.put("cn", cn);
73          attributes.put("member", member);
74  
75          return attributes;
76      }
77  
78      /***
79       * Create context, a person entry and a group.
80       */
81      public void setUp() throws Exception
82      {
83          super.setUp();
84  
85          Hashtable env = new Hashtable();
86          env.put("java.naming.factory.initial", "com.sun.jndi.ldap.LdapCtxFactory");
87          env.put("java.naming.provider.url", "ldap://localhost:" + port + "/ou=system");
88          env.put("java.naming.security.principal", "uid=admin,ou=system");
89          env.put("java.naming.security.credentials", "secret");
90          env.put("java.naming.security.authentication", "simple");
91  
92          ctx = new InitialLdapContext(env, null);
93          assertNotNull(ctx);
94  
95          // Create a person
96          Attributes attributes = this.getPersonAttributes(PERSON_SN, PERSON_CN);
97          attributes.put("telephoneNumber", PERSON_TELEPHONE);
98          attributes.put("userPassword", PERSON_PWD);
99          ctx.createSubcontext(PERSON_RDN, attributes);
100 
101         // Create a group
102         DirContext member = (DirContext) ctx.lookup(PERSON_RDN);
103         attributes = this.getGroupOfNamesAttributes(GROUP_CN, member.getNameInNamespace());
104         ctx.createSubcontext(GROUP_RDN, attributes);
105     }
106 
107     /***
108      * Remove entries and close context.
109      */
110     public void tearDown() throws Exception
111     {
112         ctx.unbind(PERSON_RDN);
113         ctx.unbind(GROUP_RDN);
114 
115         ctx.close();
116 
117         super.tearDown();
118     }
119 
120     /***
121      * Compare with caseIgnoreMatch matching rule.
122      * 
123      * @throws NamingException
124      */
125     public void testCaseIgnoreMatch() throws NamingException
126     {
127         // Setting up search controls for compare op
128         SearchControls ctls = new SearchControls();
129         ctls.setReturningAttributes(new String[] {}); // no attributes
130         ctls.setSearchScope(SearchControls.OBJECT_SCOPE);
131 
132         String[] values = { PERSON_SN, PERSON_SN.toUpperCase(), PERSON_SN.toLowerCase(), PERSON_SN + "X" };
133         boolean[] expected = { true, true, true, false };
134 
135         for (int i = 0; i < values.length; i++) {
136             String value = values[i];
137 
138             NamingEnumeration enumeration = ctx.search(PERSON_RDN, "sn={0}", new String[] { value }, ctls);
139             boolean result = enumeration.hasMore();
140 
141             assertEquals("compare sn value '" + PERSON_SN + "' with '" + value + "'", expected[i], result);
142 
143             enumeration.close();
144         }
145     }
146 
147     //
148 
149     /***
150      * Compare with telephoneNumberMatch matching rule.
151      * 
152      * @throws NamingException
153      */
154 
155 // Comment this out until we have the telephone number match working.
156 
157 //    public void testTelephoneNumberMatch() throws NamingException
158 //    {
159 //        // Setting up search controls for compare op
160 //        SearchControls ctls = new SearchControls();
161 //        ctls.setReturningAttributes(new String[] {}); // no attributes
162 //        ctls.setSearchScope(SearchControls.OBJECT_SCOPE);
163 //
164 //        String[] values = { "", "1234567890abc", "   1234567890 A B C", "123 456 7890 abc", "123-456-7890 abC",
165 //                "123456-7890 A bc" };
166 //        boolean[] expected = { false, true, true, true, true, true };
167 //
168 //        for (int i = 0; i < values.length; i++) {
169 //            String value = values[i];
170 //
171 //            NamingEnumeration enumeration = ctx.search(PERSON_RDN, "telephoneNumber={0}", new String[] { value }, ctls);
172 //            boolean result = enumeration.hasMore();
173 //
174 //            assertEquals("compare '" + PERSON_TELEPHONE + "' with '" + value + "'", expected[i], result);
175 //
176 //            enumeration.close();
177 //        }
178 //    }
179 
180     /***
181      * Compare with octetStringMatch matching rule.
182      * 
183      * @throws NamingException
184      */
185     public void testOctetStringMatch() throws NamingException
186     {
187         // Setting up search controls for compare op
188         SearchControls ctls = new SearchControls();
189         ctls.setReturningAttributes(new String[] {}); // no attributes
190         ctls.setSearchScope(SearchControls.OBJECT_SCOPE);
191 
192         String[] values = { "", PERSON_PWD, PERSON_PWD.toUpperCase(), PERSON_PWD.toLowerCase(), PERSON_PWD + "X" };
193         boolean[] expected = { false, true, false, false, false };
194 
195         for (int i = 0; i < values.length; i++) {
196             String value = values[i];
197 
198             NamingEnumeration enumeration = ctx.search(PERSON_RDN, "userPassword={0}", new String[] { value }, ctls);
199             boolean result = enumeration.hasMore();
200 
201             assertEquals("compare '" + PERSON_PWD + "' with '" + value + "'", expected[i], result);
202 
203             enumeration.close();
204         }
205     }
206 
207     /***
208      * Compare with distinguishedNameMatch matching rule.
209      * 
210      * @throws NamingException
211      */
212     public void testDistinguishedNameMatch() throws NamingException
213     {
214         // determine member DN of person
215         DirContext member = (DirContext) ctx.lookup(PERSON_RDN);
216         String memberDN = member.getNameInNamespace();
217 
218         // Setting up search controls for compare op
219         SearchControls ctls = new SearchControls();
220         ctls.setReturningAttributes(new String[] {}); // no attributes
221         ctls.setSearchScope(SearchControls.OBJECT_SCOPE);
222 
223         String[] values = { "", memberDN, "cn=nobody", memberDN.toLowerCase(),
224                 PERSON_RDN + " , " + ctx.getNameInNamespace() };
225         boolean[] expected = { false, true, false, true, true };
226 
227         for (int i = 0; i < values.length; i++) {
228             String value = values[i];
229 
230             NamingEnumeration enumeration = ctx.search(GROUP_RDN, "member={0}", new Object[] { value }, ctls);
231             boolean result = enumeration.hasMore();
232 
233             assertEquals("compare '" + memberDN + "' with '" + value + "'", expected[i], result);
234 
235             enumeration.close();
236         }
237     }
238 
239 }