ConnectionConfiguration.java

  1. /**
  2.  *
  3.  * Copyright 2003-2007 Jive Software.
  4.  *
  5.  * Licensed under the Apache License, Version 2.0 (the "License");
  6.  * you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.jivesoftware.smack;

  18. import org.jivesoftware.smack.packet.Session;
  19. import org.jivesoftware.smack.proxy.ProxyInfo;
  20. import org.jxmpp.jid.DomainBareJid;

  21. import javax.net.SocketFactory;
  22. import javax.net.ssl.HostnameVerifier;
  23. import javax.net.ssl.SSLContext;
  24. import javax.security.auth.callback.CallbackHandler;

  25. /**
  26.  * Configuration to use while establishing the connection to the server.
  27.  *
  28.  * @author Gaston Dombiak
  29.  */
  30. public abstract class ConnectionConfiguration {

  31.     static {
  32.         // Ensure that Smack is initialized when ConnectionConfiguration is used, or otherwise e.g.
  33.         // SmackConfiguration.DEBUG may not be initialized yet.
  34.         SmackConfiguration.getVersion();
  35.     }

  36.     /**
  37.      * Hostname of the XMPP server. Usually servers use the same service name as the name
  38.      * of the server. However, there are some servers like google where host would be
  39.      * talk.google.com and the serviceName would be gmail.com.
  40.      */
  41.     protected final DomainBareJid serviceName;
  42.     protected final String host;
  43.     protected final int port;

  44.     private final String keystorePath;
  45.     private final String keystoreType;
  46.     private final String pkcs11Library;
  47.     private final SSLContext customSSLContext;

  48.     /**
  49.      * Used to get information from the user
  50.      */
  51.     private final CallbackHandler callbackHandler;

  52.     private final boolean debuggerEnabled;

  53.     // Holds the socket factory that is used to generate the socket in the connection
  54.     private final SocketFactory socketFactory;

  55.     private final CharSequence username;
  56.     private final String password;
  57.     private final String resource;

  58.     /**
  59.      * Initial presence as of RFC 6121 § 4.2
  60.      * @see <a href="http://xmpp.org/rfcs/rfc6121.html#presence-initial">RFC 6121 § 4.2 Initial Presence</a>
  61.      */
  62.     private final boolean sendPresence;

  63.     private final boolean legacySessionDisabled;
  64.     private final SecurityMode securityMode;

  65.     /**
  66.      *
  67.      */
  68.     private final String[] enabledSSLProtocols;

  69.     /**
  70.      *
  71.      */
  72.     private final String[] enabledSSLCiphers;

  73.     private final HostnameVerifier hostnameVerifier;

  74.     // Holds the proxy information (such as proxyhost, proxyport, username, password etc)
  75.     protected final ProxyInfo proxy;

  76.     protected final boolean allowNullOrEmptyUsername;

  77.     protected ConnectionConfiguration(Builder<?,?> builder) {
  78.         username = builder.username;
  79.         password = builder.password;
  80.         callbackHandler = builder.callbackHandler;

  81.         // Resource can be null, this means that the server must provide one
  82.         resource = builder.resource;

  83.         serviceName = builder.serviceName;
  84.         if (serviceName == null) {
  85.             throw new IllegalArgumentException("Must provide XMPP service name");
  86.         }
  87.         host = builder.host;
  88.         port = builder.port;

  89.         proxy = builder.proxy;
  90.         if (proxy != null) {
  91.             if (builder.socketFactory != null) {
  92.                 throw new IllegalArgumentException("Can not use proxy together with custom socket factory");
  93.             }
  94.             socketFactory = proxy.getSocketFactory();
  95.         } else {
  96.             socketFactory = builder.socketFactory;
  97.         }

  98.         securityMode = builder.securityMode;
  99.         keystoreType = builder.keystoreType;
  100.         keystorePath = builder.keystorePath;
  101.         pkcs11Library = builder.pkcs11Library;
  102.         customSSLContext = builder.customSSLContext;
  103.         enabledSSLProtocols = builder.enabledSSLProtocols;
  104.         enabledSSLCiphers = builder.enabledSSLCiphers;
  105.         hostnameVerifier = builder.hostnameVerifier;
  106.         sendPresence = builder.sendPresence;
  107.         legacySessionDisabled = builder.legacySessionDisabled;
  108.         debuggerEnabled = builder.debuggerEnabled;
  109.         allowNullOrEmptyUsername = builder.allowEmptyOrNullUsername;
  110.     }

  111.     /**
  112.      * Returns the server name of the target server.
  113.      *
  114.      * @return the server name of the target server.
  115.      */
  116.     public DomainBareJid getServiceName() {
  117.         return serviceName;
  118.     }

  119.     /**
  120.      * Returns the TLS security mode used when making the connection. By default,
  121.      * the mode is {@link SecurityMode#ifpossible}.
  122.      *
  123.      * @return the security mode.
  124.      */
  125.     public SecurityMode getSecurityMode() {
  126.         return securityMode;
  127.     }

  128.     /**
  129.      * Retuns the path to the keystore file. The key store file contains the
  130.      * certificates that may be used to authenticate the client to the server,
  131.      * in the event the server requests or requires it.
  132.      *
  133.      * @return the path to the keystore file.
  134.      */
  135.     public String getKeystorePath() {
  136.         return keystorePath;
  137.     }

  138.     /**
  139.      * Returns the keystore type, or <tt>null</tt> if it's not set.
  140.      *
  141.      * @return the keystore type.
  142.      */
  143.     public String getKeystoreType() {
  144.         return keystoreType;
  145.     }

  146.     /**
  147.      * Returns the PKCS11 library file location, needed when the
  148.      * Keystore type is PKCS11.
  149.      *
  150.      * @return the path to the PKCS11 library file
  151.      */
  152.     public String getPKCS11Library() {
  153.         return pkcs11Library;
  154.     }

  155.     /**
  156.      * Gets the custom SSLContext previously set with {@link ConnectionConfiguration.Builder#setCustomSSLContext(SSLContext)} for
  157.      * SSL sockets. This is null by default.
  158.      *
  159.      * @return the custom SSLContext or null.
  160.      */
  161.     public SSLContext getCustomSSLContext() {
  162.         return this.customSSLContext;
  163.     }

  164.     /**
  165.      * Return the enabled SSL/TLS protocols.
  166.      *
  167.      * @return the enabled SSL/TLS protocols
  168.      */
  169.     public String[] getEnabledSSLProtocols() {
  170.         return enabledSSLProtocols;
  171.     }

  172.     /**
  173.      * Return the enabled SSL/TLS ciphers.
  174.      *
  175.      * @return the enabled SSL/TLS ciphers
  176.      */
  177.     public String[] getEnabledSSLCiphers() {
  178.         return enabledSSLCiphers;
  179.     }

  180.     /**
  181.      * Returns the configured HostnameVerifier of this ConnectionConfiguration or the Smack default
  182.      * HostnameVerifier configured with
  183.      * {@link SmackConfiguration#setDefaultHostnameVerifier(HostnameVerifier)}.
  184.      *
  185.      * @return a configured HostnameVerifier or <code>null</code>
  186.      */
  187.     public HostnameVerifier getHostnameVerifier() {
  188.         if (hostnameVerifier != null)
  189.             return hostnameVerifier;
  190.         return SmackConfiguration.getDefaultHostnameVerifier();
  191.     }

  192.     /**
  193.      * Returns true if the new connection about to be establish is going to be debugged. By
  194.      * default the value of {@link SmackConfiguration#DEBUG} is used.
  195.      *
  196.      * @return true if the new connection about to be establish is going to be debugged.
  197.      */
  198.     public boolean isDebuggerEnabled() {
  199.         return debuggerEnabled;
  200.     }

  201.     /**
  202.      * Returns true if a {@link Session} will be requested on login if the server
  203.      * supports it. Although this was mandatory on RFC 3921, RFC 6120/6121 don't
  204.      * even mention this part of the protocol.
  205.      *
  206.      * @return true if a session has to be requested when logging in.
  207.      * @deprecated Smack processes the 'optional' element of the session stream feature.
  208.      * @see Builder#setLegacySessionDisabled(boolean)
  209.      */
  210.     @Deprecated
  211.     public boolean isLegacySessionDisabled() {
  212.         return legacySessionDisabled;
  213.     }

  214.     /**
  215.      * Returns a CallbackHandler to obtain information, such as the password or
  216.      * principal information during the SASL authentication. A CallbackHandler
  217.      * will be used <b>ONLY</b> if no password was specified during the login while
  218.      * using SASL authentication.
  219.      *
  220.      * @return a CallbackHandler to obtain information, such as the password or
  221.      * principal information during the SASL authentication.
  222.      */
  223.     public CallbackHandler getCallbackHandler() {
  224.         return callbackHandler;
  225.     }

  226.     /**
  227.      * Returns the socket factory used to create new xmppConnection sockets.
  228.      * This is useful when connecting through SOCKS5 proxies.
  229.      *
  230.      * @return socketFactory used to create new sockets.
  231.      */
  232.     public SocketFactory getSocketFactory() {
  233.         return this.socketFactory;
  234.     }

  235.     /**
  236.      * An enumeration for TLS security modes that are available when making a connection
  237.      * to the XMPP server.
  238.      */
  239.     public static enum SecurityMode {

  240.         /**
  241.          * Securirty via TLS encryption is required in order to connect. If the server
  242.          * does not offer TLS or if the TLS negotiaton fails, the connection to the server
  243.          * will fail.
  244.          */
  245.         required,

  246.         /**
  247.          * Security via TLS encryption is used whenever it's available. This is the
  248.          * default setting.
  249.          * <p>
  250.          * <b>Do not use this setting</b> unless you can't use {@link #required}. An attacker could easily perform a
  251.          * Man-in-the-middle attack and prevent TLS from being used, leaving you with an unencrypted (and
  252.          * unauthenticated) connection.
  253.          * </p>
  254.          */
  255.         ifpossible,

  256.         /**
  257.          * Security via TLS encryption is disabled and only un-encrypted connections will
  258.          * be used. If only TLS encryption is available from the server, the connection
  259.          * will fail.
  260.          */
  261.         disabled
  262.     }

  263.     /**
  264.      * Returns the username to use when trying to reconnect to the server.
  265.      *
  266.      * @return the username to use when trying to reconnect to the server.
  267.      */
  268.     public CharSequence getUsername() {
  269.         return this.username;
  270.     }

  271.     /**
  272.      * Returns the password to use when trying to reconnect to the server.
  273.      *
  274.      * @return the password to use when trying to reconnect to the server.
  275.      */
  276.     public String getPassword() {
  277.         return this.password;
  278.     }

  279.     /**
  280.      * Returns the resource to use when trying to reconnect to the server.
  281.      *
  282.      * @return the resource to use when trying to reconnect to the server.
  283.      */
  284.     public String getResource() {
  285.         return resource;
  286.     }

  287.     /**
  288.      * Returns true if an available presence should be sent when logging in while reconnecting.
  289.      *
  290.      * @return true if an available presence should be sent when logging in while reconnecting
  291.      */
  292.     public boolean isSendPresence() {
  293.         return sendPresence;
  294.     }

  295.     /**
  296.      * Returns true if the connection is going to use stream compression. Stream compression
  297.      * will be requested after TLS was established (if TLS was enabled) and only if the server
  298.      * offered stream compression. With stream compression network traffic can be reduced
  299.      * up to 90%. By default compression is disabled.
  300.      *
  301.      * @return true if the connection is going to use stream compression.
  302.      */
  303.     public boolean isCompressionEnabled() {
  304.         // Compression for non-TCP connections is always disabled
  305.         return false;
  306.     }

  307.     /**
  308.      * A builder for XMPP connection configurations.
  309.      * <p>
  310.      * This is an abstract class that uses the builder design pattern and the "getThis() trick" to recover the type of
  311.      * the builder in a class hierarchies with a self-referential generic supertype. Otherwise chaining of build
  312.      * instructions from the superclasses followed by build instructions of a sublcass would not be possible, because
  313.      * the superclass build instructions would return the builder of the superclass and not the one of the subclass. You
  314.      * can read more about it a Angelika Langer's Generics FAQ, especially the entry <a
  315.      * href="http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ206">What is the
  316.      * "getThis()" trick?</a>.
  317.      * </p>
  318.      *
  319.      * @param <B> the builder type parameter.
  320.      * @param <C> the resulting connection configuration type parameter.
  321.      */
  322.     public static abstract class Builder<B extends Builder<B, C>, C extends ConnectionConfiguration> {
  323.         private SecurityMode securityMode = SecurityMode.ifpossible;
  324.         private String keystorePath = System.getProperty("javax.net.ssl.keyStore");
  325.         private String keystoreType = "jks";
  326.         private String pkcs11Library = "pkcs11.config";
  327.         private SSLContext customSSLContext;
  328.         private String[] enabledSSLProtocols;
  329.         private String[] enabledSSLCiphers;
  330.         private HostnameVerifier hostnameVerifier;
  331.         private CharSequence username;
  332.         private String password;
  333.         private String resource = "Smack";
  334.         private boolean sendPresence = true;
  335.         private boolean legacySessionDisabled = false;
  336.         private ProxyInfo proxy;
  337.         private CallbackHandler callbackHandler;
  338.         private boolean debuggerEnabled = SmackConfiguration.DEBUG;
  339.         private SocketFactory socketFactory;
  340.         private DomainBareJid serviceName;
  341.         private String host;
  342.         private int port = 5222;
  343.         private boolean allowEmptyOrNullUsername = false;

  344.         protected Builder() {
  345.         }

  346.         /**
  347.          * Set the XMPP entities username and password.
  348.          * <p>
  349.          * The username is usually the localpart of the clients JID. But some SASL mechanisms or services may require a different
  350.          * format (e.g. the full JID) as used authorization identity.
  351.          * </p>
  352.          *
  353.          * @param username the username or authorization identity
  354.          * @param password the password or token used to authenticate
  355.          * @return a reference to this builder.
  356.          */
  357.         public B setUsernameAndPassword(CharSequence username, String password) {
  358.             this.username = username;
  359.             this.password = password;
  360.             return getThis();
  361.         }

  362.         /**
  363.          * Set the service name of this XMPP service (i.e., the XMPP domain).
  364.          *
  365.          * @param serviceName the service name
  366.          * @return a reference to this builder.
  367.          */
  368.         public B setServiceName(DomainBareJid serviceName) {
  369.             this.serviceName = serviceName;
  370.             return getThis();
  371.         }

  372.         /**
  373.          * Set the resource to use.
  374.          * <p>
  375.          * If <code>resource</code> is <code>null</code>, then the server will automatically create a resource for the
  376.          * client. Default resource is "Smack".
  377.          * </p>
  378.          *
  379.          * @param resource the resource to use.
  380.          * @return a reference to this builder.
  381.          */
  382.         public B setResource(String resource) {
  383.             this.resource = resource;
  384.             return getThis();
  385.         }

  386.         public B setHost(String host) {
  387.             this.host = host;
  388.             return getThis();
  389.         }

  390.         public B setPort(int port) {
  391.             this.port = port;
  392.             return getThis();
  393.         }

  394.         /**
  395.          * Sets a CallbackHandler to obtain information, such as the password or
  396.          * principal information during the SASL authentication. A CallbackHandler
  397.          * will be used <b>ONLY</b> if no password was specified during the login while
  398.          * using SASL authentication.
  399.          *
  400.          * @param callbackHandler to obtain information, such as the password or
  401.          * principal information during the SASL authentication.
  402.          * @return a reference to this builder.
  403.          */
  404.         public B setCallbackHandler(CallbackHandler callbackHandler) {
  405.             this.callbackHandler = callbackHandler;
  406.             return getThis();
  407.         }

  408.         /**
  409.          * Sets the TLS security mode used when making the connection. By default,
  410.          * the mode is {@link SecurityMode#ifpossible}.
  411.          *
  412.          * @param securityMode the security mode.
  413.          * @return a reference to this builder.
  414.          */
  415.         public B setSecurityMode(SecurityMode securityMode) {
  416.             this.securityMode = securityMode;
  417.             return getThis();
  418.         }

  419.         /**
  420.          * Sets the path to the keystore file. The key store file contains the
  421.          * certificates that may be used to authenticate the client to the server,
  422.          * in the event the server requests or requires it.
  423.          *
  424.          * @param keystorePath the path to the keystore file.
  425.          * @return a reference to this builder.
  426.          */
  427.         public B setKeystorePath(String keystorePath) {
  428.             this.keystorePath = keystorePath;
  429.             return getThis();
  430.         }

  431.         /**
  432.          * Sets the keystore type.
  433.          *
  434.          * @param keystoreType the keystore type.
  435.          * @return a reference to this builder.
  436.          */
  437.         public B setKeystoreType(String keystoreType) {
  438.             this.keystoreType = keystoreType;
  439.             return getThis();
  440.         }

  441.         /**
  442.          * Sets the PKCS11 library file location, needed when the
  443.          * Keystore type is PKCS11
  444.          *
  445.          * @param pkcs11Library the path to the PKCS11 library file.
  446.          * @return a reference to this builder.
  447.          */
  448.         public B setPKCS11Library(String pkcs11Library) {
  449.             this.pkcs11Library = pkcs11Library;
  450.             return getThis();
  451.         }

  452.         /**
  453.          * Sets a custom SSLContext for creating SSL sockets.
  454.          * <p>
  455.          * For more information on how to create a SSLContext see <a href=
  456.          * "http://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#X509TrustManager"
  457.          * >Java Secure Socket Extension (JSEE) Reference Guide: Creating Your Own X509TrustManager</a>
  458.          *
  459.          * @param context the custom SSLContext for new sockets.
  460.          * @return a reference to this builder.
  461.          */
  462.         public B setCustomSSLContext(SSLContext context) {
  463.             this.customSSLContext = context;
  464.             return getThis();
  465.         }

  466.         /**
  467.          * Set the enabled SSL/TLS protocols.
  468.          *
  469.          * @param enabledSSLProtocols
  470.          * @return a reference to this builder.
  471.          */
  472.         public B setEnabledSSLProtocols(String[] enabledSSLProtocols) {
  473.             this.enabledSSLProtocols = enabledSSLProtocols;
  474.             return getThis();
  475.         }

  476.         /**
  477.          * Set the enabled SSL/TLS ciphers.
  478.          *
  479.          * @param enabledSSLCiphers the enabled SSL/TLS ciphers
  480.          * @return a reference to this builder.
  481.          */
  482.         public B setEnabledSSLCiphers(String[] enabledSSLCiphers) {
  483.             this.enabledSSLCiphers = enabledSSLCiphers;
  484.             return getThis();
  485.         }

  486.         /**
  487.          * Set the HostnameVerifier used to verify the hostname of SSLSockets used by XMPP connections
  488.          * created with this ConnectionConfiguration.
  489.          *
  490.          * @param verifier
  491.          * @return a reference to this builder.
  492.          */
  493.         public B setHostnameVerifier(HostnameVerifier verifier) {
  494.             hostnameVerifier = verifier;
  495.             return getThis();
  496.         }

  497.         /**
  498.          * Sets if a {@link Session} will be requested on login if the server supports
  499.          * it. Although this was mandatory on RFC 3921, RFC 6120/6121 don't even
  500.          * mention this part of the protocol.
  501.          * <p>
  502.          * Deprecation notice: This setting is no longer required in most cases because Smack processes the 'optional'
  503.          * element eventually found in the session stream feature. See also <a
  504.          * href="https://tools.ietf.org/html/draft-cridland-xmpp-session-01">Here Lies Extensible Messaging and Presence
  505.          * Protocol (XMPP) Session Establishment</a>
  506.          * </p>
  507.          *
  508.          * @param legacySessionDisabled if a session has to be requested when logging in.
  509.          * @return a reference to this builder.
  510.          * @deprecated Smack processes the 'optional' element of the session stream feature.
  511.          */
  512.         @Deprecated
  513.         public B setLegacySessionDisabled(boolean legacySessionDisabled) {
  514.             this.legacySessionDisabled = legacySessionDisabled;
  515.             return getThis();
  516.         }

  517.         /**
  518.          * Sets if an initial available presence will be sent to the server. By default
  519.          * an available presence will be sent to the server indicating that this presence
  520.          * is not online and available to receive messages. If you want to log in without
  521.          * being 'noticed' then pass a <tt>false</tt> value.
  522.          *
  523.          * @param sendPresence true if an initial available presence will be sent while logging in.
  524.          * @return a reference to this builder.
  525.          */
  526.         public B setSendPresence(boolean sendPresence) {
  527.             this.sendPresence = sendPresence;
  528.             return getThis();
  529.         }

  530.         /**
  531.          * Sets if the new connection about to be establish is going to be debugged. By
  532.          * default the value of {@link SmackConfiguration#DEBUG} is used.
  533.          *
  534.          * @param debuggerEnabled if the new connection about to be establish is going to be debugged.
  535.          * @return a reference to this builder.
  536.          */
  537.         public B setDebuggerEnabled(boolean debuggerEnabled) {
  538.             this.debuggerEnabled = debuggerEnabled;
  539.             return getThis();
  540.         }

  541.         /**
  542.          * Sets the socket factory used to create new xmppConnection sockets.
  543.          * This is useful when connecting through SOCKS5 proxies.
  544.          *
  545.          * @param socketFactory used to create new sockets.
  546.          * @return a reference to this builder.
  547.          */
  548.         public B setSocketFactory(SocketFactory socketFactory) {
  549.             this.socketFactory = socketFactory;
  550.             return getThis();
  551.         }

  552.         /**
  553.          * Allow <code>null</code> or the empty String as username.
  554.          *
  555.          * Some SASL mechanisms (e.g. SASL External) may also signal the username (as "authorization identity"), in
  556.          * which case Smack should not throw an IllegalArgumentException when the username is not set.
  557.          *
  558.          * @return a reference to this builder.
  559.          */
  560.         public B allowEmptyOrNullUsernames() {
  561.             allowEmptyOrNullUsername = true;
  562.             return getThis();
  563.         }

  564.         public abstract C build();

  565.         protected abstract B getThis();
  566.     }
  567. }