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