001/** 002 * 003 * Copyright 2003-2007 Jive Software. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.jivesoftware.smack; 019 020import org.jivesoftware.smack.packet.Session; 021import org.jivesoftware.smack.proxy.ProxyInfo; 022 023import javax.net.SocketFactory; 024import javax.net.ssl.HostnameVerifier; 025import javax.net.ssl.SSLContext; 026import javax.security.auth.callback.CallbackHandler; 027 028/** 029 * Configuration to use while establishing the connection to the server. 030 * 031 * @author Gaston Dombiak 032 */ 033public abstract class ConnectionConfiguration { 034 035 static { 036 // Ensure that Smack is initialized when ConnectionConfiguration is used, or otherwise e.g. 037 // SmackConfiguration.DEBUG may not be initialized yet. 038 SmackConfiguration.getVersion(); 039 } 040 041 /** 042 * Hostname of the XMPP server. Usually servers use the same service name as the name 043 * of the server. However, there are some servers like google where host would be 044 * talk.google.com and the serviceName would be gmail.com. 045 */ 046 protected final String serviceName; 047 protected final String host; 048 protected final int port; 049 050 private final String keystorePath; 051 private final String keystoreType; 052 private final String pkcs11Library; 053 private final SSLContext customSSLContext; 054 055 /** 056 * Used to get information from the user 057 */ 058 private final CallbackHandler callbackHandler; 059 060 private final boolean debuggerEnabled; 061 062 // Holds the socket factory that is used to generate the socket in the connection 063 private final SocketFactory socketFactory; 064 065 private final CharSequence username; 066 private final String password; 067 private final String resource; 068 069 /** 070 * Initial presence as of RFC 6121 § 4.2 071 * @see <a href="http://xmpp.org/rfcs/rfc6121.html#presence-initial">RFC 6121 § 4.2 Initial Presence</a> 072 */ 073 private final boolean sendPresence; 074 075 private final boolean legacySessionDisabled; 076 private final SecurityMode securityMode; 077 078 /** 079 * 080 */ 081 private final String[] enabledSSLProtocols; 082 083 /** 084 * 085 */ 086 private final String[] enabledSSLCiphers; 087 088 private final HostnameVerifier hostnameVerifier; 089 090 // Holds the proxy information (such as proxyhost, proxyport, username, password etc) 091 protected final ProxyInfo proxy; 092 093 protected final boolean allowNullOrEmptyUsername; 094 095 protected ConnectionConfiguration(Builder<?,?> builder) { 096 username = builder.username; 097 password = builder.password; 098 callbackHandler = builder.callbackHandler; 099 100 // Resource can be null, this means that the server must provide one 101 resource = builder.resource; 102 103 serviceName = builder.serviceName; 104 if (serviceName == null) { 105 throw new IllegalArgumentException("Must provide XMPP service name"); 106 } 107 host = builder.host; 108 port = builder.port; 109 110 proxy = builder.proxy; 111 if (proxy != null) { 112 if (builder.socketFactory != null) { 113 throw new IllegalArgumentException("Can not use proxy together with custom socket factory"); 114 } 115 socketFactory = proxy.getSocketFactory(); 116 } else { 117 socketFactory = builder.socketFactory; 118 } 119 120 securityMode = builder.securityMode; 121 keystoreType = builder.keystoreType; 122 keystorePath = builder.keystorePath; 123 pkcs11Library = builder.pkcs11Library; 124 customSSLContext = builder.customSSLContext; 125 enabledSSLProtocols = builder.enabledSSLProtocols; 126 enabledSSLCiphers = builder.enabledSSLCiphers; 127 hostnameVerifier = builder.hostnameVerifier; 128 sendPresence = builder.sendPresence; 129 legacySessionDisabled = builder.legacySessionDisabled; 130 debuggerEnabled = builder.debuggerEnabled; 131 allowNullOrEmptyUsername = builder.allowEmptyOrNullUsername; 132 } 133 134 /** 135 * Returns the server name of the target server. 136 * 137 * @return the server name of the target server. 138 */ 139 public String getServiceName() { 140 return serviceName; 141 } 142 143 /** 144 * Returns the TLS security mode used when making the connection. By default, 145 * the mode is {@link SecurityMode#ifpossible}. 146 * 147 * @return the security mode. 148 */ 149 public SecurityMode getSecurityMode() { 150 return securityMode; 151 } 152 153 /** 154 * Retuns the path to the keystore file. The key store file contains the 155 * certificates that may be used to authenticate the client to the server, 156 * in the event the server requests or requires it. 157 * 158 * @return the path to the keystore file. 159 */ 160 public String getKeystorePath() { 161 return keystorePath; 162 } 163 164 /** 165 * Returns the keystore type, or <tt>null</tt> if it's not set. 166 * 167 * @return the keystore type. 168 */ 169 public String getKeystoreType() { 170 return keystoreType; 171 } 172 173 /** 174 * Returns the PKCS11 library file location, needed when the 175 * Keystore type is PKCS11. 176 * 177 * @return the path to the PKCS11 library file 178 */ 179 public String getPKCS11Library() { 180 return pkcs11Library; 181 } 182 183 /** 184 * Gets the custom SSLContext previously set with {@link ConnectionConfiguration.Builder#setCustomSSLContext(SSLContext)} for 185 * SSL sockets. This is null by default. 186 * 187 * @return the custom SSLContext or null. 188 */ 189 public SSLContext getCustomSSLContext() { 190 return this.customSSLContext; 191 } 192 193 /** 194 * Return the enabled SSL/TLS protocols. 195 * 196 * @return the enabled SSL/TLS protocols 197 */ 198 public String[] getEnabledSSLProtocols() { 199 return enabledSSLProtocols; 200 } 201 202 /** 203 * Return the enabled SSL/TLS ciphers. 204 * 205 * @return the enabled SSL/TLS ciphers 206 */ 207 public String[] getEnabledSSLCiphers() { 208 return enabledSSLCiphers; 209 } 210 211 /** 212 * Returns the configured HostnameVerifier of this ConnectionConfiguration or the Smack default 213 * HostnameVerifier configured with 214 * {@link SmackConfiguration#setDefaultHostnameVerifier(HostnameVerifier)}. 215 * 216 * @return a configured HostnameVerifier or <code>null</code> 217 */ 218 public HostnameVerifier getHostnameVerifier() { 219 if (hostnameVerifier != null) 220 return hostnameVerifier; 221 return SmackConfiguration.getDefaultHostnameVerifier(); 222 } 223 224 /** 225 * Returns true if the new connection about to be establish is going to be debugged. By 226 * default the value of {@link SmackConfiguration#DEBUG} is used. 227 * 228 * @return true if the new connection about to be establish is going to be debugged. 229 */ 230 public boolean isDebuggerEnabled() { 231 return debuggerEnabled; 232 } 233 234 /** 235 * Returns true if a {@link Session} will be requested on login if the server 236 * supports it. Although this was mandatory on RFC 3921, RFC 6120/6121 don't 237 * even mention this part of the protocol. 238 * 239 * @return true if a session has to be requested when logging in. 240 * @deprecated Smack processes the 'optional' element of the session stream feature. 241 * @see Builder#setLegacySessionDisabled(boolean) 242 */ 243 @Deprecated 244 public boolean isLegacySessionDisabled() { 245 return legacySessionDisabled; 246 } 247 248 /** 249 * Returns a CallbackHandler to obtain information, such as the password or 250 * principal information during the SASL authentication. A CallbackHandler 251 * will be used <b>ONLY</b> if no password was specified during the login while 252 * using SASL authentication. 253 * 254 * @return a CallbackHandler to obtain information, such as the password or 255 * principal information during the SASL authentication. 256 */ 257 public CallbackHandler getCallbackHandler() { 258 return callbackHandler; 259 } 260 261 /** 262 * Returns the socket factory used to create new xmppConnection sockets. 263 * This is useful when connecting through SOCKS5 proxies. 264 * 265 * @return socketFactory used to create new sockets. 266 */ 267 public SocketFactory getSocketFactory() { 268 return this.socketFactory; 269 } 270 271 /** 272 * An enumeration for TLS security modes that are available when making a connection 273 * to the XMPP server. 274 */ 275 public static enum SecurityMode { 276 277 /** 278 * Securirty via TLS encryption is required in order to connect. If the server 279 * does not offer TLS or if the TLS negotiaton fails, the connection to the server 280 * will fail. 281 */ 282 required, 283 284 /** 285 * Security via TLS encryption is used whenever it's available. This is the 286 * default setting. 287 * <p> 288 * <b>Do not use this setting</b> unless you can't use {@link #required}. An attacker could easily perform a 289 * Man-in-the-middle attack and prevent TLS from being used, leaving you with an unencrypted (and 290 * unauthenticated) connection. 291 * </p> 292 */ 293 ifpossible, 294 295 /** 296 * Security via TLS encryption is disabled and only un-encrypted connections will 297 * be used. If only TLS encryption is available from the server, the connection 298 * will fail. 299 */ 300 disabled 301 } 302 303 /** 304 * Returns the username to use when trying to reconnect to the server. 305 * 306 * @return the username to use when trying to reconnect to the server. 307 */ 308 public CharSequence getUsername() { 309 return this.username; 310 } 311 312 /** 313 * Returns the password to use when trying to reconnect to the server. 314 * 315 * @return the password to use when trying to reconnect to the server. 316 */ 317 public String getPassword() { 318 return this.password; 319 } 320 321 /** 322 * Returns the resource to use when trying to reconnect to the server. 323 * 324 * @return the resource to use when trying to reconnect to the server. 325 */ 326 public String getResource() { 327 return resource; 328 } 329 330 /** 331 * Returns true if an available presence should be sent when logging in while reconnecting. 332 * 333 * @return true if an available presence should be sent when logging in while reconnecting 334 */ 335 public boolean isSendPresence() { 336 return sendPresence; 337 } 338 339 /** 340 * Returns true if the connection is going to use stream compression. Stream compression 341 * will be requested after TLS was established (if TLS was enabled) and only if the server 342 * offered stream compression. With stream compression network traffic can be reduced 343 * up to 90%. By default compression is disabled. 344 * 345 * @return true if the connection is going to use stream compression. 346 */ 347 public boolean isCompressionEnabled() { 348 // Compression for non-TCP connections is always disabled 349 return false; 350 } 351 352 /** 353 * A builder for XMPP connection configurations. 354 * <p> 355 * This is an abstract class that uses the builder design pattern and the "getThis() trick" to recover the type of 356 * the builder in a class hierarchies with a self-referential generic supertype. Otherwise chaining of build 357 * instructions from the superclasses followed by build instructions of a sublcass would not be possible, because 358 * the superclass build instructions would return the builder of the superclass and not the one of the subclass. You 359 * can read more about it a Angelika Langer's Generics FAQ, especially the entry <a 360 * href="http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ206">What is the 361 * "getThis()" trick?</a>. 362 * </p> 363 * 364 * @param <B> the builder type parameter. 365 * @param <C> the resulting connection configuration type parameter. 366 */ 367 public static abstract class Builder<B extends Builder<B, C>, C extends ConnectionConfiguration> { 368 private SecurityMode securityMode = SecurityMode.ifpossible; 369 private String keystorePath = System.getProperty("javax.net.ssl.keyStore"); 370 private String keystoreType = "jks"; 371 private String pkcs11Library = "pkcs11.config"; 372 private SSLContext customSSLContext; 373 private String[] enabledSSLProtocols; 374 private String[] enabledSSLCiphers; 375 private HostnameVerifier hostnameVerifier; 376 private CharSequence username; 377 private String password; 378 private String resource = "Smack"; 379 private boolean sendPresence = true; 380 private boolean legacySessionDisabled = false; 381 private ProxyInfo proxy; 382 private CallbackHandler callbackHandler; 383 private boolean debuggerEnabled = SmackConfiguration.DEBUG; 384 private SocketFactory socketFactory; 385 private String serviceName; 386 private String host; 387 private int port = 5222; 388 private boolean allowEmptyOrNullUsername = false; 389 390 protected Builder() { 391 } 392 393 /** 394 * Set the XMPP entities username and password. 395 * <p> 396 * The username is usually the localpart of the clients JID. But some SASL mechanisms or services may require a different 397 * format (e.g. the full JID) as used authorization identity. 398 * </p> 399 * 400 * @param username the username or authorization identity 401 * @param password the password or token used to authenticate 402 * @return a reference to this builder. 403 */ 404 public B setUsernameAndPassword(CharSequence username, String password) { 405 this.username = username; 406 this.password = password; 407 return getThis(); 408 } 409 410 /** 411 * Set the service name of this XMPP service (i.e., the XMPP domain). 412 * 413 * @param serviceName the service name 414 * @return a reference to this builder. 415 */ 416 public B setServiceName(String serviceName) { 417 this.serviceName = serviceName; 418 return getThis(); 419 } 420 421 /** 422 * Set the resource to use. 423 * <p> 424 * If <code>resource</code> is <code>null</code>, then the server will automatically create a resource for the 425 * client. Default resource is "Smack". 426 * </p> 427 * 428 * @param resource the resource to use. 429 * @return a reference to this builder. 430 */ 431 public B setResource(String resource) { 432 this.resource = resource; 433 return getThis(); 434 } 435 436 public B setHost(String host) { 437 this.host = host; 438 return getThis(); 439 } 440 441 public B setPort(int port) { 442 this.port = port; 443 return getThis(); 444 } 445 446 /** 447 * Sets a CallbackHandler to obtain information, such as the password or 448 * principal information during the SASL authentication. A CallbackHandler 449 * will be used <b>ONLY</b> if no password was specified during the login while 450 * using SASL authentication. 451 * 452 * @param callbackHandler to obtain information, such as the password or 453 * principal information during the SASL authentication. 454 * @return a reference to this builder. 455 */ 456 public B setCallbackHandler(CallbackHandler callbackHandler) { 457 this.callbackHandler = callbackHandler; 458 return getThis(); 459 } 460 461 /** 462 * Sets the TLS security mode used when making the connection. By default, 463 * the mode is {@link SecurityMode#ifpossible}. 464 * 465 * @param securityMode the security mode. 466 * @return a reference to this builder. 467 */ 468 public B setSecurityMode(SecurityMode securityMode) { 469 this.securityMode = securityMode; 470 return getThis(); 471 } 472 473 /** 474 * Sets the path to the keystore file. The key store file contains the 475 * certificates that may be used to authenticate the client to the server, 476 * in the event the server requests or requires it. 477 * 478 * @param keystorePath the path to the keystore file. 479 * @return a reference to this builder. 480 */ 481 public B setKeystorePath(String keystorePath) { 482 this.keystorePath = keystorePath; 483 return getThis(); 484 } 485 486 /** 487 * Sets the keystore type. 488 * 489 * @param keystoreType the keystore type. 490 * @return a reference to this builder. 491 */ 492 public B setKeystoreType(String keystoreType) { 493 this.keystoreType = keystoreType; 494 return getThis(); 495 } 496 497 /** 498 * Sets the PKCS11 library file location, needed when the 499 * Keystore type is PKCS11 500 * 501 * @param pkcs11Library the path to the PKCS11 library file. 502 * @return a reference to this builder. 503 */ 504 public B setPKCS11Library(String pkcs11Library) { 505 this.pkcs11Library = pkcs11Library; 506 return getThis(); 507 } 508 509 /** 510 * Sets a custom SSLContext for creating SSL sockets. 511 * <p> 512 * For more information on how to create a SSLContext see <a href= 513 * "http://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#X509TrustManager" 514 * >Java Secure Socket Extension (JSEE) Reference Guide: Creating Your Own X509TrustManager</a> 515 * 516 * @param context the custom SSLContext for new sockets. 517 * @return a reference to this builder. 518 */ 519 public B setCustomSSLContext(SSLContext context) { 520 this.customSSLContext = context; 521 return getThis(); 522 } 523 524 /** 525 * Set the enabled SSL/TLS protocols. 526 * 527 * @param enabledSSLProtocols 528 * @return a reference to this builder. 529 */ 530 public B setEnabledSSLProtocols(String[] enabledSSLProtocols) { 531 this.enabledSSLProtocols = enabledSSLProtocols; 532 return getThis(); 533 } 534 535 /** 536 * Set the enabled SSL/TLS ciphers. 537 * 538 * @param enabledSSLCiphers the enabled SSL/TLS ciphers 539 * @return a reference to this builder. 540 */ 541 public B setEnabledSSLCiphers(String[] enabledSSLCiphers) { 542 this.enabledSSLCiphers = enabledSSLCiphers; 543 return getThis(); 544 } 545 546 /** 547 * Set the HostnameVerifier used to verify the hostname of SSLSockets used by XMPP connections 548 * created with this ConnectionConfiguration. 549 * 550 * @param verifier 551 * @return a reference to this builder. 552 */ 553 public B setHostnameVerifier(HostnameVerifier verifier) { 554 hostnameVerifier = verifier; 555 return getThis(); 556 } 557 558 /** 559 * Sets if a {@link Session} will be requested on login if the server supports 560 * it. Although this was mandatory on RFC 3921, RFC 6120/6121 don't even 561 * mention this part of the protocol. 562 * <p> 563 * Deprecation notice: This setting is no longer required in most cases because Smack processes the 'optional' 564 * element eventually found in the session stream feature. See also <a 565 * href="https://tools.ietf.org/html/draft-cridland-xmpp-session-01">Here Lies Extensible Messaging and Presence 566 * Protocol (XMPP) Session Establishment</a> 567 * </p> 568 * 569 * @param legacySessionDisabled if a session has to be requested when logging in. 570 * @return a reference to this builder. 571 * @deprecated Smack processes the 'optional' element of the session stream feature. 572 */ 573 @Deprecated 574 public B setLegacySessionDisabled(boolean legacySessionDisabled) { 575 this.legacySessionDisabled = legacySessionDisabled; 576 return getThis(); 577 } 578 579 /** 580 * Sets if an initial available presence will be sent to the server. By default 581 * an available presence will be sent to the server indicating that this presence 582 * is not online and available to receive messages. If you want to log in without 583 * being 'noticed' then pass a <tt>false</tt> value. 584 * 585 * @param sendPresence true if an initial available presence will be sent while logging in. 586 * @return a reference to this builder. 587 */ 588 public B setSendPresence(boolean sendPresence) { 589 this.sendPresence = sendPresence; 590 return getThis(); 591 } 592 593 /** 594 * Sets if the new connection about to be establish is going to be debugged. By 595 * default the value of {@link SmackConfiguration#DEBUG} is used. 596 * 597 * @param debuggerEnabled if the new connection about to be establish is going to be debugged. 598 * @return a reference to this builder. 599 */ 600 public B setDebuggerEnabled(boolean debuggerEnabled) { 601 this.debuggerEnabled = debuggerEnabled; 602 return getThis(); 603 } 604 605 /** 606 * Sets the socket factory used to create new xmppConnection sockets. 607 * This is useful when connecting through SOCKS5 proxies. 608 * 609 * @param socketFactory used to create new sockets. 610 * @return a reference to this builder. 611 */ 612 public B setSocketFactory(SocketFactory socketFactory) { 613 this.socketFactory = socketFactory; 614 return getThis(); 615 } 616 617 /** 618 * Set the information about the Proxy used for the connection. 619 * 620 * @param proxyInfo the Proxy information. 621 * @return a reference to this builder. 622 */ 623 public B setProxyInfo(ProxyInfo proxyInfo) { 624 this.proxy = proxyInfo; 625 return getThis(); 626 } 627 628 /** 629 * Allow <code>null</code> or the empty String as username. 630 * 631 * Some SASL mechanisms (e.g. SASL External) may also signal the username (as "authorization identity"), in 632 * which case Smack should not throw an IllegalArgumentException when the username is not set. 633 * 634 * @return a reference to this builder. 635 */ 636 public B allowEmptyOrNullUsernames() { 637 allowEmptyOrNullUsername = true; 638 return getThis(); 639 } 640 641 public abstract C build(); 642 643 protected abstract B getThis(); 644 } 645}