Search in sources :

Example 1 with SparkTrustManager

use of org.jivesoftware.sparkimpl.certificates.SparkTrustManager in project Spark by igniterealtime.

the class LoginUIPanel method login.

/**
 * Login to the specified server using username, password, and workgroup.
 * Handles error representation as well as logging.
 *
 * @return true if login was successful, false otherwise
 */
private boolean login() {
    localPref = SettingsManager.getLocalPreferences();
    localPref.setLoginAsInvisible(cbLoginInvisible.isSelected());
    localPref.setLoginAnonymously(cbAnonymous.isSelected());
    if (localPref.isDebuggerEnabled()) {
        SmackConfiguration.DEBUG = true;
    }
    SmackConfiguration.setDefaultReplyTimeout(localPref.getTimeOut() * 1000);
    try {
        // TODO: SPARK-2140 - add support to Spark for stream management. Challenges expected around reconnection logic!
        XMPPTCPConnection.setUseStreamManagementDefault(false);
        connection = new XMPPTCPConnection(retrieveConnectionConfiguration());
        connection.setParsingExceptionCallback(new ExceptionLoggingCallback());
        // If we want to launch the Smack debugger, we have to check if we are on the dispatch thread, because Smack will create an UI.
        if (localPref.isDebuggerEnabled() && !EventQueue.isDispatchThread()) {
            // Exception handling should be no different from the regular flow.
            final Exception[] exception = new Exception[1];
            EventQueue.invokeAndWait(() -> {
                try {
                    connection.connect();
                } catch (IOException | SmackException | XMPPException | InterruptedException e) {
                    exception[0] = e;
                }
            });
            if (exception[0] != null) {
                throw exception[0];
            }
        } else {
            connection.connect();
        }
        if (localPref.isLoginAnonymously() && !localPref.isSSOEnabled()) {
            // ConnectionConfiguration.performSaslAnonymousAuthentication() used earlier in connection configuration builder,
            // so now we can just login()
            connection.login();
        } else {
            String resource = localPref.getResource();
            if (Default.getBoolean(Default.USE_HOSTNAME_AS_RESOURCE) || localPref.isUseHostnameAsResource()) {
                try {
                    resource = InetAddress.getLocalHost().getHostName();
                } catch (UnknownHostException e) {
                    Log.warning("Cannot set hostname as resource - unable to retrieve hostname.", e);
                }
            } else if (Default.getBoolean(Default.USE_VERSION_AS_RESOURCE) || localPref.isUseVersionAsResource()) {
                resource = JiveInfo.getName() + " " + JiveInfo.getVersion();
            }
            Resourcepart resourcepart = Resourcepart.from(modifyWildcards(resource).trim());
            connection.login(getLoginUsername(), getLoginPassword(), resourcepart);
        }
        final SessionManager sessionManager = SparkManager.getSessionManager();
        sessionManager.setServerAddress(connection.getXMPPServiceDomain());
        sessionManager.initializeSession(connection, getLoginUsername(), getLoginPassword());
        sessionManager.setJID(connection.getUser());
        final ReconnectionManager reconnectionManager = ReconnectionManager.getInstanceFor(connection);
        reconnectionManager.setFixedDelay(localPref.getReconnectDelay());
        reconnectionManager.setReconnectionPolicy(ReconnectionManager.ReconnectionPolicy.FIXED_DELAY);
        reconnectionManager.enableAutomaticReconnection();
        final CarbonManager carbonManager = CarbonManager.getInstanceFor(connection);
        if (carbonManager.isSupportedByServer()) {
            carbonManager.enableCarbons();
        }
    } catch (Exception xee) {
        Log.error("Exception in Login:", xee);
        final String errorMessage;
        if (localPref.isSSOEnabled()) {
            errorMessage = Res.getString("title.advanced.connection.sso.unable");
        } else if (xee.getMessage() != null && xee.getMessage().contains("not-authorized")) {
            errorMessage = Res.getString("message.invalid.username.password");
        } else if (xee.getMessage() != null && (xee.getMessage().contains("java.net.UnknownHostException:") || xee.getMessage().contains("Network is unreachable") || xee.getMessage().contains("java.net.ConnectException: Connection refused:"))) {
            errorMessage = Res.getString("message.server.unavailable");
        } else if (xee.getMessage() != null && xee.getMessage().contains("Hostname verification of certificate failed")) {
            errorMessage = Res.getString("message.cert.hostname.verification.failed");
        } else if (xee.getMessage() != null && xee.getMessage().contains("unable to find valid certification path to requested target")) {
            errorMessage = Res.getString("message.cert.verification.failed");
        } else if (xee.getMessage() != null && xee.getMessage().contains("StanzaError: conflict")) {
            errorMessage = Res.getString("label.conflict.error");
        } else if (xee instanceof SmackException) {
            errorMessage = xee.getLocalizedMessage();
        } else {
            errorMessage = Res.getString("message.unrecoverable.error");
        }
        EventQueue.invokeLater(() -> {
            lblProgress.setVisible(false);
            // Show error dialog
            UIManager.put("OptionPane.okButtonText", Res.getString("ok"));
            if (!loginDialog.isVisible()) {
                loginDialog.setVisible(true);
            }
            if (loginDialog.isVisible()) {
                if (xee.getMessage() != null && xee.getMessage().contains("Self Signed certificate")) {
                    // Handle specific case: if server certificate is self-signed, but self-signed certs are not allowed, show a popup allowing the user to override.
                    // Prompt user if they'd like to add the failed chain to the trust store.
                    final Object[] options = { Res.getString("yes"), Res.getString("no") };
                    final int userChoice = JOptionPane.showOptionDialog(this, Res.getString("dialog.certificate.ask.allow.self-signed"), Res.getString("title.certificate"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[1]);
                    if (userChoice == JOptionPane.YES_OPTION) {
                        // Toggle the preference.
                        localPref.setAcceptSelfSigned(true);
                        SettingsManager.saveSettings();
                        // Attempt to login again.
                        validateLogin();
                    }
                } else {
                    final X509Certificate[] lastFailedChain = SparkTrustManager.getLastFailedChain();
                    final SparkTrustManager sparkTrustManager = (SparkTrustManager) SparkTrustManager.getTrustManagerList()[0];
                    // Handle specific case: if path validation failed because of an unrecognized CA, show popup allowing the user to add the certificate.
                    if (lastFailedChain != null && ((xee.getMessage() != null && xee.getMessage().contains("Certificate not in the TrustStore")) || !sparkTrustManager.containsTrustAnchorFor(lastFailedChain))) {
                        // Prompt user if they'd like to add the failed chain to the trust store.
                        final CertificateModel certModel = new CertificateModel(lastFailedChain[0]);
                        final Object[] options = { Res.getString("yes"), Res.getString("no") };
                        final int userChoice = JOptionPane.showOptionDialog(this, new UnrecognizedServerCertificatePanel(certModel), Res.getString("title.certificate"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[1]);
                        if (userChoice == JOptionPane.YES_OPTION) {
                            // Add the certificate chain to the truststore.
                            sparkTrustManager.addChain(lastFailedChain);
                            // Attempt to login again.
                            validateLogin();
                        }
                    } else {
                        // For anything else, show a generic error dialog.
                        MessageDialog.showErrorDialog(loginDialog, errorMessage, xee);
                    }
                }
            }
        });
        setEnabled(true);
        return false;
    }
    // Since the connection and workgroup are valid. Add a ConnectionListener
    connection.addConnectionListener(SparkManager.getSessionManager());
    // Initialize chat state notification mechanism in smack
    ChatStateManager.getInstance(SparkManager.getConnection());
    // Persist information
    localPref.setLastUsername(getLoginUsername());
    // Check to see if the password should be saved or cleared from file.
    if (cbSavePassword.isSelected()) {
        try {
            localPref.setPasswordForUser(getBareJid(), getPassword());
        } catch (Exception e) {
            Log.error("Error encrypting password.", e);
        }
    } else {
        try {
            // clearPasswordForUser(getBareJid());
            localPref.clearPasswordForAllUsers();
        } catch (Exception e) {
            Log.debug("Unable to clear saved password..." + e);
        }
    }
    localPref.setSavePassword(cbSavePassword.isSelected());
    localPref.setAutoLogin(cbAutoLogin.isSelected());
    localPref.setServer(tfDomain.getText());
    SettingsManager.saveSettings();
    return true;
}
Also used : XMPPTCPConnection(org.jivesoftware.smack.tcp.XMPPTCPConnection) UnknownHostException(java.net.UnknownHostException) ReconnectionManager(org.jivesoftware.smack.ReconnectionManager) SessionManager(org.jivesoftware.spark.SessionManager) UnrecognizedServerCertificatePanel(org.jivesoftware.sparkimpl.certificates.UnrecognizedServerCertificatePanel) SmackException(org.jivesoftware.smack.SmackException) IOException(java.io.IOException) KeyStoreException(java.security.KeyStoreException) KeyManagementException(java.security.KeyManagementException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) XmppStringprepException(org.jxmpp.stringprep.XmppStringprepException) XMPPException(org.jivesoftware.smack.XMPPException) IOException(java.io.IOException) UnknownHostException(java.net.UnknownHostException) LoginException(javax.security.auth.login.LoginException) SmackException(org.jivesoftware.smack.SmackException) NamingException(javax.naming.NamingException) DocumentException(org.dom4j.DocumentException) UnrecoverableKeyException(java.security.UnrecoverableKeyException) NoSuchProviderException(java.security.NoSuchProviderException) Resourcepart(org.jxmpp.jid.parts.Resourcepart) CertificateModel(org.jivesoftware.sparkimpl.certificates.CertificateModel) ExceptionLoggingCallback(org.jivesoftware.smack.parsing.ExceptionLoggingCallback) SparkTrustManager(org.jivesoftware.sparkimpl.certificates.SparkTrustManager) XMPPException(org.jivesoftware.smack.XMPPException) CarbonManager(org.jivesoftware.smackx.carbons.CarbonManager)

Example 2 with SparkTrustManager

use of org.jivesoftware.sparkimpl.certificates.SparkTrustManager in project Spark by igniterealtime.

the class LoginUIPanel method retrieveConnectionConfiguration.

protected XMPPTCPConnectionConfiguration retrieveConnectionConfiguration() {
    int port = localPref.getXmppPort();
    int checkForPort = loginServer.indexOf(":");
    if (checkForPort != -1) {
        String portString = loginServer.substring(checkForPort + 1);
        if (ModelUtil.hasLength(portString)) {
            // Set new port.
            port = Integer.valueOf(portString);
        }
    }
    ConnectionConfiguration.SecurityMode securityMode = localPref.getSecurityMode();
    boolean useOldSSL = localPref.isSSL();
    boolean hostPortConfigured = localPref.isHostAndPortConfigured();
    ProxyInfo proxyInfo = null;
    if (localPref.isProxyEnabled()) {
        ProxyInfo.ProxyType pType = localPref.getProtocol().equals("SOCKS") ? ProxyInfo.ProxyType.SOCKS5 : ProxyInfo.ProxyType.HTTP;
        String pHost = ModelUtil.hasLength(localPref.getHost()) ? localPref.getHost() : null;
        int pPort = ModelUtil.hasLength(localPref.getPort()) ? Integer.parseInt(localPref.getPort()) : 0;
        String pUser = ModelUtil.hasLength(localPref.getProxyUsername()) ? localPref.getProxyUsername() : null;
        String pPass = ModelUtil.hasLength(localPref.getProxyPassword()) ? localPref.getProxyPassword() : null;
        if (pHost != null && pPort != 0) {
            if (pUser == null || pPass == null) {
                proxyInfo = new ProxyInfo(pType, pHost, pPort, null, null);
            } else {
                proxyInfo = new ProxyInfo(pType, pHost, pPort, pUser, pPass);
            }
        } else {
            Log.error("No proxy info found but proxy type is enabled!");
        }
    }
    DomainBareJid xmppDomain;
    try {
        xmppDomain = JidCreate.domainBareFrom(loginServer);
    } catch (XmppStringprepException e) {
        throw new IllegalStateException(e);
    }
    final XMPPTCPConnectionConfiguration.Builder builder = XMPPTCPConnectionConfiguration.builder().setUsernameAndPassword(loginUsername, loginPassword).setXmppDomain(xmppDomain).setPort(port).setSendPresence(false).setCompressionEnabled(localPref.isCompressionEnabled()).setSecurityMode(securityMode);
    if (securityMode != ConnectionConfiguration.SecurityMode.disabled && localPref.isDisableHostnameVerification()) {
        TLSUtils.disableHostnameVerificationForTlsCertificates(builder);
    }
    if (localPref.isDebuggerEnabled()) {
        builder.enableDefaultDebugger();
    }
    if (hostPortConfigured) {
        builder.setHost(localPref.getXmppHost());
    }
    if (localPref.isProxyEnabled()) {
        builder.setProxyInfo(proxyInfo);
    }
    if (securityMode != ConnectionConfiguration.SecurityMode.disabled && !useOldSSL) {
        // This use STARTTLS which starts initially plain connection to upgrade it to TLS, it use the same port as
        // plain connections which is 5222.
        SparkSSLContextCreator.Options options;
        if (localPref.isAllowClientSideAuthentication()) {
            options = SparkSSLContextCreator.Options.BOTH;
        } else {
            options = SparkSSLContextCreator.Options.ONLY_SERVER_SIDE;
        }
        try {
            SSLContext context = SparkSSLContextCreator.setUpContext(options);
            builder.setSslContextFactory(() -> {
                return context;
            });
            builder.setSecurityMode(securityMode);
            builder.setCustomX509TrustManager(new SparkTrustManager());
        } catch (NoSuchAlgorithmException | KeyManagementException | UnrecoverableKeyException | KeyStoreException | NoSuchProviderException e) {
            Log.warning("Couldnt establish secured connection", e);
        }
    }
    if (securityMode != ConnectionConfiguration.SecurityMode.disabled && useOldSSL) {
        if (!hostPortConfigured) {
            // SMACK 4.1.9 does not support XEP-0368, and does not apply a port change, if the host is not changed too.
            // Here, we force the host to be set (by doing a DNS lookup), and force the port to 5223 (which is the
            // default 'old-style' SSL port).
            DnsName serverNameDnsName = DnsName.from(loginServer);
            java.util.List<InetAddress> resolvedAddresses = DNSUtil.getDNSResolver().lookupHostAddress(serverNameDnsName, null, DnssecMode.disabled);
            if (resolvedAddresses.isEmpty()) {
                throw new RuntimeException("Could not resolve " + serverNameDnsName);
            }
            builder.setHost(resolvedAddresses.get(0).getHostName());
            builder.setPort(5223);
        }
        SparkSSLContextCreator.Options options;
        if (localPref.isAllowClientSideAuthentication()) {
            options = SparkSSLContextCreator.Options.BOTH;
        } else {
            options = SparkSSLContextCreator.Options.ONLY_SERVER_SIDE;
        }
        builder.setSocketFactory(new SparkSSLSocketFactory(options));
        // SMACK 4.1.9  does not recognize an 'old-style' SSL socket as being secure, which will cause a failure when
        // the 'required' Security Mode is defined. Here, we work around this by replacing that security mode with an
        // 'if-possible' setting.
        builder.setSecurityMode(ConnectionConfiguration.SecurityMode.ifpossible);
    }
    if (securityMode != ConnectionConfiguration.SecurityMode.disabled) {
        SASLAuthentication.registerSASLMechanism(new SASLExternalMechanism());
    }
    // SPARK-1747: Don't use the GSS-API SASL mechanism when SSO is disabled.
    SASLAuthentication.unregisterSASLMechanism(SASLGSSAPIMechanism.class.getName());
    SASLAuthentication.unregisterSASLMechanism(SASLGSSAPIv3CompatMechanism.class.getName());
    // Add the mechanism only when SSO is enabled (which allows us to register the correct one).
    if (localPref.isSSOEnabled()) {
        // SPARK-1740: Register a mechanism that's compatible with Smack 3, when requested.
        if (localPref.isSaslGssapiSmack3Compatible()) {
            // SPARK-1747: Don't use the GSSAPI mechanism when SSO is disabled.
            SASLAuthentication.registerSASLMechanism(new SASLGSSAPIv3CompatMechanism());
        } else {
            SASLAuthentication.registerSASLMechanism(new SASLGSSAPIMechanism());
        }
    }
    if (localPref.isLoginAnonymously() && !localPref.isSSOEnabled()) {
        // later login() is called without arguments
        builder.performSaslAnonymousAuthentication();
    }
    // }
    return builder.build();
}
Also used : XMPPTCPConnectionConfiguration(org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration) SparkSSLSocketFactory(org.jivesoftware.sparkimpl.certificates.SparkSSLSocketFactory) XmppStringprepException(org.jxmpp.stringprep.XmppStringprepException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) SparkSSLContextCreator(org.jivesoftware.sparkimpl.certificates.SparkSSLContextCreator) KeyManagementException(java.security.KeyManagementException) ProxyInfo(org.jivesoftware.smack.proxy.ProxyInfo) UnrecoverableKeyException(java.security.UnrecoverableKeyException) SparkTrustManager(org.jivesoftware.sparkimpl.certificates.SparkTrustManager) DomainBareJid(org.jxmpp.jid.DomainBareJid) DnsName(org.minidns.dnsname.DnsName) SSLContext(javax.net.ssl.SSLContext) KeyStoreException(java.security.KeyStoreException) XMPPTCPConnectionConfiguration(org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration) ConnectionConfiguration(org.jivesoftware.smack.ConnectionConfiguration) SASLGSSAPIv3CompatMechanism(org.jivesoftware.spark.sasl.SASLGSSAPIv3CompatMechanism) NoSuchProviderException(java.security.NoSuchProviderException) InetAddress(java.net.InetAddress) SASLExternalMechanism(org.jivesoftware.smack.sasl.javax.SASLExternalMechanism) SASLGSSAPIMechanism(org.jivesoftware.smack.sasl.javax.SASLGSSAPIMechanism)

Aggregations

KeyManagementException (java.security.KeyManagementException)2 KeyStoreException (java.security.KeyStoreException)2 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)2 NoSuchProviderException (java.security.NoSuchProviderException)2 UnrecoverableKeyException (java.security.UnrecoverableKeyException)2 SparkTrustManager (org.jivesoftware.sparkimpl.certificates.SparkTrustManager)2 XmppStringprepException (org.jxmpp.stringprep.XmppStringprepException)2 IOException (java.io.IOException)1 InetAddress (java.net.InetAddress)1 UnknownHostException (java.net.UnknownHostException)1 NamingException (javax.naming.NamingException)1 SSLContext (javax.net.ssl.SSLContext)1 LoginException (javax.security.auth.login.LoginException)1 DocumentException (org.dom4j.DocumentException)1 ConnectionConfiguration (org.jivesoftware.smack.ConnectionConfiguration)1 ReconnectionManager (org.jivesoftware.smack.ReconnectionManager)1 SmackException (org.jivesoftware.smack.SmackException)1 XMPPException (org.jivesoftware.smack.XMPPException)1 ExceptionLoggingCallback (org.jivesoftware.smack.parsing.ExceptionLoggingCallback)1 ProxyInfo (org.jivesoftware.smack.proxy.ProxyInfo)1