package org.ovirt.engine.core.config.entity.helper; import java.io.File; import java.io.IOException; import java.security.GeneralSecurityException; import org.apache.commons.lang.StringUtils; import org.ovirt.engine.core.config.EngineConfigCLIParser; import org.ovirt.engine.core.config.EngineConfigLogic; import org.ovirt.engine.core.config.entity.ConfigKey; import org.ovirt.engine.core.tools.ToolConsole; import org.ovirt.engine.core.utils.crypt.EngineEncryptionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class PasswordValueHelper implements ValueHelper { // The log: private static final Logger log = LoggerFactory.getLogger(PasswordValueHelper.class); // The console: private static final ToolConsole console = ToolConsole.getInstance(); public static final String INTERACTIVE_MODE = "Interactive"; private EngineConfigCLIParser parser; String encrypt(String value) throws Exception { return EngineEncryptionUtils.encrypt(value); } String decrypt(String value) throws Exception { return EngineEncryptionUtils.decrypt(value); } @Override public String getValue(String value) throws GeneralSecurityException { /* * The idea of this method would normally be to decrypt and return * the decrypted value. Due to security reasons, we do not wish to return * the real value. Just an indication if we have a value in the DB or not. * So if there's no value we return "Empty". * If there's a value we try to decrypt. On success we return "Set", * On failure we return an error. */ String returnedValue = "Empty"; if (value != null && !value.equals("")){ try { decrypt(value); returnedValue = "Set"; } catch (Exception exception) { String msg = "Failed to decrypt the current value."; console.writeLine(msg); log.error("Exception", exception); throw new GeneralSecurityException(msg); } } return returnedValue; } /** * this method is ignoring the value! if the value is "Interactive" it will open a console input for the password * else it will look for the password from a file * * @return The user's encrypted password */ @Override public String setValue(String value) throws GeneralSecurityException { String returnedValue = null; String password = null; try { password = extractPasswordValue(value); if (StringUtils.isBlank(password)) { return StringUtils.EMPTY; } returnedValue = encrypt(password); } catch (Throwable exception) { String msg = "Failed to encrypt the current value."; console.writeLine(msg); log.error(msg, exception); throw new GeneralSecurityException(msg); } return returnedValue; } public String extractPasswordValue(String value) throws IOException { String password = null; if (StringUtils.isNotBlank(value) && value.equalsIgnoreCase(INTERACTIVE_MODE)) { password = EngineConfigLogic.startPasswordDialog(null); String passwordConfirm = EngineConfigLogic.startPasswordDialog(null, "Please reenter password"); if (!StringUtils.equals(password, passwordConfirm)) { console.writeLine("Passwords don't match."); return extractPasswordValue(value); } } else { password = EngineConfigLogic.getPassFromFile(StringUtils.isNotBlank(value) ? value : parser.getAdminPassFile()); } return password; } @Override public ValidationResult validate(ConfigKey key, String value) { // check if value is file path if (StringUtils.isNotBlank(value) && new File(value).exists()) { return new ValidationResult(true); } // The only valid value is "Interactive" if (StringUtils.isNotBlank(value) && value.equalsIgnoreCase(INTERACTIVE_MODE)) { return new ValidationResult(true); } // or if we have the password in --admin-pass-file if (StringUtils.isNotBlank(parser.getAdminPassFile())) { if (new File(parser.getAdminPassFile()).exists()) { return new ValidationResult(true); } else { return new ValidationResult(false, String.format("The file %1$s does not exist. Cannot change password for %2$s", parser.getAdminPassFile(), key.getKey())); } } return new ValidationResult(false, String.format("It appears you tried to change a password for %1$s in a wrong way. " + "You should use interactive mode or provide a file cotaining the password. Run the utility with --help for more information.", key.getKey())); } @Override public void setParser(EngineConfigCLIParser parser) { this.parser = parser; } @Override public String getHelpNote(ConfigKey key) { return String.format("%n%n%n" + "### Notes:%n" + "### 1. Passwords: password can be set in interactive mode ie:%n" + "### engine-config -s %1$s=interactive%n" + "### or via file with one of the following options:%n" + "### engine-config -s %1$s --admin-pass-file=/tmp/mypass%n" + "### engine-config -s %1$s=/tmp/mypass%n" + "### 2. In order for your change(s) to take effect,%n" + "### restart the oVirt engine service (using: 'service ovirt-engine restart').%n" + "################################################################################%n%n", key.getKey()); } }