001/*
002 * Copyright 2011-2017 UnboundID Corp.
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2011-2017 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 */
021package com.unboundid.ldap.listener;
022
023
024
025import java.net.InetAddress;
026import javax.net.SocketFactory;
027import javax.net.ServerSocketFactory;
028import javax.net.ssl.SSLSocketFactory;
029import javax.net.ssl.SSLServerSocketFactory;
030
031import com.unboundid.ldap.sdk.LDAPException;
032import com.unboundid.ldap.sdk.ResultCode;
033import com.unboundid.util.Debug;
034import com.unboundid.util.NotMutable;
035import com.unboundid.util.StaticUtils;
036import com.unboundid.util.ThreadSafety;
037import com.unboundid.util.ThreadSafetyLevel;
038import com.unboundid.util.ssl.SSLUtil;
039import com.unboundid.util.ssl.TrustAllTrustManager;
040
041import 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)
057public 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}