View Javadoc
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  package org.apache.directory.server.core.integ;
20  
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.util.ArrayList;
25  import java.util.List;
26  
27  import javax.naming.NamingException;
28  import javax.naming.ldap.LdapContext;
29  import javax.naming.ldap.LdapName;
30  
31  import org.apache.directory.api.ldap.model.constants.AuthenticationLevel;
32  import org.apache.directory.api.ldap.model.constants.SchemaConstants;
33  import org.apache.directory.api.ldap.model.entry.Attribute;
34  import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
35  import org.apache.directory.api.ldap.model.entry.DefaultEntry;
36  import org.apache.directory.api.ldap.model.entry.DefaultModification;
37  import org.apache.directory.api.ldap.model.entry.Modification;
38  import org.apache.directory.api.ldap.model.entry.ModificationOperation;
39  import org.apache.directory.api.ldap.model.exception.LdapException;
40  import org.apache.directory.api.ldap.model.ldif.ChangeType;
41  import org.apache.directory.api.ldap.model.ldif.LdifEntry;
42  import org.apache.directory.api.ldap.model.ldif.LdifReader;
43  import org.apache.directory.api.ldap.model.name.Dn;
44  import org.apache.directory.api.ldap.model.name.Rdn;
45  import org.apache.directory.api.ldap.model.schema.registries.Schema;
46  import org.apache.directory.api.util.FileUtils;
47  import org.apache.directory.api.util.Network;
48  import org.apache.directory.api.util.Strings;
49  import org.apache.directory.ldap.client.api.LdapConnection;
50  import org.apache.directory.ldap.client.api.LdapNetworkConnection;
51  import org.apache.directory.server.constants.ServerDNConstants;
52  import org.apache.directory.server.core.api.CoreSession;
53  import org.apache.directory.server.core.api.DirectoryService;
54  import org.apache.directory.server.core.api.LdapCoreSessionConnection;
55  import org.apache.directory.server.core.api.LdapPrincipal;
56  import org.apache.directory.server.core.jndi.ServerLdapContext;
57  import org.apache.directory.server.i18n.I18n;
58  import org.apache.directory.server.ldap.LdapServer;
59  import org.slf4j.Logger;
60  import org.slf4j.LoggerFactory;
61  
62  
63  /**
64   * Integration test utility methods.
65   *
66   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
67   */
68  public class IntegrationUtils
69  {
70      /** The class logger */
71      private static final Logger LOG = LoggerFactory.getLogger( IntegrationUtils.class );
72  
73      private static final List<LdapConnection> OPEN_CONNECTIONS = new ArrayList<>();
74  
75  
76      /**
77       * Deletes the working directory.
78       *
79       * @param wkdir the working directory to delete
80       * @throws IOException if the working directory cannot be deleted
81       */
82      public static void doDelete( File wkdir ) throws IOException
83      {
84          if ( wkdir.exists() )
85          {
86              try
87              {
88                  FileUtils.deleteDirectory( wkdir );
89              }
90              catch ( IOException e )
91              {
92                  LOG.error( I18n.err( I18n.ERR_115 ), e );
93              }
94          }
95          if ( wkdir.exists() )
96          {
97              throw new IOException( I18n.err( I18n.ERR_116, wkdir ) );
98          }
99      }
100 
101 
102     /**
103      * Inject an ldif String into the server. Dn must be relative to the
104      * root.
105      *
106      * @param service the directory service to use
107      * @param ldif the ldif containing entries to add to the server.
108      * @throws NamingException if there is a problem adding the entries from the LDIF
109      */
110     public static void injectEntries( DirectoryService service, String ldif ) throws Exception
111     {
112         try ( LdifReader reader = new LdifReader() )
113         {
114             List<LdifEntry> entries = reader.parseLdif( ldif );
115     
116             for ( LdifEntry entry : entries )
117             {
118                 if ( entry.isEntry() )
119                 {
120                     service.getAdminSession().add(
121                         new DefaultEntry( service.getSchemaManager(), entry.getEntry() ) );
122                 }
123                 else if ( entry.isChangeModify() )
124                 {
125                     service.getAdminSession().modify(
126                         entry.getDn(), entry.getModifications() );
127                 }
128                 else
129                 {
130                     String message = I18n.err( I18n.ERR_117, entry.getChangeType() );
131                     LOG.error( message );
132                     throw new NamingException( message );
133                 }
134             }
135         }
136     }
137 
138 
139     public static LdifEntry getUserAddLdif() throws LdapException
140     {
141         return getUserAddLdif( "uid=akarasulu,ou=users,ou=system", Strings.getBytesUtf8( "test" ),
142             "Alex Karasulu", "Karasulu" );
143     }
144 
145 
146     public static LdapContext getContext( String principalDn, DirectoryService service, String dn )
147         throws Exception
148     {
149         if ( principalDn == null )
150         {
151             principalDn = "";
152         }
153 
154         Dn userDn = new Dn( service.getSchemaManager(), principalDn );
155         LdapPrincipal/api/LdapPrincipal.html#LdapPrincipal">LdapPrincipal principal = new LdapPrincipal( service.getSchemaManager(), userDn, AuthenticationLevel.SIMPLE );
156 
157         if ( dn == null )
158         {
159             dn = "";
160         }
161 
162         CoreSession session = service.getSession( principal );
163 
164         return new ServerLdapContext( service, session, new LdapName( dn ) );
165     }
166 
167 
168     public static CoreSession getCoreSession( String principalDn, DirectoryService service, String dn )
169         throws LdapException
170     {
171         if ( principalDn == null )
172         {
173             principalDn = "";
174         }
175 
176         Dn userDn = new Dn( service.getSchemaManager(), principalDn );
177         LdapPrincipal/api/LdapPrincipal.html#LdapPrincipal">LdapPrincipal principal = new LdapPrincipal( service.getSchemaManager(), userDn, AuthenticationLevel.SIMPLE );
178 
179         return service.getSession( principal );
180     }
181 
182 
183     public static LdapContext getSystemContext( DirectoryService service ) throws Exception
184     {
185         return getContext( ServerDNConstants.ADMIN_SYSTEM_DN, service, ServerDNConstants.SYSTEM_DN );
186     }
187 
188 
189     public static LdapContext getSchemaContext( DirectoryService service ) throws Exception
190     {
191         return getContext( ServerDNConstants.ADMIN_SYSTEM_DN, service, SchemaConstants.OU_SCHEMA );
192     }
193 
194 
195     public static LdapContext getRootContext( DirectoryService service ) throws Exception
196     {
197         return getContext( ServerDNConstants.ADMIN_SYSTEM_DN, service, "" );
198     }
199 
200 
201     public static void apply( DirectoryService service, LdifEntry entry ) throws LdapException
202     {
203         Dn dn = entry.getDn();
204         CoreSession session = service.getAdminSession();
205 
206         switch ( entry.getChangeType().getChangeType() )
207         {
208             case ( ChangeType.ADD_ORDINAL ):
209                 session.add(
210                     new DefaultEntry( service.getSchemaManager(), entry.getEntry() ) );
211                 break;
212 
213             case ( ChangeType.DELETE_ORDINAL ):
214                 session.delete( dn );
215                 break;
216 
217             case ( ChangeType.MODDN_ORDINAL ):
218             case ( ChangeType.MODRDN_ORDINAL ):
219                 Rdn newRdn = new Rdn( entry.getNewRdn() );
220 
221                 if ( entry.getNewSuperior() != null )
222                 {
223                     // It's a move. The superior have changed
224                     // Let's see if it's a rename too
225                     Rdn oldRdn = dn.getRdn();
226                     Dn newSuperior = new Dn( entry.getNewSuperior() );
227 
228                     if ( dn.size() == 0 )
229                     {
230                         throw new IllegalStateException( I18n.err( I18n.ERR_475 ) );
231                     }
232                     else if ( oldRdn.equals( newRdn ) )
233                     {
234                         // Same rdn : it's a move
235                         session.move( dn, newSuperior );
236                     }
237                     else
238                     {
239                         // it's a move and rename
240                         session.moveAndRename( dn, newSuperior, newRdn, entry.isDeleteOldRdn() );
241                     }
242                 }
243                 else
244                 {
245                     // it's a rename
246                     session.rename( dn, newRdn, entry.isDeleteOldRdn() );
247                 }
248 
249                 break;
250 
251             case ( ChangeType.MODIFY_ORDINAL ):
252                 session.modify( dn, entry.getModifications() );
253                 break;
254 
255             default:
256                 throw new IllegalStateException( I18n.err( I18n.ERR_476, entry.getChangeType() ) );
257         }
258     }
259 
260 
261     public static LdifEntry getUserAddLdif( String dnstr, byte[] password, String cn, String sn )
262         throws LdapException
263     {
264         Dn dn = new Dn( dnstr );
265         LdifEntry ldif = new LdifEntry();
266         ldif.setDn( dnstr );
267         ldif.setChangeType( ChangeType.Add );
268 
269         Attribute attr = new DefaultAttribute( "objectClass",
270             "top", "person", "organizationalPerson", "inetOrgPerson" );
271         ldif.addAttribute( attr );
272 
273         attr = new DefaultAttribute( "ou", "Engineering", "People" );
274         ldif.addAttribute( attr );
275 
276         String uid = dn.getRdn().getValue();
277         ldif.putAttribute( "uid", uid );
278 
279         ldif.putAttribute( "l", "Bogusville" );
280         ldif.putAttribute( "cn", cn );
281         ldif.putAttribute( "sn", sn );
282         ldif.putAttribute( "mail", uid + "@apache.org" );
283         ldif.putAttribute( "telephoneNumber", "+1 408 555 4798" );
284         ldif.putAttribute( "facsimileTelephoneNumber", "+1 408 555 9751" );
285         ldif.putAttribute( "roomnumber", "4612" );
286         ldif.putAttribute( "userPassword", password );
287 
288         String givenName = cn.split( " " )[0];
289         ldif.putAttribute( "givenName", givenName );
290 
291         return ldif;
292     }
293 
294 
295     // -----------------------------------------------------------------------
296     // Enable/Disable Schema Tests
297     // -----------------------------------------------------------------------
298 
299     public static void enableSchema( DirectoryService service, String schemaName ) throws LdapException
300     {
301         LdapConnection connection = getAdminConnection( service );
302 
303         // now enable the test schema
304         connection.modify( "cn=" + schemaName + ",ou=schema",
305             new DefaultModification(
306                 ModificationOperation.REPLACE_ATTRIBUTE, "m-disabled", "FALSE" ) );
307     }
308 
309 
310     public static void disableSchema( DirectoryService service, String schemaName ) throws LdapException
311     {
312         LdapConnection connection = getAdminConnection( service );
313 
314         // now enable the test schema
315         Modification mod = new DefaultModification(
316             ModificationOperation.REPLACE_ATTRIBUTE, "m-disabled", "TRUE" );
317 
318         connection.modify( "cn=" + schemaName + ",ou=schema", mod );
319     }
320 
321 
322     /**
323      * A helper method which tells if a schema is disabled.
324      * 
325      * @param service The Directory Service 
326      * @param schemaName The name of the Schema to check
327      * @return <tt>true</tt> if the schema is enabled
328      */
329     public static boolean isDisabled( DirectoryService service, String schemaName )
330     {
331         Schema schema = service.getSchemaManager().getLoadedSchema( schemaName );
332 
333         return ( schema == null ) || schema.isDisabled();
334     }
335 
336 
337     /**
338      * A helper method which tells if a schema is loaded.
339      * 
340      * @param service The Directory Service 
341      * @param schemaName The schema to check
342      * @return <tt>true</tt> if the schema is loaded
343      */
344     public static boolean isLoaded( DirectoryService service, String schemaName )
345     {
346         Schema schema = service.getSchemaManager().getLoadedSchema( schemaName );
347 
348         return ( schema != null );
349     }
350 
351 
352     /**
353      * A helper method which tells if a schema is enabled. A shema must be
354      * loaded and enabled.
355      * 
356      * @param service The Directory Service 
357      * @param schemaName The name of the Schema to check
358      * @return <tt>true</tt> if the schema is enabled
359      */
360     public static boolean isEnabled( DirectoryService service, String schemaName )
361     {
362         Schema schema = service.getSchemaManager().getLoadedSchema( schemaName );
363 
364         return ( schema != null ) && schema.isEnabled();
365     }
366 
367 
368     /**
369      * Gets a LdapCoreSessionConnection bound using the default admin Dn uid=admin,ou=system and password "secret"
370      * 
371      * @param dirService The Directory Service to be connected to
372      * @return A LdapCoreSessionConnection instance
373      * @exception LdapException If the connection could not be established.
374      */
375     public static LdapConnection getAdminConnection( DirectoryService dirService ) throws LdapException
376     {
377         return getConnectionAs( dirService, ServerDNConstants.ADMIN_SYSTEM_DN, "secret" );
378     }
379 
380 
381     /**
382      * Gets a LdapCoreSessionConnection bound using a user's DN and a password. We will bind using those
383      * credentials.
384      * 
385      * @param dirService The Directory Service to be connected to
386      * @param dn The User's DN as a String
387      * @param password The User's password as a String
388      * @return A LdapCoreSessionConnection instance
389      * @exception LdapException If the connection could not be established.
390      */
391     public static LdapConnection getConnectionAs( DirectoryService dirService, String dn, String password )
392         throws LdapException
393     {
394         return getConnectionAs( dirService, new Dn( dn ), password );
395     }
396 
397 
398     /**
399      * Gets a LdapCoreSessionConnection bound using a user's DN and a password. We will bind using those
400      * credentials.
401      * 
402      * @param dirService The Directory Service to be connected to
403      * @param dn The User's DN
404      * @param password The User's password as a String
405      * @return A LdapCoreSessionConnection instance
406      * @exception LdapException If the connection could not be established.
407      */
408     public static LdapConnection getConnectionAs( DirectoryService dirService, Dn dn, String password )
409         throws LdapException
410     {
411         LdapCoreSessionConnectionSessionConnection.html#LdapCoreSessionConnection">LdapCoreSessionConnection connection = new LdapCoreSessionConnection();
412 
413         connection.setDirectoryService( dirService );
414 
415         connection.bind( dn, password );
416 
417         return connection;
418     }
419 
420 
421     /**
422      * Gets a LdapNetworkConnection bound using a user's DN and a password. We will bind using those
423      * credentials.
424      * 
425      * @param host The server to connect to
426      * @param port The port to connect on
427      * @param dn The User's DN as a String
428      * @param password The User's password as a String
429      * @return A LdapNetworkConnection instance
430      * @exception LdapException If the connection could not be established.
431      */
432     public static LdapConnection getNetworkConnectionAs( String host, int port, String dn, String password )
433         throws LdapException
434     {
435         LdapConnection connection = new LdapNetworkConnection( host, port );
436 
437         connection.bind( dn, password );
438         OPEN_CONNECTIONS.add( connection );
439         
440         return connection;
441     }
442 
443 
444     /**
445      * Gets an anonymous LdapNetworkConnection
446      * 
447      * @param ldapServer The LdapServer to be connected to
448      * @return A LdapNetworkConnection instance
449      * @exception LdapException If the connection could not be established.
450      */
451     public static LdapConnection getAnonymousNetworkConnection( LdapServer ldapServer ) throws LdapException
452     {
453         return getAnonymousNetworkConnection( Network.LOOPBACK_HOSTNAME, ldapServer.getPort() );
454     }
455 
456 
457     /**
458      * Gets an anonymous LdapNetworkConnection
459      * 
460      * @param host The server to connect to
461      * @param port The port to connect on
462      * @return A LdapNetworkConnection instance
463      * @exception LdapException If the connection could not be established.
464      */
465     public static LdapConnection getAnonymousNetworkConnection( String host, int port ) throws LdapException
466     {
467         LdapConnection connection = new LdapNetworkConnection( host, port );
468         connection.bind();
469 
470         OPEN_CONNECTIONS.add( connection );
471 
472         return connection;
473     }
474 
475 
476     /**
477      * Gets a LdapNetworkConnection bound to the Admin user (uid=admin,ou=system).
478      * 
479      * @param ldapServer The LdapServer to be connected to
480      * @return A LdapNetworkConnection instance
481      * @exception LdapException If the connection could not be established.
482      */
483     public static LdapConnection getAdminNetworkConnection( LdapServer ldapServer ) throws LdapException
484     {
485         LdapConnection connection = new LdapNetworkConnection( Network.LOOPBACK_HOSTNAME, ldapServer.getPort() );
486 
487         connection.setTimeOut( 30000L );
488         connection.bind( ServerDNConstants.ADMIN_SYSTEM_DN, "secret" );
489 
490         OPEN_CONNECTIONS.add( connection );
491 
492         return connection;
493     }
494 
495 
496     /**
497      * Gets a LdapNetworkConnection bound using a user's DN and a password. We will bind using those
498      * credentials. We specify a LdapServer instance too.
499      * 
500      * @param ldapServer The LdapServer to be connected to
501      * @param userDn The User's DN as a String
502      * @param password The User's password as a String
503      * @return A LdapNetworkConnection instance
504      * @exception LdapException If the connection could not be established.
505      */
506     public static LdapConnection getNetworkConnectionAs( LdapServer ldapServer, String userDn, String password )
507         throws LdapException
508     {
509         return getNetworkConnectionAs( Network.LOOPBACK_HOSTNAME, ldapServer.getPort(), userDn, password );
510     }
511 
512 
513     public static void closeConnections()
514     {
515 
516         for ( LdapConnection con : OPEN_CONNECTIONS )
517         {
518             if ( con == null )
519             {
520                 continue;
521             }
522 
523             try
524             {
525                 if ( con.isConnected() )
526                 {
527                     con.close();
528                 }
529             }
530             catch ( Exception e )
531             {
532                 // shouldn't happen, but print the stacktrace so that less pain during development to find the cause
533                 e.printStackTrace();
534             }
535         }
536 
537         OPEN_CONNECTIONS.clear();
538     }
539 }