001    /*
002     * Copyright 2011-2015 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2011-2015 UnboundID Corp.
007     *
008     * This program is free software; you can redistribute it and/or modify
009     * it under the terms of the GNU General Public License (GPLv2 only)
010     * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011     * as published by the Free Software Foundation.
012     *
013     * This program is distributed in the hope that it will be useful,
014     * but WITHOUT ANY WARRANTY; without even the implied warranty of
015     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016     * GNU General Public License for more details.
017     *
018     * You should have received a copy of the GNU General Public License
019     * along with this program; if not, see <http://www.gnu.org/licenses>.
020     */
021    package com.unboundid.ldap.listener;
022    
023    
024    
025    import java.net.InetAddress;
026    import javax.net.SocketFactory;
027    import javax.net.ServerSocketFactory;
028    import javax.net.ssl.SSLSocketFactory;
029    import javax.net.ssl.SSLServerSocketFactory;
030    
031    import com.unboundid.ldap.sdk.LDAPException;
032    import com.unboundid.ldap.sdk.ResultCode;
033    import com.unboundid.util.Debug;
034    import com.unboundid.util.NotMutable;
035    import com.unboundid.util.StaticUtils;
036    import com.unboundid.util.ThreadSafety;
037    import com.unboundid.util.ThreadSafetyLevel;
038    import com.unboundid.util.ssl.SSLUtil;
039    import com.unboundid.util.ssl.TrustAllTrustManager;
040    
041    import static com.unboundid.ldap.listener.ListenerMessages.*;
042    
043    
044    
045    /**
046     * This class provides a data structure that can be used to configure a
047     * listener for use in the in-memory directory server.  Each in-memory directory
048     * server instance has the ability to have multiple listeners, and those
049     * listeners may have different settings (e.g., listen on one port for
050     * unencrypted LDAP communication with optional support for StartTLS, and listen
051     * on a separate port for SSL-encrypted communication).  If the server is to
052     * provide support for SSL and/or StartTLS, then the {@link SSLUtil} class can
053     * make it easy to create the necessary socket factories.
054     */
055    @NotMutable()
056    @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
057    public final class InMemoryListenerConfig
058    {
059      // The address on which this listener should accept client connections.
060      private final InetAddress listenAddress;
061    
062      // The port on which this listener should accept client connections.
063      private final int listenPort;
064    
065      // The socket factory that should be used for accepting new connections.
066      private final ServerSocketFactory serverSocketFactory;
067    
068      // The socket factory that should be used for creating client connections.
069      private final SocketFactory clientSocketFactory;
070    
071      // The socket factory that will be used to add StartTLS encryption to an
072      // existing connection.
073      private final SSLSocketFactory startTLSSocketFactory;
074    
075      // The used to refer to this listener.
076      private final String listenerName;
077    
078    
079    
080      /**
081       * Creates a new in-memory directory server listener configuration with the
082       * provided settings.
083       *
084       * @param  listenerName           The name to assign to this listener.  It
085       *                                must not be {@code null} and must not be the
086       *                                same as the name for any other listener
087       *                                configured in the server.
088       * @param  listenAddress          The address on which the listener should
089       *                                accept connections from clients.  It may be
090       *                                {@code null} to indicate that it should
091       *                                accept connections on all addresses on all
092       *                                interfaces.
093       * @param  listenPort             The port on which the listener should accept
094       *                                connections from clients.  It may be 0 to
095       *                                indicate that the server should
096       *                                automatically choose an available port.
097       * @param  serverSocketFactory    The socket factory that should be used to
098       *                                create sockets when accepting client
099       *                                connections.  It may be {@code null} if the
100       *                                JVM-default server socket factory should be
101       *                                used.
102       * @param  clientSocketFactory    The socket factory that should be used to
103       *                                create client connections to the server.  It
104       *                                may be {@code null} if the JVM-default
105       *                                socket factory should be used.
106       * @param  startTLSSocketFactory  The socket factory that should be used to
107       *                                add StartTLS encryption to existing
108       *                                connections.  It may be {@code null} if
109       *                                StartTLS is not to be supported on this
110       *                                listener, and should be {@code null} if the
111       *                                server socket factory already provides some
112       *                                other form of communication security.
113       *
114       * @throws  LDAPException  If the provided listener name is {@code null} or
115       *                         the configured listen port is out of range.
116       */
117      public InMemoryListenerConfig(final String listenerName,
118                                    final InetAddress listenAddress,
119                                    final int listenPort,
120                                    final ServerSocketFactory serverSocketFactory,
121                                    final SocketFactory clientSocketFactory,
122                                    final SSLSocketFactory startTLSSocketFactory)
123             throws LDAPException
124      {
125        if ((listenerName == null) || (listenerName.length() == 0))
126        {
127          throw new LDAPException(ResultCode.PARAM_ERROR,
128               ERR_LISTENER_CFG_NO_NAME.get());
129        }
130    
131        if ((listenPort < 0) || (listenPort > 65535))
132        {
133          throw new LDAPException(ResultCode.PARAM_ERROR,
134               ERR_LISTENER_CFG_INVALID_PORT.get(listenPort));
135        }
136    
137        this.listenerName          = listenerName;
138        this.listenAddress         = listenAddress;
139        this.listenPort            = listenPort;
140        this.serverSocketFactory   = serverSocketFactory;
141        this.clientSocketFactory   = clientSocketFactory;
142        this.startTLSSocketFactory = startTLSSocketFactory;
143      }
144    
145    
146    
147      /**
148       * Creates a new listener configuration that will listen for unencrypted LDAP
149       * communication on an automatically-selected port on all available addresses.
150       * It will not support StartTLS.
151       *
152       * @param  listenerName  The name to use for the listener.  It must not be
153       *                       {@code null}.
154       *
155       * @return  The newly-created listener configuration.
156       *
157       * @throws  LDAPException  If the provided name is {@code null}.
158       */
159      public static InMemoryListenerConfig createLDAPConfig(
160                                                final String listenerName)
161             throws LDAPException
162      {
163        return new InMemoryListenerConfig(listenerName, null, 0, null, null, null);
164      }
165    
166    
167    
168      /**
169       * Creates a new listener configuration that will listen for unencrypted LDAP
170       * communication on the specified port on all available addresses.  It will
171       * not support StartTLS.
172       *
173       * @param  listenerName  The name to use for the listener.  It must not be
174       *                       {@code null}.
175       * @param  listenPort    The port on which the listener should accept
176       *                       connections from clients.  It may be 0 to indicate
177       *                       that the server should automatically choose an
178       *                       available port.
179       *
180       * @return  The newly-created listener configuration.
181       *
182       * @throws  LDAPException  If the provided listener name is {@code null} or
183       *                         the configured listen port is out of range.
184       */
185      public static InMemoryListenerConfig createLDAPConfig(
186                                                final String listenerName,
187                                                final int listenPort)
188             throws LDAPException
189      {
190        return new InMemoryListenerConfig(listenerName, null, listenPort, null,
191             null, null);
192      }
193    
194    
195    
196      /**
197       * Creates a new listener configuration that will listen for unencrypted LDAP
198       * communication, and may optionally support StartTLS.
199       *
200       * @param  listenerName           The name to assign to this listener.  It
201       *                                must not be {@code null} and must not be the
202       *                                same as the name for any other listener
203       *                                configured in the server.
204       * @param  listenAddress          The address on which the listener should
205       *                                accept connections from clients.  It may be
206       *                                {@code null} to indicate that it should
207       *                                accept connections on all addresses on all
208       *                                interfaces.
209       * @param  listenPort             The port on which the listener should accept
210       *                                connections from clients.  It may be 0 to
211       *                                indicate that the server should
212       *                                automatically choose an available port.
213       * @param  startTLSSocketFactory  The socket factory that should be used to
214       *                                add StartTLS encryption to an existing
215       *                                connection.  It may be {@code null} if
216       *                                StartTLS is not to be supported on this
217       *                                listener, and should be {@code null} if the
218       *                                server socket factory already provides some
219       *                                other form of communication security.
220       *
221       * @return  The newly-created listener configuration.
222       *
223       * @throws  LDAPException  If the provided listener name is {@code null} or
224       *                         the configured listen port is out of range.
225       */
226      public static InMemoryListenerConfig createLDAPConfig(
227                         final String listenerName, final InetAddress listenAddress,
228                         final int listenPort,
229                         final SSLSocketFactory startTLSSocketFactory)
230             throws LDAPException
231      {
232        return new InMemoryListenerConfig(listenerName, listenAddress, listenPort,
233             null, null, startTLSSocketFactory);
234      }
235    
236    
237    
238      /**
239       * Creates a new listener configuration that will listen for SSL-encrypted
240       * LDAP communication on an automatically-selected port on all available
241       * addresses.
242       *
243       * @param  listenerName         The name to use for the listener.  It must not
244       *                              be {@code null}.
245       * @param  serverSocketFactory  The SSL server socket factory that will be
246       *                              used for accepting SSL-based connections from
247       *                              clients.  It must not be {@code null}.
248       *
249       * @return  The newly-created listener configuration.
250       *
251       * @throws  LDAPException  If the provided name is {@code null}.
252       */
253      public static InMemoryListenerConfig createLDAPSConfig(
254                         final String listenerName,
255                         final SSLServerSocketFactory serverSocketFactory)
256             throws LDAPException
257      {
258        return createLDAPSConfig(listenerName, null, 0, serverSocketFactory, null);
259      }
260    
261    
262    
263      /**
264       * Creates a new listener configuration that will listen for SSL-encrypted
265       * LDAP communication on the specified port on all available addresses.
266       *
267       * @param  listenerName         The name to use for the listener.  It must not
268       *                              be {@code null}.
269       * @param  listenPort           The port on which the listener should accept
270       *                              connections from clients.  It may be 0 to
271       *                              indicate that the server should
272       *                              automatically choose an available port.
273       * @param  serverSocketFactory  The SSL server socket factory that will be
274       *                              used for accepting SSL-based connections from
275       *                              clients.  It must not be {@code null}.
276       *
277       * @return  The newly-created listener configuration.
278       *
279       * @throws  LDAPException  If the provided name is {@code null}.
280       */
281      public static InMemoryListenerConfig createLDAPSConfig(
282                         final String listenerName, final int listenPort,
283                         final SSLServerSocketFactory serverSocketFactory)
284             throws LDAPException
285      {
286        return createLDAPSConfig(listenerName, null, listenPort,
287             serverSocketFactory, null);
288      }
289    
290    
291    
292      /**
293       * Creates a new listener configuration that will listen for SSL-encrypted
294       * LDAP communication on an automatically-selected port on all available
295       * addresses.
296       *
297       * @param  listenerName         The name to use for the listener.  It must not
298       *                              be {@code null}.
299       * @param  listenAddress        The address on which the listener should
300       *                              accept connections from clients.  It may be
301       *                              {@code null} to indicate that it should
302       *                              accept connections on all addresses on all
303       *                              interfaces.
304       * @param  listenPort           The port on which the listener should accept
305       *                              connections from clients.  It may be 0 to
306       *                              indicate that the server should
307       *                              automatically choose an available port.
308       * @param  serverSocketFactory  The SSL server socket factory that will be
309       *                              used for accepting SSL-based connections from
310       *                              clients.  It must not be {@code null}.
311       * @param  clientSocketFactory  The SSL socket factory that will be used to
312       *                              create secure connections to the server.  It
313       *                              may be {@code null} if a default "trust all"
314       *                              socket factory should be used.
315       *
316       * @return  The newly-created listener configuration.
317       *
318       * @throws  LDAPException  If the provided name or server socket factory is
319       *          {@code null}, or an error occurs while attempting to create a
320       *          client socket factory.
321       */
322      public static InMemoryListenerConfig createLDAPSConfig(
323                         final String listenerName, final InetAddress listenAddress,
324                         final int listenPort,
325                         final SSLServerSocketFactory serverSocketFactory,
326                         final SSLSocketFactory clientSocketFactory)
327             throws LDAPException
328      {
329        if (serverSocketFactory == null)
330        {
331          throw new LDAPException(ResultCode.PARAM_ERROR,
332               ERR_LISTENER_CFG_NO_SSL_SERVER_SOCKET_FACTORY.get());
333        }
334    
335        final SSLSocketFactory clientFactory;
336        if (clientSocketFactory == null)
337        {
338          try
339          {
340            final SSLUtil sslUtil = new SSLUtil(new TrustAllTrustManager());
341            clientFactory = sslUtil.createSSLSocketFactory();
342          }
343          catch (final Exception e)
344          {
345            Debug.debugException(e);
346            throw new LDAPException(ResultCode.LOCAL_ERROR,
347                 ERR_LISTENER_CFG_COULD_NOT_CREATE_SSL_SOCKET_FACTORY.get(
348                      StaticUtils.getExceptionMessage(e)),
349                 e);
350          }
351        }
352        else
353        {
354          clientFactory = clientSocketFactory;
355        }
356    
357        return new InMemoryListenerConfig(listenerName, listenAddress, listenPort,
358             serverSocketFactory, clientFactory, null);
359      }
360    
361    
362    
363      /**
364       * Retrieves the name for this listener configuration.
365       *
366       * @return  The name for this listener configuration.
367       */
368      public String getListenerName()
369      {
370        return listenerName;
371      }
372    
373    
374    
375      /**
376       * Retrieves the address on which the listener should accept connections from
377       * clients, if defined.
378       *
379       * @return  The address on which the listener should accept connections from
380       *          clients, or {@code null} if it should accept connections on all
381       *          addresses on all interfaces.
382       */
383      public InetAddress getListenAddress()
384      {
385        return listenAddress;
386      }
387    
388    
389    
390      /**
391       * Retrieves the port on which the listener should accept connections from
392       * clients, if defined.
393       *
394       * @return  The port on which the listener should accept connections from
395       *          clients, or 0 if the listener should automatically select an
396       *          available port.
397       */
398      public int getListenPort()
399      {
400        return listenPort;
401      }
402    
403    
404    
405      /**
406       * Retrieves the socket factory that should be used to create sockets when
407       * accepting client connections, if defined.
408       *
409       * @return  The socket factory that should be used to create sockets when
410       *          accepting client connections, or {@code null} if the JVM-default
411       *          server socket factory should be used.
412       */
413      public ServerSocketFactory getServerSocketFactory()
414      {
415        return serverSocketFactory;
416      }
417    
418    
419    
420      /**
421       * Retrieves the socket factory that should be used to create client
422       * connections to the server, if defined.
423       *
424       * @return  The socket factory that should be used to create client
425       *          connections to the server, or {@code null} if the JVM-default
426       *          socket factory should be used.
427       */
428      public SocketFactory getClientSocketFactory()
429      {
430        return clientSocketFactory;
431      }
432    
433    
434    
435      /**
436       * Retrieves the socket factory that should be used to add StartTLS encryption
437       * to existing connections, if defined.
438       *
439       * @return  The socket factory that should be used to add StartTLS encryption
440       *          to existing connections, or {@code null} if StartTLS should not be
441       *          supported.
442       */
443      public SSLSocketFactory getStartTLSSocketFactory()
444      {
445        return startTLSSocketFactory;
446      }
447    
448    
449    
450      /**
451       * Retrieves a string representation of this listener configuration.
452       *
453       * @return  A string representation of this listener configuration.
454       */
455      @Override()
456      public String toString()
457      {
458        final StringBuilder buffer = new StringBuilder();
459        toString(buffer);
460        return buffer.toString();
461      }
462    
463    
464    
465      /**
466       * Appends a string representation of this listener configuration to the
467       * provided buffer.
468       *
469       * @param  buffer  The buffer to which the information should be appended.
470       */
471      public void toString(final StringBuilder buffer)
472      {
473        buffer.append("InMemoryListenerConfig(name='");
474        buffer.append(listenerName);
475        buffer.append('\'');
476    
477        if (listenAddress != null)
478        {
479          buffer.append(", listenAddress='");
480          buffer.append(listenAddress.getHostAddress());
481          buffer.append('\'');
482        }
483    
484        buffer.append(", listenPort=");
485        buffer.append(listenPort);
486    
487        if (serverSocketFactory != null)
488        {
489          buffer.append(", serverSocketFactoryClass='");
490          buffer.append(serverSocketFactory.getClass().getName());
491          buffer.append('\'');
492        }
493    
494        if (clientSocketFactory != null)
495        {
496          buffer.append(", clientSocketFactoryClass='");
497          buffer.append(clientSocketFactory.getClass().getName());
498          buffer.append('\'');
499        }
500    
501        if (startTLSSocketFactory != null)
502        {
503          buffer.append(", startTLSSocketFactoryClass='");
504          buffer.append(startTLSSocketFactory.getClass().getName());
505          buffer.append('\'');
506        }
507    
508        buffer.append(')');
509      }
510    }