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