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.operations.search;
21  
22   
23  import java.io.StringReader;
24  import java.util.HashMap;
25  import java.util.Map;
26  
27  import javax.naming.Context;
28  import javax.naming.NamingEnumeration;
29  import javax.naming.ReferralException;
30  import javax.naming.directory.DirContext;
31  import javax.naming.directory.SearchControls;
32  import javax.naming.directory.SearchResult;
33  
34  import org.apache.directory.server.core.entry.DefaultServerEntry;
35  import org.apache.directory.server.core.integ.annotations.ApplyLdifs;
36  import org.apache.directory.server.integ.SiRunner;
37  
38  import static org.apache.directory.server.integ.ServerIntegrationUtils.getWiredContextThrowOnRefferal;
39  import static org.apache.directory.server.integ.ServerIntegrationUtils.getWiredContext;
40  
41  import org.apache.directory.server.ldap.LdapService;
42  import org.apache.directory.shared.ldap.ldif.LdifEntry;
43  import org.apache.directory.shared.ldap.ldif.LdifReader;
44  import org.junit.Before;
45  import org.junit.Test;
46  import org.junit.runner.RunWith;
47  
48  import static org.junit.Assert.fail;
49  import static org.junit.Assert.assertNull;
50  import static org.junit.Assert.assertTrue;
51  import static org.junit.Assert.assertFalse;
52  import static org.junit.Assert.assertEquals;
53  import static org.junit.Assert.assertNotNull;
54  
55  
56  /**
57   * Tests to make sure the server is operating correctly when handling referrals.
58   *
59   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
60   * @version $Rev: 545029 $
61   */
62  @RunWith ( SiRunner.class )
63  @ApplyLdifs( {
64      // Add new ref for ou=RemoteUsers
65      "dn: ou=RemoteUsers,ou=system\n" +
66      "objectClass: top\n" +
67      "objectClass: referral\n" +
68      "objectClass: extensibleObject\n" +
69      "ou: RemoteUsers\n" +
70      "ref: ldap://fermi:10389/ou=users,ou=system\n" +
71      "ref: ldap://hertz:10389/ou=users,dc=example,dc=com\n" +
72      "ref: ldap://maxwell:10389/ou=users,ou=system\n\n" +
73      
74      "dn: c=France,ou=system\n" +
75      "objectClass: top\n" +
76      "objectClass: country\n" +
77      "c: France\n\n" +
78      
79      "dn: c=USA,ou=system\n" +
80      "objectClass: top\n" +
81      "objectClass: country\n" +
82      "c: USA\n\n" +
83      
84      "dn: l=Paris,c=france,ou=system\n" +
85      "objectClass: top\n" +
86      "objectClass: locality\n" +
87      "l: Paris\n\n" +
88      
89      "dn: l=Jacksonville,c=usa,ou=system\n" +
90      "objectClass: top\n" +
91      "objectClass: locality\n" +
92      "l: Jacksonville\n\n" +
93      
94      "dn: cn=emmanuel lecharny,l=paris,c=france,ou=system\n" +
95      "objectClass: top\n" +
96      "objectClass: person\n" +
97      "objectClass: residentialPerson\n" +
98      "cn: emmanuel lecharny\n" +
99      "sn: elecharny\n" +
100     "l: Paris\n\n" +
101     
102     "dn: cn=alex karasulu,l=jacksonville,c=usa,ou=system\n" +
103     "objectClass: top\n" +
104     "objectClass: person\n" +
105     "objectClass: residentialPerson\n" +
106     "cn: alex karasulu\n" +
107     "sn: karasulu\n" +
108     "l: Jacksonville\n\n" +
109     
110     "dn: ou=Countries,ou=system\n" +
111     "objectClass: top\n" +
112     "objectClass: organizationalUnit\n" +
113     "ou: Countries\n\n"
114     }
115 )
116 public class ReferralSearchIT
117 {
118     public static LdapService ldapService;
119 
120     
121     @Before
122     public void setupReferrals() throws Exception
123     {
124         String ldif =
125         "dn: c=europ,ou=Countries,ou=system\n" +
126         "objectClass: top\n" +
127         "objectClass: referral\n" +
128         "objectClass: extensibleObject\n" +
129         "c: europ\n" +
130         "ref: ldap://localhost:" + ldapService.getIpPort() + "/c=france,ou=system\n\n" +
131 
132         "dn: c=america,ou=Countries,ou=system\n" +
133         "objectClass: top\n" +
134         "objectClass: referral\n" +
135         "objectClass: extensibleObject\n" +
136         "c: america\n" +
137         "ref: ldap://localhost:" + ldapService.getIpPort() + "/c=usa,ou=system\n\n";
138 
139         LdifReader reader = new LdifReader( new StringReader( ldif ) );
140         while ( reader.hasNext() )
141         {
142             LdifEntry entry = reader.next();
143             ldapService.getDirectoryService().getAdminSession().add( 
144                 new DefaultServerEntry( ldapService.getDirectoryService().getRegistries(), entry.getEntry() ) ); 
145         }
146     }
147     
148     
149     @Test
150     public void testSearchBaseIsReferral() throws Exception
151     {
152         DirContext ctx = getWiredContextThrowOnRefferal( ldapService );
153         SearchControls controls = new SearchControls();
154         controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
155         
156         try
157         {
158             ctx.search( "ou=RemoteUsers,ou=system", "(objectClass=*)", controls );
159             fail( "should never get here" );
160         }
161         catch ( ReferralException e )
162         {
163             assertEquals( "ldap://fermi:10389/ou=users,ou=system??sub", e.getReferralInfo() );
164             assertTrue( e.skipReferral() );
165             assertEquals( "ldap://hertz:10389/ou=users,dc=example,dc=com??sub", e.getReferralInfo() );
166             assertTrue( e.skipReferral() );
167             assertEquals( "ldap://maxwell:10389/ou=users,ou=system??sub", e.getReferralInfo() );
168             assertFalse( e.skipReferral() );
169         }
170     }
171 
172 
173     @Test
174     public void testSearchBaseParentIsReferral() throws Exception
175     {
176         DirContext ctx = getWiredContextThrowOnRefferal( ldapService );
177         SearchControls controls = new SearchControls();
178         controls.setSearchScope( SearchControls.OBJECT_SCOPE );
179 
180         try
181         {
182             ctx.search( "cn=alex karasulu,ou=RemoteUsers,ou=system", "(objectClass=*)", controls );
183         }
184         catch ( ReferralException e )
185         {
186             assertEquals( "ldap://fermi:10389/cn=alex%20karasulu,ou=users,ou=system??base", e.getReferralInfo() );
187             assertTrue( e.skipReferral() );
188             assertEquals( "ldap://hertz:10389/cn=alex%20karasulu,ou=users,dc=example,dc=com??base", e.getReferralInfo() );
189             assertTrue( e.skipReferral() );
190             assertEquals( "ldap://maxwell:10389/cn=alex%20karasulu,ou=users,ou=system??base", e.getReferralInfo() );
191             assertFalse( e.skipReferral() );
192         }
193     }
194 
195 
196     @Test
197     public void testSearchBaseAncestorIsReferral() throws Exception
198     {
199         DirContext ctx = getWiredContextThrowOnRefferal( ldapService );
200         SearchControls controls = new SearchControls();
201         controls.setSearchScope( SearchControls.OBJECT_SCOPE );
202 
203         try
204         {
205             ctx.search( "cn=alex karasulu,ou=apache,ou=RemoteUsers,ou=system", "(objectClass=*)", controls );
206         }
207         catch ( ReferralException e )
208         {
209             assertEquals( "ldap://fermi:10389/cn=alex%20karasulu,ou=apache,ou=users,ou=system??base", e.getReferralInfo() );
210             assertTrue( e.skipReferral() );
211             assertEquals( "ldap://hertz:10389/cn=alex%20karasulu,ou=apache,ou=users,dc=example,dc=com??base", e
212                 .getReferralInfo() );
213             assertTrue( e.skipReferral() );
214             assertEquals( "ldap://maxwell:10389/cn=alex%20karasulu,ou=apache,ou=users,ou=system??base", e
215                 .getReferralInfo() );
216             assertFalse( e.skipReferral() );
217         }
218     }
219 
220 
221     @Test
222     public void testSearchContinuations() throws Exception
223     {
224         DirContext ctx = getWiredContext( ldapService );
225 
226         SearchControls controls = new SearchControls();
227         controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
228         NamingEnumeration<SearchResult> list = ctx.search( "ou=system", "(objectClass=*)", controls );
229         Map<String,SearchResult> results = new HashMap<String,SearchResult>();
230         while ( list.hasMore() )
231         {
232             SearchResult result = list.next();
233             results.put( result.getName(), result );
234         }
235 
236         assertNotNull( results.get( "ou=users" ) );
237 
238         // -------------------------------------------------------------------
239         // Now we will throw exceptions when searching for referrals 
240         // -------------------------------------------------------------------
241 
242         ctx.addToEnvironment( Context.REFERRAL, "throw" );
243         list = ctx.search( "ou=system", "(objectClass=*)", controls );
244         results = new HashMap<String,SearchResult>();
245 
246         try
247         {
248             while ( list.hasMore() )
249             {
250                 SearchResult result = list.next();
251                 results.put( result.getName(), result );
252             }
253         }
254         catch ( ReferralException e )
255         {
256             assertEquals( "ldap://fermi:10389/ou=users,ou=system??sub", e.getReferralInfo() );
257             assertTrue( e.skipReferral() );
258             assertEquals( "ldap://hertz:10389/ou=users,dc=example,dc=com??sub", e.getReferralInfo() );
259             assertTrue( e.skipReferral() );
260             assertEquals( "ldap://maxwell:10389/ou=users,ou=system??sub", e.getReferralInfo() );
261         }
262 
263         assertNull( results.get( "ou=remoteusers" ) );
264 
265         // try again but this time with single level scope
266 
267         controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
268         list = ctx.search( "ou=system", "(objectClass=*)", controls );
269         results = new HashMap<String,SearchResult>();
270 
271         try
272         {
273             while ( list.hasMore() )
274             {
275                 SearchResult result = list.next();
276                 results.put( result.getName(), result );
277             }
278         }
279         catch ( ReferralException e )
280         {
281             assertEquals( "ldap://fermi:10389/ou=users,ou=system??base", e.getReferralInfo() );
282             assertTrue( e.skipReferral() );
283             assertEquals( "ldap://hertz:10389/ou=users,dc=example,dc=com??base", e.getReferralInfo() );
284             assertTrue( e.skipReferral() );
285             assertEquals( "ldap://maxwell:10389/ou=users,ou=system??base", e.getReferralInfo() );
286         }
287 
288         assertNull( results.get( "ou=remoteusers" ) );
289     }
290 
291 
292     /**
293      * Test of an search operation with a referral
294      *
295      * search for "cn=alex karasulu" on "c=america, ou=system"
296      * we should get a referral URL thrown, which point to
297      * "c=usa, ou=system", and ask for a subtree search
298      */
299     @Test
300     public void testSearchWithReferralThrow() throws Exception
301     {
302         DirContext ctx = getWiredContextThrowOnRefferal( ldapService );
303 
304         try
305         {
306             SearchControls controls = new SearchControls();
307             controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
308             ctx.search( "c=america,ou=Countries,ou=system", "(cn=alex karasulu)", controls );
309             fail( "Should fail here throwing a ReferralException" );
310         }
311         catch ( ReferralException re )
312         {
313             String referral = (String)re.getReferralInfo();
314             assertEquals( "ldap://localhost:" + ldapService.getIpPort() + "/c=usa,ou=system??sub", referral );
315         }
316     }
317 
318 
319     /**
320      * Test of an search operation with a referral
321      *
322      * search for "cn=alex karasulu" on "c=america, ou=system"
323      * we should get a referral URL thrown, which point to
324      * "c=usa, ou=system", and ask for a subtree search
325      */
326     @Test
327     public void testSearchBaseWithReferralThrow() throws Exception
328     {
329         DirContext ctx = getWiredContextThrowOnRefferal( ldapService );
330 
331         SearchControls controls = new SearchControls();
332         controls.setSearchScope( SearchControls.OBJECT_SCOPE );
333 
334         try
335         {
336             ctx.search( "c=america,ou=Countries,ou=system", "(cn=alex karasulu)", controls );
337             fail( "Should fail here throwing a ReferralException" );
338         }
339         catch ( ReferralException re )
340         {
341             String referral = (String)re.getReferralInfo();
342             assertEquals( "ldap://localhost:" + ldapService.getIpPort() + "/c=usa,ou=system??base", referral );
343         }
344     }
345 
346     
347     /**
348      * Test of an search operation with a referral
349      *
350      * search for "cn=alex karasulu" on "c=america, ou=system"
351      * we should get a referral URL thrown, which point to
352      * "c=usa, ou=system", and ask for a subtree search
353      */
354     @Test
355     public void testSearchOneLevelWithReferralThrow() throws Exception
356     {
357         DirContext ctx = getWiredContextThrowOnRefferal( ldapService );
358 
359         SearchControls controls = new SearchControls();
360         controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
361 
362         try
363         {
364             ctx.search( "c=america,ou=Countries,ou=system", "(cn=alex karasulu)", controls );
365             fail( "Should fail here throwing a ReferralException" );
366         }
367         catch ( ReferralException re )
368         {
369             String referral = (String)re.getReferralInfo();
370             assertEquals( "ldap://localhost:" + ldapService.getIpPort() + "/c=usa,ou=system??one", referral );
371         }
372     }
373 }