diff --git a/rse/plugins/org.eclipse.rse.core/META-INF/MANIFEST.MF b/rse/plugins/org.eclipse.rse.core/META-INF/MANIFEST.MF index fc632b6fb0d..38cd455ebb3 100644 --- a/rse/plugins/org.eclipse.rse.core/META-INF/MANIFEST.MF +++ b/rse/plugins/org.eclipse.rse.core/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.rse.core;singleton:=true -Bundle-Version: 3.2.100.qualifier +Bundle-Version: 3.3.0.qualifier Bundle-Activator: org.eclipse.rse.core.RSECorePlugin Bundle-Localization: plugin Require-Bundle: org.eclipse.core.runtime, diff --git a/rse/plugins/org.eclipse.rse.core/pom.xml b/rse/plugins/org.eclipse.rse.core/pom.xml index 6a3eaa3fdc1..7eedba206c2 100644 --- a/rse/plugins/org.eclipse.rse.core/pom.xml +++ b/rse/plugins/org.eclipse.rse.core/pom.xml @@ -10,6 +10,6 @@ org.eclipse.tm org.eclipse.rse.core - 3.2.100-SNAPSHOT + 3.3.0-SNAPSHOT eclipse-plugin diff --git a/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/core/PasswordPersistenceManager.java b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/core/PasswordPersistenceManager.java index 87fda795404..589dc860468 100644 --- a/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/core/PasswordPersistenceManager.java +++ b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/core/PasswordPersistenceManager.java @@ -23,20 +23,25 @@ package org.eclipse.rse.core; +import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; -import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.equinox.security.storage.ISecurePreferences; +import org.eclipse.equinox.security.storage.SecurePreferencesFactory; +import org.eclipse.equinox.security.storage.StorageException; import org.eclipse.rse.core.model.SystemSignonInformation; import org.eclipse.rse.internal.core.RSECoreMessages; +import org.osgi.framework.Bundle; /** * PasswordPersistenceManager manages the saving and retrieving of user ID / @@ -54,24 +59,23 @@ public class PasswordPersistenceManager { */ private static class DefaultSystemType extends AbstractRSESystemType implements IRSESystemType { private static final String DEFAULT_ID = "DEFAULT"; //$NON-NLS-1$ - + private DefaultSystemType() { super(DEFAULT_ID, DEFAULT_ID, RSECoreMessages.DefaultSystemType_Label, null, null); } - + public String getId() { - //TODO consider a space character at the beginning to ensure uniqueness return DEFAULT_ID; } - + public String[] getSubsystemConfigurationIds() { return null; } - + public Object getAdapter(Class adapter) { return null; } - + public boolean isEnabled() { return true; } @@ -91,8 +95,8 @@ public class PasswordPersistenceManager { public static final int RC_DENIED = 2; public static final int RC_ERROR = -1; - // Default System Type, on a lookup if the specified system type and hostname is not found - // then the call will automatically lookup the default system type and hostname + // Default System Type, on a lookup if the specified system type and host name is not found + // then the call will automatically lookup the default system type and host name public static final IRSESystemType DEFAULT_SYSTEM_TYPE = new DefaultSystemType(); // Default user name @@ -109,23 +113,126 @@ public class PasswordPersistenceManager { public static final synchronized PasswordPersistenceManager getInstance() { if (_instance == null) { _instance = new PasswordPersistenceManager(); - _instance.initExtensions(); + _instance.initializeSystemTypes(); } return _instance; } /** - * Inner class used for storing registered system types + * Tests the existence of the Eclipse keyring API by looking for installation of the bundle containing + * the API. + * @return true if the API is installed. + */ + private static boolean isAuthorizationCompatabilityInstalled() { + boolean result = false; + Bundle authorizationBundle = Platform.getBundle("org.eclipse.core.runtime.compatability.auth"); //$NON-NLS-1$ + if (authorizationBundle == null) { + IStatus status = new Status(IStatus.INFO, RSECorePlugin.PLUGIN_ID, "Saved passwords are not available for migration to secure storage. Deprecated authorization classes (org.eclipse.core.runtime.compatability.auth) are not installed."); //$NON-NLS-1$ + RSECorePlugin.getDefault().getLog().log(status); + } else { + result = true; + } + return result; + } + + /** + * Examine the preferences to see if password saving is allowed. + * @param systemType The system type to check + * @param hostName The host name to check + * @return true if we are allow to save password for this system type and host + */ + private static boolean isSaveAllowed(IRSESystemType systemType, String hostName) { + boolean allowed = !RSEPreferencesManager.getDenyPasswordSave(systemType, hostName); + return allowed; + } + + /** + * Build the key to lookup the password for a specific + * user ID and host name + * @param hostName the name of the host + * @param userId the name of the user + * @return a key composed of the host and user name + */ + private static String getKey(String hostName, String userId) { + StringBuffer buffer = new StringBuffer(hostName); + buffer.append("//"); //$NON-NLS-1$ + buffer.append(userId); + return buffer.toString(); + } + + /** + * Retrieve a host name from a key. + * @param passwordKey the key to examine for a host + * @return the host name from the key + */ + private static String getHostNameFromKey(String passwordKey) { + int sepIndex = passwordKey.indexOf("//"); //$NON-NLS-1$ + return passwordKey.substring(0, sepIndex); + } + + /** + * Retrieve a user id from a key. + * @param passwordKey the key to examine for a host + * @return the user id from the key + */ + private static String getUserIdFromKey(String passwordKey) { + int sepIndex = passwordKey.indexOf("//"); //$NON-NLS-1$ + return passwordKey.substring(sepIndex + 2, passwordKey.length()); + } + + /** + * Given an array of keys into a password node for a system type return the ones that match the host name and user id criteria. + * Fuzzy matching will match hosts if one is a prefix of the other and they both resolve to the same network location. + * @param keys the original array of keys + * @param hostName the host name to match. + * @param userId the userId to match. This may be null. If it is then all users for this host name are matched. + * @param respectCase true if case must be respected to match a user id. + * @param fuzzy true if a fuzzy host name match is desired. + * @return a new array of keys from the original array that match the criteria. + */ + private static String[] getMatchingKeys(String[] keys, String hostName, String userId, boolean respectCase, boolean fuzzy) { + List selectedKeys = new ArrayList(); + for (int i = 0; i < keys.length; i++) { + String key = keys[i]; + String keyHostName = getHostNameFromKey(key); + String keyUserId = getUserIdFromKey(key); + boolean match = (userId == null || (respectCase ? userId.equals(keyUserId) : userId.equalsIgnoreCase(keyUserId))); + if (match) { + if (fuzzy) { + if (hostName.startsWith(keyHostName) || keyHostName.startsWith(hostName)) { + String khn = RSECorePlugin.getQualifiedHostName(keyHostName); + String phn = RSECorePlugin.getQualifiedHostName(hostName); + match = khn.equalsIgnoreCase(phn); + } else { + match = false; + } + } else { + match = hostName.equals(keyHostName); + } + } + if (match) { + selectedKeys.add(key); + } + } + String[] result = new String[selectedKeys.size()]; + selectedKeys.toArray(result); + return result; + } + + /** + * Inner class used for storing registered system types. + * In particular this class can be used to determine whether a given + * system type supports case-sensitive user id */ private class RegisteredSystemType { private IRSESystemType _systemType; private boolean _userIDCaseSensitive; - + protected RegisteredSystemType(IRSESystemType systemType, boolean caseSensitive) { _systemType = systemType; _userIDCaseSensitive = caseSensitive; } - + /** * Returns the system type. * @return the system type. @@ -133,7 +240,7 @@ public class PasswordPersistenceManager { public IRSESystemType getSystemType() { return _systemType; } - + /** * Returns whether the user ID is case sensitive. * @return true if the user ID is case sensitive, false otherwise. @@ -143,193 +250,236 @@ public class PasswordPersistenceManager { } } - // New URL to store password map - private String newURL = null; - - /* - * Instance variables - */ + private String mapLocation = null; private RegisteredSystemType[] systemTypes; /** - * Singleton so private constructor + * Singleton so this is a private constructor */ private PasswordPersistenceManager() { String userName = System.getProperty("user.name"); //$NON-NLS-1$ - if (userName == null) { userName = DEFAULT_USER_NAME; } - - newURL = SERVER_URL + userName; + if (isAuthorizationCompatabilityInstalled()) { + mapLocation = SERVER_URL + userName; + } } - - /* - * initialization - register system types + + /** + * Examine the system type extensions and construct an array of installed system types. */ - private void initExtensions() { + private void initializeSystemTypes() { IRSESystemType[] sysTypes = RSECorePlugin.getTheCoreRegistry().getSystemTypes(); systemTypes = new RegisteredSystemType[sysTypes.length]; - for (int i = 0; i < sysTypes.length; i++) { systemTypes[i] = new RegisteredSystemType(sysTypes[i], true); } } /** - * Helper class for building the key to lookup the password for a specific - * userid and hostname in the Map + * Retrieve the old password map from the Eclipse keyring for the specified system type. + * This uses deprecated APIs only if those APIs are installed. + * This should only be used to retrieve maps for migration to the new secure-storage API. + * @param systemTypeId the id of the system type to retrieve the map for + * @return a Map that maps keys composed of host names and user ids to passwords for this particular + * system type. Returns null if the API is not installed or there is no map found. */ - private String getPasswordKey(String hname, String userid) { - String hostname = hname;//RSEUIPlugin.getQualifiedHostName(hname); - StringBuffer buffer = new StringBuffer(hostname); - buffer.append("//"); //$NON-NLS-1$ - buffer.append(userid); - return buffer.toString(); + private Map getMap(String systemTypeId) { + Map passwordMap = null; + if (mapLocation != null) { + try { + URL serverURL = new URL(mapLocation); + passwordMap = Platform.getAuthorizationInfo(serverURL, systemTypeId, AUTH_SCHEME); + if (passwordMap == null) { + URL oldServerURL1 = new URL(SERVER_URL + ResourcesPlugin.getWorkspace().getRoot().getLocation().toOSString()); + passwordMap = Platform.getAuthorizationInfo(oldServerURL1, systemTypeId, AUTH_SCHEME); + if (passwordMap == null) { + URL oldServerURL2 = new URL(SERVER_URL); + passwordMap = Platform.getAuthorizationInfo(oldServerURL2, systemTypeId, AUTH_SCHEME); + } + } + } catch (MalformedURLException e) { + RSECorePlugin.getDefault().getLogger().logError("PasswordPersistenceManager.getPasswordMap", e); //$NON-NLS-1$ + } + } + return passwordMap; } - private String getHostnameFromPasswordKey(String passwordKey) { - int sepIndex = passwordKey.indexOf("//"); //$NON-NLS-1$ - return passwordKey.substring(0, sepIndex); - } - - private String getUserIdFromPasswordKey(String passwordKey) { - int sepIndex = passwordKey.indexOf("//"); //$NON-NLS-1$ - return passwordKey.substring(sepIndex + 2, passwordKey.length()); - } - - /* - * Retrieve the password map from the keyring for the specified system type + /** + * Migrates passwords stored in their old map form into a node of the + * secure preferences tree. The old map is left intact. + * @param parentNode the parent node of the new node for a system type that will + * hold all the passwords for that system type. The new node is created under this + * parent node. + * @param systemTypeId the id of this system type to create. The node is named with + * this identifier. */ - private Map getPasswordMap(IRSESystemType systemType) { - Map passwords = null; - String systemTypeId = systemType.getId(); - + private void migrateMap(ISecurePreferences parentNode, String systemTypeId) { + ISecurePreferences systemTypeNode = parentNode.node(systemTypeId); + Map passwordMap = getMap(systemTypeId); + if (passwordMap != null) { + Set entries = passwordMap.entrySet(); + for (Iterator z = entries.iterator(); z.hasNext();) { + Map.Entry entry = (Map.Entry) z.next(); + String key = (String) entry.getKey(); + String value = (String) entry.getValue(); + basicPut(systemTypeNode, key, value); + } + } + basicSave(systemTypeNode); + } + + /** + * Returns the preferences node that matches the system type. + * It will not return null but will create the node if it does not exist. + * If the node does not previous exist then an attempt will be made + * to migrate the values from the old map form to this newly created node + * of the secure preferences tree. + * @param systemType the system type to retrieve + * @return the matching secure preferences node. + */ + private ISecurePreferences getNode(IRSESystemType systemType) { + String id = systemType.getId(); + ISecurePreferences preferences = SecurePreferencesFactory.getDefault(); + ISecurePreferences rseNode = preferences.node("org.eclipse.rse.core.security"); //$NON-NLS-1$ + ISecurePreferences systemTypeNode = null; + if (!rseNode.nodeExists(id)) { + migrateMap(rseNode, id); + } + systemTypeNode = rseNode.node(id); + return systemTypeNode; + } + + /** + * Saves a node of the secure preferences tree. + * Logs an error if this cannot be saved for some reason. + * @param node the node to save. + */ + private void basicSave(ISecurePreferences node) { try { - URL serverURL = new URL(newURL); - passwords = Platform.getAuthorizationInfo(serverURL, systemTypeId, AUTH_SCHEME); - - // if no passwords found with new URL, check old URL - if (passwords == null) { - - URL oldServerURL1 = new URL(SERVER_URL + ResourcesPlugin.getWorkspace().getRoot().getLocation().toOSString()); - passwords = Platform.getAuthorizationInfo(oldServerURL1, systemTypeId, AUTH_SCHEME); - - // passwords found, so migrate to using new URL - if (passwords != null) { - savePasswordMap(systemTypeId, passwords); - } - // if still no passwords found, check with even older URL - else { - URL oldServerURL2 = new URL(SERVER_URL); - passwords = Platform.getAuthorizationInfo(oldServerURL2, systemTypeId, AUTH_SCHEME); - - // passwords found, so migrate to using new URL - if (passwords != null) { - savePasswordMap(systemTypeId, passwords); - } - } - } - } catch (MalformedURLException e) { - RSECorePlugin.getDefault().getLogger().logError("PasswordPersistenceManager.getPasswordMap", e); //$NON-NLS-1$ + node.flush(); + } catch (IOException e) { + IStatus status = new Status(IStatus.ERROR, RSECorePlugin.PLUGIN_ID, "Unexpected error saving password.", e); //$NON-NLS-1$ + RSECorePlugin.getDefault().getLog().log(status); } - - return passwords; } - - /* - * Retrieve the password map from the keyring for the specified system type + + /** + * Removes an entry from a node in the secure preferences tree. + * This entry is a password for a given host name and user id. + * @param node the node from which to remove the password entry. + * @param key the key consisting of a host name, user id pair + * @see #getKey(String, String) */ - private void savePasswordMap(String systemTypeId, Map passwords) { + private void basicRemove(ISecurePreferences node, String key) { + node.remove(key); + } + + /** + * Finds a password in a secure preferences node given its key. + * Logs an error if this cannot be found for some malfunction of the storage mechanism. + * @param node the node in which to find the password entry. + * @param key the key consisting of a host name, user id pair + * @see #getKey(String, String) + * @return the password associated with this key or null if the + * entry was not found. + */ + private String basicGet(ISecurePreferences node, String key) { + String value = null; try { - URL serverURL = new URL(newURL); - Platform.flushAuthorizationInfo(serverURL, systemTypeId, AUTH_SCHEME); - Platform.addAuthorizationInfo(serverURL, systemTypeId, AUTH_SCHEME, passwords); - } catch (MalformedURLException e) { - RSECorePlugin.getDefault().getLogger().logError("PasswordPersistenceManager.savePasswordMap", e); //$NON-NLS-1$ - } catch (CoreException e) { - RSECorePlugin.getDefault().getLogger().logError("PasswordPersistenceManager.savePasswordMap", e); //$NON-NLS-1$ + value = node.get(key, null); + } catch (StorageException e) { + IStatus status = new Status(IStatus.ERROR, RSECorePlugin.PLUGIN_ID, "Unexpected error retrieving password.", e); //$NON-NLS-1$ + RSECorePlugin.getDefault().getLog().log(status); + } + return value; + } + + /** + * Writes a password to a secure preferences node. + * Logs an error if this cannot be found for some malfunction of the storage mechanism. + * @param node the node in which to write the password entry. + * @param key the key consisting of a host name, user id pair + * @param value the password value to store for this key + * @see #getKey(String, String) + */ + private void basicPut(ISecurePreferences node, String key, String value) { + try { + node.put(key, value, true); + } catch (StorageException e) { + IStatus status = new Status(IStatus.ERROR, RSECorePlugin.PLUGIN_ID, "Unexpected error updating password.", e); //$NON-NLS-1$ + RSECorePlugin.getDefault().getLog().log(status); } } - private boolean removeFromPasswordMap(Map passwords, String hostname, String userid) { - boolean removed = false; - String password = null; - - String passwordKey = getPasswordKey(hostname, userid); - password = (String) passwords.get(passwordKey); - if (password != null) { - passwords.remove(passwordKey); - removed = true; - } else { - String phostname = hostname.toUpperCase(); - - // DKM - fallback for different case uids, hostnames or qualified/unqualified hostnames - Iterator keys = passwords.keySet().iterator(); - while (keys.hasNext() && password == null) { - String key = (String) keys.next(); - if (key.equalsIgnoreCase(passwordKey)) { - password = (String) passwords.get(key); - } else { - String khostname = getHostnameFromPasswordKey(key).toUpperCase(); - String kuid = getUserIdFromPasswordKey(key); - if (kuid.equalsIgnoreCase(userid)) { - // uid matches, check if hosts are the same - if (khostname.startsWith(phostname) || phostname.startsWith(khostname)) { - String qkhost = RSECorePlugin.getQualifiedHostName(khostname); - String qphost = RSECorePlugin.getQualifiedHostName(phostname); - if (qkhost.equals(qphost)) { - password = (String) passwords.get(key); - } - } - } - } - if (password != null) { - passwords.remove(key); - removed = true; - - } - } + /** + * Retrieves the password node for the given system type and removes password entries from that node. + * Removes only those that match the host name and user id exactly if one such entries exist. + * If no such entries exist then it will remove those for the host names that resolve to the same target as the specified host. + * @param systemType the IRSESystemType instance to remove passwords for. + * @param hostName the name of the host we are removing passwords for. + * @param userId the user id to remove passwords for. This may be null. If so then all users for this host name are affected. + * @return the number of passwords removed. + */ + private int removePassword(IRSESystemType systemType, String hostName, String userId) { + ISecurePreferences passwords = getNode(systemType); + boolean respectCase = isUserIDCaseSensitive(systemType); + String keys[] = getMatchingKeys(passwords.keys(), hostName, userId, respectCase, false); + if (keys.length == 0) { + keys = getMatchingKeys(passwords.keys(), hostName, userId, respectCase, true); } - return removed; - + for (int i = 0; i < keys.length; i++) { + String key = keys[i]; + basicRemove(passwords, key); + } + if (keys.length > 0) { + basicSave(passwords); + } + return keys.length; } - - private String getFromPasswordMap(Map passwords, String hostname, String userid) { + + /** + * Retrieves the password node for the given system type and finds a password in that node. + * Initially looks only at those entries that match the host name and user id exactly. + * If no such entries exist then it will examine those for the host names that resolve to the same target as the specified host. + * @param systemType the IRSESystemType instance to find a password for. + * @param hostName the name of the host we are examining for a password. + * @param userId the user id to find passwords for. + * @return the first such password found that meets these criteria or null if no entry in this + * system type node matches the criteria. + */ + private String findPassword(IRSESystemType systemType, String hostName, String userId) { String password = null; - - String passwordKey = getPasswordKey(hostname, userid); - password = (String) passwords.get(passwordKey); - if (password != null) return password; - - String phostname = hostname.toUpperCase(); - - // DKM - fallback for different case uids, hostnames or qualified/unqualified hostnames - Iterator keys = passwords.keySet().iterator(); - while (keys.hasNext() && password == null) { - String key = (String) keys.next(); - if (key.equalsIgnoreCase(passwordKey)) { - password = (String) passwords.get(key); - } else { - String khostname = getHostnameFromPasswordKey(key).toUpperCase(); - String kuid = getUserIdFromPasswordKey(key); - if (kuid.equalsIgnoreCase(userid)) { - // uid matches, check if hosts are the same - if (khostname.startsWith(phostname) || phostname.startsWith(khostname)) { - String qkhost = RSECorePlugin.getQualifiedHostName(khostname); - String qphost = RSECorePlugin.getQualifiedHostName(phostname); - if (qkhost.equals(qphost)) { - password = (String) passwords.get(key); - } - } - } - } + ISecurePreferences passwords = getNode(systemType); + boolean respectCase = isUserIDCaseSensitive(systemType); + String keys[] = getMatchingKeys(passwords.keys(), hostName, userId, respectCase, false); + if (keys.length == 0) { + keys = getMatchingKeys(passwords.keys(), hostName, userId, respectCase, true); + } + if (keys.length > 0) { + String key = keys[0]; + password = basicGet(passwords, key); } - return password; - } + /** + * Updates the password node for the given system type and finds a password in that node. + * Updates only that entry that matches the host name and user id exactly. + * If no such entries exist then it will add an entry for that host name and user id. + * @param systemType the IRSESystemType instance to find a password for. + * @param hostName the name of the host we are examining for a password. + * @param userId the user id to find passwords for. + * @param password the password to save for this entry. + */ + private void updatePassword(IRSESystemType systemType, String hostName, String userId, String password) { + ISecurePreferences passwords = getNode(systemType); + String key = getKey(hostName, userId); + basicPut(passwords, key, password); + basicSave(passwords); + } + /** * Add a password to the password database. * This will not update the entry for the default system type @@ -345,9 +495,9 @@ public class PasswordPersistenceManager { /** * Add a password to the password database. - * @param info The signon information to store - * @param overwrite If true then overwrite the existing entry for this systemtype, hostname, and userid. - * @param updateDefault if true then set the entry for the default systemtype, hostname, and user ID, according to the overwrite setting. + * @param info The SystemSignonInformation to store + * @param overwrite If true then overwrite the existing entry for this system type, host name, and user id. + * @param updateDefault if true then set the entry for the default system type, host name, and user ID, according to the overwrite setting. * @return * RC_OK if the password was successfully stored. * RC_ALREADY_EXISTS if the password already exists and overwrite was false @@ -359,8 +509,7 @@ public class PasswordPersistenceManager { String hostName = info.getHostname(); String userId = info.getUserId(); String newPassword = info.getPassword(); - boolean deny = RSEPreferencesManager.getDenyPasswordSave(systemType, hostName); - if (!deny) { + if (isSaveAllowed(systemType, hostName)) { if (!isUserIDCaseSensitive(systemType)) { userId = userId.toUpperCase(); info.setUserId(userId); @@ -371,22 +520,11 @@ public class PasswordPersistenceManager { result = add(newInfo, overwrite, false); } } - Map passwords = getPasswordMap(systemType); - if (passwords == null) { - passwords = new HashMap(5); - } - String oldPassword = getFromPasswordMap(passwords, hostName, userId); - if (oldPassword != null) { - if (overwrite) { - removeFromPasswordMap(passwords, hostName, userId); - } else { - result = RC_ALREADY_EXISTS; - } - } - if (result == RC_OK) { - String passwordKey = getPasswordKey(hostName, userId); - passwords.put(passwordKey, newPassword); - savePasswordMap(systemType.getId(), passwords); + String oldPassword = findPassword(systemType, hostName, userId); + if (oldPassword == null || (overwrite && !newPassword.equals(oldPassword))) { + updatePassword(systemType, hostName, userId, newPassword); + } else if (oldPassword != null) { + result = RC_ALREADY_EXISTS; } } else { result = RC_DENIED; @@ -395,73 +533,76 @@ public class PasswordPersistenceManager { } /** - * Check if a password entry exists for the specified system type, hostname - * and userid. + * Determines if password entry exists for a given system type, host name, and user id. + * @param systemType the IRSESystemType instance to find a password for. + * @param hostName the name of the host we are examining for a password. + * @param userId the user id to find passwords for. + * @return true if a password exists that meets the search criteria. */ - public boolean passwordExists(IRSESystemType systemtype, String hostname, String userid) { - - return passwordExists(systemtype, hostname, userid, true); + public boolean passwordExists(IRSESystemType systemType, String hostName, String userId) { + return passwordExists(systemType, hostName, userId, true); } /** - * Check if a password entry exists for the specified system type, hostname - * and userid. - * - * @param systemtype The system type to check for. - * @param hname The hostname to check for. - * @param userid The user ID to check for. + * Determine if a password entry exists for the specified system type, host name, and user id. + * @param systemType the IRSESystemType instance to find a password for. + * @param hostName the name of the host we are examining for a password. + * @param userId the user id to find passwords for. * @param checkDefault Whether or not to check for a default system type if the specified system type is not found. + * @return true if a password exists that meets the search criteria. */ - public boolean passwordExists(IRSESystemType systemtype, String hname, String userid, boolean checkDefault) { - String hostname = hname;//RSEUIPlugin.getQualifiedHostName(hname); - return (find(systemtype, hostname, userid) != null); + public boolean passwordExists(IRSESystemType systemType, String hostName, String userId, boolean checkDefault) { + SystemSignonInformation info = find(systemType, hostName, userId, checkDefault); + return (info != null); } /** - * Find the password for the specified systemtype, hostname and userid. - * If one is not found then the default system type is used. - * The system type in the signon information returned may not be the same as the system type - * specfied in the argument. + * Find the password for the specified system type, host name and user id. + * If one is not found then the default system type is also searched, thus + * the system type in the returned SystemSignonInformation may not be the same as the system type + * specified in the argument. + * @param systemType the IRSESystemType instance to find a password for. + * @param hostName the name of the host we are examining for a password. + * @param userId the user id to find passwords for. + * @return the {@link SystemSignonInformation} for the specified criteria. */ - public SystemSignonInformation find(IRSESystemType systemtype, String hostname, String userid) { - return find(systemtype, hostname, userid, true); + public SystemSignonInformation find(IRSESystemType systemType, String hostName, String userId) { + return find(systemType, hostName, userId, true); } /** - * Find the persisted password for the specified systemtype, hostname and userid. - * - * @param systemtype The system type to check for. - * @param hname The hostname to check for. - * @param userid The user ID to check for. - * @param checkDefault Whether or not to check for a default system type if the specified system type is not found. + * Find the password for the specified system type, host name and user id. + * If one is not found then the default system type is also searched, thus + * the system type in the returned SystemSignonInformation may not be the same as the system type + * specified in the argument. + * @param systemType the IRSESystemType instance to find a password for. + * @param hostName the name of the host we are examining for a password. + * @param userId the user id to find passwords for. + * @param checkDefault true if the default system type should be checked if the specified system type is not found + * @return the {@link SystemSignonInformation} for the specified criteria. */ - public SystemSignonInformation find(IRSESystemType systemtype, String hname, String userid, boolean checkDefault) { - String hostname = hname;//RSEUIPlugin.getQualifiedHostName(hname); - // Convert userid to upper case if required - if (!isUserIDCaseSensitive(systemtype) && userid != null) { - userid = userid.toUpperCase(); + public SystemSignonInformation find(IRSESystemType systemType, String hostName, String userId, boolean checkDefault) { + SystemSignonInformation result = null; + if (userId != null && !isUserIDCaseSensitive(systemType)) { + userId = userId.toUpperCase(); } - - Map passwords = getPasswordMap(systemtype); - - if (passwords != null) { - String password = getFromPasswordMap(passwords, hostname, userid); - + if (result == null) { + String password = findPassword(systemType, hostName, userId); if (password != null) { - return new SystemSignonInformation(hostname, userid, password, systemtype); + result = new SystemSignonInformation(hostName, userId, password, systemType); } } - - // yantzi: RSE6.2 check for default system type entry with this hostname and user ID - if (checkDefault && !DEFAULT_SYSTEM_TYPE.equals(systemtype)) { - return find(DEFAULT_SYSTEM_TYPE, hostname, userid, false); + if (result == null && checkDefault && !systemType.equals(DEFAULT_SYSTEM_TYPE)) { + String password = findPassword(DEFAULT_SYSTEM_TYPE, hostName, userId); + if (password != null) { + result = new SystemSignonInformation(hostName, userId, password, DEFAULT_SYSTEM_TYPE); + } } - - return null; + return result; } /** - * Remove the entry from the keyring that matches the systemtype, hostname and + * Remove the password entry that matches the system type, host name and * user ID from the SystemSignonInfo parameter. */ public void remove(SystemSignonInformation info) { @@ -469,127 +610,85 @@ public class PasswordPersistenceManager { } /** - * Removes all passwords for a host name for a given system type. Use the - * default system type explicitly to remove those entries. - * + * Removes all passwords for a host name for a given system type. + * This does not remove entries for the default system type. + * The default system type must be explicitly stated to remove those entries. * @param systemType The system type of the host - * @param hostName The IP address of the host in canonical format - * @return the number of passwords removed from the keyring + * @param hostName The IP address or name of the host in canonical format + * @return the number of passwords removed * @since org.eclipse.rse.core 3.0 */ public int remove(IRSESystemType systemType, String hostName) { - Map passwords = getPasswordMap(systemType); - int numberRemoved = 0; - if (passwords != null) { - String hostPrefix = hostName + "//"; //$NON-NLS-1$ - Set keys = passwords.keySet(); - for (Iterator z = keys.iterator(); z.hasNext();) { - String key = (String) z.next(); - if (key.startsWith(hostPrefix)) { - z.remove(); // safely removes the key and the entry from the map - numberRemoved++; - } - } - if (numberRemoved > 0) { - savePasswordMap(systemType.getId(), passwords); - } - } - return numberRemoved; + int result = removePassword(systemType, hostName, null); + return result; } /** - * Removes all entries from the keyring that match the hostname, userid, and system type. - * Use the default system type explicitly to remove those entries. + * Removes all entries that match the host name, user id, and system type. + * This does not remove entries for the default system type. + * The default system type must be explicitly stated to remove those entries. * @param systemType the systemType * @param hostName the connection name - * @param userid the user id + * @param userId the user id */ - public void remove(IRSESystemType systemType, String hostName, String userid) { - String hostname = hostName;//RSEUIPlugin.getQualifiedHostName(hname); - // Convert userid to upper case if required + public void remove(IRSESystemType systemType, String hostName, String userId) { if (!isUserIDCaseSensitive(systemType)) { - userid = userid.toUpperCase(); - } - Map passwords = getPasswordMap(systemType); - if (passwords != null) { - if (removeFromPasswordMap(passwords, hostname, userid)) { - savePasswordMap(systemType.getId(), passwords); - } + userId = userId.toUpperCase(); } + removePassword(systemType, hostName, userId); } /** - * Retrieve the list of registered system types + * Retrieve the list of registered system types. + * This includes the default system type as well. + * @return an array of {@link IRSESystemType}. */ public IRSESystemType[] getRegisteredSystemTypes() { - // yantzi: artemis 6.2, added default system type to list IRSESystemType[] types = new IRSESystemType[systemTypes.length + 1]; - types[0] = DEFAULT_SYSTEM_TYPE; - for (int i = 0; i < systemTypes.length; i++) { types[i + 1] = systemTypes[i].getSystemType(); } - return types; } /** - * Retrieve a list of the stored user IDs. - * + * Retrieves a list of SystemSignonInformation instances that have been saved. + * These instances do not contain the saved passwords. * @return List A list of the stored user IDs as SystemSignonInformation instances * without the saved passwords. */ public List getSavedUserIDs() { List savedUserIDs = new ArrayList(); - Map passwords; - String key; - int separator; - + IRSESystemType[] systemTypes = getRegisteredSystemTypes(); for (int i = 0; i < systemTypes.length; i++) { - passwords = getPasswordMap(systemTypes[i].getSystemType()); - if (passwords != null) { - Iterator keys = passwords.keySet().iterator(); - while (keys.hasNext()) { - key = (String) keys.next(); - separator = key.indexOf("//"); //$NON-NLS-1$ - savedUserIDs.add(new SystemSignonInformation(key.substring(0, separator), // hostname - key.substring(separator + 2), // userid - systemTypes[i].getSystemType())); // system type - } + IRSESystemType systemType = systemTypes[i]; + ISecurePreferences node = getNode(systemType); + String[] keys = node.keys(); + for (int j = 0; j < keys.length; j++) { + String key = keys[j]; + String hostName = getHostNameFromKey(key); + String userId = getUserIdFromKey(key); + SystemSignonInformation info = new SystemSignonInformation(hostName, userId, systemType); + savedUserIDs.add(info); } } - - // yantzi: RSE 6.2 Get DEFAULT system types too - passwords = getPasswordMap(DEFAULT_SYSTEM_TYPE); - if (passwords != null) { - Iterator keys = passwords.keySet().iterator(); - while (keys.hasNext()) { - key = (String) keys.next(); - separator = key.indexOf("//"); //$NON-NLS-1$ - savedUserIDs.add(new SystemSignonInformation(key.substring(0, separator), // hostname - key.substring(separator + 2), // userid - DEFAULT_SYSTEM_TYPE)); // system type - } - } - return savedUserIDs; } /** - * Helper method for determining if system type uses case sensitive user IDs + * Helper method for determining if system type uses case sensitive user IDs. + * @return true if the system type treats user ids as case sensitive. */ public boolean isUserIDCaseSensitive(IRSESystemType systemType) { - // First find the correct provider + boolean result = true; for (int i = 0; i < systemTypes.length; i++) { - if (systemTypes[i].getSystemType().equals(systemType)) { - return systemTypes[i].isUserIDCaseSensitive(); + result = systemTypes[i].isUserIDCaseSensitive(); + break; } } - - //Not found: Default system type is case sensitive - return true; + return result; } } \ No newline at end of file