001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *  http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing,
013     * software distributed under the License is distributed on an
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     * KIND, either express or implied.  See the License for the
016     * specific language governing permissions and limitations
017     * under the License.
018     */
019    package org.apache.directory.server.core.integ;
020    
021    
022    import java.io.File;
023    import java.io.IOException;
024    import java.util.ArrayList;
025    import java.util.List;
026    
027    import javax.naming.NamingException;
028    import javax.naming.directory.Attribute;
029    import javax.naming.directory.BasicAttribute;
030    import javax.naming.directory.DirContext;
031    import javax.naming.directory.ModificationItem;
032    import javax.naming.ldap.LdapContext;
033    import javax.naming.ldap.LdapName;
034    
035    import org.apache.commons.io.FileUtils;
036    import org.apache.directory.ldap.client.api.LdapConnection;
037    import org.apache.directory.server.constants.ServerDNConstants;
038    import org.apache.directory.server.core.CoreSession;
039    import org.apache.directory.server.core.DirectoryService;
040    import org.apache.directory.server.core.LdapPrincipal;
041    import org.apache.directory.server.core.jndi.ServerLdapContext;
042    import org.apache.directory.server.i18n.I18n;
043    import org.apache.directory.server.ldap.LdapServer;
044    import org.apache.directory.shared.ldap.constants.AuthenticationLevel;
045    import org.apache.directory.shared.ldap.constants.SchemaConstants;
046    import org.apache.directory.shared.ldap.entry.DefaultServerEntry;
047    import org.apache.directory.shared.ldap.entry.EntryAttribute;
048    import org.apache.directory.shared.ldap.entry.client.DefaultClientAttribute;
049    import org.apache.directory.shared.ldap.exception.LdapException;
050    import org.apache.directory.shared.ldap.ldif.ChangeType;
051    import org.apache.directory.shared.ldap.ldif.LdifEntry;
052    import org.apache.directory.shared.ldap.ldif.LdifReader;
053    import org.apache.directory.shared.ldap.name.DN;
054    import org.apache.directory.shared.ldap.name.RDN;
055    import org.apache.directory.shared.ldap.schema.registries.Schema;
056    import org.slf4j.Logger;
057    import org.slf4j.LoggerFactory;
058    
059    
060    /**
061     * Integration test utility methods.
062     *
063     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
064     * @version $Rev$, $Date$
065     */
066    public class IntegrationUtils
067    {
068        /** The class logger */
069        private static final Logger LOG = LoggerFactory.getLogger( IntegrationUtils.class );
070    
071        private static final List<LdapConnection> openConnections = new ArrayList<LdapConnection>();
072    
073        /**
074         * Deletes the working directory.
075         *
076         * @param wkdir the working directory to delete
077         * @throws IOException if the working directory cannot be deleted
078         */
079        public static void doDelete( File wkdir ) throws IOException
080        {
081            if ( wkdir.exists() )
082            {
083                try
084                {
085                    FileUtils.deleteDirectory( wkdir );
086                }
087                catch ( IOException e )
088                {
089                    LOG.error( I18n.err( I18n.ERR_115 ), e );
090                }
091            }
092            if ( wkdir.exists() )
093            {
094                throw new IOException( I18n.err( I18n.ERR_116, wkdir ) );
095            }
096        }
097    
098    
099        /**
100         * Inject an ldif String into the server. DN must be relative to the
101         * root.
102         *
103         * @param service the directory service to use 
104         * @param ldif the ldif containing entries to add to the server.
105         * @throws NamingException if there is a problem adding the entries from the LDIF
106         */
107        public static void injectEntries( DirectoryService service, String ldif ) throws Exception
108        {
109            LdifReader reader = new LdifReader();
110            List<LdifEntry> entries = reader.parseLdif( ldif );
111    
112            for ( LdifEntry entry : entries )
113            {
114                if ( entry.isChangeAdd() )
115                {
116                    service.getAdminSession().add( 
117                        new DefaultServerEntry( service.getSchemaManager(), entry.getEntry() ) );
118                }
119                else if ( entry.isChangeModify() )
120                {
121                    service.getAdminSession().modify( 
122                        entry.getDn(), entry.getModificationItems() );
123                }
124                else
125                {
126                    String message = I18n.err( I18n.ERR_117, entry.getChangeType() );
127                    LOG.error( message );
128                    throw new NamingException( message );
129                }
130            }
131            
132            // And close the reader
133            reader.close();
134        }
135    
136    
137        public static LdifEntry getUserAddLdif() throws LdapException
138        {
139            return getUserAddLdif( "uid=akarasulu,ou=users,ou=system", "test".getBytes(), "Alex Karasulu", "Karasulu" );
140        }
141    
142    
143        public static LdapContext getContext( String principalDn, DirectoryService service, String dn )
144                throws Exception
145        {
146            if ( principalDn == null )
147            {
148                principalDn = "";
149            }
150    
151            DN userDn = new DN( principalDn );
152            userDn.normalize( service.getSchemaManager().getNormalizerMapping() );
153            LdapPrincipal principal = new LdapPrincipal( userDn, AuthenticationLevel.SIMPLE );
154    
155            if ( dn == null )
156            {
157                dn = "";
158            }
159    
160            CoreSession session = service.getSession( principal );
161            LdapContext ctx = new ServerLdapContext( service, session, new LdapName( dn ) );
162            return ctx;
163        }
164    
165    
166        public static CoreSession getCoreSession( String principalDn, DirectoryService service, String dn )
167            throws Exception
168        {
169            if ( principalDn == null )
170            {
171                principalDn = "";
172            }
173            
174            DN userDn = new DN( principalDn );
175            userDn.normalize( service.getSchemaManager().getNormalizerMapping() );
176            LdapPrincipal principal = new LdapPrincipal( userDn, AuthenticationLevel.SIMPLE );
177            
178            if ( dn == null )
179            {
180                dn = "";
181            }
182            
183            CoreSession session = service.getSession( principal );
184            return session;
185        }
186    
187    
188        public static LdapContext getSystemContext( DirectoryService service ) throws Exception
189        {
190            return getContext( ServerDNConstants.ADMIN_SYSTEM_DN, service, ServerDNConstants.SYSTEM_DN );
191        }
192    
193    
194        public static LdapContext getSchemaContext( DirectoryService service ) throws Exception
195        {
196            return getContext( ServerDNConstants.ADMIN_SYSTEM_DN, service, SchemaConstants.OU_SCHEMA );
197        }
198    
199    
200        public static LdapContext getRootContext( DirectoryService service ) throws Exception
201        {
202            return getContext( ServerDNConstants.ADMIN_SYSTEM_DN, service, "" );
203        }
204    
205    
206        public static void apply( DirectoryService service, LdifEntry entry ) throws Exception
207        {
208            DN dn = new DN( entry.getDn() );
209            CoreSession session = service.getAdminSession();
210    
211            switch( entry.getChangeType().getChangeType() )
212            {
213                case( ChangeType.ADD_ORDINAL ):
214                    session.add( 
215                        new DefaultServerEntry( service.getSchemaManager(), entry.getEntry() ) ); 
216                    break;
217                    
218                case( ChangeType.DELETE_ORDINAL ):
219                    session.delete( dn );
220                    break;
221                    
222                case( ChangeType.MODDN_ORDINAL ):
223                case( ChangeType.MODRDN_ORDINAL ):
224                    RDN newRdn = new RDN( entry.getNewRdn() );
225                
226                    if ( entry.getNewSuperior() != null )
227                    {
228                        // It's a move. The superior have changed
229                        // Let's see if it's a rename too
230                        RDN oldRdn = dn.getRdn();
231                        DN newSuperior = new DN( entry.getNewSuperior() );
232                        
233                        if ( dn.size() == 0 )
234                        {
235                            throw new IllegalStateException( I18n.err( I18n.ERR_475 ) );
236                        }
237                        else if ( oldRdn.equals( newRdn ) )
238                        {
239                            // Same rdn : it's a move
240                            session.move( dn, newSuperior );
241                        }
242                        else
243                        {
244                            // it's a move and rename 
245                            session.moveAndRename( dn, newSuperior, newRdn, entry.isDeleteOldRdn() );
246                        }
247                    }
248                    else
249                    {
250                        // it's a rename
251                        session.rename( dn, newRdn, entry.isDeleteOldRdn() );
252                    }
253                    
254                    break;
255    
256                case( ChangeType.MODIFY_ORDINAL ):
257                    session.modify( dn, entry.getModificationItems() );
258                    break;
259    
260                default:
261                    throw new IllegalStateException( I18n.err( I18n.ERR_476, entry.getChangeType() ) );
262            }
263        }
264    
265    
266        public static LdifEntry getUserAddLdif( String dnstr, byte[] password, String cn, String sn )
267                throws LdapException
268        {
269            DN dn = new DN( dnstr );
270            LdifEntry ldif = new LdifEntry();
271            ldif.setDn( dnstr );
272            ldif.setChangeType( ChangeType.Add );
273    
274            EntryAttribute attr = new DefaultClientAttribute( "objectClass", 
275                "top", "person", "organizationalPerson", "inetOrgPerson" );
276            ldif.addAttribute( attr );
277    
278            attr = new DefaultClientAttribute( "ou", "Engineering", "People" );
279            ldif.addAttribute( attr );
280    
281            String uid = ( String ) dn.getRdn().getNormValue();
282            ldif.putAttribute( "uid", uid );
283    
284            ldif.putAttribute( "l", "Bogusville" );
285            ldif.putAttribute( "cn", cn );
286            ldif.putAttribute( "sn", sn );
287            ldif.putAttribute( "mail", uid + "@apache.org" );
288            ldif.putAttribute( "telephoneNumber", "+1 408 555 4798" );
289            ldif.putAttribute( "facsimileTelephoneNumber", "+1 408 555 9751" );
290            ldif.putAttribute( "roomnumber", "4612" );
291            ldif.putAttribute( "userPassword", password );
292    
293            String givenName = cn.split( " " )[0];
294            ldif.putAttribute( "givenName", givenName );
295            return ldif;
296        }
297    
298        // -----------------------------------------------------------------------
299        // Enable/Disable Schema Tests
300        // -----------------------------------------------------------------------
301    
302    
303        public static void enableSchema( DirectoryService service, String schemaName ) throws Exception
304        {
305            LdapContext schemaRoot = getSchemaContext( service );
306    
307            // now enable the test schema
308            ModificationItem[] mods = new ModificationItem[1];
309            Attribute attr = new BasicAttribute( "m-disabled", "FALSE" );
310            mods[0] = new ModificationItem( DirContext.REPLACE_ATTRIBUTE, attr );
311            schemaRoot.modifyAttributes( "cn=" + schemaName, mods );
312        }
313        
314        
315        public static void disableSchema( DirectoryService service, String schemaName ) throws Exception
316        {
317            LdapContext schemaRoot = getSchemaContext( service );
318    
319            // now enable the test schema
320            ModificationItem[] mods = new ModificationItem[1];
321            Attribute attr = new BasicAttribute( "m-disabled", "TRUE" );
322            mods[0] = new ModificationItem( DirContext.REPLACE_ATTRIBUTE, attr );
323            schemaRoot.modifyAttributes( "cn=" + schemaName, mods );
324        }
325        
326        
327        /**
328         * A helper method which tells if a schema is disabled.
329         */
330        public static boolean isDisabled( DirectoryService service, String schemaName )
331        {
332            Schema schema = service.getSchemaManager().getLoadedSchema( schemaName );
333            
334            return ( schema == null ) || schema.isDisabled();
335        }
336        
337        
338        /**
339         * A helper method which tells if a schema is loaded.
340         */
341        public static boolean isLoaded( DirectoryService service, String schemaName )
342        {
343            Schema schema = service.getSchemaManager().getLoadedSchema( schemaName );
344            
345            return ( schema != null );
346        }
347        
348        
349        /**
350         * A helper method which tells if a schema is enabled. A shema must be
351         * loaded and enabled.
352         */
353        public static boolean isEnabled( DirectoryService service, String schemaName )
354        {
355            Schema schema = service.getSchemaManager().getLoadedSchema( schemaName );
356            
357            return ( schema != null ) && schema.isEnabled();
358        }
359        
360        
361        /**
362         * gets a LdapConnection bound using the default admin DN uid=admin,ou=system and password "secret"
363         */
364        public static LdapConnection getAdminConnection( LdapServer ldapServer ) throws Exception
365        {
366            return getConnectionAs( ldapServer, ServerDNConstants.ADMIN_SYSTEM_DN, "secret" );
367        }
368    
369    
370        public static LdapConnection getConnectionAs( LdapServer ldapServer, String dn, String password ) throws Exception
371        {
372            return getConnectionAs( "localhost", ldapServer.getPort(), dn, password );
373        }
374    
375    
376        public static LdapConnection getConnectionAs( LdapServer ldapServer, DN dn, String password ) throws Exception
377        {
378            return getConnectionAs( "localhost", ldapServer.getPort(), dn.getName(), password );
379        }
380    
381    
382        public static LdapConnection getConnectionAs( String host, int port, String dn, String password ) throws Exception
383        {
384            LdapConnection connection = new LdapConnection( host, port );
385            connection.bind( dn, password );
386            openConnections.add( connection );
387            return connection;
388        }
389        
390        
391        public static void closeConections()
392        {
393            
394            for( LdapConnection con : openConnections )
395            {
396                if( con == null )
397                {
398                    continue;
399                }
400                
401                try
402                {
403                    if( con.isConnected() )
404                    {
405                        con.close();
406                    }
407                }
408                catch( Exception e )
409                {
410                    // shouldn't happen, but print the stacktrace so that less pain during development to find the cause
411                    e.printStackTrace();
412                }
413            }
414            
415            openConnections.clear();
416        }
417    }