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     */
020    package org.apache.directory.server.ldap;
021    
022    
023    import java.io.FileInputStream;
024    import java.io.IOException;
025    import java.security.KeyStore;
026    import java.security.KeyStoreSpi;
027    import java.security.Provider;
028    import java.security.Security;
029    import java.util.ArrayList;
030    import java.util.Collection;
031    import java.util.HashMap;
032    import java.util.HashSet;
033    import java.util.Iterator;
034    import java.util.List;
035    import java.util.Map;
036    import java.util.Set;
037    
038    
039    import org.apache.directory.server.core.DirectoryService;
040    import org.apache.directory.server.core.partition.PartitionNexus;
041    import org.apache.directory.server.core.security.CoreKeyStoreSpi;
042    import org.apache.directory.server.ldap.handlers.LdapRequestHandler;
043    import org.apache.directory.server.ldap.handlers.AbandonHandler;
044    import org.apache.directory.server.ldap.handlers.AddHandler;
045    import org.apache.directory.server.ldap.handlers.BindHandler;
046    import org.apache.directory.server.ldap.handlers.CompareHandler;
047    import org.apache.directory.server.ldap.handlers.DeleteHandler;
048    import org.apache.directory.server.ldap.handlers.ExtendedHandler;
049    import org.apache.directory.server.ldap.handlers.ModifyDnHandler;
050    import org.apache.directory.server.ldap.handlers.ModifyHandler;
051    import org.apache.directory.server.ldap.handlers.SearchHandler;
052    import org.apache.directory.server.ldap.handlers.UnbindHandler;
053    import org.apache.directory.server.ldap.handlers.bind.MechanismHandler;
054    import org.apache.directory.server.ldap.handlers.ssl.LdapsInitializer;
055    import org.apache.directory.server.ldap.replication.ReplicationSystem;
056    import org.apache.directory.server.protocol.shared.DirectoryBackedService;
057    import org.apache.directory.server.protocol.shared.transport.TcpTransport;
058    import org.apache.directory.server.protocol.shared.transport.Transport;
059    import org.apache.directory.server.protocol.shared.transport.UdpTransport;
060    import org.apache.directory.shared.ldap.constants.SaslQoP;
061    import org.apache.directory.shared.ldap.exception.LdapConfigurationException;
062    import org.apache.directory.shared.ldap.message.InternalAbandonRequest;
063    import org.apache.directory.shared.ldap.message.InternalAddRequest;
064    import org.apache.directory.shared.ldap.message.InternalBindRequest;
065    import org.apache.directory.shared.ldap.message.InternalCompareRequest;
066    import org.apache.directory.shared.ldap.message.InternalDeleteRequest;
067    import org.apache.directory.shared.ldap.message.InternalExtendedRequest;
068    import org.apache.directory.shared.ldap.message.InternalModifyDnRequest;
069    import org.apache.directory.shared.ldap.message.InternalModifyRequest;
070    import org.apache.directory.shared.ldap.message.InternalSearchRequest;
071    import org.apache.directory.shared.ldap.message.InternalUnbindRequest;
072    import org.apache.directory.shared.ldap.message.control.CascadeControl;
073    import org.apache.directory.shared.ldap.message.control.EntryChangeControl;
074    import org.apache.directory.shared.ldap.message.control.ManageDsaITControl;
075    import org.apache.directory.shared.ldap.message.control.PagedSearchControl;
076    import org.apache.directory.shared.ldap.message.control.PersistentSearchControl;
077    import org.apache.directory.shared.ldap.message.control.SubentriesControl;
078    import org.apache.directory.shared.ldap.message.control.replication.SyncDoneValueControl;
079    import org.apache.directory.shared.ldap.message.control.replication.SyncInfoValueControl;
080    import org.apache.directory.shared.ldap.message.control.replication.SyncRequestValueControl;
081    import org.apache.directory.shared.ldap.message.control.replication.SyncStateValueControl;
082    import org.apache.directory.shared.ldap.message.extended.NoticeOfDisconnect;
083    import org.apache.directory.shared.ldap.util.StringTools;
084    import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
085    import org.apache.mina.core.filterchain.IoFilterChainBuilder;
086    import org.apache.mina.core.future.WriteFuture;
087    import org.apache.mina.core.service.IoHandler;
088    import org.apache.mina.core.session.IoEventType;
089    import org.apache.mina.core.session.IoSession;
090    import org.apache.mina.filter.codec.ProtocolCodecFactory;
091    import org.apache.mina.filter.codec.ProtocolCodecFilter;
092    import org.apache.mina.filter.executor.ExecutorFilter;
093    import org.apache.mina.filter.executor.UnorderedThreadPoolExecutor;
094    import org.apache.mina.handler.demux.MessageHandler;
095    import org.apache.mina.transport.socket.SocketAcceptor;
096    import org.slf4j.Logger;
097    import org.slf4j.LoggerFactory;
098    
099    
100    /**
101     * An LDAP protocol provider implementation which dynamically associates
102     * handlers.
103     *
104     * @org.apache.xbean.XBean
105     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
106     * @version $Rev: 688548 $
107     */
108    public class LdapServer extends DirectoryBackedService
109    {
110        private static final long serialVersionUID = 3757127143811666817L;
111    
112        /** logger for this class */
113        private static final Logger LOG = LoggerFactory.getLogger( LdapServer.class.getName() );
114    
115        /** Value (0) for configuration where size limit is unlimited. */
116        public static final int NO_SIZE_LIMIT = 0;
117    
118        /** Value (0) for configuration where time limit is unlimited. */
119        public static final int NO_TIME_LIMIT = 0;
120    
121        /** the constant service name of this ldap protocol provider **/
122        public static final String SERVICE_NAME = "ldap";
123        
124        /** The default maximum size limit. */
125        private static final int MAX_SIZE_LIMIT_DEFAULT = 100;
126    
127        /** The default maximum time limit. */
128        private static final int MAX_TIME_LIMIT_DEFAULT = 10000;
129    
130        /** The default service pid. */
131        private static final String SERVICE_PID_DEFAULT = "org.apache.directory.server.ldap";
132    
133        /** The default service name. */
134        private static final String SERVICE_NAME_DEFAULT = "ApacheDS LDAP Service";
135    
136        /** The default IP port. */
137        private static final int DEFAULT_IP_PORT = 389;
138    
139        /** the session manager for this LdapServer */
140        private LdapSessionManager ldapSessionManager = new LdapSessionManager();
141        
142        /** a set of supported controls */
143        private Set<String> supportedControls;
144    
145        /** 
146         * The maximum size limit. 
147         * @see {@link LdapServer#MAX_SIZE_LIMIT_DEFAULT }
148         */
149        private int maxSizeLimit = MAX_SIZE_LIMIT_DEFAULT; 
150    
151        /** 
152         * The maximum time limit.
153         * @see {@link LdapServer#MAX_TIME_LIMIT_DEFAULT }
154         */
155        private int maxTimeLimit = MAX_TIME_LIMIT_DEFAULT; 
156    
157        /** If LDAPS is activated : the external Keystore file, if defined */
158        private String keystoreFile;
159        
160        /** If LDAPS is activated : the certificate password */
161        private String certificatePassword;
162    
163        /** Whether to allow anonymous access: enabled by default. */
164        private boolean allowAnonymousAccess = true;
165    
166        /** The extended operation handlers. */
167        private final Collection<ExtendedOperationHandler> extendedOperationHandlers =
168            new ArrayList<ExtendedOperationHandler>();
169    
170        /** The supported authentication mechanisms. */
171        private Map<String, MechanismHandler> saslMechanismHandlers =
172            new HashMap<String, MechanismHandler>();
173    
174        /** The name of this host, validated during SASL negotiation. */
175        private String saslHost = "ldap.example.com";
176    
177        /** The service principal, used by GSSAPI. */
178        private String saslPrincipal = "ldap/ldap.example.com@EXAMPLE.COM";
179    
180        /** The quality of protection (QoP), used by DIGEST-MD5 and GSSAPI. */
181        private Set<String> saslQop;
182        private String      saslQopString;
183    
184        /** The list of realms serviced by this host. */
185        private List<String> saslRealms;
186    
187        /** The potocol handlers */
188        private LdapRequestHandler<InternalAbandonRequest> abandonHandler;
189        private LdapRequestHandler<InternalAddRequest> addHandler;
190        private LdapRequestHandler<InternalBindRequest> bindHandler;
191        private LdapRequestHandler<InternalCompareRequest> compareHandler;
192        private LdapRequestHandler<InternalDeleteRequest> deleteHandler;
193        private LdapRequestHandler<InternalExtendedRequest> extendedHandler;
194        private LdapRequestHandler<InternalModifyRequest> modifyHandler;
195        private LdapRequestHandler<InternalModifyDnRequest> modifyDnHandler;
196        private LdapRequestHandler<InternalSearchRequest> searchHandler;
197        private LdapRequestHandler<InternalUnbindRequest> unbindHandler;
198    
199    
200        /** the underlying provider codec factory */
201        private ProtocolCodecFactory codecFactory;
202    
203        /** the MINA protocol handler */
204        private final LdapProtocolHandler handler = new LdapProtocolHandler(this);
205    
206        /** tracks start state of the server */
207        private boolean started;
208    
209        /** 
210         * Whether or not confidentiality (TLS secured connection) is required: 
211         * disabled by default. 
212         */
213        private boolean confidentialityRequired;
214    
215        
216        private ReplicationSystem replicationSystem;
217    
218        /**
219         * Creates an LDAP protocol provider.
220         */
221        public LdapServer()
222        {
223            super.setEnabled( true );
224            super.setServiceId( SERVICE_PID_DEFAULT );
225            super.setServiceName( SERVICE_NAME_DEFAULT );
226    
227            saslQop = new HashSet<String>();
228            saslQop.add( SaslQoP.QOP_AUTH );
229            saslQop.add( SaslQoP.QOP_AUTH_INT );
230            saslQop.add( SaslQoP.QOP_AUTH_CONF );
231            saslQopString = SaslQoP.QOP_AUTH + ',' + SaslQoP.QOP_AUTH_INT + ',' + SaslQoP.QOP_AUTH_CONF;
232    
233            saslRealms = new ArrayList<String>();
234            saslRealms.add( "example.com" );
235    
236            this.supportedControls = new HashSet<String>();
237            this.supportedControls.add( PersistentSearchControl.CONTROL_OID );
238            this.supportedControls.add( EntryChangeControl.CONTROL_OID );
239            this.supportedControls.add( SubentriesControl.CONTROL_OID );
240            this.supportedControls.add( ManageDsaITControl.CONTROL_OID );
241            this.supportedControls.add( CascadeControl.CONTROL_OID );
242            this.supportedControls.add( PagedSearchControl.CONTROL_OID );
243            // Replication controls
244            this.supportedControls.add( SyncDoneValueControl.CONTROL_OID );
245            this.supportedControls.add( SyncInfoValueControl.CONTROL_OID );
246            this.supportedControls.add( SyncRequestValueControl.CONTROL_OID );
247            this.supportedControls.add( SyncStateValueControl.CONTROL_OID );
248        }
249    
250    
251        /**
252         * Install the LDAP request handlers.
253         */
254        private void installDefaultHandlers()
255        {
256            if ( getAbandonHandler() == null )
257            {
258                setAbandonHandler( new AbandonHandler() );
259            }
260            
261            if ( getAddHandler() == null )
262            {
263                setAddHandler( new AddHandler() );
264            }
265            
266            if ( getBindHandler() == null )
267            {
268                BindHandler handler = new BindHandler();
269                handler.setSaslMechanismHandlers( saslMechanismHandlers );
270                setBindHandler( handler );
271            }
272            
273            if ( getCompareHandler() == null )
274            {
275                setCompareHandler( new CompareHandler() );
276            }
277            
278            if ( getDeleteHandler() == null )
279            {
280                setDeleteHandler( new DeleteHandler() );
281            }
282            
283            if ( getExtendedHandler() == null )
284            {
285                setExtendedHandler( new ExtendedHandler() );
286            }
287            
288            if ( getModifyHandler() == null )
289            {
290                setModifyHandler( new ModifyHandler() );
291            }
292            
293            if ( getModifyDnHandler() == null )
294            {
295                setModifyDnHandler( new ModifyDnHandler() );
296            }
297            
298            if ( getSearchHandler() == null )
299            {
300                setSearchHandler( new SearchHandler() );
301            }
302            
303            if ( getUnbindHandler() == null )
304            {
305                setUnbindHandler( new UnbindHandler() );
306            }
307        }
308    
309        
310        private class AdsKeyStore extends KeyStore
311        {
312            public AdsKeyStore( KeyStoreSpi keyStoreSpi, Provider provider, String type )
313            {
314                super( keyStoreSpi, provider, type );
315            }
316        }
317    
318        /**
319         * @throws IOException if we cannot bind to the specified port
320         * @throws NamingException if the LDAP server cannot be started
321         */
322        public void start() throws Exception
323        {
324            if ( ! isEnabled() )
325            {
326                return;
327            }
328    
329            for ( Transport transport:transports )
330            {
331                if ( !(transport instanceof TcpTransport ) )
332                {
333                    LOG.warn( "Cannot listen on an UDP transport : {}", transport );
334                    continue;
335                }
336                
337                IoFilterChainBuilder chain;
338                
339                if ( transport.isSSLEnabled() )
340                {
341                    KeyStore keyStore = null;
342                    
343                    if ( StringTools.isEmpty( keystoreFile ) )
344                    {
345                        Provider provider = Security.getProvider( "SUN" );
346                        LOG.debug( "provider = {}", provider );
347                        CoreKeyStoreSpi coreKeyStoreSpi = new CoreKeyStoreSpi( getDirectoryService() );
348                        keyStore = new AdsKeyStore( coreKeyStoreSpi, provider, "JKS" );
349                        
350                        try
351                        {
352                            keyStore.load( null, null );
353                        }
354                        catch ( Exception e )
355                        {
356                            // nothing really happens with this keystore
357                        }
358                    }
359                    else
360                    {
361                        keyStore = AdsKeyStore.getInstance( KeyStore.getDefaultType() );
362                        FileInputStream fis = new FileInputStream( keystoreFile );
363                        
364                        
365                        keyStore.load( fis, null );
366                    }
367                    
368                    chain = LdapsInitializer.init( keyStore, certificatePassword );
369                }
370                else
371                {
372                    chain = new DefaultIoFilterChainBuilder();
373                }
374                
375                // Inject the codec into the chain
376                ((DefaultIoFilterChainBuilder)chain).addLast( "codec", 
377                        new ProtocolCodecFilter( this.getProtocolCodecFactory() ) );
378                
379                // Now inject an ExecutorFilter for the write operations
380                // We use the same number of thread than the number of IoProcessor
381                // (NOTE : this has to be double checked)
382                ((DefaultIoFilterChainBuilder)chain).addLast( "executor", 
383                        new ExecutorFilter( 
384                            new UnorderedThreadPoolExecutor( transport.getNbThreads() ),
385                            IoEventType.MESSAGE_RECEIVED ) );
386    
387                /*
388                 * The server is now initialized, we can
389                 * install the default requests handlers, which need 
390                 * access to the DirectoryServer instance.
391                 */ 
392                installDefaultHandlers();      
393    
394                startNetwork( transport, chain );
395            }
396            
397            started = true;
398            
399            LOG.info( "Ldap service started." );
400        }
401    
402    
403        /**
404         * {@inheritDoc}
405         */
406        public void stop()
407        {
408            try
409            {
410                for ( Transport transport:transports )
411                {
412                    if ( !(transport instanceof TcpTransport ) )
413                    {
414                        continue;
415                    }
416                    
417                    // we should unbind the service before we begin sending the notice
418                    // of disconnect so new connections are not formed while we process
419                    List<WriteFuture> writeFutures = new ArrayList<WriteFuture>();
420        
421                    // If the socket has already been unbound as with a successful
422                    // GracefulShutdownRequest then this will complain that the service
423                    // is not bound - this is ok because the GracefulShutdown has already
424                    // sent notices to to the existing active sessions
425                    List<IoSession> sessions;
426        
427                    try
428                    {
429                        sessions = new ArrayList<IoSession>(
430                                getSocketAcceptor( transport ).getManagedSessions().values() );
431                    }
432                    catch ( IllegalArgumentException e )
433                    {
434                        LOG.warn( "Seems like the LDAP service (" + getPort() + ") has already been unbound." );
435                        return;
436                    }
437        
438                    getSocketAcceptor( transport ).dispose();
439        
440                    if ( LOG.isInfoEnabled() )
441                    {
442                        LOG.info( "Unbind of an LDAP service (" + getPort() + ") is complete." );
443                        LOG.info( "Sending notice of disconnect to existing clients sessions." );
444                    }
445        
446                    // Send Notification of Disconnection messages to all connected clients.
447                    if ( sessions != null )
448                    {
449                        for ( IoSession session:sessions )
450                        {
451                            writeFutures.add( session.write( NoticeOfDisconnect.UNAVAILABLE ) );
452                        }
453                    }
454        
455                    // And close the connections when the NoDs are sent.
456                    Iterator<IoSession> sessionIt = sessions.iterator();
457        
458                    for ( WriteFuture future:writeFutures )
459                    {
460                        future.await( 1000L );
461                        sessionIt.next().close( true );
462                    }
463                }
464            }
465            catch ( Exception e )
466            {
467                LOG.warn( "Failed to sent NoD.", e );
468            }
469    
470            LOG.info( "Ldap service stopped." );
471        }
472    
473    
474        private void startNetwork( Transport transport, IoFilterChainBuilder chainBuilder )
475            throws Exception
476        {
477            if ( transport.getBackLog() < 0 ) 
478            {
479                // Set the backlog to the default value when it's below 0
480                transport.setBackLog( 50 );
481            }
482    
483            PartitionNexus nexus = getDirectoryService().getPartitionNexus();
484    
485            for ( ExtendedOperationHandler h : extendedOperationHandlers )
486            {
487                LOG.info( "Added Extended Request Handler: " + h.getOid() );
488                h.setLdapServer( this );
489                nexus.registerSupportedExtensions( h.getExtensionOids() );
490            }
491    
492            nexus.registerSupportedSaslMechanisms( saslMechanismHandlers.keySet() );
493    
494            try
495            {
496                SocketAcceptor acceptor = getSocketAcceptor( transport );
497                
498                // Now, configure the acceptor
499                // Disable the disconnection of the clients on unbind
500                acceptor.setCloseOnDeactivation( false );
501                
502                // Allow the port to be reused even if the socket is in TIME_WAIT state
503                acceptor.setReuseAddress( true );
504                
505                // No Nagle's algorithm
506                acceptor.getSessionConfig().setTcpNoDelay( true );
507                
508                // Inject the chain
509                acceptor.setFilterChainBuilder( chainBuilder );
510                
511                // Inject the protocol handler
512                acceptor.setHandler( getHandler() );
513                
514                // Bind to the configured address
515                acceptor.bind();
516                
517                // We are done !
518                started = true;
519    
520                if ( LOG.isInfoEnabled() )
521                {
522                    LOG.info( "Successful bind of an LDAP Service (" + transport.getPort() + ") is completed." );
523                }
524            }
525            catch ( IOException e )
526            {
527                String msg = "Failed to bind an LDAP service (" + transport.getPort() + ") to the service registry.";
528                LdapConfigurationException lce = new LdapConfigurationException( msg );
529                lce.setRootCause( e );
530                LOG.error( msg, e );
531                throw lce;
532            }
533        }
534    
535    
536        public String getName()
537        {
538            return SERVICE_NAME;
539        }
540    
541    
542        public IoHandler getHandler()
543        {
544            return handler;
545        }
546        
547        
548        public LdapSessionManager getLdapSessionManager()
549        {
550            return ldapSessionManager;
551        }
552        
553        
554        public ProtocolCodecFactory getProtocolCodecFactory()
555        {
556            return codecFactory;
557        }
558    
559        
560        // ------------------------------------------------------------------------
561        // Configuration Methods
562        // ------------------------------------------------------------------------
563    
564    
565        /**
566         * Registeres the specified {@link ExtendedOperationHandler} to this
567         * protocol provider to provide a specific LDAP extended operation.
568         *
569         * @param eoh an extended operation handler
570         * @throws NamingException on failure to add the handler
571         */
572        public void addExtendedOperationHandler( ExtendedOperationHandler eoh ) throws Exception
573        {
574            if ( started )
575            {
576                eoh.setLdapServer( this );
577                PartitionNexus nexus = getDirectoryService().getPartitionNexus();
578                nexus.registerSupportedExtensions( eoh.getExtensionOids() );
579            }
580            else
581            {
582                extendedOperationHandlers.add( eoh );
583            }
584        }
585    
586    
587        /**
588         * Deregisteres an {@link ExtendedOperationHandler} with the specified <tt>oid</tt>
589         * from this protocol provider.
590         *
591         * @param oid the numeric identifier for the extended operation associated with
592         * the handler to remove
593         */
594        public void removeExtendedOperationHandler( String oid )
595        {
596            // need to do something like this to make this work right
597            //            PartitionNexus nexus = getDirectoryService().getPartitionNexus();
598            //            nexus.unregisterSupportedExtensions( eoh.getExtensionOids() );
599    
600            ExtendedOperationHandler handler = null;
601            for ( ExtendedOperationHandler h : extendedOperationHandlers )
602            {
603                if ( h.getOid().equals( oid ) )
604                {
605                    handler = h;
606                    break;
607                }
608            }
609            extendedOperationHandlers.remove( handler );
610        }
611    
612    
613        /**
614         * Returns an {@link ExtendedOperationHandler} with the specified <tt>oid</tt>
615         * which is registered to this protocol provider.
616         *
617         * @param oid the oid of the extended request of associated with the extended
618         * request handler
619         * @return the exnteded operation handler
620         */
621        public ExtendedOperationHandler getExtendedOperationHandler( String oid )
622        {
623            for ( ExtendedOperationHandler h : extendedOperationHandlers )
624            {
625                if ( h.getOid().equals( oid ) )
626                {
627                    return h;
628                }
629            }
630    
631            return null;
632        }
633    
634    
635        /**
636         * Sets the mode for this LdapServer to accept requests with or without a
637         * TLS secured connection via either StartTLS extended operations or using
638         * LDAPS.
639         * 
640         * @param confidentialityRequired true to require confidentiality
641         */
642        public void setConfidentialityRequired( boolean confidentialityRequired )
643        {
644            this.confidentialityRequired = confidentialityRequired;
645        }
646    
647    
648        /**
649         * Gets whether or not TLS secured connections are required to perform 
650         * operations on this LdapServer.
651         * 
652         * @return true if TLS secured connections are required, false otherwise
653         */
654        public boolean isConfidentialityRequired()
655        {
656            return confidentialityRequired;
657        }
658    
659        
660        /**
661         * Returns <tt>true</tt> if LDAPS is enabled.
662         *
663         * @return True if LDAPS is enabled.
664         */
665        public boolean isEnableLdaps( Transport transport )
666        {
667            return transport.isSSLEnabled();
668        }
669    
670    
671        /**
672         * Returns <code>true</code> if anonymous access is allowed.
673         *
674         * @return True if anonymous access is allowed.
675         */
676        public boolean isAllowAnonymousAccess()
677        {
678            return allowAnonymousAccess;
679        }
680    
681    
682        /**
683         * Sets whether to allow anonymous access or not.
684         *
685         * @param enableAnonymousAccess Set <code>true</code> to allow anonymous access.
686         */
687        public void setAllowAnonymousAccess( boolean enableAnonymousAccess )
688        {
689            this.allowAnonymousAccess = enableAnonymousAccess;
690        }
691    
692    
693        /**
694         * Sets the maximum size limit in number of entries to return for search.
695         *
696         * @param maxSizeLimit the maximum number of entries to return for search
697         */
698        public void setMaxSizeLimit( int maxSizeLimit )
699        {
700            this.maxSizeLimit = maxSizeLimit;
701        }
702    
703    
704        /**
705         * Returns the maximum size limit in number of entries to return for search.
706         *
707         * @return The maximum size limit.
708         */
709        public int getMaxSizeLimit()
710        {
711            return maxSizeLimit;
712        }
713    
714    
715        /**
716         * Sets the maximum time limit in milliseconds to conduct a search.
717         *
718         * @param maxTimeLimit the maximum length of time in milliseconds for search
719         */
720        public void setMaxTimeLimit( int maxTimeLimit )
721        {
722            this.maxTimeLimit = maxTimeLimit;
723        }
724    
725    
726        /**
727         * Returns the maximum time limit in milliseconds to conduct a search.
728         *
729         * @return The maximum time limit in milliseconds for search
730         */
731        public int getMaxTimeLimit()
732        {
733            return maxTimeLimit;
734        }
735    
736    
737        /**
738         * Gets the {@link ExtendedOperationHandler}s.
739         *
740         * @return A collection of {@link ExtendedOperationHandler}s.
741         */
742        public Collection<ExtendedOperationHandler> getExtendedOperationHandlers()
743        {
744            return new ArrayList<ExtendedOperationHandler>( extendedOperationHandlers );
745        }
746    
747    
748        /**
749         * Sets the {@link ExtendedOperationHandler}s.
750         *
751         * @org.apache.xbean.Property nestedType="org.apache.directory.server.ldap.ExtendedOperationHandler"
752         *
753         * @param handlers A collection of {@link ExtendedOperationHandler}s.
754         */
755        public void setExtendedOperationHandlers( Collection<ExtendedOperationHandler> handlers )
756        {
757            this.extendedOperationHandlers.clear();
758            this.extendedOperationHandlers.addAll( handlers );
759        }
760    
761    
762        /**
763         * Returns the FQDN of this SASL host, validated during SASL negotiation.
764         *
765         * @return The FQDN of this SASL host, validated during SASL negotiation.
766         */
767        public String getSaslHost()
768        {
769            return saslHost;
770        }
771    
772    
773        /**
774         * Sets the FQDN of this SASL host, validated during SASL negotiation.
775         *
776         * @param saslHost The FQDN of this SASL host, validated during SASL negotiation.
777         */
778        public void setSaslHost( String saslHost )
779        {
780            this.saslHost = saslHost;
781        }
782    
783    
784        /**
785         * Returns the Kerberos principal name for this LDAP service, used by GSSAPI.
786         *
787         * @return The Kerberos principal name for this LDAP service, used by GSSAPI.
788         */
789        public String getSaslPrincipal()
790        {
791            return saslPrincipal;
792        }
793    
794    
795        /**
796         * Sets the Kerberos principal name for this LDAP service, used by GSSAPI.
797         *
798         * @param saslPrincipal The Kerberos principal name for this LDAP service, used by GSSAPI.
799         */
800        public void setSaslPrincipal( String saslPrincipal )
801        {
802            this.saslPrincipal = saslPrincipal;
803        }
804    
805    
806        /**
807         * Returns the quality-of-protection, used by DIGEST-MD5 and GSSAPI.
808         *
809         * @return The quality-of-protection, used by DIGEST-MD5 and GSSAPI.
810         */
811        public String getSaslQopString()
812        {
813            return saslQopString;
814        }
815    
816    
817        /**
818         * Returns the Set of quality-of-protection, used by DIGEST-MD5 and GSSAPI.
819         *
820         * @return The quality-of-protection, used by DIGEST-MD5 and GSSAPI.
821         */
822        public Set<String> getSaslQop()
823        {
824            return saslQop;
825        }
826    
827    
828        /**
829         * Returns the realms serviced by this SASL host, used by DIGEST-MD5 and GSSAPI.
830         *
831         * @return The realms serviced by this SASL host, used by DIGEST-MD5 and GSSAPI.
832         */
833        public List<String> getSaslRealms()
834        {
835            return saslRealms;
836        }
837    
838    
839        /**
840         * Sets the realms serviced by this SASL host, used by DIGEST-MD5 and GSSAPI.
841         *
842         * @org.apache.xbean.Property nestedType="java.lang.String"
843         *
844         * @param saslRealms The realms serviced by this SASL host, used by DIGEST-MD5 and GSSAPI.
845         */
846        public void setSaslRealms( List<String> saslRealms )
847        {
848            this.saslRealms = saslRealms;
849        }
850    
851    
852        /**
853         * @org.apache.xbean.Map flat="true" dups="replace" keyName="mech-name"
854         */
855        public Map<String, MechanismHandler> getSaslMechanismHandlers()
856        {
857            return saslMechanismHandlers;
858        }
859    
860        public void setSaslMechanismHandlers( Map<String, MechanismHandler> saslMechanismHandlers )
861        {
862            this.saslMechanismHandlers = saslMechanismHandlers;
863        }
864    
865    
866        public MechanismHandler addSaslMechanismHandler( String mechanism, MechanismHandler handler )
867        {
868            return this.saslMechanismHandlers.put( mechanism, handler );
869        }
870    
871    
872        public MechanismHandler removeSaslMechanismHandler( String mechanism )
873        {
874            return this.saslMechanismHandlers.remove( mechanism );
875        }
876    
877    
878        public MechanismHandler getMechanismHandler( String mechanism )
879        {
880            return this.saslMechanismHandlers.get( mechanism );
881        }
882    
883    
884        public Set<String> getSupportedMechanisms()
885        {
886            return saslMechanismHandlers.keySet();
887        }
888    
889    
890        public void setDirectoryService( DirectoryService directoryService )
891        {
892            super.setDirectoryService( directoryService );
893            this.codecFactory = new LdapProtocolCodecFactory( directoryService );
894        }
895    
896    
897        public Set<String> getSupportedControls()
898        {
899            return supportedControls;
900        }
901    
902    
903        /**
904         * @org.apache.xbean.Property hidden="true"
905         */
906        public void setSupportedControls( Set<String> supportedControls )
907        {
908            this.supportedControls = supportedControls;
909        }
910    
911    
912        public MessageHandler<InternalAbandonRequest> getAbandonHandler()
913        {
914            return abandonHandler;
915        }
916    
917    
918        /**
919         * @org.apache.xbean.Property hidden="true"
920         * @param abandonHandler The AbandonRequest handler
921         */
922        public void setAbandonHandler( LdapRequestHandler<InternalAbandonRequest> abandonHandler )
923        {
924            this.handler.removeReceivedMessageHandler( InternalAbandonRequest.class );
925            this.abandonHandler = abandonHandler;
926            this.abandonHandler.setLdapServer( this );
927            this.handler.addReceivedMessageHandler( InternalAbandonRequest.class, this.abandonHandler );
928        }
929    
930    
931        public LdapRequestHandler<InternalAddRequest> getAddHandler()
932        {
933            return addHandler;
934        }
935    
936    
937        /**
938         * @org.apache.xbean.Property hidden="true"
939         * @param abandonHandler The AddRequest handler
940         */
941        public void setAddHandler( LdapRequestHandler<InternalAddRequest> addHandler )
942        {
943            this.handler.removeReceivedMessageHandler( InternalAddRequest.class );
944            this.addHandler = addHandler;
945            this.addHandler.setLdapServer( this );
946            this.handler.addReceivedMessageHandler( InternalAddRequest.class, this.addHandler );
947        }
948    
949    
950        public LdapRequestHandler<InternalBindRequest> getBindHandler()
951        {
952            return bindHandler;
953        }
954    
955    
956        /**
957         * @org.apache.xbean.Property hidden="true"
958         * @param abandonHandler The BindRequest handler
959         */
960        public void setBindHandler( LdapRequestHandler<InternalBindRequest> bindHandler )
961        {
962            this.bindHandler = bindHandler;
963            this.bindHandler.setLdapServer( this );
964    
965            handler.removeReceivedMessageHandler( InternalBindRequest.class );
966            handler.addReceivedMessageHandler( InternalBindRequest.class, this.bindHandler );
967        }
968    
969    
970        public LdapRequestHandler<InternalCompareRequest> getCompareHandler()
971        {
972            return compareHandler;
973        }
974    
975    
976        /**
977         * @org.apache.xbean.Property hidden="true"
978         * @param abandonHandler The CompareRequest handler
979         */
980        public void setCompareHandler( LdapRequestHandler<InternalCompareRequest> compareHandler )
981        {
982            this.handler.removeReceivedMessageHandler( InternalCompareRequest.class );
983            this.compareHandler = compareHandler;
984            this.compareHandler.setLdapServer( this );
985            this.handler.addReceivedMessageHandler( InternalCompareRequest.class, this.compareHandler );
986        }
987    
988    
989        public LdapRequestHandler<InternalDeleteRequest> getDeleteHandler()
990        {
991            return deleteHandler;
992        }
993    
994    
995        /**
996         * @org.apache.xbean.Property hidden="true"
997         * @param abandonHandler The DeleteRequest handler
998         */
999        public void setDeleteHandler( LdapRequestHandler<InternalDeleteRequest> deleteHandler )
1000        {
1001            this.handler.removeReceivedMessageHandler( InternalDeleteRequest.class );
1002            this.deleteHandler = deleteHandler;
1003            this.deleteHandler.setLdapServer( this );
1004            this.handler.addReceivedMessageHandler( InternalDeleteRequest.class, this.deleteHandler );
1005        }
1006    
1007    
1008        public LdapRequestHandler<InternalExtendedRequest> getExtendedHandler()
1009        {
1010            return extendedHandler;
1011        }
1012    
1013    
1014        /**
1015         * @org.apache.xbean.Property hidden="true"
1016         * @param abandonHandler The ExtendedRequest handler
1017         */
1018        public void setExtendedHandler( LdapRequestHandler<InternalExtendedRequest> extendedHandler )
1019        {
1020            this.handler.removeReceivedMessageHandler( InternalExtendedRequest.class );
1021            this.extendedHandler = extendedHandler;
1022            this.extendedHandler.setLdapServer( this );
1023            this.handler.addReceivedMessageHandler( InternalExtendedRequest.class, this.extendedHandler );
1024        }
1025    
1026    
1027        public LdapRequestHandler<InternalModifyRequest> getModifyHandler()
1028        {
1029            return modifyHandler;
1030        }
1031    
1032    
1033        /**
1034         * @org.apache.xbean.Property hidden="true"
1035         * @param abandonHandler The ModifyRequest handler
1036         */
1037        public void setModifyHandler( LdapRequestHandler<InternalModifyRequest> modifyHandler )
1038        {
1039            this.handler.removeReceivedMessageHandler( InternalModifyRequest.class );
1040            this.modifyHandler = modifyHandler;
1041            this.modifyHandler.setLdapServer( this );
1042            this.handler.addReceivedMessageHandler( InternalModifyRequest.class, this.modifyHandler );
1043        }
1044    
1045    
1046        public LdapRequestHandler<InternalModifyDnRequest> getModifyDnHandler()
1047        {
1048            return modifyDnHandler;
1049        }
1050    
1051    
1052        /**
1053         * @org.apache.xbean.Property hidden="true"
1054         * @param abandonHandler The ModifyDNRequest handler
1055         */
1056        public void setModifyDnHandler( LdapRequestHandler<InternalModifyDnRequest> modifyDnHandler )
1057        {
1058            this.handler.removeReceivedMessageHandler( InternalModifyDnRequest.class );
1059            this.modifyDnHandler = modifyDnHandler;
1060            this.modifyDnHandler.setLdapServer( this );
1061            this.handler.addReceivedMessageHandler( InternalModifyDnRequest.class, this.modifyDnHandler );
1062        }
1063    
1064    
1065        public LdapRequestHandler<InternalSearchRequest> getSearchHandler()
1066        {
1067            return searchHandler;
1068        }
1069    
1070    
1071        /**
1072         * @org.apache.xbean.Property hidden="true"
1073         * @param abandonHandler The SearchRequest handler
1074         */
1075        public void setSearchHandler( LdapRequestHandler<InternalSearchRequest> searchHandler )
1076        {
1077            this.handler.removeReceivedMessageHandler( InternalSearchRequest.class );
1078            this.searchHandler = searchHandler;
1079            this.searchHandler.setLdapServer( this );
1080            this.handler.addReceivedMessageHandler( InternalSearchRequest.class, this.searchHandler );
1081        }
1082    
1083    
1084        public LdapRequestHandler<InternalUnbindRequest> getUnbindHandler()
1085        {
1086            return unbindHandler;
1087        }
1088        
1089        
1090        /**
1091         * @return The underlying TCP transport port, or -1 if no transport has been 
1092         * initialized
1093         */
1094        public int getPort()
1095        {
1096            if ( transports == null )
1097            {
1098                return -1;
1099            }
1100            
1101            for ( Transport transport:transports )
1102            {
1103                if ( transport instanceof UdpTransport )
1104                {
1105                    continue;
1106                }
1107                
1108                if ( !transport.isSSLEnabled() )
1109                {
1110                    return transport.getPort();
1111                }
1112            }
1113            
1114            return -1;
1115        }
1116    
1117    
1118        /**
1119         * @return The underlying SSL enabled TCP transport port, or -1 if no transport has been 
1120         * initialized
1121         */
1122        public int getPortSSL()
1123        {
1124            if ( transports == null )
1125            {
1126                return -1;
1127            }
1128            
1129            for ( Transport transport:transports )
1130            {
1131                if ( transport instanceof UdpTransport )
1132                {
1133                    continue;
1134                }
1135                
1136                if ( transport.isSSLEnabled() )
1137                {
1138                    return transport.getPort();
1139                }
1140            }
1141            
1142            return -1;
1143        }
1144    
1145        /**
1146         * @org.apache.xbean.Property hidden="true"
1147         * @param abandonHandler The UnbindRequest handler
1148         */
1149        public void setUnbindHandler( LdapRequestHandler<InternalUnbindRequest> unbindHandler )
1150        {
1151            this.handler.removeReceivedMessageHandler( InternalUnbindRequest.class );
1152            this.unbindHandler = unbindHandler;
1153            this.unbindHandler.setLdapServer( this );
1154            this.handler.addReceivedMessageHandler( InternalUnbindRequest.class, this.unbindHandler );
1155        }
1156    
1157    
1158        public boolean isStarted()
1159        {
1160            return started;
1161        }
1162    
1163    
1164        /**
1165         * @org.apache.xbean.Property hidden="true"
1166         */
1167        public void setStarted( boolean started )
1168        {
1169            this.started = started;
1170        }
1171    
1172    
1173        /**
1174         * @return The keystore path
1175         */
1176        public String getKeystoreFile()
1177        {
1178            return keystoreFile;
1179        }
1180    
1181    
1182        /**
1183         * Set the external keystore path
1184         * @param keystoreFile The external keystore path
1185         */
1186        public void setKeystoreFile( String keystoreFile )
1187        {
1188            this.keystoreFile = keystoreFile;
1189        }
1190    
1191    
1192        /**
1193         * @return The certificate passord
1194         */
1195        public String getCertificatePassword()
1196        {
1197            return certificatePassword;
1198        }
1199    
1200    
1201        /**
1202         * Set the certificate passord.
1203         * @param certificatePassword the certificate passord
1204         */
1205        public void setCertificatePassword( String certificatePassword )
1206        {
1207            this.certificatePassword = certificatePassword;
1208        }
1209    
1210    
1211        /**
1212         * @param replicationSystem the replicationSystem to set
1213         */
1214        public void setReplicationSystem( ReplicationSystem replicationSystem )
1215        {
1216            this.replicationSystem = replicationSystem;
1217        }
1218    
1219    
1220        /**
1221         * @return the replicationSystem
1222         */
1223        public ReplicationSystem getReplicationSystem()
1224        {
1225            return replicationSystem;
1226        }
1227        
1228        
1229        /**
1230         * @see Object#toString()
1231         */
1232        public String toString()
1233        {
1234            StringBuilder sb = new StringBuilder();
1235            
1236            sb.append( "LdapServer[" ).append( getServiceName() ).append( "], listening on :" ).append( '\n' );
1237            
1238            if ( getTransports() != null )
1239            {
1240                for ( Transport transport:getTransports() )
1241                {
1242                    sb.append( "    " ).append( transport ).append( '\n' );
1243                }
1244            }
1245            
1246            return sb.toString();
1247        }
1248    }