/*
* JBoss, Home of Professional Open Source.
* Copyright 2015, 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.testsuite.integration.secman.subsystem;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.net.URI;
import java.net.URL;
import java.util.PropertyPermission;
import javax.servlet.http.HttpServletResponse;
import org.jboss.arquillian.container.test.api.Deployer;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.as.arquillian.api.ServerSetup;
import org.jboss.as.test.integration.security.common.Utils;
import org.jboss.as.test.shared.TestSuiteEnvironment;
import org.jboss.as.test.shared.integration.ejb.security.PermissionUtils;
import org.jboss.as.testsuite.integration.secman.servlets.PrintSystemPropertyServlet;
import org.jboss.logging.Logger;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
* This class contains test for maximum-permissions attribute in security-manager subsystem. The deployment should failed if the
* deployed application asks more permissions than is allowed by the maximum-permissions.
*
* @author Josef Cacek
*/
@RunWith(Arquillian.class)
@RunAsClient
@ServerSetup(RemoveDeploymentPermissionsServerSetupTask.class)
public class MaximumPermissionsTestCase extends ReloadableCliTestBase {
private static final String DEPLOYMENT_PERM = "deployment-perm";
private static final String DEPLOYMENT_JBOSS_PERM = "deployment-jboss-perm";
private static final String DEPLOYMENT_NO_PERM = "deployment-no-perm";
private static Logger LOGGER = Logger.getLogger(MaximumPermissionsTestCase.class);
private static final String ADDRESS_WEB = "http://" + TestSuiteEnvironment.getServerAddress() + ":8080/";
private static final String INDEX_HTML = "OK";
@ArquillianResource
private Deployer deployer;
/**
* Returns Arquillian deployment which defines requested permissions in permissions.xml.
*/
@Deployment(name = DEPLOYMENT_PERM, testable = false, managed = false)
public static WebArchive deploymentPerm() {
return createDeployment("permissions.xml", DEPLOYMENT_PERM);
}
/**
* Returns Arquillian deployment which defines requested permissions in jboss-permissions.xml.
*/
@Deployment(name = DEPLOYMENT_JBOSS_PERM, testable = false, managed = false)
public static WebArchive deploymentJBossPerm() {
return createDeployment("jboss-permissions.xml", DEPLOYMENT_JBOSS_PERM);
}
/**
* Returns Arquillian deployment which doesn't define requested permissions.
*/
@Deployment(name = DEPLOYMENT_NO_PERM, testable = false)
public static WebArchive deploymentNoPerm() {
return createDeployment(null, DEPLOYMENT_NO_PERM);
}
/**
* Tests if deployment fails
* <ul>
* <li>when maximum-permissions is not defined and {@code permissions.xml} requests some permissions;</li>
* <li>when maximum-permissions is not defined and {@code jboss-permissions.xml} requests some permissions.</li>
* </ul>
*/
@Test
public void testMaximumPermissionsEmpty() throws Exception {
try {
doCliOperation(
"/subsystem=security-manager/deployment-permissions=default:add(maximum-permissions=[])");
reloadServer();
assertNotDeployable(DEPLOYMENT_PERM);
assertNotDeployable(DEPLOYMENT_JBOSS_PERM);
} finally {
doCliOperationWithoutChecks("/subsystem=security-manager/deployment-permissions=default:remove()");
reloadServer();
}
}
/**
* Tests if deployment succeeds but doing protected action fails, when maximum-permissions is not defined and requested
* permissions declaration is not part of deployment.
*/
@Test
public void testNoPermEmptySet() throws Exception {
assertPropertyNonReadable(DEPLOYMENT_NO_PERM);
}
/**
* Tests if deployment fails, when maximum-permissions is contains another permissions than requested by deployment.
*/
@Test
public void testFilePerm(@ArquillianResource URL webAppURL) throws Exception {
try {
doCliOperation(
"/subsystem=security-manager/deployment-permissions=default:add(maximum-permissions=[{class=java.io.FilePermission, actions=read, name=\"/-\"}])");
reloadServer();
assertNotDeployable(DEPLOYMENT_PERM);
assertNotDeployable(DEPLOYMENT_JBOSS_PERM);
assertPropertyNonReadable(DEPLOYMENT_NO_PERM);
} finally {
doCliOperationWithoutChecks("/subsystem=security-manager/deployment-permissions=default:remove()");
reloadServer();
}
}
/**
* Tests if deployment succeeds and permissions are granted, when maximum-permissions is contains permissions requested by
* deployment.
*/
@Test
public void testPropertyPerm(@ArquillianResource URL webAppURL) throws Exception {
try {
doCliOperation(
"/subsystem=security-manager/deployment-permissions=default:add(maximum-permissions=[{class=java.util.PropertyPermission, actions=read, name=\"*\"}])");
reloadServer();
assertDeployable(DEPLOYMENT_PERM, true);
assertDeployable(DEPLOYMENT_JBOSS_PERM, true);
assertPropertyNonReadable(DEPLOYMENT_NO_PERM);
} finally {
doCliOperationWithoutChecks("/subsystem=security-manager/deployment-permissions=default:remove()");
reloadServer();
}
}
/**
* Tests if deployments succeeds and permissions are granted, when maximum-permissions contains AllPermission entry.
*/
@Test
public void testAllPermAndEmptySet(@ArquillianResource URL webAppURL) throws Exception {
try {
doCliOperation(
"/subsystem=security-manager/deployment-permissions=default:add(maximum-permissions=[{class=java.security.AllPermission}])");
reloadServer();
// check the test apps are deployable and they have requested permissions
try {
deployer.deploy(DEPLOYMENT_PERM);
assertPropertyReadable(DEPLOYMENT_PERM);
deployer.deploy(DEPLOYMENT_JBOSS_PERM);
assertPropertyReadable(DEPLOYMENT_JBOSS_PERM);
assertPropertyNonReadable(DEPLOYMENT_NO_PERM);
try {
// after removing permissions from maximum-set the deployment which requests non-granted permissions should
// fail.
doCliOperation(
"/subsystem=security-manager/deployment-permissions=default:write-attribute(name=maximum-permissions, value=[])");
reloadServer();
assertNotDeployed(DEPLOYMENT_PERM);
assertNotDeployed(DEPLOYMENT_JBOSS_PERM);
assertDeployed(DEPLOYMENT_NO_PERM);
} finally {
// clean-up - undeploy
doCliOperation(
"/subsystem=security-manager/deployment-permissions=default:write-attribute(name=maximum-permissions, value=[{class=java.security.AllPermission}])");
reloadServer();
}
} finally {
deployer.undeploy(DEPLOYMENT_PERM);
deployer.undeploy(DEPLOYMENT_JBOSS_PERM);
}
} finally {
doCliOperationWithoutChecks("/subsystem=security-manager/deployment-permissions=default:remove()");
reloadServer();
}
}
/**
* Checks access to a system property on the server using {@link PrintSystemPropertyServlet}.
*
* @param deploymentName
*
* @param expectedCode expected HTTP Status code
* @throws Exception
*/
protected void checkPropertyAccess(boolean successExpected, String deploymentName) throws Exception {
final String propertyName = "java.home";
final URI sysPropUri = new URI(ADDRESS_WEB + deploymentName + PrintSystemPropertyServlet.SERVLET_PATH + "?"
+ Utils.encodeQueryParam(PrintSystemPropertyServlet.PARAM_PROPERTY_NAME, propertyName));
Utils.makeCall(sysPropUri, successExpected ? HttpServletResponse.SC_OK : HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
/**
* Asserts the system property is readable from deployment with given name.
*
* @param deploymentName
* @throws Exception
*/
protected void assertPropertyReadable(String deploymentName) throws Exception {
checkPropertyAccess(true, deploymentName);
}
/**
* Asserts the system property is not readable from deployment with given name.
*
* @param deploymentName
* @throws Exception
*/
protected void assertPropertyNonReadable(String deploymentName) throws Exception {
checkPropertyAccess(false, deploymentName);
}
/**
* Asserts the deployment of the application with given name succeeds and checks if system property is
* readable/non-readable.
*
* @param deploymentName
* @param expectedPropertyReadable expected "readability" of system property from deployment
* @throws Exception
*/
protected void assertDeployable(String deploymentName, boolean expectedPropertyReadable) throws Exception {
deployer.deploy(deploymentName);
LOGGER.debug("Manually deployed: " + deploymentName);
if (expectedPropertyReadable) {
assertPropertyReadable(deploymentName);
} else {
assertPropertyNonReadable(deploymentName);
}
deployer.undeploy(deploymentName);
}
/**
* Asserts the deployment of the application with given name fails.
*
* @param deploymentName
* @throws Exception
*/
protected void assertNotDeployable(String deploymentName) {
try {
deployer.deploy(deploymentName);
fail("Deployment failure expected for deployment: " + deploymentName);
} catch (Exception e) {
// expected
} finally {
try {
deployer.undeploy(deploymentName);
} catch (Exception e) {
LOGGER.debug(e);
}
}
}
/**
* Asserts the application with given name is deployed.
*
* @param deploymentName
* @throws Exception
*/
protected void assertDeployed(String deploymentName) throws Exception {
final URI sysPropUri = new URI(ADDRESS_WEB + deploymentName + "/");
final String strBody = Utils.makeCall(sysPropUri, HttpServletResponse.SC_OK);
assertEquals("Unexpected message body returned.", INDEX_HTML, strBody);
}
/**
* Asserts the application with given name is not-deployed.
*
* @param deploymentName
* @throws Exception
*/
protected void assertNotDeployed(String deploymentName) throws Exception {
final URI sysPropUri = new URI(ADDRESS_WEB + deploymentName + "/");
Utils.makeCall(sysPropUri, HttpServletResponse.SC_NOT_FOUND);
}
/**
* Creates deployment with {@link PrintSystemPropertyServlet} and index.html simple page. If permissionsFilename parameter
* is not-<code>null</code>, then permission declaration file with given name is also generated to the deployment.
*
* @param permissionsFilename filename under META-INF where to store requested permissions (usually permissions.xml,
* jboss-permissions.xml or null to skip requesting permissions)
* @param deploymentName
* @return
*/
private static WebArchive createDeployment(String permissionsFilename, String deploymentName) {
LOGGER.debug("Start WAR deployment");
final WebArchive war = ShrinkWrap.create(WebArchive.class, deploymentName + ".war");
war.addClasses(PrintSystemPropertyServlet.class);
war.addAsWebResource(new StringAsset(INDEX_HTML), "index.html");
if (permissionsFilename != null) {
war.addAsManifestResource(PermissionUtils.createPermissionsXmlAsset(new PropertyPermission("*", "read")),
permissionsFilename);
}
return war;
}
}