From 222379eaa32af589f746774a496d6fea0dcc83a4 Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sat, 14 Sep 2024 21:00:23 +0300 Subject: [PATCH 1/7] LoginDialog: remove unused TitlePanel.ImagePanel and its bg image --- .../spark/component/TitlePanel.java | 32 ------------------ core/src/main/resources/default.properties | 1 - core/src/main/resources/images/steel.png | Bin 1638 -> 0 bytes 3 files changed, 33 deletions(-) delete mode 100644 core/src/main/resources/images/steel.png diff --git a/core/src/main/java/org/jivesoftware/spark/component/TitlePanel.java b/core/src/main/java/org/jivesoftware/spark/component/TitlePanel.java index 3dad19de7..7ddcf0ad0 100644 --- a/core/src/main/java/org/jivesoftware/spark/component/TitlePanel.java +++ b/core/src/main/java/org/jivesoftware/spark/component/TitlePanel.java @@ -15,25 +15,16 @@ */ package org.jivesoftware.spark.component; -import org.jivesoftware.resource.Default; - import java.awt.Color; import java.awt.Font; -import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; -import java.awt.Image; import java.awt.Insets; -import java.awt.LayoutManager; -import java.awt.geom.AffineTransform; import javax.swing.BorderFactory; import javax.swing.Icon; -import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JPanel; -import javax.swing.SwingUtilities; /** * TitlePanel class is the top panel displayed in this application. @@ -128,28 +119,5 @@ public final void setDescription(String desc) { } descriptionLabel.setText(desc); } - - public static class ImagePanel extends JPanel { - private static final long serialVersionUID = 5155908601530113727L; - final ImageIcon icons = Default.getImageIcon(Default.SECONDARY_BACKGROUND_IMAGE); - - public ImagePanel() { - - } - - public ImagePanel(LayoutManager layout) { - super(layout); - } - - @Override - public void paintComponent(Graphics g) { - Image backgroundImage = icons.getImage(); - double scaleX = getWidth() / (double) backgroundImage.getWidth(null); - double scaleY = getHeight() / (double) backgroundImage.getHeight(null); - AffineTransform xform = AffineTransform.getScaleInstance(scaleX, scaleY); - ((Graphics2D) g).drawImage(backgroundImage, xform, this); - } - } - } diff --git a/core/src/main/resources/default.properties b/core/src/main/resources/default.properties index dfa076bc2..9b517b6c1 100644 --- a/core/src/main/resources/default.properties +++ b/core/src/main/resources/default.properties @@ -12,7 +12,6 @@ USER_DIRECTORY_MAC = Library/Application Support/Spark LOGIN_DIALOG_BACKGROUND_IMAGE = images/login_dialog_background.png TOP_BOTTOM_BACKGROUND_IMAGE = images/top_bottom_background_image.png -SECONDARY_BACKGROUND_IMAGE = images/steel.png # Specify a fixed Hostname # Changing the Hostname will also be prohibited if set diff --git a/core/src/main/resources/images/steel.png b/core/src/main/resources/images/steel.png deleted file mode 100644 index 306eb8a09d2dfc18af0d898e088daca14908f643..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1638 zcmbVNJ#XAL7*?AGa8no^x)fbXC_@so6iI#EiH(vvcW&;A$~Bw=>}=&xygR{?sED%f z>?KHn4%s@V{R3UH6&*bE4`k{Z6e!T4lhLtjsrwL|z)pe)(upD;KJW8>@V&>|TX)y5 zd~(GwjP-u6yQANq*3a6z`uE3Yk8=Hbzv$gphVj8i_4AJL z4X!vS)4B1OBaw|^#kaN*$ za8wAiBa}QSx!63^GOyO&6tq(cR>^W8Wx7h#_DV9aiDiT9yGb6)sk(7ygXpqKgl3&J zNHD~~fDr1oDZ!s%hhn^dMlw!DM-7xftZxl%QQM`S^8!?tOw20wT5!ziNR}DX4ksBK z3smG|6EtC@9hu5f8`kQav-ABAU))>D(gM)TQpr zUl0E{(LMb}zq>K$JwAQ5v2GY^?}1+*{^R`c(}!zcUi-ySyU$M#PyWn*dwz=kyPU#H WU;Op-(v$k1puf4*eR}7+@Baq_jQjZj From 019ca9d685b5d85418fafe9bb51ea46cadb0755b Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sat, 14 Sep 2024 22:41:00 +0300 Subject: [PATCH 2/7] LoginUIPanel: copy header from LoginDialog --- .../org/jivesoftware/gui/LoginUIPanel.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/jivesoftware/gui/LoginUIPanel.java b/core/src/main/java/org/jivesoftware/gui/LoginUIPanel.java index ab564fbbf..33ef237a5 100644 --- a/core/src/main/java/org/jivesoftware/gui/LoginUIPanel.java +++ b/core/src/main/java/org/jivesoftware/gui/LoginUIPanel.java @@ -1,7 +1,17 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. +/** + * Copyright (C) 2004-2011 Jive Software. All rights reserved. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.jivesoftware.gui; @@ -130,7 +140,8 @@ import org.minidns.record.A; /** - * + * Dialog to log in a user into the XMPP server. + * The LoginDialog is used only for login in registered users into the XMPP server. * @author KeepToo */ public class LoginUIPanel extends javax.swing.JPanel implements KeyListener, ActionListener, FocusListener, CallbackHandler { From 4de57dd4b0ca60ebeaaff459075161dc30c1f6d4 Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sat, 14 Sep 2024 22:42:19 +0300 Subject: [PATCH 3/7] remove unused LoginDialog because it was replaced with LoginUIPanel --- .../java/org/jivesoftware/LoginDialog.java | 1634 ----------------- .../spark/util/UIComponentRegistry.java | 1 - 2 files changed, 1635 deletions(-) delete mode 100644 core/src/main/java/org/jivesoftware/LoginDialog.java diff --git a/core/src/main/java/org/jivesoftware/LoginDialog.java b/core/src/main/java/org/jivesoftware/LoginDialog.java deleted file mode 100644 index ed24cb482..000000000 --- a/core/src/main/java/org/jivesoftware/LoginDialog.java +++ /dev/null @@ -1,1634 +0,0 @@ -/** - * Copyright (C) 2004-2011 Jive Software. All rights reserved. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jivesoftware; - -import org.dom4j.Document; -import org.dom4j.DocumentException; -import org.dom4j.Element; -import org.dom4j.io.SAXReader; -import org.jivesoftware.resource.Default; -import org.jivesoftware.resource.Res; -import org.jivesoftware.resource.SparkRes; -import org.jivesoftware.smack.*; -import org.jivesoftware.smack.ConnectionConfiguration.DnssecMode; -import org.jivesoftware.smack.parsing.ExceptionLoggingCallback; -import org.jivesoftware.smack.proxy.ProxyInfo; -import org.jivesoftware.smack.sasl.javax.SASLExternalMechanism; -import org.jivesoftware.smack.sasl.javax.SASLGSSAPIMechanism; -import org.jivesoftware.smack.tcp.XMPPTCPConnection; -import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration; -import org.jivesoftware.smack.util.DNSUtil; -import org.jivesoftware.smack.util.TLSUtils; -import org.jivesoftware.smackx.carbons.CarbonManager; -import org.jivesoftware.smackx.chatstates.ChatStateManager; -import org.jivesoftware.spark.PluginManager; -import org.jivesoftware.spark.SessionManager; -import org.jivesoftware.spark.SparkManager; -import org.jivesoftware.spark.Workspace; -import org.jivesoftware.spark.component.MessageDialog; -import org.jivesoftware.spark.component.RolloverButton; -import org.jivesoftware.spark.sasl.SASLGSSAPIv3CompatMechanism; -import org.jivesoftware.spark.ui.login.GSSAPIConfiguration; -import org.jivesoftware.spark.ui.login.LoginSettingDialog; -import org.jivesoftware.spark.util.*; -import org.jivesoftware.spark.util.SwingWorker; -import org.jivesoftware.spark.util.log.Log; -import org.jivesoftware.sparkimpl.certificates.*; -import org.jivesoftware.sparkimpl.plugin.manager.Enterprise; -import org.jivesoftware.sparkimpl.plugin.layout.LayoutSettings; -import org.jivesoftware.sparkimpl.plugin.layout.LayoutSettingsManager; -import org.jivesoftware.sparkimpl.settings.JiveInfo; -import org.jivesoftware.sparkimpl.settings.local.LocalPreferences; -import org.jivesoftware.sparkimpl.settings.local.SettingsManager; -import org.jxmpp.jid.DomainBareJid; -import org.jxmpp.jid.impl.JidCreate; -import org.jxmpp.jid.parts.Resourcepart; -import org.jxmpp.stringprep.XmppStringprepException; -import org.jxmpp.util.XmppStringUtils; -import org.minidns.dnsname.DnsName; - -import javax.naming.NamingException; -import javax.naming.directory.Attribute; -import javax.naming.directory.Attributes; -import javax.naming.directory.DirContext; -import javax.naming.directory.InitialDirContext; -import javax.net.ssl.SSLContext; -import javax.security.auth.Subject; -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.login.Configuration; -import javax.security.auth.login.LoginContext; -import javax.security.auth.login.LoginException; -import javax.swing.*; -import javax.swing.text.JTextComponent; -import java.awt.*; -import java.awt.event.*; -import java.awt.geom.AffineTransform; -import java.io.File; -import java.io.IOException; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.security.KeyManagementException; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.Principal; -import java.security.UnrecoverableKeyException; -import java.security.cert.X509Certificate; -import java.util.*; -import java.util.List; - -import static org.jivesoftware.spark.util.StringUtils.modifyWildcards; -import static org.jivesoftware.sparkimpl.certificates.SparkSSLContextCreator.Options.BOTH; -import static org.jivesoftware.sparkimpl.certificates.SparkSSLContextCreator.Options.ONLY_SERVER_SIDE; - -/** - * Dialog to log in a user into the Spark Server. The LoginDialog is used only - * for login in registered users into the Spark Server. - */ -public class LoginDialog { - private JFrame loginDialog; - private static final String BUTTON_PANEL = "buttonpanel"; // NOTRANS - private static final String PROGRESS_BAR = "progressbar"; // NOTRANS - private LocalPreferences localPref; - private final ArrayList _usernames = new ArrayList<>(); - private String loginUsername; - private String loginPassword; - private String loginServer; - - /** - * Empty Constructor - */ - public LoginDialog() { - localPref = SettingsManager.getLocalPreferences(); - - // Check if upgraded needed. - try { - checkForOldSettings(); - } catch (Exception e) { - Log.error(e); - } - } - - /** - * Invokes the LoginDialog to be visible. - * - * @param parentFrame the parentFrame of the Login Dialog. This is used - * for correct parenting. - */ - public void invoke(final JFrame parentFrame) { - // Before creating any connections. Update proxy if needed. - try { - updateProxyConfig(); - } catch (Exception e) { - Log.error(e); - } - - // Construct Dialog - EventQueue.invokeLater(() -> { - loginDialog = new JFrame(JiveInfo.getName()); - loginDialog.setIconImage(SparkManager.getApplicationImage().getImage()); - LoginPanel loginPanel = new LoginPanel(); - final JPanel mainPanel = new LoginBackgroundPanel(); - final GridBagLayout mainLayout = new GridBagLayout(); - mainPanel.setLayout(mainLayout); - - final ImagePanel imagePanel = new ImagePanel(); - - mainPanel.add(imagePanel, - new GridBagConstraints(0, 0, 4, 1, - 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, - new Insets(0, 0, 0, 0), 0, 0)); - - final boolean showPoweredBy = Default.getBoolean(Default.SHOW_POWERED_BY); - if (showPoweredBy) { - // Handle Powered By for custom clients. - final JLabel poweredBy = new JLabel(SparkRes.getImageIcon(SparkRes.POWERED_BY_IMAGE)); - mainPanel.add(poweredBy, - new GridBagConstraints(0, 1, 4, 1, - 1.0, 0.0, GridBagConstraints.NORTHEAST, GridBagConstraints.HORIZONTAL, - new Insets(0, 0, 2, 0), 0, 0)); - - } - - loginPanel.setOpaque(false); - mainPanel.add(loginPanel, - new GridBagConstraints(0, 2, 2, 1, - 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, - new Insets(0, 0, 2, 0), 0, 20)); - - loginDialog.setContentPane(mainPanel); - loginDialog.setLocationRelativeTo(parentFrame); - - loginDialog.setResizable(false); - loginDialog.pack(); - - // Center dialog on screen - GraphicUtils.centerWindowOnScreen(loginDialog); - - // Show dialog - loginDialog.addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - quitLogin(); - } - }); - if (ModelUtil.hasLength(loginPanel.getUsername())) { - loginPanel.getPasswordField().requestFocus(); - } - - if (!localPref.isStartedHidden() || !localPref.isAutoLogin()) { - // Make dialog top most. - loginDialog.setVisible(true); - } - }); - - } - - //This method can be overwritten by subclasses to provide additional validations - //(such as certificate download functionality when connecting) - protected boolean beforeLoginValidations() { - return true; - } - - protected void afterLogin() { - // Make certain Enterprise features persist across future logins - persistEnterprise(); - - // Load plugins before Workspace initialization to avoid any UI delays during plugin rendering, but after - // Enterprise initialization, which can pull in additional plugin configuration (eg: blacklist). - PluginManager.getInstance().loadPlugins(); - - // Initialize and write default values from "Advanced Connection Preferences" to disk - initAdvancedDefaults(); - } - - 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.parseInt(portString); - } - } - - ConnectionConfiguration.SecurityMode securityMode = localPref.getSecurityMode(); - boolean useDirectTls = localPref.isDirectTls(); - 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 (localPref.isDebuggerEnabled()) { - builder.enableDefaultDebugger(); - } - - if (hostPortConfigured) { - builder.setHost(localPref.getXmppHost()); - } - - if (localPref.isProxyEnabled()) { - builder.setProxyInfo(proxyInfo); - } - configureConnectionTls(builder, securityMode, useDirectTls, hostPortConfigured, loginServer); - - // 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(); - } - - // TODO These were used in Smack 3. Find Smack 4 alternative. -// config.setRosterLoadedAtLogin(true); -// if(ModelUtil.hasLength(localPref.getTrustStorePath())) { -// config.setTruststorePath(localPref.getTrustStorePath()); -// config.setTruststorePassword(localPref.getTrustStorePassword()); -// } - return builder.build(); - } - - private void configureConnectionTls(XMPPTCPConnectionConfiguration.Builder builder, ConnectionConfiguration.SecurityMode securityMode, boolean useDirectTls, boolean hostPortConfigured, String serverName) { - if (securityMode != ConnectionConfiguration.SecurityMode.disabled) { - if (localPref.isDisableHostnameVerification()) { - TLSUtils.disableHostnameVerificationForTlsCertificates(builder); - } - if (!useDirectTls) { - // 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 = localPref.isAllowClientSideAuthentication() ? BOTH : ONLY_SERVER_SIDE; - try { - SSLContext context = SparkSSLContextCreator.setUpContext(options); - builder.setSslContextFactory(() -> context); - builder.setSecurityMode(securityMode); - builder.setCustomX509TrustManager(new SparkTrustManager()); - } catch (NoSuchAlgorithmException | KeyManagementException | UnrecoverableKeyException | KeyStoreException | NoSuchProviderException e) { - Log.warning("Could not establish secured connection", e); - } - } else { // useDirectTls - 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(serverName); - java.util.List 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 = localPref.isAllowClientSideAuthentication() ? BOTH : 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); - } - SASLAuthentication.registerSASLMechanism(new SASLExternalMechanism()); - } - } - - /** - * Define Login Panel implementation. - */ - private final class LoginPanel extends JPanel implements KeyListener, ActionListener, FocusListener, CallbackHandler { - private static final long serialVersionUID = 2445523786538863459L; - private final JLabel usernameLabel = new JLabel(); - private final JTextField usernameField = new JTextField(); - - private final JLabel passwordLabel = new JLabel(); - private final JPasswordField passwordField = new JPasswordField(); - - private final JLabel serverLabel = new JLabel(); - private final JTextField serverField = new JTextField(); - - private final JCheckBox savePasswordBox = new JCheckBox(); - private final JCheckBox autoLoginBox = new JCheckBox(); - private final RolloverButton loginButton = new RolloverButton(); - private final RolloverButton advancedButton = new RolloverButton(); - private final RolloverButton quitButton = new RolloverButton(); - private final JCheckBox loginAsInvisibleBox = new JCheckBox(); - private final JCheckBox loginAnonymouslyBox = new JCheckBox(); - - private final RolloverButton createAccountButton = new RolloverButton(); - private final RolloverButton passwordResetButton = new RolloverButton(); - - private final JLabel progressBar = new JLabel(); - - // Panel used to hold buttons - private final CardLayout cardLayout = new CardLayout(0, 5); - final JPanel cardPanel = new JPanel(cardLayout); - - final JPanel buttonPanel = new JPanel(new GridBagLayout()); - private final GridBagLayout GRIDBAGLAYOUT = new GridBagLayout(); - private AbstractXMPPConnection connection = null; - - private final JLabel headerLabel = new JLabel(); - private final JLabel accountLabel = new JLabel(); - private final JLabel accountNameLabel = new JLabel(); - private final JLabel serverNameLabel = new JLabel(); - private final JLabel ssoServerLabel = new JLabel(); - - private final RolloverButton otherUsers = new RolloverButton(SparkRes.getImageIcon(SparkRes.PANE_UP_ARROW_IMAGE)); - - - LoginPanel() { - //setBorder(BorderFactory.createTitledBorder("Sign In Now")); - ResourceUtils.resButton(savePasswordBox, Res.getString("checkbox.save.password")); - ResourceUtils.resButton(autoLoginBox, Res.getString("checkbox.auto.login")); - ResourceUtils.resLabel(serverLabel, serverField, Res.getString("label.server")); - ResourceUtils.resButton(createAccountButton, Res.getString("label.accounts")); - ResourceUtils.resButton(passwordResetButton, Res.getString("label.passwordreset")); - ResourceUtils.resButton(loginAsInvisibleBox, Res.getString("checkbox.login.as.invisible")); - ResourceUtils.resButton(loginAnonymouslyBox, Res.getString("checkbox.login.anonymously")); - - savePasswordBox.setOpaque(false); - autoLoginBox.setOpaque(false); - loginAsInvisibleBox.setOpaque(false); - loginAnonymouslyBox.setOpaque(false); - setLayout(GRIDBAGLAYOUT); - - // Set default visibility - headerLabel.setVisible(false); - accountLabel.setVisible(false); - accountNameLabel.setVisible(false); - serverNameLabel.setVisible(false); - - headerLabel.setText(Res.getString("title.advanced.connection.sso")); - headerLabel.setFont(headerLabel.getFont().deriveFont(Font.BOLD)); - accountLabel.setText("Account:"); - ssoServerLabel.setText("Server:"); - accountNameLabel.setFont(accountLabel.getFont().deriveFont(Font.BOLD)); - serverNameLabel.setFont(ssoServerLabel.getFont().deriveFont(Font.BOLD)); - - accountNameLabel.setForeground(new Color(106, 127, 146)); - serverNameLabel.setForeground(new Color(106, 127, 146)); - - otherUsers.setFocusable(false); - - add(usernameLabel, - new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, - GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 0, 5), 0, 0)); - add(usernameField, - new GridBagConstraints(1, 0, 2, 1, - 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, - new Insets(5, 5, 0, 0), 0, 0)); - - add(otherUsers, new GridBagConstraints(3, 0, 1, 1, - 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, - new Insets(5, 0, 0, 0), 0, 0)); - - add(accountLabel, - new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, - GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 0, 5), 0, 0)); - add(accountNameLabel, - new GridBagConstraints(1, 1, 1, 1, - 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, - new Insets(5, 5, 0, 5), 0, 0)); - - add(passwordLabel, - new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, - GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 0, 5), 5, 0)); - add(passwordField, - new GridBagConstraints(1, 1, 2, 1, - 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, - new Insets(5, 5, 0, 0), 0, 0)); - - // Add Server Field Properties - add(serverLabel, - new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, - GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 0, 5), 5, 0)); - add(serverField, - new GridBagConstraints(1, 2, 2, 1, - 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, - new Insets(5, 5, 0, 0), 0, 0)); - - add(serverNameLabel, - new GridBagConstraints(1, 2, 2, 1, - 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, - new Insets(5, 5, 0, 5), 0, 0)); - - add(headerLabel, - new GridBagConstraints(0, 5, 2, 1, 1.0, 0.0, - GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); - - if (!Default.getBoolean(Default.HIDE_SAVE_PASSWORD_AND_AUTO_LOGIN) && localPref.getPswdAutologin()) { - add(savePasswordBox, - new GridBagConstraints(1, 5, 2, 1, 1.0, 0.0, - GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0)); - add(autoLoginBox, - new GridBagConstraints(1, 6, 2, 1, 1.0, 0.0, - GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0)); - } - - // Add option to hide "Login as invisible" selection on the login screen - if (!Default.getBoolean(Default.HIDE_LOGIN_AS_INVISIBLE) && localPref.getInvisibleLogin()) { - add(loginAsInvisibleBox, - new GridBagConstraints(1, 7, 2, 1, 1.0, 0.0, - GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0)); - } - - // Add option to hide "Login anonymously" selection on the login screen - if (!Default.getBoolean(Default.HIDE_LOGIN_ANONYMOUSLY) && localPref.getAnonymousLogin()) { - add(loginAnonymouslyBox, - new GridBagConstraints(1, 8, 2, 1, 1.0, 0.0, - GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0)); - } - - // Add button but disable the login button initially - savePasswordBox.addActionListener(this); - autoLoginBox.addActionListener(this); - loginAsInvisibleBox.addActionListener(this); - loginAnonymouslyBox.addActionListener(this); - - if (!Default.getBoolean(Default.ACCOUNT_DISABLED) && localPref.getAccountsReg()) { - buttonPanel.add(createAccountButton, - new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, - GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 0, 5), 0, 0)); - } - - if (Default.getBoolean(Default.PASSWORD_RESET_ENABLED)) { - buttonPanel.add(passwordResetButton, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 0, 5), 0, 0)); - passwordResetButton.addActionListener(new ActionListener() { - final String url = Default.getString(Default.PASSWORD_RESET_URL); - private static final long serialVersionUID = 2680369963282231348L; - - @Override - public void actionPerformed(ActionEvent actionEvent) { - try { - BrowserLauncher.openURL(url); - } catch (Exception e) { - Log.error("Unable to load password " + - "reset.", e); - } - } - }); - } - - if (!Default.getBoolean(Default.ADVANCED_DISABLED) && localPref.getAdvancedConfig()) { - buttonPanel.add(advancedButton, - new GridBagConstraints(2, 0, 1, 1, 1.0, 0.0, - GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 0, 5), 0, 0)); - } - - buttonPanel.add(loginButton, - new GridBagConstraints(3, 0, 4, 1, 1.0, 0.0, - GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 0, 5), 0, 0)); - - cardPanel.add(buttonPanel, BUTTON_PANEL); - - cardPanel.setOpaque(false); - buttonPanel.setOpaque(false); - - ImageIcon icon = new ImageIcon(getClass().getClassLoader().getResource("images/ajax-loader.gif")); - progressBar.setIcon(icon); - cardPanel.add(progressBar, PROGRESS_BAR); - - - add(cardPanel, new GridBagConstraints(0, 9, 4, 1, - 1.0, 1.0, GridBagConstraints.SOUTH, GridBagConstraints.HORIZONTAL, - new Insets(2, 2, 2, 2), 0, 0)); - loginButton.setEnabled(false); - - // Add KeyListener - usernameField.addKeyListener(this); - passwordField.addKeyListener(this); - serverField.addKeyListener(this); - - passwordField.addFocusListener(this); - usernameField.addFocusListener(this); - serverField.addFocusListener(this); - - // Add ActionListener - quitButton.addActionListener(this); - loginButton.addActionListener(this); - advancedButton.addActionListener(this); - - otherUsers.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - getPopup().show(otherUsers, e.getX(), e.getY()); - } - }); - - // Make same size - GraphicUtils.makeSameSize(usernameField, passwordField); - - // Set progress bar description - progressBar.setText(Res.getString("message.authenticating")); - progressBar.setVerticalTextPosition(JLabel.BOTTOM); - progressBar.setHorizontalTextPosition(JLabel.CENTER); - progressBar.setHorizontalAlignment(JLabel.CENTER); - - // Set Resources - ResourceUtils.resLabel(usernameLabel, usernameField, Res.getString("label.username")); - ResourceUtils.resLabel(passwordLabel, passwordField, Res.getString("label.password")); - ResourceUtils.resButton(quitButton, Res.getString("button.quit")); - ResourceUtils.resButton(loginButton, Res.getString("button.login")); - ResourceUtils.resButton(advancedButton, Res.getString("button.advanced")); - - // Load previous instances - String userProp = localPref.getLastUsername(); - String serverProp = localPref.getServer(); - - File file = new File(Spark.getSparkUserHome(), "/user/"); - File[] userprofiles = file.listFiles(); - - for (File f : userprofiles) { - if (f.getName().contains("@")) { - _usernames.add(f.getName()); - } else { - Log.error("Profile contains wrong format: \"" + f.getName() - + "\" located at: " + f.getAbsolutePath()); - } - } - - if (userProp != null) { - usernameField.setText(XmppStringUtils.unescapeLocalpart(userProp)); - } - if (serverProp != null) { - serverField.setText(serverProp); - serverNameLabel.setText(serverProp); - } - - // Check Settings - if (localPref.isSavePassword()) { - String encryptedPassword = localPref.getPasswordForUser(getBareJid()); - if (encryptedPassword != null) { - passwordField.setText(encryptedPassword); - } - savePasswordBox.setSelected(true); - loginButton.setEnabled(true); - } - autoLoginBox.setSelected(localPref.isAutoLogin()); - loginAsInvisibleBox.setSelected(localPref.isLoginAsInvisible()); - loginAnonymouslyBox.setSelected(localPref.isLoginAnonymously()); - usernameField.setEnabled(!loginAnonymouslyBox.isSelected()); - passwordField.setEnabled(!loginAnonymouslyBox.isSelected()); - useSSO(localPref.isSSOEnabled()); - if (autoLoginBox.isSelected()) { - validateLogin(); - return; - } - - // Handle arguments - String username = Spark.getArgumentValue("username"); - String password = Spark.getArgumentValue("password"); - String server = Spark.getArgumentValue("server"); - - if (username != null) { - usernameField.setText(username); - } - - if (password != null) { - passwordField.setText(password); - } - - if (server != null) { - serverField.setText(server); - } - - if (username != null && server != null && password != null) { - validateLogin(); - } - - createAccountButton.addActionListener(this); - - final String lockedDownURL = Default.getString(Default.HOST_NAME); - if (ModelUtil.hasLength(lockedDownURL)) { - serverField.setText(lockedDownURL); - } - - setComponentsAvailable(true); - } - - /** - * Returns the username the user defined. - * - * @return the username. - */ - private String getUsername() { - return XmppStringUtils.escapeLocalpart(usernameField.getText().trim()); - } - - /** - * Returns the resulting bareJID from username and server - * @return - */ - private String getBareJid() { - return usernameField.getText() + "@" + serverField.getText(); - } - - /** - * Returns the password specified by the user. - * - * @return the password. - */ - private String getPassword() { - return new String(passwordField.getPassword()); - } - - /** - * Returns the server name specified by the user. - * - * @return the server name. - */ - private String getServerName() { - return serverField.getText().trim(); - } - - /** - * Return whether user wants to login as invisible or not. - * - * @return the true if user wants to login as invisible. - */ - boolean isLoginAsInvisible() { - return loginAsInvisibleBox.isSelected(); - } - - /** - * ActionListener implementation. - * - * @param e the ActionEvent - */ - @Override - public void actionPerformed(ActionEvent e) { - if (e.getSource() == quitButton) { - quitLogin(); - } else if (e.getSource() == createAccountButton) { - AccountCreationWizard createAccountPanel = new AccountCreationWizard(); - createAccountPanel.invoke(loginDialog); - - if (createAccountPanel.isRegistered()) { - usernameField.setText(createAccountPanel.getUsernameWithoutEscape()); - passwordField.setText(createAccountPanel.getPassword()); - serverField.setText(createAccountPanel.getServer()); - loginButton.setEnabled(true); - } - } else if (e.getSource() == loginButton) { - validateLogin(); - - } else if (e.getSource() == advancedButton) { - final LoginSettingDialog loginSettingsDialog = new LoginSettingDialog(); - loginSettingsDialog.invoke(loginDialog); - useSSO(localPref.isSSOEnabled()); - } else if (e.getSource() == savePasswordBox) { - autoLoginBox.setEnabled(savePasswordBox.isSelected()); - - if (!savePasswordBox.isSelected()) { - autoLoginBox.setSelected(false); - } - } else if (e.getSource() == autoLoginBox) { - if ((autoLoginBox.isSelected() && (!localPref.isSSOEnabled()))) { - savePasswordBox.setSelected(true); - } - } else if (e.getSource() == loginAnonymouslyBox) { - usernameField.setEnabled(!loginAnonymouslyBox.isSelected()); - passwordField.setEnabled(!loginAnonymouslyBox.isSelected()); - validateDialog(); - } - } - - private JPopupMenu getPopup() { - JPopupMenu popup = new JPopupMenu(); - for (final String key : _usernames) { - - JMenuItem menu = new JMenuItem(key); - - final String username = key.split("@")[0]; - final String host = key.split("@")[1]; - menu.addActionListener(e -> { - usernameField.setText(username); - serverField.setText(host); - - try { - passwordField.setText(localPref.getPasswordForUser(getBareJid())); - if (passwordField.getPassword().length < 1) { - loginButton.setEnabled(loginAnonymouslyBox.isSelected()); - } else { - loginButton.setEnabled(true); - } - } catch (Exception e1) { - Log.error(e1); - } - - }); - - popup.add(menu); - } - return popup; - } - - /** - * KeyListener implementation. - * - * @param e the KeyEvent to process. - */ - @Override - public void keyTyped(KeyEvent e) { - validate(e); - } - - @Override - public void keyPressed(KeyEvent e) { - if (e.getKeyCode() == KeyEvent.VK_RIGHT && - ((JTextField) e.getSource()).getCaretPosition() == ((JTextField) e.getSource()).getText().length()) { - getPopup().show(otherUsers, 0, 0); - } - } - - @Override - public void keyReleased(KeyEvent e) { - validateDialog(); - } - - /** - * Checks the users input and enables/disables the login button depending on state. - */ - private void validateDialog() { - loginButton.setEnabled(loginAnonymouslyBox.isSelected() || - ModelUtil.hasLength(getUsername()) && - (ModelUtil.hasLength(getPassword()) || localPref.isSSOEnabled()) && - ModelUtil.hasLength(getServerName())); - } - - /** - * Validates key input. - * - * @param e the keyEvent. - */ - private void validate(KeyEvent e) { - if (loginButton.isEnabled() && e.getKeyChar() == KeyEvent.VK_ENTER) { - validateLogin(); - } - } - - @Override - public void focusGained(FocusEvent e) { - Object o = e.getSource(); - if (o instanceof JTextComponent) { - ((JTextComponent) o).selectAll(); - } - } - - @Override - public void focusLost(FocusEvent e) { - } - - /** - * Enables/Disables the editable components in the login screen. - * - * @param available true to enable components, otherwise false to disable. - */ - private void setComponentsAvailable(boolean available) { - savePasswordBox.setEnabled(available); - autoLoginBox.setEnabled(available); - loginAsInvisibleBox.setEnabled(available); - loginAnonymouslyBox.setEnabled(available); - - // Need to set both editable and enabled for best behavior. - usernameField.setEditable(available); - usernameField.setEnabled(available && !loginAnonymouslyBox.isSelected()); - - passwordField.setEditable(available); - passwordField.setEnabled(available && !loginAnonymouslyBox.isSelected()); - - if (Default.getBoolean(Default.HOST_NAME_CHANGE_DISABLED) || !localPref.getHostNameChange()) { - serverField.setEditable(false); - serverField.setEnabled(false); - } else { - serverField.setEditable(available); - serverField.setEnabled(available); - } - - if (available) { - // Reapply focus to password field - passwordField.requestFocus(); - } - } - - /** - * Displays the progress bar. - * - * @param visible true to display progress bar, false to hide it. - */ - private void setProgressBarVisible(boolean visible) { - if (visible) { - cardLayout.show(cardPanel, PROGRESS_BAR); - // progressBar.setIndeterminate(true); - } else { - cardLayout.show(cardPanel, BUTTON_PANEL); - } - } - - /** - * Validates the users login information. - */ - private void validateLogin() { - final SwingWorker loginValidationThread = new SwingWorker() { - @Override - public Object construct() { - setLoginUsername(getUsername()); - setLoginPassword(getPassword()); - setLoginServer(getServerName()); - boolean loginSuccessfull = beforeLoginValidations() && login(); - if (loginSuccessfull) { - afterLogin(); - progressBar.setText(Res.getString("message.connecting.please.wait")); - - // Startup Spark - startSpark(); - - // dispose login dialog - loginDialog.dispose(); - - // Show ChangeLog if we need to. - // new ChangeLogDialog().showDialog(); - } else { - EventQueue.invokeLater(() -> { - setComponentsAvailable(true); - setProgressBarVisible(false); - }); - - } - return loginSuccessfull; - } - }; - - // Start the login process in separate thread. - // Disable text fields - setComponentsAvailable(false); - - // Show progressbar - setProgressBarVisible(true); - - loginValidationThread.start(); - } - - public JPasswordField getPasswordField() { - return passwordField; - } - - @Override - public Dimension getPreferredSize() { - final Dimension dim = super.getPreferredSize(); - dim.height = 230; - return dim; - } - - public void useSSO(boolean use) { - if (use) { - usernameLabel.setVisible(true); - usernameField.setVisible(true); - - passwordLabel.setVisible(false); - passwordField.setVisible(false); - - savePasswordBox.setVisible(false); - savePasswordBox.setSelected(false); - - accountLabel.setVisible(true); - accountNameLabel.setVisible(true); - - serverField.setVisible(true); - - autoLoginBox.setVisible(true); - serverLabel.setVisible(true); - loginAsInvisibleBox.setVisible(true); - loginAnonymouslyBox.setVisible(false); - - headerLabel.setVisible(true); - - if (localPref.getDebug()) { - System.setProperty("java.security.krb5.debug", "true"); - System.setProperty("sun.security.krb5.debug", "true"); - } else { - System.setProperty("java.security.krb5.debug", "false"); - System.setProperty("sun.security.krb5.debug", "false"); - } - - String ssoMethod = localPref.getSSOMethod(); - if (!ModelUtil.hasLength(ssoMethod)) { - ssoMethod = "file"; - } - - System.setProperty("javax.security.auth.useSubjectCredsOnly", "false"); - GSSAPIConfiguration config = new GSSAPIConfiguration(ssoMethod.equals("file")); - Configuration.setConfiguration(config); - - LoginContext lc; - String princName = localPref.getLastUsername(); - String princRealm = null; - try { - lc = new LoginContext("com.sun.security.jgss.krb5.initiate"); - lc.login(); - Subject mySubject = lc.getSubject(); - - - for (Principal p : mySubject.getPrincipals()) { - //TODO: check if principal is a kerberos principal first... - String name = p.getName(); - int indexOne = name.indexOf("@"); - if (indexOne != -1) { - princName = name.substring(0, indexOne); - accountNameLabel.setText(name); - princRealm = name.substring(indexOne + 1); - } - loginButton.setEnabled(true); - } - } catch (LoginException le) { - Log.debug(le.getMessage()); - accountNameLabel.setText(Res.getString("title.login.no.account")); - //useSSO(false); - } - - String ssoKdc; - if (ssoMethod.equals("dns")) { - if (princRealm != null) { //princRealm is null if we got a LoginException above. - ssoKdc = getDnsKdc(princRealm); - System.setProperty("java.security.krb5.realm", princRealm); - System.setProperty("java.security.krb5.kdc", ssoKdc); - } - } else if (ssoMethod.equals("manual")) { - princRealm = localPref.getSSORealm(); - ssoKdc = localPref.getSSOKDC(); - System.setProperty("java.security.krb5.realm", princRealm); - System.setProperty("java.security.krb5.kdc", ssoKdc); - } else { - //Assume "file" method. We don't have to do anything special, - //java takes care of it for us. Unset the props if they are set - System.clearProperty("java.security.krb5.realm"); - System.clearProperty("java.security.krb5.kdc"); - } - - String userName = localPref.getLastUsername(); - if (ModelUtil.hasLength(userName)) { - usernameField.setText(userName); - } else { - usernameField.setText(princName); - } - } else { - autoLoginBox.setVisible(true); - usernameField.setVisible(true); - passwordField.setVisible(true); - savePasswordBox.setVisible(true); - usernameLabel.setVisible(true); - passwordLabel.setVisible(true); - serverLabel.setVisible(true); - serverField.setVisible(true); - loginAsInvisibleBox.setVisible(true); - loginAnonymouslyBox.setVisible(true); - - headerLabel.setVisible(false); - accountLabel.setVisible(false); - serverNameLabel.setVisible(false); - accountNameLabel.setVisible(false); - - Configuration.setConfiguration(null); - - validateDialog(); - } - } - - /** - * 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(loginAsInvisibleBox.isSelected()); - localPref.setLoginAnonymously(loginAnonymouslyBox.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(); - } - - localPref.setResource(resource); - 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(() -> { - progressBar.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 (savePasswordBox.isSelected()) { - try { - localPref.setPasswordForUser(getBareJid(), getPassword()); - } catch (Exception e) { - Log.error("Error encrypting password.", e); - } - } else { - try { - localPref.clearPasswordForAllUsers(); - } catch (Exception e) { - Log.debug("Unable to clear saved password..." + e); - } - } - - localPref.setSavePassword(savePasswordBox.isSelected()); - localPref.setAutoLogin(autoLoginBox.isSelected()); - - localPref.setServer(serverField.getText()); - SettingsManager.saveSettings(); - - return true; - } - - @Override - public void handle(Callback[] callbacks) { - for (Callback callback : callbacks) { - if (callback instanceof NameCallback) { - NameCallback ncb = (NameCallback) callback; - ncb.setName(getLoginUsername()); - } else if (callback instanceof PasswordCallback) { - PasswordCallback pcb = (PasswordCallback) callback; - pcb.setPassword(getPassword().toCharArray()); - } else { - Log.error("Unknown callback requested: " + callback.getClass().getSimpleName()); - } - } - } - } - - /** - * If the user quits, just shut down the - * application. - */ - private void quitLogin() { - System.exit(1); - } - - /** - * Initializes Spark and initializes all plugins. - */ - private void startSpark() { - // Invoke the MainWindow. - try { - EventQueue.invokeLater(() -> { - final MainWindow mainWindow = MainWindow.getInstance(); - - /* - if (tray != null) { - // Remove trayIcon - tray.removeTrayIcon(trayIcon); - } - */ - // Creates the Spark Workspace and add to MainWindow - Workspace workspace = Workspace.getInstance(); - - LayoutSettings settings = LayoutSettingsManager.getLayoutSettings(); - - LocalPreferences pref = SettingsManager.getLocalPreferences(); - if (pref.isDockingEnabled()) { - JSplitPane splitPane = mainWindow.getSplitPane(); - workspace.getCardPanel().setMinimumSize(null); - splitPane.setLeftComponent(workspace.getCardPanel()); - SparkManager.getChatManager().getChatContainer().setMinimumSize(null); - splitPane.setRightComponent(SparkManager.getChatManager().getChatContainer()); - int dividerLoc = settings.getSplitPaneDividerLocation(); - if (dividerLoc != -1) { - mainWindow.getSplitPane().setDividerLocation(dividerLoc); - } else { - mainWindow.getSplitPane().setDividerLocation(240); - } - - mainWindow.getContentPane().add(splitPane, BorderLayout.CENTER); - } else { - mainWindow.getContentPane().add(workspace.getCardPanel(), BorderLayout.CENTER); - } - - final Rectangle mainWindowBounds = settings.getMainWindowBounds(); - if (mainWindowBounds == null || mainWindowBounds.width <= 0 || mainWindowBounds.height <= 0) { - // Use Default size - mainWindow.setSize(310, 520); - - // Center Window on Screen - GraphicUtils.centerWindowOnScreen(mainWindow); - } else { - mainWindow.setBounds(mainWindowBounds); - } - - if (loginDialog.isVisible()) { - mainWindow.setVisible(true); - } - - loginDialog.setVisible(false); - - // Build the layout in the workspace - workspace.buildLayout(); - }); - } catch (Exception e) { - e.printStackTrace(); - } - - } - - /** - * Updates System properties with Proxy configuration. - * - */ - private void updateProxyConfig() { - if (ModelUtil.hasLength(Default.getString(Default.PROXY_PORT)) && ModelUtil.hasLength(Default.getString(Default.PROXY_HOST))) { - String port = Default.getString(Default.PROXY_PORT); - String host = Default.getString(Default.PROXY_HOST); - System.setProperty("socksProxyHost", host); - System.setProperty("socksProxyPort", port); - return; - } - - boolean proxyEnabled = localPref.isProxyEnabled(); - if (proxyEnabled) { - String host = localPref.getHost(); - String port = localPref.getPort(); - String username = localPref.getProxyUsername(); - String password = localPref.getProxyPassword(); - String protocol = localPref.getProtocol(); - - if (protocol.equals("SOCKS")) { - System.setProperty("socksProxyHost", host); - System.setProperty("socksProxyPort", port); - - if (ModelUtil.hasLength(username) && ModelUtil.hasLength(password)) { - System.setProperty("java.net.socks.username", username); - System.setProperty("java.net.socks.password", password); - } - } else { - System.setProperty("http.proxyHost", host); - System.setProperty("http.proxyPort", port); - System.setProperty("https.proxyHost", host); - System.setProperty("https.proxyPort", port); - - if (ModelUtil.hasLength(username) && ModelUtil.hasLength(password)) { - System.setProperty("http.proxyUser", username); - System.setProperty("http.proxyPassword", password); - } - - } - } - } - - /** - * Defines the background to use with the Login panel. - */ - public static class LoginBackgroundPanel extends JPanel { - private static final long serialVersionUID = -2449309600851007447L; - final ImageIcon icons = Default.getImageIcon(Default.LOGIN_DIALOG_BACKGROUND_IMAGE); - - /** - * Empty constructor. - */ - public LoginBackgroundPanel() { - } - - /** - * Uses an image to paint on background. - * - * @param g the graphics. - */ - @Override - public void paintComponent(Graphics g) { - Image backgroundImage = icons.getImage(); - double scaleX = getWidth() / (double) backgroundImage.getWidth(null); - double scaleY = getHeight() / (double) backgroundImage.getHeight(null); - AffineTransform xform = AffineTransform.getScaleInstance(scaleX, scaleY); - ((Graphics2D) g).drawImage(backgroundImage, xform, this); - } - } - - /** - * The image panel to display the Spark Logo. - */ - public static class ImagePanel extends JPanel { - private static final long serialVersionUID = -1778389077647562606L; - private final ImageIcon icons = Default.getImageIcon(Default.MAIN_IMAGE); - - /** - * Uses the Spark logo to paint as the background. - * - * @param g the graphics to use. - */ - @Override - public void paintComponent(Graphics g) { - final Image backgroundImage = icons.getImage(); - final double scaleX = getWidth() / (double) backgroundImage.getWidth(null); - final double scaleY = getHeight() / (double) backgroundImage.getHeight(null); - AffineTransform xform = AffineTransform.getScaleInstance(scaleX, scaleY); - ((Graphics2D) g).drawImage(backgroundImage, xform, this); - } - - @Override - public Dimension getPreferredSize() { - final Dimension size = super.getPreferredSize(); - size.width = icons.getIconWidth(); - size.height = icons.getIconHeight(); - return size; - } - } - - /** - * Checks for historic Spark settings and upgrades the user. - * - * @throws Exception thrown if an error occurs. - */ - private void checkForOldSettings() throws Exception { - // Check for old settings.xml - File settingsXML = new File(Spark.getSparkUserHome(), "/settings.xml"); - if (settingsXML.exists()) { - SAXReader saxReader = new SAXReader(); - Document pluginXML; - try { - // SPARK-2147: Disable certain features for security purposes (CVE-2020-10683) - saxReader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); - saxReader.setFeature("http://xml.org/sax/features/external-general-entities", false); - saxReader.setFeature("http://xml.org/sax/features/external-parameter-entities", false); - - pluginXML = saxReader.read(settingsXML); - } catch (DocumentException e) { - Log.error(e); - return; - } - - List plugins = pluginXML.selectNodes("/settings"); - for (Object plugin1 : plugins) { - Element plugin = (Element) plugin1; - - String username = plugin.selectSingleNode("username").getText(); - localPref.setLastUsername(username); - - String server = plugin.selectSingleNode("server").getText(); - localPref.setServer(server); - - String autoLogin = plugin.selectSingleNode("autoLogin").getText(); - localPref.setAutoLogin(Boolean.parseBoolean(autoLogin)); - - String savePassword = plugin.selectSingleNode("savePassword").getText(); - localPref.setSavePassword(Boolean.parseBoolean(savePassword)); - - String password = plugin.selectSingleNode("password").getText(); - localPref.setPasswordForUser(username + "@" + server, password); - - SettingsManager.saveSettings(); - } - - // Delete settings File - settingsXML.delete(); - } - } - - /** - * Use DNS to lookup a KDC - * @param realm The realm to look up - * @return the KDC hostname - */ - private String getDnsKdc(String realm) { - //Assumption: the KDC will be found with the SRV record - // _kerberos._udp.$realm - try { - Hashtable env = new Hashtable<>(); - env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory"); - DirContext context = new InitialDirContext(env); - Attributes dnsLookup = context.getAttributes("_kerberos._udp." + realm, new String[]{"SRV"}); - - ArrayList priorities = new ArrayList<>(); - HashMap> records = new HashMap<>(); - for (Enumeration e = dnsLookup.getAll(); e.hasMoreElements(); ) { - Attribute record = (Attribute) e.nextElement(); - for (Enumeration e2 = record.getAll(); e2.hasMoreElements(); ) { - String sRecord = (String) e2.nextElement(); - String[] sRecParts = sRecord.split(" "); - Integer pri = Integer.valueOf(sRecParts[0]); - if (priorities.contains(pri)) { - List recs = records.get(pri); - if (recs == null) recs = new ArrayList<>(); - recs.add(sRecord); - } else { - priorities.add(pri); - List recs = new ArrayList<>(); - recs.add(sRecord); - records.put(pri, recs); - } - } - } - Collections.sort(priorities); - List l = records.get(priorities.get(0)); - String toprec = l.get(0); - String[] sRecParts = toprec.split(" "); - return sRecParts[3]; - } catch (NamingException e) { - return ""; - } - } - - protected String getLoginUsername() { - return loginUsername; - } - - protected void setLoginUsername(String loginUsername) { - this.loginUsername = loginUsername; - } - - protected String getLoginPassword() { - return loginPassword; - } - - protected void setLoginPassword(String loginPassword) { - this.loginPassword = loginPassword; - } - - protected String getLoginServer() { - return loginServer; - } - - protected void setLoginServer(String loginServer) { - this.loginServer = loginServer; - } - - protected ArrayList getUsernames() { - return _usernames; - } - - private void persistEnterprise() { - new Enterprise(); - //Check that the ClientControl plugin Openfire is installed on the server. - if(Enterprise.isSparkManagerInstalled()){ - localPref.setAccountsReg(Enterprise.containsFeature(Enterprise.ACCOUNTS_REG_FEATURE)); - localPref.setAdvancedConfig(Enterprise.containsFeature(Enterprise.ADVANCED_CONFIG_FEATURE)); - localPref.setHostNameChange(Enterprise.containsFeature(Enterprise.HOST_NAME_FEATURE)); - localPref.setInvisibleLogin(Enterprise.containsFeature(Enterprise.INVISIBLE_LOGIN_FEATURE)); - localPref.setAnonymousLogin(Enterprise.containsFeature(Enterprise.ANONYMOUS_LOGIN_FEATURE)); - localPref.setPswdAutologin(Enterprise.containsFeature(Enterprise.SAVE_PASSWORD_FEATURE)); - if (Enterprise.containsFeature(Enterprise.HOSTNAME_AS_RESOURCE_FEATURE) != Enterprise.containsFeature(Enterprise.VERSION_AS_RESOURCE_FEATURE)) { - localPref.setUseHostnameAsResource(Enterprise.containsFeature(Enterprise.HOSTNAME_AS_RESOURCE_FEATURE)); - localPref.setUseVersionAsResource(Enterprise.containsFeature(Enterprise.VERSION_AS_RESOURCE_FEATURE)); - } - localPref.setFileTransferIbbOnly(Enterprise.containsFeature(Enterprise.IBB_FEATURE)); - } - } - - private void initAdvancedDefaults() { - localPref.setCompressionEnabled(localPref.isCompressionEnabled()); - localPref.setDebuggerEnabled(localPref.isDebuggerEnabled()); - localPref.setDisableHostnameVerification(localPref.isDisableHostnameVerification()); - localPref.setHostAndPortConfigured(localPref.isHostAndPortConfigured()); - localPref.setProtocol("SOCKS"); - localPref.setProxyEnabled(localPref.isProxyEnabled()); - // localPref.setProxyPassword(""); - // localPref.setProxyUsername(""); - localPref.setResource(localPref.getResource()); - localPref.setSaslGssapiSmack3Compatible(localPref.isSaslGssapiSmack3Compatible()); - localPref.setDirectTls(localPref.isDirectTls()); - localPref.setSecurityMode(localPref.getSecurityMode()); - localPref.setSSOEnabled(localPref.isSSOEnabled()); - localPref.setSSOMethod("file"); - localPref.setTimeOut(localPref.getTimeOut()); - // localPref.setTrustStorePassword(""); - // localPref.setTrustStorePath(""); - localPref.setUseHostnameAsResource(localPref.isUseHostnameAsResource()); - localPref.setUseVersionAsResource(localPref.isUseVersionAsResource()); - // localPref.setXmppHost(""); - localPref.setXmppPort(localPref.getXmppPort()); - - if(Default.getBoolean(Default.IDLE_LOCK) || !Enterprise.containsFeature(Enterprise.IDLE_FEATURE)) { - localPref.setIdleTime(Integer.parseInt(Default.getString(Default.IDLE_TIME))); - localPref.setIdleMessage(Res.getString("status.away")); - localPref.setIdleOn(true); - } - - SettingsManager.saveSettings(); - } -} diff --git a/core/src/main/java/org/jivesoftware/spark/util/UIComponentRegistry.java b/core/src/main/java/org/jivesoftware/spark/util/UIComponentRegistry.java index 641094062..eb1ebde50 100644 --- a/core/src/main/java/org/jivesoftware/spark/util/UIComponentRegistry.java +++ b/core/src/main/java/org/jivesoftware/spark/util/UIComponentRegistry.java @@ -22,7 +22,6 @@ import java.util.Arrays; import org.apache.commons.lang3.reflect.ConstructorUtils; -import org.jivesoftware.LoginDialog; import org.jivesoftware.gui.LoginUIPanel; import org.jivesoftware.smackx.muc.MultiUserChat; import org.jivesoftware.spark.ButtonFactory; From ddfb81d53463a8c540e60754282c64c96796b65e Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sat, 14 Sep 2024 22:55:52 +0300 Subject: [PATCH 4/7] LoginUIPanel: optimize port parsing --- .../main/java/org/jivesoftware/gui/LoginUIPanel.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/jivesoftware/gui/LoginUIPanel.java b/core/src/main/java/org/jivesoftware/gui/LoginUIPanel.java index 33ef237a5..154984b6a 100644 --- a/core/src/main/java/org/jivesoftware/gui/LoginUIPanel.java +++ b/core/src/main/java/org/jivesoftware/gui/LoginUIPanel.java @@ -572,8 +572,7 @@ private void btnResetActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRS try { BrowserLauncher.openURL(url); } catch (Exception e) { - Log.error("Unable to load password " - + "reset.", e); + Log.error("Unable to load password reset.", e); } }//GEN-LAST:event_btnResetActionPerformed @@ -692,11 +691,13 @@ protected XMPPTCPConnectionConfiguration retrieveConnectionConfiguration() { int checkForPort = loginServer.indexOf(":"); if (checkForPort != -1) { - String portString = loginServer.substring(checkForPort + 1); - if (ModelUtil.hasLength(portString)) { + if (checkForPort != loginServer.length() - 2) { // : at end of string, so no port + String portString = loginServer.substring(checkForPort + 1); // Set new port. - port = Integer.valueOf(portString); + port = Integer.parseInt(portString); } + // strip the port from loginServer hostname + loginServer = loginServer.substring(0, checkForPort); } ConnectionConfiguration.SecurityMode securityMode = localPref.getSecurityMode(); From a83e00a16f46c0315d1ff204848e5dfc4e82c5a8 Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sat, 14 Sep 2024 23:11:21 +0300 Subject: [PATCH 5/7] LoginUIPanel: extract configureConnectionTls() same as in AccountCreationWizard The same was previously made for LoginDialog in 6ee0092a74a9266171f71f7b97fc3578d3334237 --- .../org/jivesoftware/gui/LoginUIPanel.java | 96 +++++++++---------- 1 file changed, 44 insertions(+), 52 deletions(-) diff --git a/core/src/main/java/org/jivesoftware/gui/LoginUIPanel.java b/core/src/main/java/org/jivesoftware/gui/LoginUIPanel.java index 154984b6a..26a1d8e3a 100644 --- a/core/src/main/java/org/jivesoftware/gui/LoginUIPanel.java +++ b/core/src/main/java/org/jivesoftware/gui/LoginUIPanel.java @@ -118,6 +118,8 @@ import org.jivesoftware.spark.util.*; import static org.jivesoftware.spark.util.StringUtils.modifyWildcards; +import static org.jivesoftware.sparkimpl.certificates.SparkSSLContextCreator.Options.BOTH; +import static org.jivesoftware.sparkimpl.certificates.SparkSSLContextCreator.Options.ONLY_SERVER_SIDE; import org.jivesoftware.spark.util.log.Log; import org.jivesoftware.sparkimpl.certificates.CertificateModel; @@ -747,9 +749,6 @@ protected XMPPTCPConnectionConfiguration retrieveConnectionConfiguration() { .setCompressionEnabled(localPref.isCompressionEnabled()) .setSecurityMode(securityMode); - if (securityMode != ConnectionConfiguration.SecurityMode.disabled && localPref.isDisableHostnameVerification()) { - TLSUtils.disableHostnameVerificationForTlsCertificates(builder); - } if (localPref.isDebuggerEnabled()) { builder.enableDefaultDebugger(); } @@ -761,55 +760,7 @@ protected XMPPTCPConnectionConfiguration retrieveConnectionConfiguration() { if (localPref.isProxyEnabled()) { builder.setProxyInfo(proxyInfo); } - - if (securityMode != ConnectionConfiguration.SecurityMode.disabled && !useDirectTls) { - // 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 && useDirectTls) { - 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 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()); - } + configureConnectionTls(builder, securityMode, useDirectTls, hostPortConfigured, loginServer); // SPARK-1747: Don't use the GSS-API SASL mechanism when SSO is disabled. SASLAuthentication.unregisterSASLMechanism(SASLGSSAPIMechanism.class.getName()); @@ -840,6 +791,47 @@ protected XMPPTCPConnectionConfiguration retrieveConnectionConfiguration() { return builder.build(); } + private void configureConnectionTls(XMPPTCPConnectionConfiguration.Builder builder, ConnectionConfiguration.SecurityMode securityMode, boolean useDirectTls, boolean hostPortConfigured, String serverName) { + if (securityMode != ConnectionConfiguration.SecurityMode.disabled) { + if (localPref.isDisableHostnameVerification()) { + TLSUtils.disableHostnameVerificationForTlsCertificates(builder); + } + if (!useDirectTls) { + // This use STARTTLS which starts initially plain connection to upgrade it to TLS. + // It will use the same port as plain connections which is 5222. + SparkSSLContextCreator.Options options = localPref.isAllowClientSideAuthentication() ? BOTH : ONLY_SERVER_SIDE; + try { + SSLContext context = SparkSSLContextCreator.setUpContext(options); + builder.setSslContextFactory(() -> context); + builder.setSecurityMode(securityMode); + builder.setCustomX509TrustManager(new SparkTrustManager()); + } catch (NoSuchAlgorithmException | KeyManagementException | UnrecoverableKeyException | KeyStoreException | NoSuchProviderException e) { + Log.warning("Could not establish secured connection", e); + } + } else { // useDirectTls + 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(serverName); + List 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 = localPref.isAllowClientSideAuthentication() ? BOTH : 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); + } + SASLAuthentication.registerSASLMechanism(new SASLExternalMechanism()); + } + } + /** * Returns the username the user defined. * From fb6333a50f9335ac1a78945f7fa0dd4c9cd819e8 Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sat, 14 Sep 2024 23:16:04 +0300 Subject: [PATCH 6/7] BrowserLauncher: reformat --- .../spark/util/BrowserLauncher.java | 58 +++++++++---------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/core/src/main/java/org/jivesoftware/spark/util/BrowserLauncher.java b/core/src/main/java/org/jivesoftware/spark/util/BrowserLauncher.java index a665f33f0..99a3ef3dc 100644 --- a/core/src/main/java/org/jivesoftware/spark/util/BrowserLauncher.java +++ b/core/src/main/java/org/jivesoftware/spark/util/BrowserLauncher.java @@ -21,35 +21,31 @@ public class BrowserLauncher { - public static void openURL(String url) throws Exception { - if (url.startsWith("http") || url.startsWith("ftp") || url.startsWith("file") || url.startsWith("www")) { - - if (url.startsWith("file") && url.contains(" ")) { - url = url.replace(" ", "%20"); - } - if (url.startsWith("www")) { - url = "http://" + url; - } - try - { - Desktop.getDesktop().browse(new URI(url)); - } - catch(Exception ex) - { - Runtime.getRuntime().exec("xdg-open " + url); - - } - - } else { - File f = new File(url); - if (f.exists() && Desktop.isDesktopSupported()){ - try { - Desktop.getDesktop().open(f); - } catch (Exception ex){ - if (!url.toLowerCase().startsWith("//")) url = "//" + url; - Desktop.getDesktop().browse(new URI("http:" + url)); - } - } - } - } + public static void openURL(String url) throws Exception { + if (url.startsWith("http") || url.startsWith("ftp") || url.startsWith("file") || url.startsWith("www")) { + if (url.startsWith("file") && url.contains(" ")) { + url = url.replace(" ", "%20"); + } + if (url.startsWith("www")) { + url = "http://" + url; + } + try { + Desktop.getDesktop().browse(new URI(url)); + } catch (Exception ex) { + Runtime.getRuntime().exec("xdg-open " + url); + } + } else { + File f = new File(url); + if (f.exists() && Desktop.isDesktopSupported()) { + try { + Desktop.getDesktop().open(f); + } catch (Exception ex) { + if (!url.toLowerCase().startsWith("//")) { + url = "//" + url; + } + Desktop.getDesktop().browse(new URI("http:" + url)); + } + } + } + } } From 8669fc3b8e07be2700f3b2004c3f05e58e6d785f Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sat, 14 Sep 2024 23:22:51 +0300 Subject: [PATCH 7/7] BrowserLauncher: remove toLowerCase() --- .../java/org/jivesoftware/spark/util/BrowserLauncher.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/jivesoftware/spark/util/BrowserLauncher.java b/core/src/main/java/org/jivesoftware/spark/util/BrowserLauncher.java index 99a3ef3dc..a7cb655b1 100644 --- a/core/src/main/java/org/jivesoftware/spark/util/BrowserLauncher.java +++ b/core/src/main/java/org/jivesoftware/spark/util/BrowserLauncher.java @@ -32,7 +32,8 @@ public static void openURL(String url) throws Exception { try { Desktop.getDesktop().browse(new URI(url)); } catch (Exception ex) { - Runtime.getRuntime().exec("xdg-open " + url); + // fallback on Linux + Runtime.getRuntime().exec("xdg-open " + url); } } else { File f = new File(url); @@ -40,7 +41,7 @@ public static void openURL(String url) throws Exception { try { Desktop.getDesktop().open(f); } catch (Exception ex) { - if (!url.toLowerCase().startsWith("//")) { + if (!url.startsWith("//")) { url = "//" + url; } Desktop.getDesktop().browse(new URI("http:" + url));