/* * JBoss, Home of Professional Open Source. * Copyright 2014, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.as.test.manualmode.management.cli; import static org.hamcrest.CoreMatchers.containsString; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.READ_ATTRIBUTE_OPERATION; import static org.junit.Assert.assertThat; import java.io.File; import java.io.IOException; import javax.inject.Inject; import org.apache.commons.io.FileUtils; import org.jboss.as.test.integration.management.util.CustomCLIExecutor; import org.jboss.as.test.integration.security.PicketBoxModuleUtil; import org.jboss.as.test.integration.security.common.CoreUtils; import org.jboss.as.test.integration.security.common.SecurityTestConstants; import org.jboss.as.test.module.util.TestModule; import org.jboss.logging.Logger; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.wildfly.core.testrunner.ServerControl; import org.wildfly.core.testrunner.ServerController; import org.wildfly.core.testrunner.WildflyTestRunner; /** * Testing support of custom security vaults for encrypting passwords in * jboss-cli configuration file. It tries to invoke CLI client with vaulted * passwords for truststore in its configuration, which results in resolving * vault expression. * * @author Filip Bogyai */ @RunWith(WildflyTestRunner.class) @ServerControl(manual = true) public class CustomVaultInCLITestCase { private static Logger LOGGER = Logger.getLogger(CustomVaultInCLITestCase.class); private static final File WORK_DIR = new File("cli-custom-vault-workdir"); public static final File CLIENT_KEYSTORE_FILE = new File(WORK_DIR, SecurityTestConstants.CLIENT_KEYSTORE); public static final File CLIENT_TRUSTSTORE_FILE = new File(WORK_DIR, SecurityTestConstants.CLIENT_TRUSTSTORE); private static final String RIGHT_PASSWORD = SecurityTestConstants.KEYSTORE_PASSWORD; private static final String WRONG_PASSWORD = "someRandomWrongPass"; private static final File MODULE_FILE = new File(WORK_DIR, "module.xml"); private static final String JBOSS_CLI_FILE = "jboss-cli.xml"; private static final File RIGHT_VAULT_PASSWORD_FILE = new File(WORK_DIR, "right-vault-pass.xml"); private static final File WRONG_VAULT_PASSWORD_FILE = new File(WORK_DIR, "wrong-vault-pass.xml"); private static final File NON_EXISTING_VAULT_PASSWORD_FILE = new File(WORK_DIR, "non-existing-vault-pass.xml"); private static String MODULE_NAME = "test.custom.vault.in.cli"; private static String JAR_NAME = "custom-dummy-vault-module.jar"; private static final String CONTAINER = "default-jbossas"; private static TestModule customVaultModule; @Inject private static ServerController containerController; private static TestModule picketLinkModule; @BeforeClass public static void prepareConfiguration() throws Exception { FileUtils.deleteDirectory(WORK_DIR); WORK_DIR.mkdirs(); CoreUtils.createKeyMaterial(WORK_DIR); createCustomVaultModule(); createCustomVaultConfiguration(); LOGGER.info("*** starting server"); containerController.start(); } /** * Run CLI with vaulted keystore and truststore passwords. Vault expression * should return right password. */ @Test public void testRightVaultPassword() throws Exception { String cliOutput = CustomCLIExecutor.execute(RIGHT_VAULT_PASSWORD_FILE, READ_ATTRIBUTE_OPERATION + " server-state"); assertThat("Password should be right", cliOutput, containsString("Password is: " + RIGHT_PASSWORD)); assertThat("CLI should successfully initialize ", cliOutput, containsString("running")); } /** * Run CLI with vaulted keystore and truststore passwords. Vault expression * should return wrong password, so CliInitializationException is expected */ @Test public void testWrongVaultPassword() throws Exception { String cliOutput = CustomCLIExecutor.execute(WRONG_VAULT_PASSWORD_FILE, READ_ATTRIBUTE_OPERATION + " server-state"); assertThat("Password should be wrong", cliOutput, containsString("Password is: " + WRONG_PASSWORD)); assertThat("CLI shouldn't successfully initialize ", cliOutput, containsString("Keystore was tampered with, or password was incorrect")); } /** * Run CLI with vaulted keystore and truststore passwords. Vault expression * should not exists, so NullPointerException is expected */ @Test public void testNonExistingVaultPassword() throws Exception { String cliOutput = CustomCLIExecutor.execute(NON_EXISTING_VAULT_PASSWORD_FILE, READ_ATTRIBUTE_OPERATION + " server-state"); assertThat("Password should not exists", cliOutput, containsString("NullPointerException")); } @AfterClass public static void rollbackConfiguration() throws Exception { LOGGER.info("*** stopping server"); containerController.stop(); customVaultModule.remove(); picketLinkModule.remove(); FileUtils.deleteDirectory(WORK_DIR); } private static void createCustomVaultModule() throws Exception { String moduleXML = "<module xmlns=\"urn:jboss:module:1.1\" name=\"" + MODULE_NAME + "\">" + "<resources> <resource-root path=\"" + JAR_NAME + "\"/> </resources>" + "<dependencies> <module name=\"org.picketbox\"/> </dependencies> " + "</module>"; FileUtils.write(MODULE_FILE, moduleXML); customVaultModule = new TestModule(MODULE_NAME, MODULE_FILE); customVaultModule.addResource(JAR_NAME).addClass(CustomDummyVault.class); customVaultModule.create(true); picketLinkModule = PicketBoxModuleUtil.createTestModule(); } private static void createCustomVaultConfiguration() throws IOException { String rightBlock = "rightVaultBlock"; String wrongBlock = "wrongVaultBlock"; String vaultConfig = "<vault code=\"" + CustomDummyVault.class.getName() + "\" module=\"" + MODULE_NAME + "\">" + "<vault-option name=\"" + rightBlock + "\" value=\"" + RIGHT_PASSWORD + "\"/>" + "<vault-option name=\"" + wrongBlock + "\" value=\"" + WRONG_PASSWORD + "\"/>" + "</vault>"; //passwords are defined above and are retrieved depending only on vault block String vaultPasswordString = "VAULT::" + rightBlock + "::good::1"; String wrongVaultPasswordString = "VAULT::" + wrongBlock + "::wrong::1"; String nonExistingVaultPasswordString = "VAULT::nonExistingBlock::non::1"; // create jboss-cli configuration file with vaulted passwords and change xsd to 3.0 String rightVaultPassConfig = CoreUtils.propertiesReplacer(JBOSS_CLI_FILE, CLIENT_KEYSTORE_FILE, CLIENT_TRUSTSTORE_FILE, vaultPasswordString, vaultConfig).replaceAll("urn:jboss:cli:2.0", "urn:jboss:cli:3.0"); String wrongVaultPassConfig = CoreUtils.propertiesReplacer(JBOSS_CLI_FILE, CLIENT_KEYSTORE_FILE, CLIENT_TRUSTSTORE_FILE, wrongVaultPasswordString, vaultConfig).replaceAll("urn:jboss:cli:2.0", "urn:jboss:cli:3.0"); String nonVaultPassConfig = CoreUtils.propertiesReplacer(JBOSS_CLI_FILE, CLIENT_KEYSTORE_FILE, CLIENT_TRUSTSTORE_FILE, nonExistingVaultPasswordString, vaultConfig).replaceAll("urn:jboss:cli:2.0", "urn:jboss:cli:3.0"); FileUtils.write(RIGHT_VAULT_PASSWORD_FILE, rightVaultPassConfig); FileUtils.write(WRONG_VAULT_PASSWORD_FILE, wrongVaultPassConfig); FileUtils.write(NON_EXISTING_VAULT_PASSWORD_FILE, nonVaultPassConfig); } }