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.collective;
21  
22  
23  import org.apache.directory.server.core.DirectoryService;
24  import org.apache.directory.server.core.integ.CiRunner;
25  import org.apache.directory.server.core.integ.SetupMode;
26  import org.apache.directory.server.core.integ.annotations.Mode;
27  import static org.apache.directory.server.core.integ.IntegrationUtils.getSystemContext;
28  import static org.junit.Assert.assertTrue;
29  import static org.junit.Assert.assertNull;
30  import static org.junit.Assert.assertNotNull;
31  import static org.junit.Assert.assertEquals;
32  import static org.junit.Assert.fail;
33  import org.junit.Test;
34  import org.junit.runner.RunWith;
35  
36  import javax.naming.NamingEnumeration;
37  import javax.naming.NamingException;
38  import javax.naming.directory.Attribute;
39  import javax.naming.directory.Attributes;
40  import javax.naming.directory.BasicAttribute;
41  import javax.naming.directory.BasicAttributes;
42  import javax.naming.directory.DirContext;
43  import javax.naming.directory.ModificationItem;
44  import javax.naming.directory.SearchControls;
45  import javax.naming.directory.SearchResult;
46  
47  import java.util.HashMap;
48  import java.util.Map;
49  
50  
51  /**
52   * Test cases for the collective attribute service.
53   *
54   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
55   * @version $Rev: 691179 $
56   */
57  @RunWith ( CiRunner.class )
58  @Mode ( SetupMode.ROLLBACK )
59  public class CollectiveAttributeServiceIT
60  {
61      public static DirectoryService service;
62  
63  
64      public Attributes getTestEntry( String cn )
65      {
66          Attributes subentry = new BasicAttributes( true );
67          Attribute objectClass = new BasicAttribute( "objectClass" );
68          objectClass.add( "top" );
69          objectClass.add( "person" );
70          subentry.put( objectClass );
71          subentry.put( "cn", cn );
72          subentry.put( "sn", "testentry" );
73          return subentry;
74      }
75  
76  
77      public Attributes getTestSubentry()
78      {
79          Attributes subentry = new BasicAttributes( true );
80          Attribute objectClass = new BasicAttribute( "objectClass" );
81          objectClass.add( "top" );
82          objectClass.add( "subentry" );
83          objectClass.add( "collectiveAttributeSubentry" );
84          subentry.put( objectClass );
85          subentry.put( "c-ou", "configuration" );
86          subentry.put( "subtreeSpecification", "{ base \"ou=configuration\" }" );
87          subentry.put( "cn", "testsubentry" );
88          return subentry;
89      }
90  
91  
92      public Attributes getTestSubentry2()
93      {
94          Attributes subentry = new BasicAttributes( true );
95          Attribute objectClass = new BasicAttribute( "objectClass" );
96          objectClass.add( "top" );
97          objectClass.add( "subentry" );
98          objectClass.add( "collectiveAttributeSubentry" );
99          subentry.put( objectClass );
100         subentry.put( "c-ou", "configuration2" );
101         subentry.put( "subtreeSpecification", "{ base \"ou=configuration\" }" );
102         subentry.put( "cn", "testsubentry2" );
103         return subentry;
104     }
105 
106 
107     public Attributes getTestSubentry3()
108     {
109         Attributes subentry = new BasicAttributes( true );
110         Attribute objectClass = new BasicAttribute( "objectClass" );
111         objectClass.add( "top" );
112         objectClass.add( "subentry" );
113         objectClass.add( "collectiveAttributeSubentry" );
114         subentry.put( objectClass );
115         subentry.put( "c-st", "FL" );
116         subentry.put( "subtreeSpecification", "{ base \"ou=configuration\" }" );
117         subentry.put( "cn", "testsubentry3" );
118         return subentry;
119     }
120 
121 
122     public void addAdministrativeRole( String role ) throws Exception
123     {
124         Attribute attribute = new BasicAttribute( "administrativeRole" );
125         attribute.add( role );
126         ModificationItem item = new ModificationItem( DirContext.ADD_ATTRIBUTE, attribute );
127         getSystemContext( service ).modifyAttributes( "", new ModificationItem[] { item } );
128     }
129 
130 
131     public Map<String, Attributes> getAllEntries() throws Exception
132     {
133         Map<String, Attributes> resultMap = new HashMap<String, Attributes>();
134         SearchControls controls = new SearchControls();
135         controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
136         controls.setReturningAttributes( new String[]
137             { "+", "*" } );
138         NamingEnumeration<SearchResult> results = getSystemContext( service ).search( "", "(objectClass=*)", controls );
139         
140         while ( results.hasMore() )
141         {
142             SearchResult result = results.next();
143             resultMap.put( result.getName(), result.getAttributes() );
144         }
145         return resultMap;
146     }
147 
148 
149     public SearchResult getEntry( String name ) throws Exception
150     {
151         SearchControls controls = new SearchControls();
152         controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
153         controls.setReturningAttributes( new String[]
154             { "+", "*" } );
155         
156         NamingEnumeration<SearchResult> results = getSystemContext( service ).search( name, "(objectClass=*)", controls );
157         
158         if ( results.hasMore() )
159         {
160             return results.next();
161         }
162         
163         return null;
164     }
165 
166 
167     public Map<String, Attributes> getAllEntriesRestrictAttributes() throws Exception
168     {
169         Map<String, Attributes> resultMap = new HashMap<String, Attributes>();
170         SearchControls controls = new SearchControls();
171         controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
172         controls.setReturningAttributes( new String[]
173             { "cn" } );
174         NamingEnumeration<SearchResult> results = getSystemContext( service ).search( "", "(objectClass=*)", controls );
175         while ( results.hasMore() )
176         {
177             SearchResult result = results.next();
178             resultMap.put( result.getName(), result.getAttributes() );
179         }
180         return resultMap;
181     }
182     
183     
184     public Map<String, Attributes> getAllEntriesCollectiveAttributesOnly() throws Exception
185     {
186         Map<String, Attributes> resultMap = new HashMap<String, Attributes>();
187         SearchControls controls = new SearchControls();
188         controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
189         controls.setReturningAttributes( new String[]
190                                                     { "c-ou", "c-st" } );
191         NamingEnumeration<SearchResult> results = getSystemContext( service ).search( "", "(objectClass=*)", controls );
192         
193         while ( results.hasMore() )
194         {
195             SearchResult result = results.next();
196             resultMap.put( result.getName(), result.getAttributes() );
197         }
198         return resultMap;
199     }
200     
201 
202     @Test
203     public void testLookup() throws Exception
204     {
205         // -------------------------------------------------------------------
206         // Setup the collective attribute specific administration point
207         // -------------------------------------------------------------------
208 
209         addAdministrativeRole( "collectiveAttributeSpecificArea" );
210         getSystemContext( service ).createSubcontext( "cn=testsubentry", getTestSubentry() );
211 
212         // -------------------------------------------------------------------
213         // test an entry that should show the collective attribute c-ou
214         // -------------------------------------------------------------------
215 
216         Attributes attributes = getSystemContext( service ).getAttributes( "ou=services,ou=configuration" );
217         Attribute c_ou = attributes.get( "c-ou" );
218         assertNotNull( "a collective c-ou attribute should be present", c_ou );
219         assertEquals( "configuration", c_ou.get() );
220 
221         // -------------------------------------------------------------------
222         // test an entry that should not show the collective attribute
223         // -------------------------------------------------------------------
224 
225         attributes = getSystemContext( service ).getAttributes( "ou=users" );
226         c_ou = attributes.get( "c-ou" );
227         assertNull( "the c-ou collective attribute should not be present", c_ou );
228 
229         // -------------------------------------------------------------------
230         // now modify entries included by the subentry to have collectiveExclusions
231         // -------------------------------------------------------------------
232 
233         ModificationItem[] items = new ModificationItem[]
234             { new ModificationItem( DirContext.ADD_ATTRIBUTE,
235                 new BasicAttribute( "collectiveExclusions", "c-ou" ) ) };
236         getSystemContext( service ).modifyAttributes( "ou=services,ou=configuration", items );
237 
238         // entry should not show the c-ou collective attribute anymore
239         attributes = getSystemContext( service ).getAttributes( "ou=services,ou=configuration" );
240         c_ou = attributes.get( "c-ou" );
241         if ( c_ou != null )
242         {
243             assertEquals( "the c-ou collective attribute should not be present", 0, c_ou.size() );
244         }
245 
246         // now add more collective subentries - the c-ou should still not show due to exclusions
247         getSystemContext( service ).createSubcontext( "cn=testsubentry2", getTestSubentry2() );
248 
249         attributes = getSystemContext( service ).getAttributes( "ou=services,ou=configuration" );
250         c_ou = attributes.get( "c-ou" );
251         if ( c_ou != null )
252         {
253             assertEquals( "the c-ou collective attribute should not be present", 0, c_ou.size() );
254         }
255 
256         // entries without the collectiveExclusion should still show both values of c-ou
257         attributes = getSystemContext( service ).getAttributes( "ou=interceptors,ou=configuration" );
258         c_ou = attributes.get( "c-ou" );
259         assertNotNull( "a collective c-ou attribute should be present", c_ou );
260         assertTrue( c_ou.contains( "configuration" ) );
261         assertTrue( c_ou.contains( "configuration2" ) );
262 
263         // request the collective attribute specifically
264         
265         attributes = getSystemContext( service ).getAttributes(
266                 "ou=interceptors,ou=configuration", new String[] { "c-ou" } );
267         c_ou = attributes.get( "c-ou" );
268         assertNotNull( "a collective c-ou attribute should be present", c_ou );
269         assertTrue( c_ou.contains( "configuration" ) );
270         assertTrue( c_ou.contains( "configuration2" ) );
271         
272         // unspecify the collective attribute in the returning attribute list
273 
274         attributes = getSystemContext( service ).getAttributes(
275                 "ou=interceptors,ou=configuration", new String[] { "objectClass" } );
276         c_ou = attributes.get( "c-ou" );
277         assertNull( "a collective c-ou attribute should not be present", c_ou );
278         
279         // -------------------------------------------------------------------
280         // now add the subentry for the c-st collective attribute
281         // -------------------------------------------------------------------
282 
283         getSystemContext( service ).createSubcontext( "cn=testsubentry3", getTestSubentry3() );
284 
285         // the new attribute c-st should appear in the node with the c-ou exclusion
286         attributes = getSystemContext( service ).getAttributes( "ou=services,ou=configuration" );
287         Attribute c_st = attributes.get( "c-st" );
288         assertNotNull( "a collective c-st attribute should be present", c_st );
289         assertTrue( c_st.contains( "FL" ) );
290 
291         // in node without exclusions both values of c-ou should appear with c-st value
292         attributes = getSystemContext( service ).getAttributes( "ou=interceptors,ou=configuration" );
293         c_ou = attributes.get( "c-ou" );
294         assertNotNull( "a collective c-ou attribute should be present", c_ou );
295         assertTrue( c_ou.contains( "configuration" ) );
296         assertTrue( c_ou.contains( "configuration2" ) );
297         c_st = attributes.get( "c-st" );
298         assertNotNull( "a collective c-st attribute should be present", c_st );
299         assertTrue( c_st.contains( "FL" ) );
300 
301         // -------------------------------------------------------------------
302         // now modify an entry to exclude all collective attributes
303         // -------------------------------------------------------------------
304 
305         items = new ModificationItem[]
306             { new ModificationItem( DirContext.REPLACE_ATTRIBUTE, new BasicAttribute( "collectiveExclusions",
307                 "excludeAllCollectiveAttributes" ) ) };
308         getSystemContext( service ).modifyAttributes( "ou=interceptors,ou=configuration", items );
309 
310         // none of the attributes should appear any longer
311         attributes = getSystemContext( service ).getAttributes( "ou=interceptors,ou=configuration" );
312         c_ou = attributes.get( "c-ou" );
313         if ( c_ou != null )
314         {
315             assertEquals( "the c-ou collective attribute should not be present", 0, c_ou.size() );
316         }
317         c_st = attributes.get( "c-st" );
318         if ( c_st != null )
319         {
320             assertEquals( "the c-st collective attribute should not be present", 0, c_st.size() );
321         }
322     }
323 
324 
325     @Test
326     public void testSearch() throws Exception
327     {
328         // -------------------------------------------------------------------
329         // Setup the collective attribute specific administration point
330         // -------------------------------------------------------------------
331 
332         addAdministrativeRole( "collectiveAttributeSpecificArea" );
333         getSystemContext( service ).createSubcontext( "cn=testsubentry", getTestSubentry() );
334 
335         // -------------------------------------------------------------------
336         // test an entry that should show the collective attribute c-ou
337         // -------------------------------------------------------------------
338 
339         Map<String, Attributes> entries = getAllEntries();
340         Attributes attributes = entries.get( "ou=services,ou=configuration,ou=system" );
341         Attribute c_ou = attributes.get( "c-ou" );
342         assertNotNull( "a collective c-ou attribute should be present", c_ou );
343         assertEquals( "configuration", c_ou.get() );
344 
345         
346         // ------------------------------------------------------------------
347         // test an entry that should show the collective attribute c-ou, 
348         // but restrict returned attributes to c-ou and c-st
349         // ------------------------------------------------------------------
350         
351         entries = getAllEntriesCollectiveAttributesOnly();
352         attributes = entries.get( "ou=services,ou=configuration,ou=system" );
353         c_ou = attributes.get( "c-ou" );
354         assertNotNull( "a collective c-ou attribute should be present", c_ou );
355         assertEquals( "configuration", c_ou.get() );   
356         
357         
358         // -------------------------------------------------------------------
359         // test an entry that should not show the collective attribute
360         // -------------------------------------------------------------------
361 
362         attributes = entries.get( "ou=users,ou=system" );
363         c_ou = attributes.get( "c-ou" );
364         assertNull( "the c-ou collective attribute should not be present", c_ou );
365 
366         // -------------------------------------------------------------------
367         // now modify entries included by the subentry to have collectiveExclusions
368         // -------------------------------------------------------------------
369 
370         ModificationItem[] items = new ModificationItem[]
371             { new ModificationItem( DirContext.ADD_ATTRIBUTE,
372                 new BasicAttribute( "collectiveExclusions", "c-ou" ) ) };
373         getSystemContext( service ).modifyAttributes( "ou=services,ou=configuration", items );
374         entries = getAllEntries();
375 
376         // entry should not show the c-ou collective attribute anymore
377         attributes = entries.get( "ou=services,ou=configuration,ou=system" );
378         c_ou = attributes.get( "c-ou" );
379         if ( c_ou != null )
380         {
381             assertEquals( "the c-ou collective attribute should not be present", 0, c_ou.size() );
382         }
383 
384         // now add more collective subentries - the c-ou should still not show due to exclusions
385         getSystemContext( service ).createSubcontext( "cn=testsubentry2", getTestSubentry2() );
386         entries = getAllEntries();
387 
388         attributes = entries.get( "ou=services,ou=configuration,ou=system" );
389         c_ou = attributes.get( "c-ou" );
390         if ( c_ou != null )
391         {
392             assertEquals( "the c-ou collective attribute should not be present", 0, c_ou.size() );
393         }
394 
395         // entries without the collectiveExclusion should still show both values of c-ou
396         attributes = entries.get( "ou=interceptors,ou=configuration,ou=system" );
397         c_ou = attributes.get( "c-ou" );
398         assertNotNull( "a collective c-ou attribute should be present", c_ou );
399         assertTrue( c_ou.contains( "configuration" ) );
400         assertTrue( c_ou.contains( "configuration2" ) );
401 
402         // -------------------------------------------------------------------
403         // now add the subentry for the c-st collective attribute
404         // -------------------------------------------------------------------
405 
406         getSystemContext( service ).createSubcontext( "cn=testsubentry3", getTestSubentry3() );
407         entries = getAllEntries();
408 
409         // the new attribute c-st should appear in the node with the c-ou exclusion
410         attributes = entries.get( "ou=services,ou=configuration,ou=system" );
411         Attribute c_st = attributes.get( "c-st" );
412         assertNotNull( "a collective c-st attribute should be present", c_st );
413         assertTrue( c_st.contains( "FL" ) );
414 
415         // in node without exclusions both values of c-ou should appear with c-st value
416         attributes = entries.get( "ou=interceptors,ou=configuration,ou=system" );
417         c_ou = attributes.get( "c-ou" );
418         assertNotNull( "a collective c-ou attribute should be present", c_ou );
419         assertTrue( c_ou.contains( "configuration" ) );
420         assertTrue( c_ou.contains( "configuration2" ) );
421         c_st = attributes.get( "c-st" );
422         assertNotNull( "a collective c-st attribute should be present", c_st );
423         assertTrue( c_st.contains( "FL" ) );
424 
425         // -------------------------------------------------------------------
426         // now modify an entry to exclude all collective attributes
427         // -------------------------------------------------------------------
428 
429         items = new ModificationItem[]
430             { new ModificationItem( DirContext.REPLACE_ATTRIBUTE, new BasicAttribute( "collectiveExclusions",
431                 "excludeAllCollectiveAttributes" ) ) };
432         getSystemContext( service ).modifyAttributes( "ou=interceptors,ou=configuration", items );
433         entries = getAllEntries();
434 
435         // none of the attributes should appear any longer
436         attributes = entries.get( "ou=interceptors,ou=configuration,ou=system" );
437         c_ou = attributes.get( "c-ou" );
438         if ( c_ou != null )
439         {
440             assertEquals( "the c-ou collective attribute should not be present", 0, c_ou.size() );
441         }
442         c_st = attributes.get( "c-st" );
443         if ( c_st != null )
444         {
445             assertEquals( "the c-st collective attribute should not be present", 0, c_st.size() );
446         }
447 
448         // -------------------------------------------------------------------
449         // Now search attributes but restrict returned attributes to cn and ou
450         // -------------------------------------------------------------------
451 
452         entries = getAllEntriesRestrictAttributes();
453 
454         // we should no longer see collective attributes with restricted return attribs
455         attributes = entries.get( "ou=services,ou=configuration,ou=system" );
456         c_st = attributes.get( "c-st" );
457         assertNull( "a collective c-st attribute should NOT be present", c_st );
458 
459         attributes = entries.get( "ou=partitions,ou=configuration,ou=system" );
460         c_ou = attributes.get( "c-ou" );
461         c_st = attributes.get( "c-st" );
462         assertNull( c_ou );
463         assertNull( c_st );
464     }
465     
466     
467     @Test
468     public void testAddRegularEntryWithCollectiveAttribute()
469     {
470         Attributes entry = getTestEntry( "Ersin Er" );
471         entry.put( "c-l", "Turkiye" );
472         try
473         {
474             getSystemContext( service ).createSubcontext( "cn=Ersin Er", entry );
475             fail( "Entry addition with collective attribute should have failed." );
476         }
477         catch ( Exception e )
478         {
479             // Intended execution point
480         }
481     }
482     
483     
484     @Test
485     public void testModifyRegularEntryAddingCollectiveAttribute() throws Exception
486     {
487         Attributes entry = getTestEntry( "Ersin Er" );
488         getSystemContext( service ).createSubcontext( "cn=Ersin Er", entry );
489         Attributes changeSet = new BasicAttributes( "c-l", "Turkiye", true );
490         try
491         {
492             
493             getSystemContext( service ).modifyAttributes( "cn=Ersin Er", DirContext.ADD_ATTRIBUTE, changeSet );
494             fail( "Collective attribute addition to non-collectiveAttributeSubentry should have failed." );
495         }
496         catch ( NamingException e )
497         {
498             // Intended execution point
499         }
500     }
501     
502     
503     @Test
504     public void testModifyRegularEntryAddingCollectiveAttribute2() throws Exception
505     {
506         Attributes entry = getTestEntry( "Ersin Er" );
507         getSystemContext( service ).createSubcontext( "cn=Ersin Er", entry );
508         Attribute change = new BasicAttribute( "c-l", "Turkiye");
509         ModificationItem mod = new ModificationItem(DirContext.ADD_ATTRIBUTE, change);
510         try
511         {
512             getSystemContext( service ).modifyAttributes( "cn=Ersin Er", new ModificationItem[] { mod } );
513             fail( "Collective attribute addition to non-collectiveAttributeSubentry should have failed." );
514         }
515         catch ( NamingException e )
516         {
517             // Intended execution point
518         }
519     }
520     
521     
522     @Test
523     public void testPolymorphicReturnAttrLookup() throws Exception
524     {
525         // -------------------------------------------------------------------
526         // Setup the collective attribute specific administration point
527         // -------------------------------------------------------------------
528     
529         addAdministrativeRole( "collectiveAttributeSpecificArea" );
530         getSystemContext( service ).createSubcontext( "cn=testsubentry", getTestSubentry() );
531     
532         // request the collective attribute's super type specifically
533         Attributes attributes = getSystemContext( service ).getAttributes( "ou=interceptors,ou=configuration",
534             new String[] { "ou" } );
535         Attribute c_ou = attributes.get( "c-ou" );
536         assertNotNull( "a collective c-ou attribute should be present", c_ou );
537         assertTrue( c_ou.contains( "configuration" ) );
538     }
539     
540 }