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.jndi;
21  
22  
23  import org.apache.directory.server.core.DirectoryService;
24  import org.apache.directory.server.core.integ.CiRunner;
25  import static org.apache.directory.server.core.integ.IntegrationUtils.getSystemContext;
26  import org.apache.directory.shared.ldap.constants.JndiPropertyConstants;
27  import org.apache.directory.shared.ldap.message.AliasDerefMode;
28  import static org.junit.Assert.assertEquals;
29  import static org.junit.Assert.assertTrue;
30  import static org.junit.Assert.assertFalse;
31  import static org.junit.Assert.assertNotNull;
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.SearchControls;
43  import javax.naming.directory.SearchResult;
44  import javax.naming.ldap.LdapContext;
45  import java.util.HashMap;
46  import java.util.HashSet;
47  import java.util.Set;
48  
49  
50  /**
51   * Test DIRSERVER-757 : a UniqueMember attribute should only contain a DN completed with an
52   * optional UID. 
53   *
54   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
55   * @version $Rev$
56   */
57  @RunWith ( CiRunner.class )
58  public class UniqueMemberIT
59  {
60      public static DirectoryService service;
61  
62      
63      /**
64       * Test a valid entry
65       *
66       * @throws Exception on error
67       */
68      @Test
69      public void testValidUniqueMember() throws Exception
70      {
71          LdapContext sysRoot = getSystemContext( service );
72  
73          Attributes attrs = new BasicAttributes( true );
74          Attribute oc = new BasicAttribute( "ObjectClass", "top" );
75          oc.add( "groupOfUniqueNames" );
76          Attribute cn = new BasicAttribute( "cn", "kevin Spacey" );
77          Attribute dc = new BasicAttribute( "uniqueMember", "cn=kevin spacey, dc=example, dc=org" );
78          attrs.put( oc );
79          attrs.put( cn );
80          attrs.put( dc);
81  
82          String base = "cn=kevin Spacey";
83  
84          //create subcontext
85          try
86          {
87              sysRoot.createSubcontext( base, attrs );
88          }
89          catch ( NamingException ne )
90          {
91              fail();
92          }
93          
94          Attributes returned = sysRoot.getAttributes( "cn=kevin Spacey" );
95        
96          NamingEnumeration<? extends Attribute> attrList = returned.getAll();
97          
98          while ( attrList.hasMore() )
99          {
100             Attribute attr = attrList.next();
101           
102             if ( attr.getID().equalsIgnoreCase( "cn" ) )
103             {
104                 assertEquals( "kevin Spacey", attr.get() );
105                 continue;
106             }
107           
108             if ( attr.getID().equalsIgnoreCase( "objectClass" ) )
109             {
110                 NamingEnumeration<?> values = attr.getAll();
111                 Set<String> expectedValues = new HashSet<String>();
112                 
113                 expectedValues.add( "top" );
114                 expectedValues.add( "groupofuniquenames" );
115                 
116                 while ( values.hasMoreElements() )
117                 {
118                     String value = ( (String)values.nextElement() ).toLowerCase();
119                     assertTrue( expectedValues.contains( value ) );
120                     expectedValues.remove( value );
121                 }
122                 
123                 assertEquals( 0, expectedValues.size() );
124                 continue;
125             }
126           
127             if ( attr.getID().equalsIgnoreCase( "uniqueMember" ) )
128             {
129                 assertEquals( "cn=kevin spacey, dc=example, dc=org", attr.get() );
130             }
131         }
132     }
133 
134 
135     /**
136      * Test a valid entry, with an optional UID
137      *
138      * @throws Exception on error
139      */
140     @Test
141     public void testValidUniqueMemberWithOptionnalUID() throws Exception
142     {
143         LdapContext sysRoot = getSystemContext( service );
144 
145         Attributes attrs = new BasicAttributes( true );
146         Attribute oc = new BasicAttribute( "ObjectClass", "top" );
147         oc.add( "groupOfUniqueNames" );
148         Attribute cn = new BasicAttribute( "cn", "kevin Spacey 2" );
149         Attribute dc = new BasicAttribute( "uniqueMember", "cn=kevin spacey 2, dc=example, dc=org#'010101'B" );
150         attrs.put( oc );
151         attrs.put( cn );
152         attrs.put( dc);
153 
154         String base = "cn=kevin Spacey 2";
155 
156         //create subcontext
157         try
158         {
159             sysRoot.createSubcontext( base, attrs );
160         }
161         catch ( NamingException ne )
162         {
163             fail();
164         }
165         
166         Attributes returned = sysRoot.getAttributes( "cn=kevin Spacey 2" );
167       
168         NamingEnumeration<? extends Attribute> attrList = returned.getAll();
169         
170         while ( attrList.hasMore() )
171         {
172             Attribute attr = attrList.next();
173           
174             if ( attr.getID().equalsIgnoreCase( "cn" ) )
175             {
176                 assertEquals( "kevin Spacey 2", attr.get() );
177                 continue;
178             }
179           
180             if ( attr.getID().equalsIgnoreCase( "objectClass" ) )
181             {
182                 NamingEnumeration<?> values = attr.getAll();
183                 Set<String> expectedValues = new HashSet<String>();
184                 
185                 expectedValues.add( "top" );
186                 expectedValues.add( "groupofuniquenames" );
187                 
188                 while ( values.hasMoreElements() )
189                 {
190                     String value = ( (String)values.nextElement() ).toLowerCase();
191                     assertTrue( expectedValues.contains( value ) );
192                     expectedValues.remove( value );
193                 }
194                 
195                 assertEquals( 0, expectedValues.size() );
196                 continue;
197             }
198           
199             if ( attr.getID().equalsIgnoreCase( "uniqueMember" ) )
200             {
201                 assertEquals( "cn=kevin spacey 2, dc=example, dc=org#'010101'B", attr.get() );
202             }
203         }
204     }
205 
206 
207     /**
208      * Test a valid entry, with an optional UID
209      *
210      * @throws Exception on error
211      */
212     @Test
213     public void testInvalidUniqueMemberBadDN() throws Exception
214     {
215         LdapContext sysRoot = getSystemContext( service );
216 
217         Attributes attrs = new BasicAttributes( true );
218         Attribute oc = new BasicAttribute( "ObjectClass", "top" );
219         oc.add( "groupOfUniqueNames" );
220         Attribute cn = new BasicAttribute( "cn", "kevin Spacey bad" );
221         Attribute dc = new BasicAttribute( "uniqueMember", "kevin spacey bad, dc=example, dc=org#'010101'B" );
222         attrs.put( oc );
223         attrs.put( cn );
224         attrs.put( dc);
225 
226         String base = "cn=kevin Spacey bad";
227 
228         //create subcontext
229         try
230         {
231             sysRoot.createSubcontext( base, attrs );
232             fail();
233         }
234         catch ( NamingException ne )
235         {
236             assertTrue( true );
237         }
238     }
239 
240 
241     /**
242      * Test a valid entry, with an optional UID
243      *
244      * @throws Exception on error
245      */
246     @Test
247     public void testInvalidUniqueMemberBadUID() throws Exception
248     {
249         LdapContext sysRoot = getSystemContext( service );
250 
251         Attributes attrs = new BasicAttributes( true );
252         Attribute oc = new BasicAttribute( "ObjectClass", "top" );
253         oc.add( "groupOfUniqueNames" );
254         Attribute cn = new BasicAttribute( "cn", "kevin Spacey bad 2" );
255         Attribute dc = new BasicAttribute( "uniqueMember", "cn=kevin spacey bad 2, dc=example, dc=org#'010101'" );
256         attrs.put( oc );
257         attrs.put( cn );
258         attrs.put( dc);
259 
260         String base = "cn=kevin Spacey bad 2";
261 
262         //create subcontext
263         try
264         {
265             sysRoot.createSubcontext( base, attrs );
266             fail();
267         }
268         catch ( NamingException ne )
269         {
270             assertTrue( true );
271         }
272     }
273     
274 
275     @Test
276     public void testSearchUniqueMemberFilter() throws Exception
277     {
278         LdapContext sysRoot = getSystemContext( service );
279 
280         Attributes attrs = new BasicAttributes( true );
281         Attribute oc = new BasicAttribute( "ObjectClass", "top" );
282         oc.add( "groupOfUniqueNames" );
283         Attribute cn = new BasicAttribute( "cn", "kevin Spacey" );
284         Attribute dc = new BasicAttribute( "uniqueMember", "cn=kevin spacey, dc=example, dc=org" );
285         attrs.put( oc );
286         attrs.put( cn );
287         attrs.put( dc);
288 
289         String base = "cn=kevin Spacey";
290 
291         //create subcontext
292         try
293         {
294             sysRoot.createSubcontext( base, attrs );
295         }
296         catch ( NamingException ne )
297         {
298             fail();
299         }
300 
301         SearchControls controls = new SearchControls();
302         controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
303         controls.setDerefLinkFlag( false );
304         controls.setReturningAttributes( new String[] { "*" } );
305         sysRoot.addToEnvironment( JndiPropertyConstants.JNDI_LDAP_DAP_DEREF_ALIASES,
306                 AliasDerefMode.NEVER_DEREF_ALIASES.getJndiValue() );
307         HashMap<String, Attributes> map = new HashMap<String, Attributes>();
308 
309         NamingEnumeration<SearchResult> list = sysRoot.search( "", "(uniqueMember=cn = kevin spacey, dc=example, dc=org)", controls );
310         
311         while ( list.hasMore() )
312         {
313             SearchResult result = list.next();
314             map.put( result.getName().toLowerCase(), result.getAttributes() );
315         }
316 
317         assertEquals( "Expected number of results returned was incorrect!", 1, map.size() );
318         
319         attrs = map.get( "cn=kevin spacey,ou=system" );
320         
321         assertNotNull( attrs.get( "objectClass" ) );
322         assertNotNull( attrs.get( "cn" ) );
323         assertNotNull( attrs.get( "uniqueMember" ) );
324     }
325 
326 
327     @Test
328     public void testSearchUniqueMemberFilterWithSpaces() throws Exception
329     {
330         LdapContext sysRoot = getSystemContext( service );
331 
332         Attributes attrs = new BasicAttributes( true );
333         Attribute oc = new BasicAttribute( "ObjectClass", "top" );
334         oc.add( "groupOfUniqueNames" );
335         Attribute cn = new BasicAttribute( "cn", "kevin Spacey" );
336         Attribute dc = new BasicAttribute( "uniqueMember", "cn=kevin spacey,dc=example,dc=org" );
337         attrs.put( oc );
338         attrs.put( cn );
339         attrs.put( dc);
340 
341         String base = "cn=kevin Spacey";
342 
343         //create subcontext
344         try
345         {
346             sysRoot.createSubcontext( base, attrs );
347         }
348         catch ( NamingException ne )
349         {
350             fail();
351         }
352 
353         SearchControls controls = new SearchControls();
354         controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
355         controls.setDerefLinkFlag( false );
356         controls.setReturningAttributes( new String[] { "*" } );
357         sysRoot.addToEnvironment( JndiPropertyConstants.JNDI_LDAP_DAP_DEREF_ALIASES,
358                 AliasDerefMode.NEVER_DEREF_ALIASES.getJndiValue() );
359         HashMap<String, Attributes> map = new HashMap<String, Attributes>();
360 
361         NamingEnumeration<SearchResult> list = sysRoot.search( "", "(uniqueMember=cn = Kevin  Spacey , dc = example , dc = ORG)", controls );
362         
363         while ( list.hasMore() )
364         {
365             SearchResult result = list.next();
366             map.put( result.getName().toLowerCase(), result.getAttributes() );
367         }
368 
369         assertEquals( "Expected number of results returned was incorrect!", 1, map.size() );
370         
371         attrs = map.get( "cn=kevin spacey,ou=system" );
372         
373         assertNotNull( attrs.get( "objectClass" ) );
374         assertNotNull( attrs.get( "cn" ) );
375         assertNotNull( attrs.get( "uniqueMember" ) );
376     }
377 
378 
379     @Test
380     public void testSearchUniqueMemberFilterWithBadDN() throws Exception
381     {
382         LdapContext sysRoot = getSystemContext( service );
383 
384         Attributes attrs = new BasicAttributes( true );
385         Attribute oc = new BasicAttribute( "ObjectClass", "top" );
386         oc.add( "groupOfUniqueNames" );
387         Attribute cn = new BasicAttribute( "cn", "kevin Spacey" );
388         Attribute dc = new BasicAttribute( "uniqueMember", "cn=kevin spacey,dc=example,dc=org" );
389         attrs.put( oc );
390         attrs.put( cn );
391         attrs.put( dc);
392 
393         String base = "cn=kevin Spacey";
394 
395         //create subcontext
396         try
397         {
398             sysRoot.createSubcontext( base, attrs );
399         }
400         catch ( NamingException ne )
401         {
402             fail();
403         }
404 
405         SearchControls controls = new SearchControls();
406         controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
407         controls.setDerefLinkFlag( false );
408         controls.setReturningAttributes( new String[] { "*" } );
409         sysRoot.addToEnvironment( JndiPropertyConstants.JNDI_LDAP_DAP_DEREF_ALIASES,
410                 AliasDerefMode.NEVER_DEREF_ALIASES.getJndiValue() );
411 
412         NamingEnumeration<SearchResult> list = sysRoot.search( "", "(uniqueMember=cn=cevin spacey,dc=example,dc=org)", controls );
413         
414         assertFalse( list.hasMore() );
415     }
416 
417 
418     @Test
419     public void testSearchUniqueMemberFilterWithUID() throws Exception
420     {
421         LdapContext sysRoot = getSystemContext( service );
422 
423         Attributes attrs = new BasicAttributes( true );
424         Attribute oc = new BasicAttribute( "ObjectClass", "top" );
425         oc.add( "groupOfUniqueNames" );
426         Attribute cn = new BasicAttribute( "cn", "kevin Spacey" );
427         Attribute dc = new BasicAttribute( "uniqueMember", "cn=kevin spacey,dc=example,dc=org#'010101'B" );
428         attrs.put( oc );
429         attrs.put( cn );
430         attrs.put( dc);
431 
432         String base = "cn=kevin Spacey";
433 
434         //create subcontext
435         try
436         {
437             sysRoot.createSubcontext( base, attrs );
438         }
439         catch ( NamingException ne )
440         {
441             fail();
442         }
443 
444         SearchControls controls = new SearchControls();
445         controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
446         controls.setDerefLinkFlag( false );
447         controls.setReturningAttributes( new String[] { "*" } );
448         sysRoot.addToEnvironment( JndiPropertyConstants.JNDI_LDAP_DAP_DEREF_ALIASES,
449                 AliasDerefMode.NEVER_DEREF_ALIASES.getJndiValue() );
450         HashMap<String, Attributes> map = new HashMap<String, Attributes>();
451 
452         NamingEnumeration<SearchResult> list = sysRoot.search( "", "(uniqueMember=cn= Kevin Spacey, dc=example, dc=org #'010101'B)", controls );
453         
454         while ( list.hasMore() )
455         {
456             SearchResult result = list.next();
457             map.put( result.getName().toLowerCase(), result.getAttributes() );
458         }
459 
460         assertEquals( "Expected number of results returned was incorrect!", 1, map.size() );
461         
462         attrs = map.get( "cn=kevin spacey,ou=system" );
463         
464         assertNotNull( attrs.get( "objectClass" ) );
465         assertNotNull( attrs.get( "cn" ) );
466         assertNotNull( attrs.get( "uniqueMember" ) );
467     }
468 }