mirror of
https://github.com/igniterealtime/Spark.git
synced 2025-12-01 12:27:58 +00:00
1522 lines
57 KiB
Java
1522 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.isDisableHostnameVerification()) {
|
|
TLSUtils.disableHostnameVerificationForTlsCertificicates(builder);
|
|
}
|
|
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) {
|
|
|
|
hasErrors = true;
|
|
|
|
if (!loginDialog.isVisible()) {
|
|
loginDialog.setVisible(true);
|
|
}
|
|
|
|
if (xee.getMessage().contains("not-authorized")) {
|
|
errorMessage = Res.getString("message.invalid.username.password");
|
|
|
|
} else if (xee.getMessage().contains("failed because java.net.UnknownHostException:") | xee.getMessage().contains("Network is unreachable")) {
|
|
errorMessage = Res.getString("message.server.unavailable");
|
|
|
|
} else if (xee.getMessage().contains("Hostname verification of certificate failed")) {
|
|
errorMessage = Res.getString("message.hostname.cert.verification.failed");
|
|
ReconnectionManager.getInstanceFor(connection).disableAutomaticReconnection();
|
|
|
|
} else if (xee.getMessage().contains("unable to find valid certification path to requested target")) {
|
|
errorMessage = Res.getString("message.cert.verification.failed");
|
|
ReconnectionManager.getInstanceFor(connection).disableAutomaticReconnection();
|
|
|
|
} else if (xee.getMessage().contains("XMPPError: conflict")) {
|
|
errorMessage = Res.getString("label.conflict.error");
|
|
|
|
} else errorMessage = Res.getString("message.unrecoverable.error");
|
|
|
|
// 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;
|
|
}
|
|
|
|
|
|
}
|