| /* |
| * Copyright (C) 2012 The Android Open Source Project |
| * |
| * 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 com.motorolamobility.studio.android.certmanager.core; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.List; |
| |
| import org.eclipse.equinox.security.storage.ISecurePreferences; |
| import org.eclipse.equinox.security.storage.SecurePreferencesFactory; |
| import org.eclipse.equinox.security.storage.StorageException; |
| import org.eclipse.jface.dialogs.Dialog; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.widgets.Button; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.swt.widgets.Text; |
| import org.eclipse.ui.PlatformUI; |
| |
| import com.motorola.studio.android.common.log.StudioLogger; |
| import com.motorola.studio.android.common.utilities.EclipseUtils; |
| import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator; |
| import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException; |
| import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS; |
| |
| /** |
| * This class is responsible to retrieve passwords for a keystore and its entries. |
| * Usage: |
| * Instantiate with a keyStoreFile, call the methods getPassword. |
| * If needed a dialog will be shown, asking user to type the password. |
| */ |
| public class PasswordProvider |
| { |
| |
| private static final String PREF_ROOT_NODE = CertificateManagerActivator.PLUGIN_ID |
| + "_passwords"; //$NON-NLS-1$ |
| |
| private static final String KS_PASSWORD_KEY = "KS_PASSWORD"; //$NON-NLS-1$ |
| |
| private final class KeyStorePasswdDialog extends Dialog |
| { |
| private final File keyStoreFile; |
| |
| private String passwd; |
| |
| private boolean savePasswd; |
| |
| private Text paswordText; |
| |
| private Button saveCheckBox; |
| |
| private final String alias; |
| |
| private KeyStorePasswdDialog(Shell parentShell, File keyStoreFile, String alias) |
| { |
| super(parentShell); |
| this.keyStoreFile = keyStoreFile; |
| this.alias = alias; |
| } |
| |
| @Override |
| protected Control createDialogArea(Composite parent) |
| { |
| |
| Composite mainComposite = new Composite(parent, SWT.NONE); |
| GridLayout gridLayout = new GridLayout(2, false); |
| mainComposite.setLayout(gridLayout); |
| |
| //Creates the message |
| Label messageLabel = new Label(mainComposite, SWT.NONE); |
| GridData gridData = new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 2); |
| messageLabel.setLayoutData(gridData); |
| |
| if (this.alias.equals(KS_PASSWORD_KEY)) |
| { |
| getShell().setText(CertificateManagerNLS.PasswordProvider_DialogTitle); |
| messageLabel.setText(NLS.bind(CertificateManagerNLS.PasswordProvider_MessageLabel, |
| keyStoreFile.getName())); |
| } |
| else |
| { |
| getShell().setText(CertificateManagerNLS.CertificateBlock_KeyPassword_Label); |
| messageLabel.setText(NLS.bind( |
| CertificateManagerNLS.PasswordProvider_Key_MessageLabel, alias)); |
| } |
| |
| //Creates the text field label |
| Label passwdLabel = new Label(mainComposite, SWT.NONE); |
| gridData = new GridData(SWT.LEFT, SWT.CENTER, false, false); |
| passwdLabel.setLayoutData(gridData); |
| passwdLabel.setText(CertificateManagerNLS.PasswordProvider_PasswordLabel); |
| |
| //Creates the password text |
| paswordText = new Text(mainComposite, SWT.BORDER | SWT.PASSWORD); |
| gridData = new GridData(SWT.FILL, SWT.CENTER, true, false); |
| paswordText.setLayoutData(gridData); |
| |
| //Creates the save password checkbox |
| saveCheckBox = new Button(mainComposite, SWT.CHECK); |
| saveCheckBox.setText(CertificateManagerNLS.PasswordProvider_SaveThisPassword); |
| saveCheckBox.setSelection(false); |
| gridData = new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1); |
| saveCheckBox.setLayoutData(gridData); |
| saveCheckBox.setVisible(KeyStoreManager.getInstance().isKeystoreMapped(keyStoreFile)); |
| |
| return super.createDialogArea(parent); |
| } |
| |
| @Override |
| protected void okPressed() |
| { |
| passwd = paswordText.getText(); |
| savePasswd = saveCheckBox.getSelection(); |
| super.okPressed(); |
| } |
| |
| public String getPasswd() |
| { |
| return passwd; |
| } |
| |
| public boolean mustSavePasswd() |
| { |
| return savePasswd; |
| } |
| } |
| |
| private final File keyStoreFile; |
| |
| private final ISecurePreferences securePreferences; |
| |
| private boolean canSavePassword = true; |
| |
| public PasswordProvider(File keyStoreFile) |
| { |
| this(keyStoreFile, KeyStoreManager.getInstance().isKeystoreMapped(keyStoreFile)); |
| } |
| |
| public PasswordProvider(File keyStoreFile, boolean canSavePassword) |
| { |
| this.keyStoreFile = keyStoreFile; |
| this.securePreferences = SecurePreferencesFactory.getDefault(); |
| this.canSavePassword = canSavePassword; |
| } |
| |
| /** |
| * Retrieves the KeyStore password. |
| * @param promptPassword whether the password entry dialog will be shown or not |
| * @param useSavedPassword whether to use the keyStore saved password |
| * @return the password string or null if user canceled the dialog |
| * @throws KeyStoreManagerException |
| */ |
| public String getKeyStorePassword(boolean promptPassword, boolean useSavedPassword) |
| throws KeyStoreManagerException |
| { |
| return getPassword(KS_PASSWORD_KEY, promptPassword, useSavedPassword); |
| } |
| |
| /** |
| * Retrieves the KeyStore password. |
| * This method will always attempt to retrieve the saved password. |
| * It's behavior is the same as of calling the method getPassword(promptPassword, true) |
| * @param promptPassword whether the password entry dialog will be shown or not |
| * @return the password string or null if user canceled the dialog |
| * @throws KeyStoreManagerException |
| */ |
| public String getKeyStorePassword(boolean promptPassword) throws KeyStoreManagerException |
| { |
| return getPassword(KS_PASSWORD_KEY, promptPassword, true); |
| } |
| |
| /** |
| * Retrieves the password for a given alias within a keyStore. |
| * This method will always attempt to retrieve the saved password. |
| * It's behavior is the same as of calling the method getPassword(promptPassword, true) |
| * @param promptPassword whether the password entry dialog will be shown or not |
| * @return the password string or null if user canceled the dialog |
| * @throws KeyStoreManagerException |
| */ |
| public String getPassword(String alias, boolean promptPassword) throws KeyStoreManagerException |
| { |
| return getPassword(alias, promptPassword, true); |
| } |
| |
| /** |
| * Retrieves the password for a given alias within a keyStore. |
| * This method will always attempt to retrieve the saved password. |
| * It's behavior is the same as of calling the method getPassword(promptPassword, true) |
| * @param promptPassword whether the password entry dialog will be shown or not |
| * @param useSavedPassword whether to use the keyStore saved password |
| * @return the password string or null if user canceled the dialog |
| * @throws KeyStoreManagerException |
| */ |
| public String getPassword(String alias, boolean promptPassword, boolean useSavedPassword) |
| throws KeyStoreManagerException |
| { |
| String password = null; |
| |
| if (useSavedPassword) |
| { |
| if (securePreferences != null) |
| { |
| String prefKey = alias; |
| password = getSavedPasswd(prefKey); |
| } |
| else |
| { |
| throw new KeyStoreManagerException( |
| CertificateManagerNLS.PasswordProvider_Error_WhileSaving); |
| } |
| } |
| |
| if ((password == null) && promptPassword) |
| { |
| password = promptPassword(alias); |
| } |
| |
| return password; |
| } |
| |
| private String getSavedPasswd(String prefKey) |
| { |
| String password = null; |
| // Try to get the password from secure storage |
| if (securePreferences.nodeExists(PREF_ROOT_NODE)) |
| { |
| ISecurePreferences node = securePreferences.node(PREF_ROOT_NODE); |
| try |
| { |
| if (node.nodeExists(keyStoreFile.getAbsolutePath())) |
| { |
| ISecurePreferences ksNode = node.node(keyStoreFile.getAbsolutePath()); |
| password = ksNode.get(prefKey, null); |
| } |
| } |
| catch (StorageException e) |
| { |
| //Do nothing, password will be null. |
| } |
| } |
| return password; |
| } |
| |
| private String promptPassword(final String alias) throws KeyStoreManagerException |
| { |
| final String[] result = new String[1]; |
| final Boolean[] canProceed = new Boolean[1]; |
| |
| Display.getDefault().syncExec(new Runnable() |
| { |
| @Override |
| public void run() |
| { |
| KeyStorePasswdDialog dialog = |
| new KeyStorePasswdDialog(PlatformUI.getWorkbench() |
| .getModalDialogShellProvider().getShell(), keyStoreFile, alias); |
| |
| int diagStatus = dialog.open(); |
| |
| if (diagStatus == Dialog.OK) |
| { |
| //Read the values from the dialog and do the actions, return passwd and save if required |
| result[0] = dialog.getPasswd(); |
| |
| canSavePassword = KeyStoreManager.getInstance().isKeystoreMapped(keyStoreFile); |
| canProceed[0] = dialog.mustSavePasswd(); |
| } |
| else |
| { |
| //dialog cancelled |
| canProceed[0] = false; |
| result[0] = null; |
| } |
| } |
| }); |
| |
| if (canProceed[0] && canSavePassword) |
| { |
| if (securePreferences != null) |
| { |
| savePassword(alias, result[0]); |
| } |
| else |
| { |
| EclipseUtils.showWarningDialog(CertificateManagerNLS.PasswordProvider_DialogTitle, |
| CertificateManagerNLS.PasswordProvider_Error_WhileSaving); |
| } |
| } |
| |
| return result[0]; |
| } |
| |
| public void saveKeyStorePassword(String password) throws KeyStoreManagerException |
| { |
| savePassword(KS_PASSWORD_KEY, password); |
| } |
| |
| public void savePassword(final String alias, String password) throws KeyStoreManagerException |
| { |
| String prefKey; |
| canSavePassword = KeyStoreManager.getInstance().isKeystoreMapped(keyStoreFile); |
| if (canSavePassword) //protect from saving |
| { |
| if (alias != null) |
| { |
| prefKey = alias; |
| } |
| else |
| { |
| prefKey = KS_PASSWORD_KEY; |
| } |
| |
| ISecurePreferences rootNode = securePreferences.node(PREF_ROOT_NODE); |
| try |
| { |
| ISecurePreferences ksNode = rootNode.node(keyStoreFile.getAbsolutePath()); |
| ksNode.put(prefKey, password, true); |
| ksNode.flush(); |
| } |
| catch (Exception e) |
| { |
| throw new KeyStoreManagerException( |
| CertificateManagerNLS.PasswordProvider_Error_WhileSaving); |
| } |
| } |
| } |
| |
| /** |
| * Deletes the entire node (including KS_PASSWORD_KEY and children aliases) |
| * @throws KeyStoreManagerException |
| */ |
| public void deleteKeyStoreSavedPasswordNode() throws KeyStoreManagerException |
| { |
| deleteSavedPassword(null); |
| } |
| |
| /** |
| * Deletes only KS_PASSWORD_KEY (not children aliases) |
| */ |
| public void deleteKeyStoreSavedPassword() throws KeyStoreManagerException |
| { |
| deleteSavedPassword(KS_PASSWORD_KEY); |
| } |
| |
| public void deleteSavedPassword(String alias) throws KeyStoreManagerException |
| { |
| |
| ISecurePreferences ksNode = getKeyStoreNode(); |
| if (ksNode != null) |
| { |
| if (alias == null) |
| { |
| ksNode.removeNode(); |
| } |
| else |
| { |
| ksNode.remove(alias); |
| //if no item has no child, then we can remove the node |
| if (ksNode.keys().length == 0) |
| { |
| ksNode.removeNode(); |
| } |
| } |
| |
| try |
| { |
| ksNode.flush(); |
| } |
| catch (IllegalStateException e) |
| { |
| //Do nothing, node has already been removed |
| } |
| catch (IOException e) |
| { |
| throw new KeyStoreManagerException(NLS.bind( |
| CertificateManagerNLS.PasswordProvider_Error_WhileRemovingPassword, |
| keyStoreFile.getName())); |
| } |
| } |
| } |
| |
| /** |
| * This method will remove all saved entries for this keystore file that is not listed on the aliasList. |
| * The idea is to remove all saved passwords that makes reference to non-existant entries. |
| * @param aliasList the list of alias to be kept if available on the security keystore |
| * @throws KeyStoreManagerException if writing the security keystore fails for some reason |
| */ |
| public void cleanModel(List<String> aliasList) throws KeyStoreManagerException |
| { |
| ISecurePreferences keyStoreNode = getKeyStoreNode(); |
| if (keyStoreNode != null) |
| { |
| String[] savedKeys = keyStoreNode.keys(); |
| for (String savedAlias : savedKeys) |
| { |
| if (!savedAlias.equals(KS_PASSWORD_KEY) && !aliasList.contains(savedAlias)) |
| { |
| keyStoreNode.remove(savedAlias); |
| } |
| } |
| try |
| { |
| keyStoreNode.flush(); |
| } |
| catch (IOException e) |
| { |
| throw new KeyStoreManagerException(NLS.bind( |
| CertificateManagerNLS.PasswordProvider_Error_WhileRemovingPassword, |
| keyStoreFile.getName())); |
| } |
| } |
| } |
| |
| /* |
| * @return the keystore node if it exists |
| */ |
| private ISecurePreferences getKeyStoreNode() |
| { |
| ISecurePreferences ksNode = null; |
| if (securePreferences.nodeExists(PREF_ROOT_NODE)) |
| { |
| ISecurePreferences rootNode = securePreferences.node(PREF_ROOT_NODE); |
| |
| if (rootNode.nodeExists(keyStoreFile.getAbsolutePath())) |
| { |
| ksNode = rootNode.node(keyStoreFile.getAbsolutePath()); |
| } |
| } |
| return ksNode; |
| } |
| |
| /** |
| * If keystore password is saved. |
| */ |
| public boolean isPasswordSaved() |
| { |
| return isPasswordSaved(KS_PASSWORD_KEY); |
| } |
| |
| /** |
| * If alias password is saved. |
| */ |
| public boolean isPasswordSaved(String prefKey) |
| { |
| ISecurePreferences ksNode = null; |
| boolean isSaved = false; |
| if (securePreferences.nodeExists(PREF_ROOT_NODE)) |
| { |
| ISecurePreferences rootNode = securePreferences.node(PREF_ROOT_NODE); |
| ksNode = rootNode.node(keyStoreFile.getAbsolutePath()); |
| try |
| { |
| String value = ksNode.get(prefKey, null); |
| isSaved = value != null; //password is saved if it is not the default value (because password length should be at least 6 |
| } |
| catch (StorageException e) |
| { |
| StudioLogger.debug("It was not possible to get if the " + prefKey |
| + " is saved or not"); |
| isSaved = false; |
| } |
| } |
| return isSaved; |
| } |
| } |