/* * Copyright 2015 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.drools.compiler.integrationtests; import org.drools.compiler.CommonTestMethodBase; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.kie.api.KieBase; import org.kie.api.KieServices; import org.kie.api.builder.KieFileSystem; import org.kie.api.builder.ReleaseId; import org.kie.api.runtime.KieContainer; import org.kie.api.runtime.KieSession; import org.kie.api.runtime.rule.ConsequenceException; import org.kie.internal.io.ResourceFactory; import org.mvel2.PropertyAccessException; /** * This is a sample class to launch a rule. */ @Ignore( "This test causes problems to surefire, so it will be disabled for now. It works when executed by itself.") public class SecurityPolicyTest extends CommonTestMethodBase { @Before public void init() { String enginePolicy = SecurityPolicyTest.class.getResource("engine.policy").getFile(); String kiePolicy = SecurityPolicyTest.class.getResource("rules.policy").getFile(); System.setProperty("java.security.policy", enginePolicy); System.setProperty("kie.security.policy", kiePolicy); TestSecurityManager tsm = new TestSecurityManager(); System.setSecurityManager(tsm); } @After public void close() { System.setSecurityManager(null); System.setProperty("java.security.policy", ""); System.setProperty("kie.security.policy", ""); } @Test public void testUntrustedJavaConsequence() throws Exception { String drl = "package org.foo.bar\n" + "rule R1 when\n" + "then\n" + " System.exit(0);" + "end\n"; try { KieServices ks = KieServices.Factory.get(); KieFileSystem kfs = ks.newKieFileSystem().write(ResourceFactory.newByteArrayResource(drl.getBytes()) .setSourcePath("org/foo/bar/r1.drl")); ks.newKieBuilder(kfs).buildAll(); ReleaseId releaseId = ks.getRepository().getDefaultReleaseId(); KieContainer kc = ks.newKieContainer(releaseId); KieSession ksession = kc.newKieSession(); ksession.fireAllRules(); Assert.fail("The security policy for the rule should have prevented this from executing..."); } catch (ShouldHavePrevented e) { Assert.fail("The security policy for the rule should have prevented this from executing..."); } catch (ConsequenceException e) { // test succeeded. the policy in place prevented the rule from executing the System.exit(). } } @Test public void testUntrustedMvelConsequence() throws Exception { String drl = "package org.foo.bar\n" + "rule R1 dialect \"mvel\" when\n" + "then\n" + " System.exit(0);" + "end\n"; try { KieServices ks = KieServices.Factory.get(); KieFileSystem kfs = ks.newKieFileSystem().write(ResourceFactory.newByteArrayResource(drl.getBytes()) .setSourcePath("org/foo/bar/r1.drl")); ks.newKieBuilder(kfs).buildAll(); ReleaseId releaseId = ks.getRepository().getDefaultReleaseId(); KieContainer kc = ks.newKieContainer(releaseId); KieSession ksession = kc.newKieSession(); ksession.fireAllRules(); Assert.fail("The security policy for the rule should have prevented this from executing..."); } catch (ShouldHavePrevented e) { Assert.fail("The security policy for the rule should have prevented this from executing..."); } catch (ConsequenceException e) { // test succeeded. the policy in place prevented the rule from executing the System.exit(). } } @Test public void testSerializationUntrustedMvelConsequence() throws Exception { String drl = "package org.foo.bar\n" + "rule R1 dialect \"mvel\" when\n" + "then\n" + " System.exit(0);" + "end\n"; try { KieServices ks = KieServices.Factory.get(); KieFileSystem kfs = ks.newKieFileSystem().write(ResourceFactory.newByteArrayResource(drl.getBytes()) .setSourcePath("org/foo/bar/r1.drl")); ks.newKieBuilder(kfs).buildAll(); ReleaseId releaseId = ks.getRepository().getDefaultReleaseId(); KieContainer kc = ks.newKieContainer(releaseId); KieBase kbase = kc.getKieBase(); kbase = SerializationHelper.serializeObject( kbase ); } catch (Exception e) { e.printStackTrace(); Assert.fail(e.toString()); // test succeeded. the policy in place prevented the rule from executing the System.exit(). } } @Test public void testUntrustedJavaSalience() throws Exception { String drl = "package org.foo.bar\n" + "import "+MaliciousExitHelper.class.getName().replace('$', '.')+" \n" + "rule R1 dialect \"java\" salience( MaliciousExitHelper.exit() ) \n" + "when\n" + "then\n" + "end\n"; try { KieServices ks = KieServices.Factory.get(); KieFileSystem kfs = ks.newKieFileSystem().write(ResourceFactory.newByteArrayResource(drl.getBytes()) .setSourcePath("org/foo/bar/r1.drl")); ks.newKieBuilder(kfs).buildAll(); ReleaseId releaseId = ks.getRepository().getDefaultReleaseId(); KieContainer kc = ks.newKieContainer(releaseId); KieSession ksession = kc.newKieSession(); ksession.fireAllRules(); Assert.fail("The security policy for the rule should have prevented this from executing..."); } catch (ShouldHavePrevented e) { Assert.fail("The security policy for the rule should have prevented this from executing..."); } catch (Exception e) { // test succeeded. the policy in place prevented the rule from executing the System.exit(). } } @Test public void testUntrustedMVELSalience() throws Exception { String drl = "package org.foo.bar\n" + "import "+MaliciousExitHelper.class.getName().replace('$', '.')+" \n" + "rule R1 dialect \"mvel\" salience( MaliciousExitHelper.exit() ) \n" + "when\n" + "then\n" + "end\n"; try { KieServices ks = KieServices.Factory.get(); KieFileSystem kfs = ks.newKieFileSystem().write(ResourceFactory.newByteArrayResource(drl.getBytes()) .setSourcePath("org/foo/bar/r1.drl")); ks.newKieBuilder(kfs).buildAll(); ReleaseId releaseId = ks.getRepository().getDefaultReleaseId(); KieContainer kc = ks.newKieContainer(releaseId); KieSession ksession = kc.newKieSession(); ksession.fireAllRules(); Assert.fail("The security policy for the rule should have prevented this from executing..."); } catch (PropertyAccessException e) { // weak way of testing but couldn't find a better way if( e.toString().contains( "The security policy should have prevented" ) ) { Assert.fail("The security policy for the rule should have prevented this from executing..."); } else { // test succeeded } } } @Test public void testCustomAccumulate() throws Exception { String drl = "package org.foo.bar\n" + "rule testRule\n" + " when\n" + " Number() from accumulate(Object(), " + " init(System.exit(-1);), " + " action(System.exit(-1);), " + " reverse(System.exit(-1);), " + " result(0))\n" + " then\n" + "end"; try { KieServices ks = KieServices.Factory.get(); KieFileSystem kfs = ks.newKieFileSystem().write(ResourceFactory.newByteArrayResource(drl.getBytes()) .setSourcePath("org/foo/bar/r1.drl")); ks.newKieBuilder(kfs).buildAll(); ReleaseId releaseId = ks.getRepository().getDefaultReleaseId(); KieContainer kc = ks.newKieContainer(releaseId); KieSession ksession = kc.newKieSession(); ksession.fireAllRules(); Assert.fail("The security policy for the rule should have prevented this from executing..."); } catch (ShouldHavePrevented e) { Assert.fail("The security policy for the rule should have prevented this from executing..."); } catch (Exception e) { // test succeeded. the policy in place prevented the rule from executing the System.exit(). } } @Test public void testCustomAccumulateMVEL() throws Exception { String drl = "package org.foo.bar\n" + "rule testRule dialect \"mvel\" \n" + " when\n" + " Number() from accumulate(Object(), " + " init(System.exit(-1);), " + " action(System.exit(-1);), " + " reverse(System.exit(-1);), " + " result(0))\n" + " then\n" + "end"; try { KieServices ks = KieServices.Factory.get(); KieFileSystem kfs = ks.newKieFileSystem().write(ResourceFactory.newByteArrayResource(drl.getBytes()) .setSourcePath("org/foo/bar/r1.drl")); ks.newKieBuilder(kfs).buildAll(); ReleaseId releaseId = ks.getRepository().getDefaultReleaseId(); KieContainer kc = ks.newKieContainer(releaseId); KieSession ksession = kc.newKieSession(); ksession.fireAllRules(); Assert.fail("The security policy for the rule should have prevented this from executing..."); } catch (PropertyAccessException e) { // weak way of testing but couldn't find a better way if( e.toString().contains( "The security policy should have prevented" ) ) { Assert.fail("The security policy for the rule should have prevented this from executing..."); } else { // test succeeded } } catch( Exception e ) { if( e.toString().contains("access denied (\"java.lang.RuntimePermission\" \"exitVM.-1\")")) { // test succeeded } else { throw e; } } } @Test public void testAccumulateFunctionMVEL() throws Exception { String drl = "package org.foo.bar\n" + "import "+MaliciousExitHelper.class.getName().replace('$', '.')+" \n" + "rule testRule dialect \"mvel\" \n" + " when\n" + " Number() from accumulate(Object(), " + " sum(MaliciousExitHelper.exit()))\n" + " then\n" + "end"; try { KieServices ks = KieServices.Factory.get(); KieFileSystem kfs = ks.newKieFileSystem().write(ResourceFactory.newByteArrayResource(drl.getBytes()) .setSourcePath("org/foo/bar/r1.drl")); ks.newKieBuilder(kfs).buildAll(); ReleaseId releaseId = ks.getRepository().getDefaultReleaseId(); KieContainer kc = ks.newKieContainer(releaseId); KieSession ksession = kc.newKieSession(); ksession.insert("foo"); ksession.fireAllRules(); Assert.fail("The security policy for the rule should have prevented this from executing..."); } catch (PropertyAccessException e) { // weak way of testing but couldn't find a better way if( e.toString().contains( "The security policy should have prevented" ) ) { Assert.fail("The security policy for the rule should have prevented this from executing..."); } else { // test succeeded } } catch( Exception e ) { if( e.toString().contains("access denied (\"java.lang.RuntimePermission\" \"exitVM.0\")")) { // test succeeded } else { throw e; } } } @Test public void testAccumulateFunctionJava() throws Exception { String drl = "package org.foo.bar\n" + "import "+MaliciousExitHelper.class.getName().replace('$', '.')+" \n" + "rule testRule dialect \"java\" \n" + " when\n" + " Number() from accumulate(Object(), " + " sum(MaliciousExitHelper.exit()))\n" + " then\n" + "end"; try { KieServices ks = KieServices.Factory.get(); KieFileSystem kfs = ks.newKieFileSystem().write(ResourceFactory.newByteArrayResource(drl.getBytes()) .setSourcePath("org/foo/bar/r1.drl")); ks.newKieBuilder(kfs).buildAll(); ReleaseId releaseId = ks.getRepository().getDefaultReleaseId(); KieContainer kc = ks.newKieContainer(releaseId); KieSession ksession = kc.newKieSession(); ksession.insert("foo"); ksession.fireAllRules(); Assert.fail("The security policy for the rule should have prevented this from executing..."); } catch (PropertyAccessException e) { // weak way of testing but couldn't find a better way if( e.toString().contains( "The security policy should have prevented" ) ) { Assert.fail("The security policy for the rule should have prevented this from executing..."); } else { // test succeeded } } catch( Exception e ) { if( e.toString().contains("access denied (\"java.lang.RuntimePermission\" \"exitVM.0\")")) { // test succeeded } else { throw e; } } } @Test public void testUntrustedEnabled() throws Exception { String drl = "package org.foo.bar\n" + "import "+MaliciousExitHelper.class.getName().replace('$', '.')+" \n" + "rule R1 enabled( MaliciousExitHelper.isEnabled() ) \n" + "when\n" + "then\n" + "end\n"; try { KieServices ks = KieServices.Factory.get(); KieFileSystem kfs = ks.newKieFileSystem().write(ResourceFactory.newByteArrayResource(drl.getBytes()) .setSourcePath("org/foo/bar/r1.drl")); ks.newKieBuilder(kfs).buildAll(); ReleaseId releaseId = ks.getRepository().getDefaultReleaseId(); KieContainer kc = ks.newKieContainer(releaseId); KieSession ksession = kc.newKieSession(); ksession.fireAllRules(); Assert.fail("The security policy for the rule should have prevented this from executing..."); } catch (ShouldHavePrevented e) { Assert.fail("The security policy for the rule should have prevented this from executing..."); } catch (Exception e) { // test succeeded. the policy in place prevented the rule from executing the System.exit(). } } @Test public void testUntrustedMVELEnabled() throws Exception { String drl = "package org.foo.bar\n" + "import "+MaliciousExitHelper.class.getName().replace('$', '.')+" \n" + "rule R1 dialect \"mvel\" enabled( MaliciousExitHelper.isEnabled() ) \n" + "when\n" + "then\n" + "end\n"; try { KieServices ks = KieServices.Factory.get(); KieFileSystem kfs = ks.newKieFileSystem().write(ResourceFactory.newByteArrayResource(drl.getBytes()) .setSourcePath("org/foo/bar/r1.drl")); ks.newKieBuilder(kfs).buildAll(); ReleaseId releaseId = ks.getRepository().getDefaultReleaseId(); KieContainer kc = ks.newKieContainer(releaseId); KieSession ksession = kc.newKieSession(); ksession.fireAllRules(); Assert.fail("The security policy for the rule should have prevented this from executing..."); } catch (PropertyAccessException e) { // weak way of testing but couldn't find a better way if( e.toString().contains( "The security policy should have prevented" ) ) { Assert.fail("The security policy for the rule should have prevented this from executing..."); } else { // test succeeded } } } public static class MaliciousExitHelper { public static int exit() { System.exit(0); return 0; } public static boolean isEnabled() { System.exit(0); return true; } } public static class TestSecurityManager extends SecurityManager { @Override public void checkExit(int status) { super.checkExit(status); throw new ShouldHavePrevented("The security policy should have prevented the call to System.exit()"); } } public static class ShouldHavePrevented extends SecurityException { public ShouldHavePrevented(String message) { super(message); } } }