mirror of
https://github.com/igniterealtime/Spark.git
synced 2025-12-01 12:27:58 +00:00
* SPARK-1735: MUC occupants list should have width This commit attempts to prevent that the occupants list in a MUC screen has a near-zero width. * SPARK-1772: Icons for muc role fix * SPARK-1735: MUC occupants list should have vertical scrollbar * SPARK-1740: Allow SASL GSS-API to be executed as it was in SMACK 3 SMACK 4 uses the fully qualified host name, when negotiating GSS-API via SASL. SMACK 3 used the XMPP domain name instead. Spark should have a configurable option that allows it to fall back to the old mechanism (which is likely needed to connect to servers that have already been configured to accept SSO from older versions of Spark). This commit also brings a reorganization of the code of the 'advanced connection settings' dialog - simply because it was pretty unpractical as it was. Small modifications have been made to the layout.
1526 lines
57 KiB
Java
1526 lines
57 KiB
Java
/**
|
|
* $RCSfile: ,v $
|
|
* $Revision: $
|
|
* $Date: $
|
|
*
|
|
* 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.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.TLSUtils;
|
|
import org.jivesoftware.smackx.chatstates.ChatStateManager;
|
|
import org.jivesoftware.spark.SessionManager;
|
|
import org.jivesoftware.spark.SparkManager;
|
|
import org.jivesoftware.spark.Workspace;
|
|
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.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.util.XmppStringUtils;
|
|
|
|
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.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.NoSuchAlgorithmException;
|
|
import java.security.Principal;
|
|
import java.util.*;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* 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 ArrayList<String> _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(Default.getString(Default.APPLICATION_NAME));
|
|
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 String showPoweredBy = Default.getString(Default.SHOW_POWERED_BY);
|
|
if (ModelUtil.hasLength(showPoweredBy) && "true".equals(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, 0, 0), 0, 0));
|
|
|
|
loginDialog.setContentPane(mainPanel);
|
|
loginDialog.setLocationRelativeTo(parentFrame);
|
|
|
|
loginDialog.setResizable(false);
|
|
loginDialog.pack();
|
|
|
|
// Center dialog on screen
|
|
GraphicUtils.centerWindowOnScreen(loginDialog);
|
|
|
|
// Show dialog
|
|
loginDialog.addWindowListener(new WindowAdapter() {
|
|
public void windowClosing(WindowEvent e) {
|
|
quitLogin();
|
|
}
|
|
});
|
|
if (loginPanel.getUsername().trim().length() > 0) {
|
|
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() {
|
|
// Does noting by default - but can be overwritten by subclasses to provide additional
|
|
// settings
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
boolean useSSL = 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!");
|
|
}
|
|
}
|
|
|
|
final XMPPTCPConnectionConfiguration.Builder builder = XMPPTCPConnectionConfiguration.builder()
|
|
.setUsernameAndPassword(loginUsername, loginPassword)
|
|
.setServiceName(loginServer)
|
|
.setPort(port)
|
|
.setSendPresence(false)
|
|
.setCompressionEnabled(localPref.isCompressionEnabled());
|
|
|
|
if (localPref.isAcceptAllCertificates()) {
|
|
try {
|
|
TLSUtils.acceptAllCertificates(builder);
|
|
} catch (NoSuchAlgorithmException | KeyManagementException e) {
|
|
Log.warning( "Unable to create configuration.", e );
|
|
}
|
|
}
|
|
if ( localPref.isDebuggerEnabled()) {
|
|
builder.setDebuggerEnabled( true );
|
|
}
|
|
|
|
if ( hostPortConfigured ) {
|
|
builder.setHost( localPref.getXmppHost() );
|
|
}
|
|
|
|
if ( localPref.isProxyEnabled() )
|
|
{
|
|
builder.setProxyInfo( proxyInfo );
|
|
}
|
|
|
|
if (useSSL) {
|
|
if (!hostPortConfigured) {
|
|
builder.setPort( 5223 );
|
|
}
|
|
builder.setSocketFactory( new DummySSLSocketFactory() );
|
|
}
|
|
|
|
final XMPPTCPConnectionConfiguration configuration = builder.build();
|
|
|
|
if (localPref.isPKIEnabled()) {
|
|
SASLAuthentication.registerSASLMechanism( new SASLExternalMechanism() );
|
|
builder.setKeystoreType(localPref.getPKIStore());
|
|
if(localPref.getPKIStore().equals("PKCS11")) {
|
|
builder.setPKCS11Library(localPref.getPKCS11Library());
|
|
}
|
|
else if(localPref.getPKIStore().equals("JKS")) {
|
|
builder.setKeystoreType("JKS");
|
|
builder.setKeystorePath(localPref.getJKSPath());
|
|
|
|
}
|
|
else if(localPref.getPKIStore().equals("X509")) {
|
|
//do something
|
|
}
|
|
else if(localPref.getPKIStore().equals("Apple")) {
|
|
builder.setKeystoreType("Apple");
|
|
}
|
|
}
|
|
|
|
// 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() );
|
|
}
|
|
}
|
|
|
|
ReconnectionManager.setEnabledPerDefault( true );
|
|
|
|
// 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();
|
|
}
|
|
|
|
/**
|
|
* 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 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 JLabel headerLabel = new JLabel();
|
|
private JLabel accountLabel = new JLabel();
|
|
private JLabel accountNameLabel = new JLabel();
|
|
private JLabel serverNameLabel = new JLabel();
|
|
private JLabel ssoServerLabel = new JLabel();
|
|
|
|
private 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"));
|
|
|
|
savePasswordBox.setOpaque(false);
|
|
autoLoginBox.setOpaque(false);
|
|
loginAsInvisibleBox.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("HIDE_SAVE_PASSWORD_AND_AUTOLOGIN")) {
|
|
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(loginAsInvisibleBox,
|
|
new GridBagConstraints(1, 7, 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);
|
|
|
|
if (!Default.getBoolean(Default.ACCOUNT_DISABLED)) {
|
|
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;
|
|
|
|
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)){
|
|
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, 8, 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.autenticating"));
|
|
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());
|
|
useSSO(localPref.isSSOEnabled());
|
|
if (autoLoginBox.isSelected()) {
|
|
savePasswordBox.setEnabled(false);
|
|
autoLoginBox.setEnabled(false);
|
|
loginAsInvisibleBox.setEnabled(false);
|
|
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) {
|
|
savePasswordBox.setEnabled(false);
|
|
autoLoginBox.setEnabled(false);
|
|
loginAsInvisibleBox.setEnabled(false);
|
|
validateLogin();
|
|
}
|
|
|
|
createAccountButton.addActionListener(this);
|
|
|
|
final String lockedDownURL = Default.getString(Default.HOST_NAME);
|
|
if (ModelUtil.hasLength(lockedDownURL)) {
|
|
serverField.setText(lockedDownURL);
|
|
}
|
|
if (Default.getBoolean("HOST_NAME_CHANGE_DISABLED"))
|
|
serverField.setEnabled(false);
|
|
|
|
|
|
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
*/
|
|
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()) {
|
|
savePasswordBox.setSelected(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
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(false);
|
|
}
|
|
else {
|
|
loginButton.setEnabled(true);
|
|
}
|
|
} catch (Exception e1) {
|
|
}
|
|
|
|
} );
|
|
|
|
popup.add(menu);
|
|
}
|
|
return popup;
|
|
}
|
|
|
|
/**
|
|
* KeyListener implementation.
|
|
*
|
|
* @param e the KeyEvent to process.
|
|
*/
|
|
public void keyTyped(KeyEvent e) {
|
|
validate(e);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
public void keyReleased(KeyEvent e) {
|
|
validateDialog();
|
|
}
|
|
|
|
/**
|
|
* Checks the users input and enables/disables the login button depending on state.
|
|
*/
|
|
private void validateDialog() {
|
|
loginButton.setEnabled(
|
|
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();
|
|
}
|
|
}
|
|
|
|
public void focusGained(FocusEvent e) {
|
|
Object o = e.getSource();
|
|
if (o instanceof JTextComponent) {
|
|
((JTextComponent)o).selectAll();
|
|
}
|
|
}
|
|
|
|
public void focusLost(FocusEvent e) {
|
|
}
|
|
|
|
/**
|
|
* Enables/Disables the editable components in the login screen.
|
|
*
|
|
* @param editable true to enable components, otherwise false to disable.
|
|
*/
|
|
private void enableComponents(boolean editable) {
|
|
|
|
// Need to set both editable and enabled for best behavior.
|
|
usernameField.setEditable(editable);
|
|
usernameField.setEnabled(editable);
|
|
|
|
passwordField.setEditable(editable);
|
|
passwordField.setEnabled(editable);
|
|
|
|
final String lockedDownURL = Default.getString(Default.HOST_NAME);
|
|
if (!ModelUtil.hasLength(lockedDownURL)) {
|
|
serverField.setEditable(editable);
|
|
serverField.setEnabled(editable);
|
|
}
|
|
|
|
|
|
if (editable) {
|
|
// Reapply focus to username 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() {
|
|
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( () -> {
|
|
savePasswordBox.setEnabled(true);
|
|
autoLoginBox.setEnabled(true);
|
|
loginAsInvisibleBox.setVisible(true);
|
|
enableComponents(true);
|
|
setProgressBarVisible(false);
|
|
} );
|
|
|
|
}
|
|
return loginSuccessfull;
|
|
}
|
|
};
|
|
|
|
// Start the login process in seperate thread.
|
|
// Disable textfields
|
|
enableComponents(false);
|
|
|
|
// Show progressbar
|
|
setProgressBarVisible(true);
|
|
|
|
loginValidationThread.start();
|
|
}
|
|
|
|
public JPasswordField getPasswordField() {
|
|
return passwordField;
|
|
}
|
|
|
|
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);
|
|
|
|
accountLabel.setVisible(true);
|
|
accountNameLabel.setVisible(true);
|
|
|
|
serverField.setVisible(true);
|
|
|
|
autoLoginBox.setVisible(true);
|
|
serverLabel.setVisible(true);
|
|
loginAsInvisibleBox.setVisible(true);
|
|
|
|
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);
|
|
|
|
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() {
|
|
final SessionManager sessionManager = SparkManager.getSessionManager();
|
|
|
|
boolean hasErrors = false;
|
|
String errorMessage = null;
|
|
|
|
localPref.setLoginAsInvisible(loginAsInvisibleBox.isSelected());
|
|
|
|
// Handle specifyed Workgroup
|
|
String serverName = getServerName();
|
|
|
|
|
|
if (!hasErrors) {
|
|
localPref = SettingsManager.getLocalPreferences();
|
|
if (localPref.isDebuggerEnabled()) {
|
|
SmackConfiguration.DEBUG = true;
|
|
}
|
|
|
|
SmackConfiguration.setDefaultPacketReplyTimeout(localPref.getTimeOut() * 1000);
|
|
|
|
// Get connection
|
|
try {
|
|
connection = new XMPPTCPConnection(retrieveConnectionConfiguration());
|
|
connection.setParsingExceptionCallback( new ExceptionLoggingCallback() );
|
|
//If we want to use the debug version of smack, we have to check if
|
|
//we are on the dispatch thread because smack will create an UI
|
|
if (localPref.isDebuggerEnabled()) {
|
|
if (EventQueue.isDispatchThread()) {
|
|
connection.connect();
|
|
} else {
|
|
EventQueue.invokeAndWait( () -> {
|
|
try {
|
|
connection.connect();
|
|
} catch (IOException | XMPPException | SmackException e) {
|
|
Log.error("connection error",e);
|
|
}
|
|
|
|
} );
|
|
}
|
|
} else {
|
|
connection.connect();
|
|
}
|
|
|
|
String resource = localPref.getResource();
|
|
if (Default.getBoolean("HOSTNAME_AS_RESOURCE")) {
|
|
try {
|
|
resource = InetAddress.getLocalHost().getHostName();
|
|
} catch(UnknownHostException e) {
|
|
Log.error("unable to retrieve hostname",e);
|
|
}
|
|
} else if (localPref.isUseHostnameAsResource()) {
|
|
try {
|
|
resource = InetAddress.getLocalHost().getHostName();
|
|
} catch(UnknownHostException e) {
|
|
Log.error("unable to retrieve hostname",e);
|
|
}
|
|
} else if (Default.getBoolean("VERSION_AS_RESOURCE")) {
|
|
resource = Default.getString(Default.APPLICATION_NAME) + " " + JiveInfo.getVersion() + "." + Default.getString(Default.BUILD_NUMBER);
|
|
} else if (localPref.isUseVersionAsResource()) {
|
|
resource = Default.getString(Default.APPLICATION_NAME) + " " + JiveInfo.getVersion() + "." + Default.getString(Default.BUILD_NUMBER);
|
|
}
|
|
connection.login(getLoginUsername(), getLoginPassword(),
|
|
org.jivesoftware.spark.util.StringUtils.modifyWildcards(resource).trim());
|
|
|
|
sessionManager.setServerAddress(connection.getServiceName());
|
|
sessionManager.initializeSession(connection, getLoginUsername(), getLoginPassword());
|
|
sessionManager.setJID(connection.getUser());
|
|
}
|
|
catch (Exception xee) {
|
|
|
|
errorMessage = SparkRes.getString(SparkRes.UNRECOVERABLE_ERROR);
|
|
hasErrors = true;
|
|
|
|
if (!loginDialog.isVisible()) {
|
|
loginDialog.setVisible(true);
|
|
}
|
|
if (xee instanceof XMPPException.XMPPErrorException) {
|
|
|
|
XMPPException.XMPPErrorException xe = (XMPPException.XMPPErrorException)xee;
|
|
switch ( xe.getXMPPError().getCondition() )
|
|
{
|
|
case conflict:
|
|
errorMessage = Res.getString("label.conflict.error");
|
|
break;
|
|
|
|
case not_authorized:
|
|
errorMessage = Res.getString("message.invalid.username.password");
|
|
break;
|
|
|
|
case remote_server_not_found:
|
|
errorMessage = Res.getString("message.server.unavailable");
|
|
break;
|
|
|
|
case remote_server_timeout:
|
|
errorMessage = Res.getString("message.server.unavailable");
|
|
break;
|
|
|
|
default:
|
|
errorMessage = Res.getString("message.unrecoverable.error");
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Log Error
|
|
Log.warning("Exception in Login:", xee);
|
|
}
|
|
}
|
|
|
|
if (hasErrors) {
|
|
|
|
final String finalerrorMessage = errorMessage;
|
|
EventQueue.invokeLater( () -> {
|
|
progressBar.setVisible(false);
|
|
//progressBar.setIndeterminate(false);
|
|
|
|
// Show error dialog
|
|
UIManager.put("OptionPane.okButtonText", Res.getString("ok"));
|
|
if (loginDialog.isVisible()) {
|
|
if (!localPref.isSSOEnabled()) {
|
|
JOptionPane.showMessageDialog(loginDialog, finalerrorMessage, Res.getString("title.login.error"),
|
|
JOptionPane.ERROR_MESSAGE);
|
|
}
|
|
else {
|
|
JOptionPane.showMessageDialog(loginDialog, Res.getString("title.advanced.connection.sso.unable"), Res.getString("title.login.error"),
|
|
JOptionPane.ERROR_MESSAGE);
|
|
//useSSO(false);
|
|
//localPref.setSSOEnabled(false);
|
|
}
|
|
}
|
|
} );
|
|
|
|
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.
|
|
if (savePasswordBox.isSelected()) {
|
|
try {
|
|
localPref.setPasswordForUser(getBareJid(), getPassword());
|
|
}
|
|
catch (Exception e) {
|
|
Log.error("Error encrypting password.", e);
|
|
}
|
|
}
|
|
|
|
localPref.setSavePassword(savePasswordBox.isSelected());
|
|
localPref.setAutoLogin(autoLoginBox.isSelected());
|
|
|
|
// if (localPref.isSSOEnabled()) {
|
|
// localPref.setAutoLogin(true);
|
|
// }
|
|
|
|
localPref.setServer(serverField.getText());
|
|
|
|
|
|
SettingsManager.saveSettings();
|
|
|
|
return !hasErrors;
|
|
}
|
|
|
|
public void handle(Callback[] callbacks) throws IOException {
|
|
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();
|
|
int x = settings.getMainWindowX();
|
|
int y = settings.getMainWindowY();
|
|
int width = settings.getMainWindowWidth();
|
|
int height = settings.getMainWindowHeight();
|
|
|
|
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);
|
|
}
|
|
|
|
if (x == 0 && y == 0) {
|
|
// Use Default size
|
|
mainWindow.setSize(310, 520);
|
|
|
|
// Center Window on Screen
|
|
GraphicUtils.centerWindowOnScreen(mainWindow);
|
|
}
|
|
else {
|
|
mainWindow.setBounds(x, y, width, height);
|
|
}
|
|
|
|
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.
|
|
*
|
|
* @throws Exception thrown if an exception occurs.
|
|
*/
|
|
private void updateProxyConfig() throws Exception {
|
|
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 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.
|
|
*/
|
|
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 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.
|
|
*/
|
|
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);
|
|
}
|
|
|
|
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 {
|
|
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<String,String> 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<Integer> priorities = new ArrayList<>();
|
|
HashMap<Integer,List<String>> 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<String> recs = records.get(pri);
|
|
if(recs == null) recs = new ArrayList<>();
|
|
recs.add(sRecord);
|
|
} else {
|
|
priorities.add(pri);
|
|
List<String> recs = new ArrayList<>();
|
|
recs.add(sRecord);
|
|
records.put(pri,recs);
|
|
}
|
|
}
|
|
}
|
|
Collections.sort(priorities);
|
|
List<String> 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<String> getUsernames() {
|
|
return _usernames;
|
|
}
|
|
|
|
|
|
}
|