| /******************************************************************************* |
| * Copyright (c) 2011, 2017 SAP AG |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Lazar Kirchev, SAP AG - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.equinox.console.storage; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileNotFoundException; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.util.HashSet; |
| import java.util.Properties; |
| import java.util.Set; |
| |
| /** |
| * This class implements a storage for users, passwords and roles. The data is stored in a |
| * properties-like file in the format /ssh/<username>/password=<password> and |
| * /ssh/<username>/roles=<comma_separated_list_of_roles> |
| * |
| * |
| */ |
| public class SecureUserStore { |
| |
| private static final String USER_STORE_FILE_NAME = "org.eclipse.equinox.console.jaas.file"; |
| private static final String PASSWORD_KEY = "password"; |
| private static final String ROLES_KEY = "roles"; |
| private static final String SSH_PREFIX = "/ssh"; |
| private static final String DELIMITER = "/"; |
| private static final int USERNAME_INDEX = 2; |
| private static final int KEY_ELEMENTS_COUNT = 4; |
| |
| /** |
| * Gets the usernames of all users. |
| * |
| * @return String array containing the usernames |
| */ |
| public static String[] getUserNames() { |
| String userFileLoc = getFileLocation(); |
| InputStream in = null; |
| |
| try { |
| in = new FileInputStream(userFileLoc); |
| Properties users = null; |
| try { |
| users = populateUserStore(in); |
| } catch (IOException e) { |
| throw new IllegalArgumentException("Cannot load properties from file " + userFileLoc); |
| } |
| Set<String> userNames = new HashSet<>(); |
| for (Object key : users.keySet()) { |
| if (!(key instanceof String)) { |
| continue; |
| } |
| String[] parts = ((String) key).split(DELIMITER); |
| // since the key starts with DELIMITER, the first element of key.split(DELIMITER) is an empty string |
| // that is why the result is {"", "ssh", "<username>", "password"} or {"", "ssh", "<username>", "roles"} |
| if (parts.length < KEY_ELEMENTS_COUNT) { |
| continue; |
| } |
| userNames.add(parts[USERNAME_INDEX]); |
| } |
| |
| return userNames.toArray(new String[0]); |
| |
| } catch (FileNotFoundException e) { |
| throw new IllegalArgumentException("File " + userFileLoc + " does not exist"); |
| } finally { |
| if (in != null) { |
| try { |
| in.close(); |
| } catch (IOException e) { |
| //do nothing |
| } |
| } |
| } |
| } |
| |
| public static String getPassword(String username) { |
| return getProperty(username, PASSWORD_KEY); |
| } |
| |
| public static String getRoles(String username) { |
| return getProperty(username, ROLES_KEY); |
| } |
| |
| /** |
| * Stores a user entry to the store. |
| * |
| * @param username the name of the user |
| * @param password the password of the user |
| * @param roles comma-separated list of the roles of the user |
| */ |
| public static void putUser(String username, String password, String roles) { |
| String userFileLoc = getFileLocation(); |
| InputStream in = null; |
| OutputStream out = null; |
| |
| try { |
| in = new FileInputStream(userFileLoc); |
| Properties users = null; |
| |
| try { |
| users = populateUserStore(in); |
| } catch (IOException e) { |
| throw new IllegalArgumentException("Cannot load properties from file " + userFileLoc); |
| } |
| |
| if (existsUser(username, users)){ |
| throw new IllegalArgumentException("The user already exists!"); |
| } |
| |
| if (roles == null) { |
| roles = ""; |
| } |
| |
| String userPassKey = constructPropertyName(username, PASSWORD_KEY); |
| String userRolesKey = constructPropertyName(username, ROLES_KEY); |
| users.put(userPassKey, password); |
| users.put(userRolesKey, roles); |
| |
| out = new FileOutputStream(userFileLoc); |
| try { |
| users.store(out, null); |
| } catch (IOException e) { |
| throw new IllegalArgumentException("Cannot store properties in file " + userFileLoc); |
| } |
| } catch (FileNotFoundException e) { |
| throw new IllegalArgumentException("File " + userFileLoc + " does not exist"); |
| } finally { |
| if (in != null) { |
| try { |
| in.close(); |
| } catch (IOException e) { |
| //do nothing |
| } |
| } |
| |
| if (out != null) { |
| try { |
| out.close(); |
| } catch (IOException e) { |
| // do nothing |
| } |
| } |
| } |
| } |
| |
| /** |
| * Adds roles for a particular user |
| * |
| * @param username user to add roles to |
| * @param roles comma-separated list of new roles for the user |
| */ |
| public static void addRoles(String username, String roles) { |
| if (roles == null || roles.length() == 0) { |
| return; |
| } |
| |
| String userFileLoc = getFileLocation(); |
| InputStream in = null; |
| OutputStream out = null; |
| |
| try { |
| in = new FileInputStream(userFileLoc); |
| Properties users = null; |
| |
| try { |
| users = populateUserStore(in); |
| } catch (IOException e) { |
| throw new IllegalArgumentException("Cannot load properties from file " + userFileLoc); |
| } |
| |
| String userRolesKey = constructPropertyName(username, ROLES_KEY); |
| String currentRoles = (String)users.remove(userRolesKey); |
| Set<String> rolesSet = new HashSet<>(); |
| |
| if (currentRoles.length() > 0) { |
| for (String role : currentRoles.split(",")) { |
| rolesSet.add(role); |
| } |
| } |
| |
| for (String role : roles.split(",")) { |
| rolesSet.add(role); |
| } |
| |
| StringBuilder builder = new StringBuilder(); |
| for (String role : rolesSet) { |
| builder.append(role); |
| builder.append(","); |
| } |
| builder.deleteCharAt(builder.lastIndexOf(",")); |
| |
| users.put(userRolesKey, builder.toString()); |
| |
| out = new FileOutputStream(userFileLoc); |
| try { |
| users.store(out, null); |
| } catch (IOException e) { |
| throw new IllegalArgumentException("Cannot store properties in file " + userFileLoc); |
| } |
| } catch (FileNotFoundException e) { |
| throw new IllegalArgumentException("File " + userFileLoc + " does not exist"); |
| } finally { |
| if (in != null) { |
| try { |
| in.close(); |
| } catch (IOException e) { |
| //do nothing |
| } |
| } |
| |
| if (out != null) { |
| try { |
| out.close(); |
| } catch (IOException e) { |
| // do nothing |
| } |
| } |
| } |
| } |
| |
| /** |
| * Removes roles from a user |
| * |
| * @param username user to remove roles from |
| * @param rolesToRemove comma-separated list of roles to be removed |
| */ |
| public static void removeRoles(String username, String rolesToRemove) { |
| if(rolesToRemove == null || rolesToRemove.length() == 0) { |
| return; |
| } |
| String userFileLoc = getFileLocation(); |
| InputStream in = null; |
| OutputStream out = null; |
| |
| try { |
| in = new FileInputStream(userFileLoc); |
| Properties users = null; |
| |
| try { |
| users = populateUserStore(in); |
| } catch (IOException e) { |
| throw new IllegalArgumentException("Cannot load properties from file " + userFileLoc); |
| } |
| |
| String userRolesKey = constructPropertyName(username, ROLES_KEY); |
| String currentRoles = (String)users.remove(userRolesKey); |
| Set<String> rolesSet = new HashSet<>(); |
| |
| for (String role : currentRoles.split(",")) { |
| rolesSet.add(role); |
| } |
| |
| for (String role : rolesToRemove.split(",")) { |
| rolesSet.remove(role); |
| } |
| |
| StringBuilder builder = new StringBuilder(); |
| for (String role : rolesSet) { |
| builder.append(role); |
| builder.append(","); |
| } |
| builder.deleteCharAt(builder.lastIndexOf(",")); |
| |
| users.put(userRolesKey, builder.toString()); |
| |
| out = new FileOutputStream(userFileLoc); |
| try { |
| users.store(out, null); |
| } catch (IOException e) { |
| throw new IllegalArgumentException("Cannot store properties in file " + userFileLoc); |
| } |
| } catch (FileNotFoundException e) { |
| throw new IllegalArgumentException("File " + userFileLoc + " does not exist"); |
| } finally { |
| if (in != null) { |
| try { |
| in.close(); |
| } catch (IOException e) { |
| //do nothing |
| } |
| } |
| |
| if (out != null) { |
| try { |
| out.close(); |
| } catch (IOException e) { |
| // do nothing |
| } |
| } |
| } |
| } |
| |
| /** |
| * Removes an entry for the user from the store. |
| * |
| * @param username user to be removed |
| */ |
| public static void deleteUser(String username) { |
| String userFileLoc = getFileLocation(); |
| InputStream in = null; |
| OutputStream out = null; |
| |
| try { |
| in = new FileInputStream(userFileLoc); |
| Properties users = null; |
| |
| try { |
| users = populateUserStore(in); |
| } catch (IOException e) { |
| throw new IllegalArgumentException("Cannot load properties from file " + userFileLoc); |
| } |
| |
| if (!existsUser(username, users)){ |
| throw new IllegalArgumentException("The user does not exist!"); |
| } |
| |
| // Set<Object> keys = users.keySet(); |
| // for (Object key : keys) { |
| // if ((key instanceof String) && ((String) key).contains(DELIMITER + username + DELIMITER)) { |
| // users.remove(key); |
| // } |
| // } |
| String rolesProperty = constructPropertyName(username, ROLES_KEY); |
| String passwordProperty = constructPropertyName(username, PASSWORD_KEY); |
| |
| users.remove(rolesProperty); |
| users.remove(passwordProperty); |
| |
| out = new FileOutputStream(userFileLoc); |
| try { |
| users.store(out, null); |
| } catch (IOException e) { |
| throw new IllegalArgumentException("Cannot store properties in file " + userFileLoc); |
| } |
| } catch (FileNotFoundException e) { |
| throw new IllegalArgumentException("File " + userFileLoc + " does not exist"); |
| } finally { |
| if (in != null) { |
| try { |
| in.close(); |
| } catch (IOException e) { |
| //do nothing |
| } |
| } |
| |
| if (out != null) { |
| try { |
| out.close(); |
| } catch (IOException e) { |
| // do nothing |
| } |
| } |
| } |
| } |
| |
| /** |
| * Removes the password for a user |
| * |
| * @param username user to reset the password |
| */ |
| public static void resetPassword(String username) { |
| String userFileLoc = getFileLocation(); |
| InputStream in = null; |
| OutputStream out = null; |
| |
| try { |
| in = new FileInputStream(userFileLoc); |
| Properties users = null; |
| |
| try { |
| users = populateUserStore(in); |
| } catch (IOException e) { |
| throw new IllegalArgumentException("Cannot load properties from file " + userFileLoc); |
| } |
| |
| if (!existsUser(username, users)){ |
| throw new IllegalArgumentException("The user does not exist!"); |
| } |
| |
| for (Object key : users.keySet()) { |
| if (key instanceof String && ((String) key).contains(DELIMITER + username + DELIMITER + PASSWORD_KEY)) { |
| users.remove(key); |
| break; |
| } |
| } |
| |
| out = new FileOutputStream(userFileLoc); |
| try { |
| users.store(out, null); |
| } catch (IOException e) { |
| throw new IllegalArgumentException("Cannot store properties in file " + userFileLoc); |
| } |
| } catch (FileNotFoundException e) { |
| throw new IllegalArgumentException("File " + userFileLoc + " does not exist"); |
| } finally { |
| if (in != null) { |
| try { |
| in.close(); |
| } catch (IOException e) { |
| //do nothing |
| } |
| } |
| |
| if (out != null) { |
| try { |
| out.close(); |
| } catch (IOException e) { |
| // do nothing |
| } |
| } |
| } |
| } |
| |
| /** |
| * Sets or changes the password for a user |
| * |
| * @param username user to set tha password for |
| * @param password the new password |
| */ |
| public static void setPassword(String username, String password) { |
| String userFileLoc = getFileLocation(); |
| InputStream in = null; |
| OutputStream out = null; |
| |
| try { |
| in = new FileInputStream(userFileLoc); |
| Properties users = null; |
| |
| try { |
| users = populateUserStore(in); |
| } catch (IOException e) { |
| throw new IllegalArgumentException("Cannot load properties from file " + userFileLoc); |
| } |
| |
| if (!existsUser(username, users)){ |
| throw new IllegalArgumentException("The user does not exist!"); |
| } |
| |
| String passwordPropertyName = constructPropertyName(username, PASSWORD_KEY); |
| for (Object key : users.keySet()) { |
| if ((key instanceof String) && ((String) key).contains(passwordPropertyName)) { |
| users.remove(key); |
| break; |
| } |
| } |
| |
| users.put(passwordPropertyName, password); |
| |
| out = new FileOutputStream(userFileLoc); |
| try { |
| users.store(out, null); |
| } catch (IOException e) { |
| throw new IllegalArgumentException("Cannot store properties in file " + userFileLoc); |
| } |
| } catch (FileNotFoundException e) { |
| throw new IllegalArgumentException("File " + userFileLoc + " does not exist"); |
| } finally { |
| if (in != null) { |
| try { |
| in.close(); |
| } catch (IOException e) { |
| //do nothing |
| } |
| } |
| |
| if (out != null) { |
| try { |
| out.close(); |
| } catch (IOException e) { |
| // do nothing |
| } |
| } |
| } |
| } |
| |
| /** |
| * CHecks if an entry for a user exists in the store |
| * |
| * @param username user to check |
| * @return true if there is an entry for this user in the store, false otherwise |
| */ |
| public static boolean existsUser(String username) { |
| String userFileLoc = getFileLocation(); |
| InputStream in = null; |
| try { |
| in = new FileInputStream(userFileLoc); |
| Properties users = null; |
| |
| try { |
| users = populateUserStore(in); |
| } catch (IOException e) { |
| throw new IllegalArgumentException("Cannot load properties from file " + userFileLoc); |
| } |
| |
| return existsUser(username, users); |
| } catch (FileNotFoundException e) { |
| throw new IllegalArgumentException("File " + userFileLoc + " does not exist"); |
| } finally { |
| if (in != null) { |
| try { |
| in.close(); |
| } catch (IOException e) { |
| //do nothing |
| } |
| } |
| } |
| } |
| |
| /** |
| * Creates the store file if it does not exist |
| * |
| * @throws IOException |
| */ |
| public static void initStorage() throws IOException { |
| String userFileLoc = getFileLocation(); |
| File file = new File(userFileLoc); |
| if (!file.exists()) { |
| Properties props = new Properties(); |
| try (OutputStream out = new FileOutputStream(file);) { |
| props.store(out, null); |
| } |
| } |
| } |
| |
| private static String getProperty(String username, String propertyName) { |
| String userFileLoc = getFileLocation(); |
| InputStream in = null; |
| try { |
| in = new FileInputStream(userFileLoc); |
| Properties users = null; |
| |
| try { |
| users = populateUserStore(in); |
| } catch (IOException e) { |
| throw new IllegalArgumentException("Cannot load properties from file " + userFileLoc); |
| } |
| |
| return users.getProperty(constructPropertyName(username, propertyName)); |
| } catch (FileNotFoundException e) { |
| throw new IllegalArgumentException("File " + userFileLoc + " does not exist"); |
| } finally { |
| if (in != null) { |
| try { |
| in.close(); |
| } catch (IOException e) { |
| //do nothing |
| } |
| } |
| } |
| } |
| |
| private static Properties populateUserStore(InputStream in) throws IOException { |
| Properties userProperties = new Properties(); |
| userProperties.load(in); |
| return userProperties; |
| } |
| |
| private static String getFileLocation(){ |
| String userFileLoc = System.getProperty(USER_STORE_FILE_NAME); |
| if (userFileLoc == null) { |
| throw new IllegalArgumentException("Property " + USER_STORE_FILE_NAME + " is not set; cannot use JAAS authentication"); |
| } |
| |
| return userFileLoc; |
| } |
| |
| private static String constructPropertyName(String user, String propertyName) { |
| StringBuilder builder = new StringBuilder(); |
| builder.append(SSH_PREFIX); |
| builder.append(DELIMITER); |
| builder.append(user); |
| builder.append(DELIMITER); |
| builder.append(propertyName); |
| return builder.toString(); |
| } |
| |
| private static boolean existsUser(String username, Properties users) { |
| for (Object user : users.keySet()) { |
| if (user instanceof String && ((String) user).contains(DELIMITER + username + DELIMITER)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| } |