org.jets3t.apps.cockpit.gui.StartupDialog Maven / Gradle / Ivy
/*
* jets3t : Java Extra-Tasty S3 Toolkit (for Amazon S3 online storage service)
* This is a java.net project, see https://jets3t.dev.java.net/
*
* Copyright 2006 James Murty, 2008 Zmanda Inc.
*
* 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.jets3t.apps.cockpit.gui;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.net.URL;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jets3t.gui.ErrorDialog;
import org.jets3t.gui.HyperlinkActivatedListener;
import org.jets3t.gui.ProgressDialog;
import org.jets3t.service.Constants;
import org.jets3t.service.Jets3tProperties;
import org.jets3t.service.S3Service;
import org.jets3t.service.S3ServiceException;
import org.jets3t.service.acl.AccessControlList;
import org.jets3t.service.impl.rest.httpclient.RestS3Service;
import org.jets3t.service.model.S3Bucket;
import org.jets3t.service.model.S3Object;
import org.jets3t.service.security.AWSCredentials;
import org.jets3t.service.security.AWSDevPayCredentials;
import org.jets3t.service.utils.ServiceUtils;
import com.centerkey.utils.BareBonesBrowserLaunch;
/**
* Dialog box for obtaining a user's AWS Credentials, and performing other startup tasks such as
* loading properties files.
*
*
* @author James Murty
* @author Nikolas Coukouma
*/
public class StartupDialog extends JDialog implements ActionListener, ChangeListener {
private static final long serialVersionUID = -2520889480615456474L;
private static final Log log = LogFactory.getLog(StartupDialog.class);
public static final String EMPTY_PASSWORD_SURROGATE = "NONE";
private Frame ownerFrame = null;
private HyperlinkActivatedListener hyperlinkListener = null;
private Jets3tProperties myProperties = null;
private AWSCredentials awsCredentials = null;
private JButton okButton = null;
private JButton cancelButton = null;
private JButton storeCredentialsButton = null;
private JTabbedPane tabbedPane = null;
private LoginPassphrasePanel loginPassphrasePanel = null;
private LoginLocalFolderPanel loginLocalFolderPanel = null;
private LoginCredentialsPanel loginCredentialsPanel = null;
private final Insets insetsZero = new Insets(0, 0, 0, 0);
private final Insets insetsDefault = new Insets(3, 5, 3, 5);
private static final int LOGIN_MODE_PASSPHRASE = 0;
private static final int LOGIN_MODE_LOCAL_FOLDER = 1;
private static final int LOGIN_MODE_DIRECT = 2;
private int loginMode = LOGIN_MODE_PASSPHRASE;
/**
* Creates a modal dialog box with a title.
*
* @param owner
* the frame within which this dialog will be displayed and centred.
* @param hyperlinkListener
*/
public StartupDialog(Frame owner, Jets3tProperties properties, HyperlinkActivatedListener hyperlinkListener) {
super(owner, "Cockpit Login", true);
this.ownerFrame = owner;
this.hyperlinkListener = hyperlinkListener;
this.myProperties = properties;
this.initGui();
}
/**
* Initialises all GUI elements.
*/
private void initGui() {
this.setResizable(false);
this.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
cancelButton = new JButton("Don't log in");
cancelButton.setActionCommand("Cancel");
cancelButton.addActionListener(this);
storeCredentialsButton = new JButton("Store Credentials");
storeCredentialsButton.setActionCommand("StoreCredentials");
storeCredentialsButton.addActionListener(this);
okButton = new JButton("Log in");
okButton.setActionCommand("LogIn");
okButton.addActionListener(this);
// Set default ENTER and ESCAPE buttons.
this.getRootPane().setDefaultButton(okButton);
this.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(KeyStroke.getKeyStroke("ESCAPE"), "ESCAPE");
this.getRootPane().getActionMap().put("ESCAPE", new AbstractAction() {
private static final long serialVersionUID = -1742280851624947873L;
public void actionPerformed(ActionEvent actionEvent) {
setVisible(false);
}
});
JPanel buttonsPanel = new JPanel(new GridBagLayout());
buttonsPanel.add(cancelButton, new GridBagConstraints(0, 0,
1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsZero, 0, 0));
buttonsPanel.add(storeCredentialsButton, new GridBagConstraints(1, 0,
1, 1, 1, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsZero, 0, 0));
buttonsPanel.add(okButton, new GridBagConstraints(2, 0,
1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsZero, 0, 0));
loginPassphrasePanel = new LoginPassphrasePanel(hyperlinkListener);
loginLocalFolderPanel = new LoginLocalFolderPanel(ownerFrame, hyperlinkListener);
loginCredentialsPanel = new LoginCredentialsPanel(false, hyperlinkListener);
// Tabbed Pane.
tabbedPane = new JTabbedPane();
tabbedPane.addChangeListener(this);
tabbedPane.add(loginPassphrasePanel, "S3 Online");
tabbedPane.add(loginLocalFolderPanel, "Local Folder");
tabbedPane.add(loginCredentialsPanel, "Direct Login");
int row = 0;
this.getContentPane().setLayout(new GridBagLayout());
this.getContentPane().add(tabbedPane, new GridBagConstraints(0, row++,
2, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsZero, 0, 0));
this.getContentPane().add(buttonsPanel, new GridBagConstraints(0, row++,
2, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0));
this.pack();
this.setSize(500, 400);
this.setLocationRelativeTo(this.getOwner());
}
/**
* Event handler for this dialog.
*/
public void actionPerformed(ActionEvent e) {
if (e.getSource().equals(okButton)) {
if (loginMode == LOGIN_MODE_PASSPHRASE) {
retrieveCredentialsFromS3(
loginPassphrasePanel.getPassphrase(), loginPassphrasePanel.getPassword());
} else if (loginMode == LOGIN_MODE_LOCAL_FOLDER) {
retrieveCredentialsFromDirectory(loginLocalFolderPanel.getHomeFolder(),
loginLocalFolderPanel.getAWSCredentialsFile(), loginLocalFolderPanel.getPassword());
} else if (loginMode == LOGIN_MODE_DIRECT) {
String[] inputErrors = loginCredentialsPanel.checkForInputErrors();
if (inputErrors.length > 0) {
String errorMessages = "Please correct the following errors:
";
for (int i = 0; i < inputErrors.length; i++) {
errorMessages += "- " + inputErrors[i] + "
";
}
errorMessages += "
";
ErrorDialog.showDialog(this, null, errorMessages, null);
} else {
if (loginCredentialsPanel.getUsingDevPay()) {
this.awsCredentials = new AWSDevPayCredentials(
loginCredentialsPanel.getAWSAccessKey(),
loginCredentialsPanel.getAWSSecretKey(),
loginCredentialsPanel.getAWSUserToken(),
loginCredentialsPanel.getAWSProductToken(),
loginCredentialsPanel.getFriendlyName());
} else {
this.awsCredentials = new AWSCredentials(
loginCredentialsPanel.getAWSAccessKey(),
loginCredentialsPanel.getAWSSecretKey(),
loginCredentialsPanel.getFriendlyName());
}
this.setVisible(false);
}
}
} else if (e.getSource().equals(storeCredentialsButton)) {
if (loginMode == LOGIN_MODE_PASSPHRASE) {
storeCredentialsInS3(
loginPassphrasePanel.getPassphrase(), loginPassphrasePanel.getPassword());
} else if (loginMode == LOGIN_MODE_LOCAL_FOLDER) {
storeCredentialsInDirectory(
loginLocalFolderPanel.getHomeFolder(), loginLocalFolderPanel.getPassword());
} else if (loginMode == LOGIN_MODE_DIRECT) {
throw new IllegalStateException("Cannot store AWS credentials from Direct Login panel");
}
} else if (e.getSource().equals(cancelButton)) {
this.awsCredentials = null;
this.setVisible(false);
}
}
public void stateChanged(ChangeEvent e) {
if (e.getSource().equals(tabbedPane)) {
loginMode = tabbedPane.getSelectedIndex();
changedLoginMode();
}
}
private void changedLoginMode() {
if (loginMode == LOGIN_MODE_PASSPHRASE) {
storeCredentialsButton.setEnabled(true);
} else if (loginMode == LOGIN_MODE_LOCAL_FOLDER) {
storeCredentialsButton.setEnabled(true);
} else if (loginMode == LOGIN_MODE_DIRECT) {
storeCredentialsButton.setEnabled(false);
} else {
throw new IllegalStateException("Invalid value for loginMode: " + loginMode);
}
}
private String generateBucketNameFromPassphrase(String passphrase) throws Exception {
return "jets3t-" + ServiceUtils.toHex(
ServiceUtils.computeMD5Hash(passphrase.getBytes(Constants.DEFAULT_ENCODING)));
}
private String generateObjectKeyFromPassphrase(String passphrase, String password) throws Exception {
String combinedString = passphrase + password;
return ServiceUtils.toHex(
ServiceUtils.computeMD5Hash(combinedString.getBytes(Constants.DEFAULT_ENCODING)))
+ "/jets3t.credentials";
}
private boolean validPassphraseInputs(String passphrase, String password) {
String invalidInputsMessage = "";
if (passphrase.length() < 6) {
invalidInputsMessage += "Passphrase must be at least 6 characters.";
}
if (password.length() < 6) {
invalidInputsMessage += (invalidInputsMessage.length() > 0
? " and password"
: "Password")
+ " must be at least 6 characters";
}
if (invalidInputsMessage.length() > 0) {
ErrorDialog.showDialog(this, hyperlinkListener, invalidInputsMessage, null);
return false;
} else {
return true;
}
}
private boolean validFolderInputs(boolean isStoreAction, File directory,
File credentialsFile, String password, boolean allowLegacyPassword)
{
if (password.length() < 6) {
if (allowLegacyPassword) {
// Legacy password allowed for login, an error will be displayed later if it's incorrect.
} else if (EMPTY_PASSWORD_SURROGATE.equals(password)) {
// Surrogate empty password was used, not an error.
} else {
ErrorDialog.showDialog(this, hyperlinkListener,
"Password must be at least 6 characters. " +
"If you do not wish to set a password, use the password " +
EMPTY_PASSWORD_SURROGATE + ".",
null);
return false;
}
}
if (!directory.exists() || !directory.canWrite()) {
String invalidInputsMessage = "Directory '" + directory.getAbsolutePath()
+ "' does not exist or cannot be written to.";
ErrorDialog.showDialog(this, hyperlinkListener, invalidInputsMessage, null);
return false;
}
if (credentialsFile == null && !isStoreAction) {
String invalidInputsMessage = "You must choose which stored login to use";
ErrorDialog.showDialog(this, hyperlinkListener, invalidInputsMessage, null);
return false;
}
return true;
}
private void retrieveCredentialsFromS3(String passphrase, final String password) {
if (!validPassphraseInputs(passphrase, password)) {
return;
}
final String[] bucketName = new String[1];
final String[] credentialObjectKey = new String[1];
try {
bucketName[0] = generateBucketNameFromPassphrase(passphrase);
credentialObjectKey[0] = generateObjectKeyFromPassphrase(passphrase, password);
} catch (Exception e) {
String message = "Unable to generate bucket name or object key";
log.error(message, e);
ErrorDialog.showDialog(this, hyperlinkListener, message, e);
return;
}
final ProgressDialog progressDialog = new ProgressDialog(
ownerFrame, "Retrieving AWS Credentials", null);
final StartupDialog myself = this;
(new Thread(new Runnable() {
public void run() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
progressDialog.startDialog("Downloading your AWS Credentials", "", 0, 0, null, null);
}
});
S3Object encryptedCredentialsObject = null;
try {
S3Service s3Service = new RestS3Service(null);
encryptedCredentialsObject = s3Service.getObject(
new S3Bucket(bucketName[0]), credentialObjectKey[0]);
} catch (S3ServiceException e) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
progressDialog.stopDialog();
}
});
String errorMessage = "Unable to find your AWS Credentials in S3"
+ "
Please check your passphrase and password ";
log.error(errorMessage, e);
ErrorDialog.showDialog(myself, hyperlinkListener, errorMessage, null);
return;
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
progressDialog.updateDialog("Decrypting your AWS Credentials", null, 0);
}
});
try {
myself.awsCredentials = AWSCredentials.load(password,
new BufferedInputStream(encryptedCredentialsObject.getDataInputStream()));
SwingUtilities.invokeLater(new Runnable() {
public void run() {
progressDialog.stopDialog();
}
});
myself.setVisible(false);
} catch (S3ServiceException e) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
progressDialog.stopDialog();
}
});
String errorMessage =
"Unable to load your AWS Credentials from S3: "
+ "
Please check your password ";
log.error(errorMessage, e);
ErrorDialog.showDialog(myself, hyperlinkListener, errorMessage, null);
}
}
})).start();
}
private void storeCredentialsInS3(String passphrase, String password) {
if (!validPassphraseInputs(passphrase, password)) {
return;
}
final AWSCredentials awsCredentials =
AWSCredentialsDialog.showDialog(ownerFrame,
(loginMode == LOGIN_MODE_LOCAL_FOLDER), hyperlinkListener);
if (awsCredentials == null) {
return;
}
final String[] bucketName = new String[1];
final String[] credentialObjectKey = new String[1];
try {
bucketName[0] = generateBucketNameFromPassphrase(passphrase);
credentialObjectKey[0] = generateObjectKeyFromPassphrase(passphrase, password);
} catch (Exception e) {
String message = "Unable to generate bucket name or object key";
log.error(message, e);
ErrorDialog.showDialog(this, hyperlinkListener, message, e);
return;
}
final ByteArrayInputStream[] bais = new ByteArrayInputStream[1];
try {
// Convert AWS Credentials into a readable input stream.
String algorithm = myProperties.getStringProperty("crypto.algorithm", "PBEWithMD5AndDES");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
awsCredentials.save(password, baos, algorithm);
bais[0] = new ByteArrayInputStream(baos.toByteArray());
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
String message = "Unable to encrypt your AWS Credentials";
log.error(message, e);
ErrorDialog.showDialog(this, hyperlinkListener, message, e);
return;
}
final ProgressDialog progressDialog = new ProgressDialog(
ownerFrame, "Storing AWS Credentials", null);
final StartupDialog myself = this;
(new Thread(new Runnable() {
public void run() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
progressDialog.startDialog("Uploading your AWS Credentials", null, 0, 0, null, null);
}
});
try {
S3Bucket bucket = new S3Bucket(bucketName[0]);
S3Object encryptedCredentialsObject = new S3Object(credentialObjectKey[0]);
encryptedCredentialsObject.setDataInputStream(bais[0]);
encryptedCredentialsObject.setAcl(AccessControlList.REST_CANNED_PUBLIC_READ);
// Store credentials
S3Service s3Service = new RestS3Service(awsCredentials);
s3Service.createBucket(bucketName[0]);
s3Service.putObject(bucket, encryptedCredentialsObject);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
progressDialog.stopDialog();
}
});
JOptionPane.showMessageDialog(ownerFrame, "Your AWS Credentials have been stored in your " +
"S3 account\n\nBucket name: " + bucketName[0] + "\nObject key: " + credentialObjectKey[0]);
} catch (S3ServiceException e) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
progressDialog.stopDialog();
}
});
String message = "Unable to store your AWS Credentials in S3";
log.error(message, e);
ErrorDialog.showDialog(myself, hyperlinkListener, message, e);
}
}
})).start();
}
private void retrieveCredentialsFromDirectory(File directory, File credentialsFile, String password) {
if (!validFolderInputs(false, directory, credentialsFile, password, true)) {
return;
}
try {
this.awsCredentials = AWSCredentials.load(password, credentialsFile);
this.setVisible(false);
} catch (Exception e) {
String message = "Unable to load your AWS Credentials from the file: "
+ credentialsFile + "
Please check your password ";
log.error(message, e);
ErrorDialog.showDialog(this, hyperlinkListener, message, null);
}
}
private void storeCredentialsInDirectory(File directory, String password) {
if (!validFolderInputs(true, directory, null, password, false)) {
return;
}
if (EMPTY_PASSWORD_SURROGATE.equals(password.trim())) {
password = "";
}
AWSCredentials awsCredentials =
AWSCredentialsDialog.showDialog(ownerFrame, true, hyperlinkListener);
if (awsCredentials == null) {
return;
}
if (awsCredentials.getFriendlyName() == null || awsCredentials.getFriendlyName().length() == 0) {
String message = "You must enter a nickname when storing your credentials";
log.error(message);
ErrorDialog.showDialog(this, hyperlinkListener, message, null);
return;
}
File credentialsFile = new File(directory, awsCredentials.getFriendlyName() + ".enc");
try {
String algorithm = myProperties.getStringProperty("crypto.algorithm", "PBEWithMD5AndDES");
awsCredentials.save(password, credentialsFile, algorithm);
loginLocalFolderPanel.clearPassword();
loginLocalFolderPanel.refreshStoredCredentialsTable();
JOptionPane.showMessageDialog(ownerFrame, "Your AWS Credentials have been stored in the file:\n" +
credentialsFile.getAbsolutePath());
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
String message = "Unable to encrypt your AWS Credentials to a folder";
log.error(message, e);
ErrorDialog.showDialog(this, hyperlinkListener, message, e);
}
}
public AWSCredentials getAWSCredentials() {
return this.awsCredentials;
}
/**
* Creates stand-alone dialog box for testing only.
*
* @param args
* @throws Exception
*/
public static void main(String args[]) throws Exception {
// String algorithm = Jets3tProperties.getInstance(Constants.JETS3T_PROPERTIES_FILENAME)
// .getStringProperty("crypto.algorithm", "PBEWithMD5AndDES");
// File file = new File("/Users/jmurty/Desktop/test.enc");
// AWSCredentials awsCredentialsTest = new AWSCredentials("a", "b");
// awsCredentialsTest.save("please", file, algorithm);
// System.err.println("Saved: " + awsCredentialsTest);
// System.err.println("Loaded: " + AWSCredentials.load("please", file));
// if (true)
// return;
//
JFrame f = new JFrame();
HyperlinkActivatedListener listener = new HyperlinkActivatedListener() {
private static final long serialVersionUID = -225585129296632961L;
public void followHyperlink(URL url, String target) {
BareBonesBrowserLaunch.openURL(url.toString());
}
};
StartupDialog startupDialog = new StartupDialog(f,
Jets3tProperties.getInstance(Constants.JETS3T_PROPERTIES_FILENAME), listener);
startupDialog.setVisible(true);
AWSCredentials awsCredentials = startupDialog.getAWSCredentials();
startupDialog.dispose();
if (awsCredentials != null) {
System.out.println("AWS Credentials: " + awsCredentials.getLogString());
} else {
System.out.println("AWS Credentials: null");
}
f.dispose();
}
}