1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.core.schema;
21  
22  
23  import java.io.StringReader;
24  import java.util.HashMap;
25  import java.util.Map;
26  import javax.naming.NamingEnumeration;
27  import javax.naming.NamingException;
28  import javax.naming.directory.Attribute;
29  import javax.naming.directory.Attributes;
30  import javax.naming.directory.BasicAttributes;
31  import javax.naming.directory.SearchControls;
32  import javax.naming.directory.SearchResult;
33  import javax.naming.ldap.LdapContext;
34  
35  import org.apache.directory.server.core.DirectoryService;
36  import org.apache.directory.server.core.entry.DefaultServerEntry;
37  import org.apache.directory.server.core.integ.CiRunner;
38  import static org.apache.directory.server.core.integ.IntegrationUtils.getRootContext;
39  import static org.apache.directory.server.core.integ.IntegrationUtils.getSystemContext;
40  import org.apache.directory.server.core.integ.annotations.ApplyLdifs;
41  
42  import org.apache.directory.shared.ldap.exception.LdapSchemaViolationException;
43  import org.apache.directory.shared.ldap.ldif.LdifEntry;
44  import org.apache.directory.shared.ldap.ldif.LdifReader;
45  import org.apache.directory.shared.ldap.message.ResultCodeEnum;
46  import static org.junit.Assert.assertEquals;
47  import static org.junit.Assert.assertFalse;
48  import static org.junit.Assert.assertNotNull;
49  import static org.junit.Assert.assertNull;
50  import static org.junit.Assert.assertTrue;
51  import static org.junit.Assert.fail;
52  
53  import org.junit.Test;
54  import org.junit.runner.RunWith;
55  
56  
57  /**
58   * Test cases for the schema service.  This is for 
59   * <a href="http://issues.apache.org/jira/browse/DIREVE-276">DIREVE-276</a>.
60   *
61   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
62   * @version $Rev: 691077 $
63   */
64  @ApplyLdifs( {
65      // Entry # 1
66      "dn: cn=person0,ou=system\n" +
67      "objectClass: person\n" +
68      "cn: person0\n" +
69      "sn: sn_person0\n",
70      // Entry # 2
71      "dn: cn=person1,ou=system\n" +
72      "objectClass: organizationalPerson\n" +
73      "cn: person1\n" +
74      "sn: sn_person1\n" +
75      "seealso: cn=Good One,ou=people,o=sevenSeas\n" +
76      "seealso:: Y249QmFkIEXDqWvDoCxvdT1wZW9wbGUsbz1zZXZlblNlYXM=\n",
77      // Entry # 3
78      "dn: cn=person2,ou=system\n" +
79      "objectClass: inetOrgPerson\n" +
80      "cn: person2\n" +
81      "sn: sn_person2\n" }
82      )
83  @RunWith ( CiRunner.class )
84  public class SchemaServiceIT
85  {
86      /** The Directory service */
87      public static DirectoryService service;
88  
89  
90      /**
91       * For <a href="https://issues.apache.org/jira/browse/DIRSERVER-925">DIRSERVER-925</a>.
92       *
93       * @throws NamingException on error
94       */
95      @Test
96      public void testNoStructuralObjectClass() throws Exception
97      {
98          Attributes attrs = new BasicAttributes( "objectClass", "top", true );
99          attrs.get( "objectClass" ).add( "uidObject" );
100         attrs.put( "uid", "invalid" );
101         
102         try
103         {
104             getSystemContext( service ).createSubcontext( "uid=invalid", attrs );
105         }
106         catch ( LdapSchemaViolationException e )
107         {
108             assertEquals( ResultCodeEnum.OBJECT_CLASS_VIOLATION, e.getResultCode() );
109         }
110     }
111     
112     
113     /**
114      * For <a href="https://issues.apache.org/jira/browse/DIRSERVER-925">DIRSERVER-925</a>.
115      *
116      * @throws NamingException on error
117      */
118     @Test
119     public void testMultipleStructuralObjectClasses() throws Exception
120     {
121         Attributes attrs = new BasicAttributes( "objectClass", "top", true );
122         attrs.get( "objectClass" ).add( "organizationalUnit" );
123         attrs.get( "objectClass" ).add( "person" );
124         attrs.put( "ou", "comedy" );
125         attrs.put( "cn", "Jack Black" );
126         attrs.put( "sn", "Black" );
127         
128         try
129         {
130             getSystemContext( service ).createSubcontext( "cn=Jack Black", attrs );
131         }
132         catch ( LdapSchemaViolationException e )
133         {
134             assertEquals( ResultCodeEnum.OBJECT_CLASS_VIOLATION, e.getResultCode() );
135         }
136     }
137     
138     
139     /**
140      * For <a href="https://issues.apache.org/jira/browse/DIRSERVER-904">DIRSERVER-904</a>.
141      *
142      * @throws NamingException on error
143      */
144     @Test
145     public void testAddingTwoDifferentEntitiesWithSameOid() throws Exception
146     {
147         String numberOfGunsAttrLdif = "dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.999,ou=attributeTypes,cn=other,ou=schema\n" +
148             "m-usage: USER_APPLICATIONS\n" +
149             "m-equality: integerOrderingMatch\n" +
150             "objectClass: metaAttributeType\n" +
151             "objectClass: metaTop\n" +
152             "objectClass: top\n" +
153             "m-name: numberOfGuns\n" +
154             "m-oid: 1.3.6.1.4.1.18060.0.4.1.2.999\n" +
155             "m-singleValue: TRUE\n" +
156             "m-description: Number of guns of a ship\n" +
157             "m-collective: FALSE\n" +
158             "m-obsolete: FALSE\n" +
159             "m-noUserModification: FALSE\n" +
160             "m-syntax: 1.3.6.1.4.1.1466.115.121.1.27\n";
161         String shipOCLdif = "dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.999,ou=objectClasses,cn=other,ou=schema\n" +
162             "objectClass: top\n" +
163             "objectClass: metaTop\n" +
164             "objectClass: metaObjectclass\n" +
165             "m-supObjectClass: top\n" +
166             "m-oid: 1.3.6.1.4.1.18060.0.4.1.2.999\n" +
167             "m-name: ship\n" +
168             "m-must: cn\n" +
169             "m-may: numberOfGuns\n" +
170             "m-may: description\n" +
171             "m-typeObjectClass: STRUCTURAL\n" +
172             "m-obsolete: FALSE\n" +
173             "m-description: A ship\n";
174 
175         StringReader in = new StringReader( numberOfGunsAttrLdif + "\n\n" + shipOCLdif );
176         LdifReader ldifReader = new LdifReader( in );
177         LdifEntry numberOfGunsAttrEntry = ldifReader.next();
178         LdifEntry shipOCEntry = ldifReader.next();
179         assertFalse( ldifReader.hasNext() );
180         
181         // should be fine with unique OID
182         service.getAdminSession().add( 
183             new DefaultServerEntry( service.getRegistries(), numberOfGunsAttrEntry.getEntry() ) ); 
184 
185         // should blow chuncks using same OID
186         try
187         {
188             service.getAdminSession().add( 
189                 new DefaultServerEntry( service.getRegistries(), shipOCEntry.getEntry() ) ); 
190             
191             fail( "Should not be possible to create two schema entities with the same OID." );
192         }
193         catch( NamingException e )
194         {
195             assertTrue( true );
196         }
197     }
198     
199     
200     /**
201      * Test that we have all the needed ObjectClasses
202      * 
203      * @throws NamingException on error
204      */
205     @Test
206     public void testFillInObjectClasses() throws Exception
207     {
208         LdapContext sysRoot = getSystemContext( service );
209         Attribute ocs = sysRoot.getAttributes( "cn=person0" ).get( "objectClass" );
210         assertEquals( 2, ocs.size() );
211         assertTrue( ocs.contains( "top" ) );
212         assertTrue( ocs.contains( "person" ) );
213 
214         ocs = sysRoot.getAttributes( "cn=person1" ).get( "objectClass" );
215         assertEquals( 3, ocs.size() );
216         assertTrue( ocs.contains( "top" ) );
217         assertTrue( ocs.contains( "person" ) );
218         assertTrue( ocs.contains( "organizationalPerson" ) );
219 
220         ocs = sysRoot.getAttributes( "cn=person2" ).get( "objectClass" );
221         assertEquals( 4, ocs.size() );
222         assertTrue( ocs.contains( "top" ) );
223         assertTrue( ocs.contains( "person" ) );
224         assertTrue( ocs.contains( "organizationalPerson" ) );
225         assertTrue( ocs.contains( "inetOrgPerson" ) );
226     }
227 
228 
229     /**
230      * Search all the entries with a 'person' ObjectClass, or an ObjectClass
231      * inheriting from 'person' 
232      *
233      * @throws NamingException on error
234      */
235     @Test
236     public void testSearchForPerson() throws Exception
237     {
238         LdapContext sysRoot = getSystemContext( service );
239         SearchControls controls = new SearchControls();
240         controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
241         Map<String, Attributes> persons = new HashMap<String, Attributes>();
242         NamingEnumeration<SearchResult> results = sysRoot.search( "", "(objectClass=*person)", controls );
243         
244         while ( results.hasMore() )
245         {
246             SearchResult result = results.next();
247             persons.put( result.getName(), result.getAttributes() );
248         }
249 
250         // admin is extra
251         assertEquals( 4, persons.size() );
252 
253         Attributes person = persons.get( "cn=person0,ou=system" );
254         assertNotNull( person );
255         Attribute ocs = person.get( "objectClass" );
256         assertEquals( 2, ocs.size() );
257         assertTrue( ocs.contains( "top" ) );
258         assertTrue( ocs.contains( "person" ) );
259 
260         person = persons.get( "cn=person1,ou=system" );
261         assertNotNull( person );
262         ocs = person.get( "objectClass" );
263         assertEquals( 3, ocs.size() );
264         assertTrue( ocs.contains( "top" ) );
265         assertTrue( ocs.contains( "person" ) );
266         assertTrue( ocs.contains( "organizationalPerson" ) );
267 
268         person = persons.get( "cn=person2,ou=system" );
269         assertNotNull( person );
270         ocs = person.get( "objectClass" );
271         assertEquals( 4, ocs.size() );
272         assertTrue( ocs.contains( "top" ) );
273         assertTrue( ocs.contains( "person" ) );
274         assertTrue( ocs.contains( "organizationalPerson" ) );
275         assertTrue( ocs.contains( "inetOrgPerson" ) );
276     }
277 
278 
279     @Test
280     public void testSearchForOrgPerson() throws Exception
281     {
282         LdapContext sysRoot = getSystemContext( service );
283         SearchControls controls = new SearchControls();
284         controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
285         Map<String, Attributes> orgPersons = new HashMap<String, Attributes>();
286         NamingEnumeration<SearchResult> results = sysRoot.search( "", "(objectClass=organizationalPerson)", controls );
287         
288         while ( results.hasMore() )
289         {
290             SearchResult result = results.next();
291             orgPersons.put( result.getName(), result.getAttributes() );
292         }
293 
294         // admin is extra
295         assertEquals( 3, orgPersons.size() );
296 
297         Attributes orgPerson = orgPersons.get( "cn=person1,ou=system" );
298         assertNotNull( orgPerson );
299         Attribute ocs = orgPerson.get( "objectClass" );
300         assertEquals( 3, ocs.size() );
301         assertTrue( ocs.contains( "top" ) );
302         assertTrue( ocs.contains( "person" ) );
303         assertTrue( ocs.contains( "organizationalPerson" ) );
304 
305         orgPerson = orgPersons.get( "cn=person2,ou=system" );
306         assertNotNull( orgPerson );
307         ocs = orgPerson.get( "objectClass" );
308         assertEquals( 4, ocs.size() );
309         assertTrue( ocs.contains( "top" ) );
310         assertTrue( ocs.contains( "person" ) );
311         assertTrue( ocs.contains( "organizationalPerson" ) );
312         assertTrue( ocs.contains( "inetOrgPerson" ) );
313     }
314 
315 
316     @Test
317     public void testSearchForInetOrgPerson() throws Exception
318     {
319         LdapContext sysRoot = getSystemContext( service );
320         SearchControls controls = new SearchControls();
321         controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
322         Map<String, Attributes> inetOrgPersons = new HashMap<String, Attributes>();
323         NamingEnumeration<SearchResult> results = sysRoot.search( "", "(objectClass=inetOrgPerson)", controls );
324         
325         while ( results.hasMore() )
326         {
327             SearchResult result = results.next();
328             inetOrgPersons.put( result.getName(), result.getAttributes() );
329         }
330 
331         // admin is extra
332         assertEquals( 2, inetOrgPersons.size() );
333 
334         Attributes inetOrgPerson = inetOrgPersons.get( "cn=person2,ou=system" );
335         assertNotNull( inetOrgPerson );
336         Attribute ocs = inetOrgPerson.get( "objectClass" );
337         assertEquals( 4, ocs.size() );
338         assertTrue( ocs.contains( "top" ) );
339         assertTrue( ocs.contains( "person" ) );
340         assertTrue( ocs.contains( "organizationalPerson" ) );
341         assertTrue( ocs.contains( "inetOrgPerson" ) );
342     }
343 
344 
345     @Test
346     public void testSearchForSubSchemaSubEntryUserAttrsOnly() throws Exception
347     {
348         SearchControls controls = new SearchControls();
349         controls.setSearchScope( SearchControls.OBJECT_SCOPE );
350         
351         Map<String, Attributes> subSchemaEntry = new HashMap<String, Attributes>();
352         NamingEnumeration<SearchResult> results = getRootContext( service ).search( "cn=schema", "(objectClass=*)", controls );
353 
354         while ( results.hasMore() )
355         {
356             SearchResult result = results.next();
357             subSchemaEntry.put( result.getName(), result.getAttributes() );
358         }
359 
360         // We should have only one entry in the result
361         assertEquals( 1, subSchemaEntry.size() );
362         
363         // It should be the normalized form of cn=schema
364         Attributes attrs = subSchemaEntry.get( "cn=schema" );
365         
366         assertNotNull( attrs );
367         
368         // We should have 2 attributes in the result :
369         // - attributeTypes
370         // - cn
371         // - objectClass
372         assertEquals( 2, attrs.size() );
373         
374         assertNotNull( attrs.get( "cn" ) );
375         assertNotNull( attrs.get( "objectClass" ) );
376     }
377 
378 
379     @Test
380     public void testSearchForSubSchemaSubEntryAllAttrs() throws Exception
381     {
382         SearchControls controls = new SearchControls();
383         controls.setSearchScope( SearchControls.OBJECT_SCOPE );
384         controls.setReturningAttributes( new String[]{ "*", "+" } );
385         
386         Map<String, Attributes> subSchemaEntry = new HashMap<String, Attributes>();
387         NamingEnumeration<SearchResult> results = getRootContext( service ).search(
388                 "cn=schema", "(objectClass=*)", controls );
389 
390         while ( results.hasMore() )
391         {
392             SearchResult result = results.next();
393             subSchemaEntry.put( result.getName(), result.getAttributes() );
394         }
395 
396         // We should have only one entry in the result
397         assertEquals( 1, subSchemaEntry.size() );
398         
399         // It should be the normalized form of cn=schema
400         Attributes attrs = subSchemaEntry.get( "cn=schema" );
401         
402         assertNotNull( attrs );
403         
404         assertNotNull( attrs.get( "nameForms" ) );
405     }
406 
407     
408     @Test
409     public void testSearchForSubSchemaSubEntrySingleAttributeSelected() throws Exception
410     {
411         SearchControls controls = new SearchControls();
412         controls.setSearchScope( SearchControls.OBJECT_SCOPE );
413         controls.setReturningAttributes( new String[]{ "nameForms" } );
414         
415         Map<String, Attributes> subSchemaEntry = new HashMap<String, Attributes>();
416         NamingEnumeration<SearchResult> results = getRootContext( service )
417                 .search( "cn=schema", "(objectClass=*)", controls );
418 
419         while ( results.hasMore() )
420         {
421             SearchResult result = results.next();
422             subSchemaEntry.put( result.getName(), result.getAttributes() );
423         }
424 
425         // We should have only one entry in the result
426         assertEquals( 1, subSchemaEntry.size() );
427         
428         // It should be the normalized form of cn=schema
429         Attributes attrs = subSchemaEntry.get( "cn=schema" );
430         
431         assertNotNull( attrs );
432         
433         // We should have 1 attribute in the result :
434         // - nameForms
435         assertEquals( 1, attrs.size() );
436         
437         assertNull( attrs.get( "attributeTypes" ) );
438         assertNull( attrs.get( "cn" ) );
439         assertNull( attrs.get( "creatorsName" ) );
440         assertNull( attrs.get( "createTimestamp" ) );
441         assertNull( attrs.get( "dITContentRules" ) );
442         assertNull( attrs.get( "dITStructureRules" ) );
443         assertNull( attrs.get( "ldapSyntaxes" ) );
444         assertNull( attrs.get( "matchingRules" ) );
445         assertNull( attrs.get( "matchingRuleUse" ) );
446         assertNull( attrs.get( "modifiersName" ) );
447         assertNull( attrs.get( "modifyTimestamp" ) );
448         assertNotNull( attrs.get( "nameForms" ) );
449         assertNull( attrs.get( "objectClass" ) );
450         assertNull( attrs.get( "objectClasses" ) );
451     }
452 
453     
454     /**
455      * Test for DIRSERVER-1055.
456      * Check if modifyTimestamp and createTimestamp are present in the search result,
457      * if they are requested.
458      */
459     @Test
460     public void testSearchForSubSchemaSubEntryOperationalAttributesSelected() throws Exception
461     {
462         SearchControls controls = new SearchControls();
463         controls.setSearchScope( SearchControls.OBJECT_SCOPE );
464         controls.setReturningAttributes( new String[]
465             { "creatorsName", "createTimestamp", "modifiersName", "modifyTimestamp" } );
466         
467         Map<String, Attributes> subSchemaEntry = new HashMap<String, Attributes>();
468         NamingEnumeration<SearchResult> results = getRootContext( service )
469         .search( "cn=schema", "(objectClass=subschema)", controls );
470         
471         while ( results.hasMore() )
472         {
473             SearchResult result = results.next();
474             subSchemaEntry.put( result.getName(), result.getAttributes() );
475         }
476         
477         // We should have only one entry in the result
478         assertEquals( 1, subSchemaEntry.size() );
479         
480         // It should be the normalized form of cn=schema
481         Attributes attrs = subSchemaEntry.get( "cn=schema" );
482         
483         assertNotNull( attrs );
484         
485         // We should have 4 attribute in the result :
486         assertEquals( 4, attrs.size() );
487         
488         assertNull( attrs.get( "attributeTypes" ) );
489         assertNull( attrs.get( "cn" ) );
490         assertNotNull( attrs.get( "creatorsName" ) );
491         assertNotNull( attrs.get( "createTimestamp" ) );
492         assertNull( attrs.get( "dITContentRules" ) );
493         assertNull( attrs.get( "dITStructureRules" ) );
494         assertNull( attrs.get( "ldapSyntaxes" ) );
495         assertNull( attrs.get( "matchingRules" ) );
496         assertNull( attrs.get( "matchingRuleUse" ) );
497         assertNotNull( attrs.get( "modifiersName" ) );
498         assertNotNull( attrs.get( "modifyTimestamp" ) );
499         assertNull( attrs.get( "nameForms" ) );
500         assertNull( attrs.get( "objectClass" ) );
501         assertNull( attrs.get( "objectClasses" ) );
502     }
503 
504 
505     @Test
506     public void testSearchForSubSchemaSubEntryBadFilter() throws Exception
507     {
508         SearchControls controls = new SearchControls();
509         controls.setSearchScope( SearchControls.OBJECT_SCOPE );
510         controls.setReturningAttributes( new String[]{ "+" } );
511         
512         Map<String, Attributes> subSchemaEntry = new HashMap<String, Attributes>();
513         NamingEnumeration<SearchResult> results = getRootContext( service )
514                 .search( "cn=schema", "(objectClass=nothing)", controls );
515 
516         while ( results.hasMore() )
517         {
518             SearchResult result = results.next();
519             subSchemaEntry.put( result.getName(), result.getAttributes() );
520         }
521 
522         // We should have no entry in the result
523         assertEquals( 0, subSchemaEntry.size() );
524     }
525 
526 
527     @Test
528     public void testSearchForSubSchemaSubEntryFilterEqualTop() throws Exception
529     {
530         SearchControls controls = new SearchControls();
531         controls.setSearchScope( SearchControls.OBJECT_SCOPE );
532         controls.setReturningAttributes( new String[]{ "*", "+" } );
533         
534         Map<String, Attributes> subSchemaEntry = new HashMap<String, Attributes>();
535         NamingEnumeration<SearchResult> results = getRootContext( service )
536                 .search( "cn=schema", "(objectClass=top)", controls );
537 
538         while ( results.hasMore() )
539         {
540             SearchResult result = results.next();
541             subSchemaEntry.put( result.getName(), result.getAttributes() );
542         }
543 
544         // We should have only one entry in the result
545         assertEquals( 1, subSchemaEntry.size() );
546         
547         // It should be the normalized form of cn=schema
548         Attributes attrs = subSchemaEntry.get( "cn=schema" );
549         
550         assertNotNull( attrs );
551         
552         // We should have 18 attribute in the result :
553         // - nameForms
554         // - comparators
555         // - normalizers
556         // - syntaxCheckers
557         assertEquals( 18, attrs.size() );
558         
559         assertNotNull( attrs.get( "attributeTypes" ) );
560         assertNotNull( attrs.get( "cn" ) );
561         assertNotNull( attrs.get( "comparators" ) );
562         assertNotNull( attrs.get( "creatorsName" ) );
563         assertNotNull( attrs.get( "createTimestamp" ) );
564         assertNotNull( attrs.get( "dITContentRules" ) );
565         assertNotNull( attrs.get( "dITStructureRules" ) );
566         assertNotNull( attrs.get( "ldapSyntaxes" ) );
567         assertNotNull( attrs.get( "matchingRules" ) );
568         assertNotNull( attrs.get( "matchingRuleUse" ) );
569         assertNotNull( attrs.get( "modifiersName" ) );
570         assertNotNull( attrs.get( "modifyTimestamp" ) );
571         assertNotNull( attrs.get( "nameForms" ) );
572         assertNotNull( attrs.get( "normalizers" ) );
573         assertNotNull( attrs.get( "objectClass" ) );
574         assertNotNull( attrs.get( "objectClasses" ) );
575         assertNotNull( attrs.get( "subtreeSpecification" ) );
576         assertNotNull( attrs.get( "syntaxCheckers" ) );
577     }
578 
579 
580     @Test
581     public void testSearchForSubSchemaSubEntryFilterEqualSubSchema() throws Exception
582     {
583         SearchControls controls = new SearchControls();
584         controls.setSearchScope( SearchControls.OBJECT_SCOPE );
585         controls.setReturningAttributes( new String[]{ "*", "+" } );
586         
587         Map<String, Attributes> subSchemaEntry = new HashMap<String, Attributes>();
588         NamingEnumeration<SearchResult> results = getRootContext( service )
589                 .search( "cn=schema", "(objectClass=subSchema)", controls );
590 
591         while ( results.hasMore() )
592         {
593             SearchResult result = results.next();
594             subSchemaEntry.put( result.getName(), result.getAttributes() );
595         }
596 
597         // We should have only one entry in the result
598         assertEquals( 1, subSchemaEntry.size() );
599         
600         // It should be the normalized form of cn=schema
601         Attributes attrs = subSchemaEntry.get( "cn=schema" );
602         
603         assertNotNull( attrs );
604         
605         // We should have 18 attribute in the result :
606         // - nameForms
607         // - comparators
608         // - normalizers
609         // - syntaxCheckers
610         assertEquals( 18, attrs.size() );
611         
612         assertNotNull( attrs.get( "attributeTypes" ) );
613         assertNotNull( attrs.get( "cn" ) );
614         assertNotNull( attrs.get( "subtreeSpecification" ) );
615         assertNotNull( attrs.get( "creatorsName" ) );
616         assertNotNull( attrs.get( "createTimestamp" ) );
617         assertNotNull( attrs.get( "dITContentRules" ) );
618         assertNotNull( attrs.get( "dITStructureRules" ) );
619         assertNotNull( attrs.get( "ldapSyntaxes" ) );
620         assertNotNull( attrs.get( "matchingRules" ) );
621         assertNotNull( attrs.get( "matchingRuleUse" ) );
622         assertNotNull( attrs.get( "modifiersName" ) );
623         assertNotNull( attrs.get( "modifyTimestamp" ) );
624         assertNotNull( attrs.get( "nameForms" ) );
625         assertNotNull( attrs.get( "objectClass" ) );
626         assertNotNull( attrs.get( "objectClasses" ) );
627     }
628 
629 
630     @Test
631     public void testSearchForSubSchemaSubEntryNotObjectScope() throws Exception
632     {
633         SearchControls controls = new SearchControls();
634         controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
635         controls.setReturningAttributes( new String[]{ "+" } );
636         
637         Map<String, Attributes> subSchemaEntry = new HashMap<String, Attributes>();
638         NamingEnumeration<SearchResult> results = getRootContext( service )
639                 .search( "cn=schema", "(objectClass=nothing)", controls );
640 
641         while ( results.hasMore() )
642         {
643             SearchResult result = results.next();
644             subSchemaEntry.put( result.getName(), result.getAttributes() );
645         }
646 
647         // We should have no entry in the result
648         assertEquals( 0, subSchemaEntry.size() );
649     }
650 
651 
652     @Test
653     public void testSearchForSubSchemaSubEntryComposedFilters() throws Exception
654     {
655         SearchControls controls = new SearchControls();
656         controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
657         controls.setReturningAttributes( new String[]{ "+" } );
658         
659         Map<String, Attributes> subSchemaEntry = new HashMap<String, Attributes>();
660         NamingEnumeration<SearchResult> results = getRootContext( service )
661                 .search( "cn=schema", "(&(objectClass=*)(objectClass=top))", controls );
662 
663         while ( results.hasMore() )
664         {
665             SearchResult result = results.next();
666             subSchemaEntry.put( result.getName(), result.getAttributes() );
667         }
668 
669         // We should have no entry in the result
670         assertEquals( 0, subSchemaEntry.size() );
671     }
672 
673 
674     /**
675      * Test for DIRSERVER-844: storing of base 64 encoded values into H-R attributes
676      *
677      * @throws NamingException on error
678      */
679     @Test
680     public void testSearchSeeAlso() throws Exception
681     {
682         SearchControls controls = new SearchControls();
683         controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
684         Map<String, Attributes> persons = new HashMap<String, Attributes>();
685         NamingEnumeration<SearchResult> results = getSystemContext( service )
686                     .search( "", "(seeAlso=cn=Good One,ou=people,o=sevenSeas)", controls );
687 
688         while ( results.hasMore() )
689         {
690             SearchResult result = results.next();
691             persons.put( result.getName(), result.getAttributes() );
692         }
693 
694         // admin is extra
695         assertEquals( 1, persons.size() );
696 
697         Attributes person;
698         Attribute ocs;
699 
700         person = persons.get( "cn=person1,ou=system" );
701         assertNotNull( person );
702         ocs = person.get( "objectClass" );
703         assertEquals( 3, ocs.size() );
704         assertTrue( ocs.contains( "top" ) );
705         assertTrue( ocs.contains( "person" ) );
706         assertTrue( ocs.contains( "organizationalPerson" ) );
707 
708         Attribute seeAlso = person.get(  "seeAlso"  );
709         assertTrue( seeAlso.contains( "cn=Good One,ou=people,o=sevenSeas" ) );
710         assertTrue( seeAlso.contains( "cn=Bad E\u00e9k\u00e0,ou=people,o=sevenSeas" ) );
711     }
712 
713 
714     /**
715      * Doing a search with filtering attributes should work even if the attribute
716      * is not valid 
717      *
718      * @throws NamingException on error
719      */
720     @Test
721     public void testSearchForUnknownAttributes() throws Exception
722     {
723         SearchControls controls = new SearchControls();
724         controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
725         Map<String, Attributes> persons = new HashMap<String, Attributes>();
726         controls.setReturningAttributes( new String[] { "9.9.9" } );
727 
728         NamingEnumeration<SearchResult> results = getSystemContext( service )
729                 .search( "", "(objectClass=person)", controls );
730         
731         while ( results.hasMore() )
732         {
733             SearchResult result = results.next();
734             persons.put( result.getName(), result.getAttributes() );
735         }
736 
737         // admin is extra
738         assertEquals( 4, persons.size() );
739 
740         Attributes person;
741         Attribute ocs;
742 
743         person = persons.get( "cn=person0,ou=system" );
744         assertNotNull( person );
745         ocs = person.get( "objectClass" );
746         assertNull( ocs );
747         
748         ocs = person.get( "9.9.9" );
749         assertNull( ocs );
750 
751         person = persons.get( "cn=person1,ou=system" );
752         assertNotNull( person );
753         ocs = person.get( "objectClass" );
754         assertNull( ocs );
755 
756         person = persons.get( "cn=person2,ou=system" );
757         assertNotNull( person );
758         ocs = person.get( "objectClass" );
759         assertNull( ocs );
760     }
761 
762     
763     /**
764      * Check that if we request a Attribute which is not an AttributeType,
765      * we still get a result
766      *
767      * @throws NamingException on error
768      */
769     @Test
770     public void testSearchAttributesOIDObjectClass() throws Exception
771     {
772         SearchControls controls = new SearchControls();
773         controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
774         Map<String, Attributes> persons = new HashMap<String, Attributes>();
775         controls.setReturningAttributes( new String[] { "2.5.6.6" } );
776 
777         NamingEnumeration<SearchResult> results = getSystemContext( service )
778                 .search( "", "(objectClass=person)", controls );
779         
780         while ( results.hasMore() )
781         {
782             SearchResult result = results.next();
783             persons.put( result.getName(), result.getAttributes() );
784         }
785 
786         // admin is extra
787         assertEquals( 4, persons.size() );
788 
789         Attributes person;
790         Attribute ocs;
791 
792         person = persons.get( "cn=person0,ou=system" );
793         assertNotNull( person );
794         ocs = person.get( "objectClass" );
795         assertNull( ocs );
796         
797         // We should not get this attribute (it's an ObjectClass)
798         ocs = person.get( "2.5.6.6" );
799         assertNull( ocs );
800 
801         person = persons.get( "cn=person1,ou=system" );
802         assertNotNull( person );
803         ocs = person.get( "objectClass" );
804         assertNull( ocs );
805 
806         person = persons.get( "cn=person2,ou=system" );
807         assertNotNull( person );
808         ocs = person.get( "objectClass" );
809         assertNull( ocs );
810     }
811 
812     
813     /**
814      * Check that if we request a Attribute which is an ObjectClass.
815      *
816      * @throws NamingException on error
817      */
818     @Test
819     public void testSearchAttributesOIDObjectClassName() throws Exception
820     {
821         SearchControls controls = new SearchControls();
822         controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
823         Map<String, Attributes> persons = new HashMap<String, Attributes>();
824         controls.setReturningAttributes( new String[] { "person" } );
825 
826         NamingEnumeration<SearchResult> results = getSystemContext( service )
827                 .search( "", "(objectClass=person)", controls );
828         
829         while ( results.hasMore() )
830         {
831             SearchResult result = results.next();
832             persons.put( result.getName(), result.getAttributes() );
833         }
834 
835         // admin is extra
836         assertEquals( 4, persons.size() );
837 
838         Attributes person;
839         Attribute ocs;
840 
841         person = persons.get( "cn=person0,ou=system" );
842         assertNotNull( person );
843         ocs = person.get( "objectClass" );
844         assertNull( ocs );
845         
846         // We should not get this attrinute (it's an ObjectClass)
847         ocs = person.get( "2.5.4.46" );
848         assertNull( ocs );
849 
850         person = persons.get( "cn=person1,ou=system" );
851         assertNotNull( person );
852         ocs = person.get( "objectClass" );
853         assertNull( ocs );
854 
855         person = persons.get( "cn=person2,ou=system" );
856         assertNotNull( person );
857         ocs = person.get( "objectClass" );
858         assertNull( ocs );
859     }
860 
861 
862     /**
863      * Check that if we search for an attribute using its inherited
864      * AttributeType (ie, looking for name instead of givenName, surname, 
865      * commonName), we find all the entries.
866      *
867      * @throws NamingException
868      */
869     @Test
870     public void testSearchForName() throws Exception
871     {
872         LdapContext sysRoot = getSystemContext( service );
873         SearchControls controls = new SearchControls();
874         controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
875         Map<String, Attributes> persons = new HashMap<String, Attributes>();
876 
877         NamingEnumeration<SearchResult> results = sysRoot.search( "", "(name=person*)", controls );
878         
879         while ( results.hasMore() )
880         {
881             SearchResult result = results.next();
882             persons.put( result.getName(), result.getAttributes() );
883         }
884 
885         assertEquals( 3, persons.size() );
886 
887         Attributes person = persons.get( "cn=person0,ou=system" );
888         assertNotNull( person );
889         Attribute ocs = person.get( "objectClass" );
890         assertEquals( 2, ocs.size() );
891         assertTrue( ocs.contains( "top" ) );
892         assertTrue( ocs.contains( "person" ) );
893 
894         person = persons.get( "cn=person1,ou=system" );
895         assertNotNull( person );
896         ocs = person.get( "objectClass" );
897         assertEquals( 3, ocs.size() );
898         assertTrue( ocs.contains( "top" ) );
899         assertTrue( ocs.contains( "person" ) );
900         assertTrue( ocs.contains( "organizationalPerson" ) );
901 
902         person = persons.get( "cn=person2,ou=system" );
903         assertNotNull( person );
904         ocs = person.get( "objectClass" );
905         assertEquals( 4, ocs.size() );
906         assertTrue( ocs.contains( "top" ) );
907         assertTrue( ocs.contains( "person" ) );
908         assertTrue( ocs.contains( "organizationalPerson" ) );
909         assertTrue( ocs.contains( "inetOrgPerson" ) );
910     }
911 }