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