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}