From 8fab9564d5c47ca174fd37efe2ce94075187e92c Mon Sep 17 00:00:00 2001 From: Antoine Levy-Lambert Date: Wed, 27 Aug 2003 14:23:17 +0000 Subject: [PATCH] PR: 22533 Submitted by: J.M. (Martijn) Kruithof (ant at kruithof dot xs4all dot nl) git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@275149 13f79535-47bb-0310-9956-ffa450edef68 --- WHATSNEW | 4 + docs/manual/CoreTasks/java.html | 12 + docs/manual/CoreTypes/permissions.html | 148 ++++++++ docs/manual/OptionalTasks/junit.html | 9 + docs/manual/conceptstypeslist.html | 1 + src/etc/testcases/taskdefs/java.xml | 29 ++ .../org/apache/tools/ant/ExitException.java | 14 +- .../tools/ant/taskdefs/ExecuteJava.java | 18 + .../org/apache/tools/ant/taskdefs/Java.java | 27 +- .../taskdefs/optional/junit/JUnitTask.java | 20 ++ .../optional/junit/JUnitTestRunner.java | 26 +- .../apache/tools/ant/types/Permissions.java | 324 ++++++++++++++++++ .../apache/tools/ant/taskdefs/JavaTest.java | 11 + .../tools/ant/types/PermissionsTest.java | 187 ++++++++++ 14 files changed, 824 insertions(+), 6 deletions(-) create mode 100644 docs/manual/CoreTypes/permissions.html create mode 100644 src/main/org/apache/tools/ant/types/Permissions.java create mode 100644 src/testcases/org/apache/tools/ant/types/PermissionsTest.java diff --git a/WHATSNEW b/WHATSNEW index 9c7e4fdc2..842f94207 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -574,6 +574,10 @@ Other changes: * 's XML formatter adds a new classname attribute to the elements. +* new type add permission handling to the code + this type can be nested in the and tasks. + Bugzilla Report 22533. + Changes from Ant 1.5.3 to Ant 1.5.4 =================================== diff --git a/docs/manual/CoreTasks/java.html b/docs/manual/CoreTasks/java.html index 457757aba..2f68b6158 100644 --- a/docs/manual/CoreTasks/java.html +++ b/docs/manual/CoreTasks/java.html @@ -212,6 +212,18 @@ support it (i.e. Java 1.1).

forked VM via nested env elements. See the description in the section about exec

Settings will be ignored if fork is disabled.

+ +

permissions

+

Security permissions can be revoked and granted during the execution of the +class via a nested permissions element. For more information please +see permissions

+

When the permission RuntimePermission exitVM has not been granted (or has +been revoked) the System.exit() call will be intercepted +and treated like indicated in failonerror.

+ +

Settings will be ignored if fork is enabled.

+ +

since Ant 1.6.

Errors and return codes

By default the return code of a <java> is ignored. Alternatively, you can set resultproperty to the name diff --git a/docs/manual/CoreTypes/permissions.html b/docs/manual/CoreTypes/permissions.html new file mode 100644 index 000000000..b86d2c68f --- /dev/null +++ b/docs/manual/CoreTypes/permissions.html @@ -0,0 +1,148 @@ + + + + +Permissions type + + + + +

Permissions

+

+Permissions represents a set of security permissions granted or revoked to +a specific part code executed in the JVM where ant is running in. +The actual Permissions are specified via a set of nested permission items either +<grant>ed or <revoke>d.

+

+In the base situation a base set of permissions granted. +Extra permissions can be +granted. A granted permission can be overruled by revoking a permission. +The security manager installed by the permissions will throw an +SecurityException if +the code subject to these permissions try to use an permission that has not been +granted or that has been revoked.

+

Nested elements

+

grant

+

+Indicates a specific permission is always granted. Its attributes indicate which +permissions are granted.

+ + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
classThe fully qualified name of the Permission class.Yes
nameThe name of the Permission. The actual contents depends on the + Permission class.No
actionsThe actions allowed. The actual contents depend on the + Permission class and name.No
+

+Implied permissions are granted. +

+

+Please note that some Permission classes may actually need a name and / or actions in order to function properly. The name and actions are parsed by the actual +Permission class. +

+

revoke

+

+Indicates a specific permission is revoked.

+ + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
classThe fully qualified name of the Permission class.Yes
nameThe name of the Permission. The actual contents depends on the + Permission class.No
actionsThe actions allowed. The actual contents depend on the + Permission class and name.No
+

+Implied permissions are not resolved and therefore also not revoked. +

+

+The name can handle the * wildcard at the end of the name, in which case all +permissions of the specified class of which the name starts with the specified name +(excluding the *) are revoked. Note that the - wildcard often supported by the +granted properties is not supported. +If the name is left empty all names match, and are revoked. +If the actions are left empty all actions match, and are revoked. +

+

Base set

+A permissions set implictly contains the following permissions: +
+<grant class="java.net.SocketPermission" name=localhost:1024-" actions="listen">
+<grant class="java.util.PropertyPermission" name=java.version" actions="read">
+<grant class="java.util.PropertyPermission" name=java.vendor" actions="read">
+<grant class="java.util.PropertyPermission" name=java.vendor.url" actions="read">
+<grant class="java.util.PropertyPermission" name=java.class.version" actions="read">
+<grant class="java.util.PropertyPermission" name=os.name" actions="read">
+<grant class="java.util.PropertyPermission" name=os.version" actions="read">
+<grant class="java.util.PropertyPermission" name=os.arch" actions="read">
+<grant class="java.util.PropertyPermission" name=file.separator" actions="read">
+<grant class="java.util.PropertyPermission" name=path.separator" actions="read">
+<grant class="java.util.PropertyPermission" name=line.separator" actions="read">
+<grant class="java.util.PropertyPermission" name=java.specification.version" actions="read">
+<grant class="java.util.PropertyPermission" name=java.specification.vendor" actions="read">
+<grant class="java.util.PropertyPermission" name=java.specification.name" actions="read">
+<grant class="java.util.PropertyPermission" name=java.vm.specification.version" actions="read">
+<grant class="java.util.PropertyPermission" name=java.vm.specification.vendor" actions="read">
+<grant class="java.util.PropertyPermission" name=java.vm.specification.name" actions="read">
+<grant class="java.util.PropertyPermission" name=java.vm.version" actions="read">
+<grant class="java.util.PropertyPermission" name=java.vm.vendor" actions="read">
+<grant class="java.util.PropertyPermission" name=java.vm.name" actions="read">
+
+These permissions can be revoked via <revoke> elements if necessary. + +

Examples

+
+<permissions>
+  <grant class="java.security.AllPermission"/>
+  <revoke class="java.util.PropertyPermission"/>
+</permissions>
+
+

+Grants all permissions to the code except for those handling Properties. +

+
+<permissions>
+  <grant class="java.net.SocketPermission" name="foo.bar.com" action="connect"/>
+  <grant class="java.util.PropertyPermission" name="user.home" action="read,write"/>
+</permissions>
+
+

+Grants the base set of permissions with the addition of a SocketPermission to connect +to foo.bar.com and the permission to read and write the user.home system property. +

+
+

Copyright © 2003 Apache Software Foundation. +All rights Reserved.

+ + diff --git a/docs/manual/OptionalTasks/junit.html b/docs/manual/OptionalTasks/junit.html index d5ddb356a..22aaeb30d 100644 --- a/docs/manual/OptionalTasks/junit.html +++ b/docs/manual/OptionalTasks/junit.html @@ -244,6 +244,15 @@ support it (i.e. Java 1.1).

since Ant 1.6.

+

permissions

+

Security permissions can be revoked and granted during the execution of the +class via a nested permissions element. For more information please +see permissions

+ +

Settings will be ignored if fork is enabled.

+ +

since Ant 1.6.

+

formatter

The results of the tests can be printed in different diff --git a/docs/manual/conceptstypeslist.html b/docs/manual/conceptstypeslist.html index dc60cab07..9f6da09b7 100644 --- a/docs/manual/conceptstypeslist.html +++ b/docs/manual/conceptstypeslist.html @@ -25,6 +25,7 @@ FilterSet
PatternSet
Path-like Structures
+Permissions
PropertySet
Selectors
XMLCatalog
diff --git a/src/etc/testcases/taskdefs/java.xml b/src/etc/testcases/taskdefs/java.xml index 9f8c12ef7..de9fd1867 100644 --- a/src/etc/testcases/taskdefs/java.xml +++ b/src/etc/testcases/taskdefs/java.xml @@ -99,6 +99,7 @@ @@ -116,12 +117,40 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/main/org/apache/tools/ant/ExitException.java b/src/main/org/apache/tools/ant/ExitException.java index 74da3a64d..5ada8b823 100644 --- a/src/main/org/apache/tools/ant/ExitException.java +++ b/src/main/org/apache/tools/ant/ExitException.java @@ -1,7 +1,7 @@ /* * The Apache Software License, Version 1.1 * - * Copyright (c) 2001-2002 The Apache Software Foundation. All rights + * Copyright (c) 2001-2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -57,8 +57,10 @@ package org.apache.tools.ant; * Used to report exit status of classes which call System.exit(). * * @see org.apache.tools.ant.util.optional.NoExitSecurityManager + * @see org.apache.tools.ant.types.Permissions * * @author Conor MacNeill + * @author Martijn Kruithof */ public class ExitException extends SecurityException { @@ -74,6 +76,16 @@ public class ExitException extends SecurityException { this.status = status; } + /** + * Constructs an exit exception. + * @param msg the messge to be displayed. + * @param status the status code returned via System.exit() + */ + public ExitException(String msg, int status) { + super(msg); + this.status = status; + } + /** * The status code returned by System.exit() * diff --git a/src/main/org/apache/tools/ant/taskdefs/ExecuteJava.java b/src/main/org/apache/tools/ant/taskdefs/ExecuteJava.java index 87847c246..7e8e8bde5 100644 --- a/src/main/org/apache/tools/ant/taskdefs/ExecuteJava.java +++ b/src/main/org/apache/tools/ant/taskdefs/ExecuteJava.java @@ -65,6 +65,7 @@ import org.apache.tools.ant.Task; import org.apache.tools.ant.types.Commandline; import org.apache.tools.ant.types.CommandlineJava; import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.types.Permissions; import org.apache.tools.ant.util.TimeoutObserver; import org.apache.tools.ant.util.Watchdog; @@ -72,6 +73,7 @@ import org.apache.tools.ant.util.Watchdog; * * @author thomas.haas@softwired-inc.com * @author Stefan Bodewig + * @author Martijn Kruithof * @since Ant 1.2 */ public class ExecuteJava implements Runnable, TimeoutObserver { @@ -79,6 +81,7 @@ public class ExecuteJava implements Runnable, TimeoutObserver { private Commandline javaCommand = null; private Path classpath = null; private CommandlineJava.SysProperties sysProperties = null; + private Permissions perm = null; private Method main = null; private Long timeout = null; private Throwable caught = null; @@ -101,6 +104,15 @@ public class ExecuteJava implements Runnable, TimeoutObserver { public void setSystemProperties(CommandlineJava.SysProperties s) { sysProperties = s; } + + /** + * Permissions for the application run. + * @since Ant 1.6 + * @param permissions + */ + public void setPermissions(Permissions permissions) { + perm = permissions; + } /** * All output (System.out as well as System.err) will be written @@ -208,6 +220,9 @@ public class ExecuteJava implements Runnable, TimeoutObserver { public void run() { final Object[] argument = {javaCommand.getArguments()}; try { + if(perm != null) { + perm.setSecurityManager(); + } main.invoke(null, argument); } catch (InvocationTargetException e) { Throwable t = e.getTargetException(); @@ -217,6 +232,9 @@ public class ExecuteJava implements Runnable, TimeoutObserver { } catch (Throwable t) { caught = t; } finally { + if(perm != null) { + perm.restoreSecurityManager(); + } synchronized (this) { notifyAll(); } diff --git a/src/main/org/apache/tools/ant/taskdefs/Java.java b/src/main/org/apache/tools/ant/taskdefs/Java.java index e42495d2f..bc1e5786b 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Java.java +++ b/src/main/org/apache/tools/ant/taskdefs/Java.java @@ -68,6 +68,7 @@ import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.PropertySet; import org.apache.tools.ant.types.Reference; import org.apache.tools.ant.types.Assertions; +import org.apache.tools.ant.types.Permissions; /** * Launcher for Java applications. Allows use of @@ -78,6 +79,7 @@ import org.apache.tools.ant.types.Assertions; * stefano@apache.org * @author Stefan Bodewig * @author Donal Quinlan + * @author Martijn Kruithof * * @since Ant 1.1 * @@ -95,7 +97,8 @@ public class Java extends Task { private Long timeout = null; private Redirector redirector = new Redirector(this); private String resultProperty; - + private Permissions perm; + private boolean spawn = false; private boolean incompatibleWithSpawn = false; /** @@ -109,7 +112,7 @@ public class Java extends Task { int err = -1; try { err = executeJava(); - if (fork && err != 0) { + if (err != 0) { if (failOnError) { throw new BuildException("Java returned: " + err, getLocation()); } else { @@ -152,6 +155,9 @@ public class Java extends Task { + "not compatible with spawn"); } if (fork) { + if(perm != null) { + log("Permissions can not be set this way in forked mode.",Project.MSG_WARN); + } log(cmdl.describeCommand(), Project.MSG_VERBOSE); } else { if (cmdl.getVmCommand().size() > 1) { @@ -180,7 +186,7 @@ public class Java extends Task { try { if (fork) { if (!spawn) { - return run(cmdl.getCommandline()); + return fork(cmdl.getCommandline()); } else { spawn(cmdl.getCommandline()); return 0; @@ -248,6 +254,18 @@ public class Java extends Task { return cmdl.createBootclasspath(getProject()).createPath(); } + /** + * Sets the permissions for the application run inside the same JVM. + * @since Ant 1.6 + * @return . + */ + public Permissions createPermissions() { + if (perm == null) { + perm = new Permissions(); + } + return perm; + } + /** * Classpath to use, by reference. * @@ -662,6 +680,7 @@ public class Java extends Task { exe.setJavaCommand(command.getJavaCommand()); exe.setClasspath(command.getClasspath()); exe.setSystemProperties(command.getSystemProperties()); + exe.setPermissions(perm); exe.setTimeout(timeout); redirector.createStreams(); exe.execute(getProject()); @@ -674,7 +693,7 @@ public class Java extends Task { /** * Executes the given classname with the given arguments in a separate VM. */ - private int run(String[] command) throws BuildException { + private int fork(String[] command) throws BuildException { Execute exe = new Execute(redirector.createHandler(), createWatchdog()); diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java b/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java index ec650aa72..edf30ce24 100644 --- a/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java +++ b/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java @@ -76,6 +76,7 @@ import org.apache.tools.ant.types.CommandlineJava; import org.apache.tools.ant.types.EnumeratedAttribute; import org.apache.tools.ant.types.Environment; import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.types.Permissions; import org.apache.tools.ant.types.PropertySet; import org.apache.tools.ant.util.FileUtils; import org.apache.tools.ant.util.LoaderUtils; @@ -180,6 +181,7 @@ public class JUnitTask extends Task { private boolean showOutput = false; private File tmpDir; private AntClassLoader classLoader = null; + private Permissions perm = null; private static final int STRING_BUFFER_SIZE = 128; /** @@ -570,6 +572,18 @@ public class JUnitTask extends Task { commandline.setAssertions(asserts); } + /** + * Sets the permissions for the application run inside the same JVM. + * @since Ant 1.6 + * @return . + */ + public Permissions createPermissions() { + if (perm == null) { + perm = new Permissions(); + } + return perm; + } + /** * Creates a new JUnitRunner and enables fork of a new Java VM. * @@ -688,6 +702,10 @@ public class JUnitTask extends Task { private int executeAsForked(JUnitTest test, ExecuteWatchdog watchdog) throws BuildException { + if(perm != null) { + log("Permissions ignored when running in forked mode!", Project.MSG_WARN); + } + CommandlineJava cmd = (CommandlineJava) commandline.clone(); cmd.setClassname("org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner"); @@ -935,6 +953,8 @@ public class JUnitTask extends Task { f.setOutput(getDefaultOutput()); runner.addFormatter(f); } + + runner.setPermissions(perm); final FormatterElement[] feArray = mergeFormatters(test); for (int i = 0; i < feArray.length; i++) { diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java b/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java index e9436af18..4174519ec 100644 --- a/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java +++ b/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java @@ -75,6 +75,7 @@ import junit.framework.TestResult; import junit.framework.TestSuite; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.Permissions; import org.apache.tools.ant.util.StringUtils; import org.apache.tools.ant.util.TeeOutputStream; @@ -95,6 +96,7 @@ import org.apache.tools.ant.util.TeeOutputStream; * * @author Stefan Bodewig * @author Erik Hatcher + * @author Martijn Kruithof * * @since Ant 1.2 */ @@ -136,6 +138,11 @@ public class JUnitTestRunner implements TestListener { */ private boolean showOutput = false; + /** + * The permissions set for the test to run. + */ + private Permissions perm = null; + private static final String[] DEFAULT_TRACE_FILTERS = new String[] { "junit.framework.TestCase", "junit.framework.TestResult", @@ -309,12 +316,20 @@ public class JUnitTestRunner implements TestListener { ) ); } + perm = null; + } else { + if(perm != null) { + perm.setSecurityManager(); + } } - + try { suite.run(res); } finally { + if(perm != null) { + perm.restoreSecurityManager(); + } if (savedOut != null) { System.setOut(savedOut); } @@ -398,6 +413,15 @@ public class JUnitTestRunner implements TestListener { res.stop(); } } + + /** + * Permissions for the test run. + * @since Ant 1.6 + * @param permissions + */ + public void setPermissions(Permissions permissions) { + perm = permissions; + } protected void handleOutput(String output) { if (systemOut != null) { diff --git a/src/main/org/apache/tools/ant/types/Permissions.java b/src/main/org/apache/tools/ant/types/Permissions.java new file mode 100644 index 000000000..8e8e27b02 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/Permissions.java @@ -0,0 +1,324 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "Ant" and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ + +package org.apache.tools.ant.types; + +import java.security.UnresolvedPermission; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.StringTokenizer; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.ExitException; + +/** + * This class implements a security manager meant for useage by tasks that run inside the + * ant VM. An examples are the Java Task and JUnitTask. + * + * The basic functionality is that nothing (except for a base set of permissions) is allowed, unless + * the permission is granted either explicitly or implicitly. + * If an permission is granted this can be overruled by explicitly revoking the permission. + * + * It is not permissible to add permissions (either granted or revoked) while the Security Manager + * is active (after calling setSecurityManager() but before calling restoreSecurityManager()). + * + * @since Ant 1.6 + * @author Martijn Kruithof + */ +public class Permissions { + + private List grantedPermissions = new LinkedList(); + private List revokedPermissions = new LinkedList(); + private java.security.Permissions granted = null; + private SecurityManager origSm = null; + private boolean active = false; + + /** + * Adds a permission to be granted. + * @param perm The Permissions.Permission to be granted. + */ + public void addConfiguredGrant(Permissions.Permission perm) { + grantedPermissions.add(perm); + } + + /** + * Adds a permission to be revoked. + * @param perm The Permissions.Permission to be revoked + */ + public void addConfiguredRevoke(Permissions.Permission perm) { + revokedPermissions.add(perm); + } + + /** + * To be used by tasks wishing to use this security model before executing the part to be + * subject to these Permissions. Note that setting the SecurityManager too early may + * prevent your part from starting, as for instance changing classloaders may be prohibited. + * The classloader for the new situation is supposed to be present. + */ + public void setSecurityManager() throws BuildException{ + origSm = System.getSecurityManager(); + init(); + System.setSecurityManager(new MySM()); + active = true; + } + + /** + * Initializes the list of granted permissions, checks the list of revoked permissions. + */ + private void init() throws BuildException { + granted = new java.security.Permissions(); + for (Iterator i = revokedPermissions.listIterator(); i.hasNext();) { + Permissions.Permission p = (Permissions.Permission) i.next(); + if (p.getClassName() == null) { + throw new BuildException("Revoked permission " + p + " does not contain a class."); + } + } + for (Iterator i = grantedPermissions.listIterator(); i.hasNext();) { + Permissions.Permission p = (Permissions.Permission) i.next(); + if (p.getClassName() == null) { + throw new BuildException("Granted permission " + p + " does not contain a class."); + } else { + java.security.Permission perm = new UnresolvedPermission(p.getClassName(),p.getName(),p.getActions(),null); + granted.add(perm); + } + } + // Add base set of permissions + granted.add(new java.net.SocketPermission("localhost:1024-", "listen")); + granted.add(new java.util.PropertyPermission("java.version", "read")); + granted.add(new java.util.PropertyPermission("java.vendor", "read")); + granted.add(new java.util.PropertyPermission("java.vendor.url", "read")); + granted.add(new java.util.PropertyPermission("java.class.version", "read")); + granted.add(new java.util.PropertyPermission("os.name", "read")); + granted.add(new java.util.PropertyPermission("os.version", "read")); + granted.add(new java.util.PropertyPermission("os.arch", "read")); + granted.add(new java.util.PropertyPermission("file.separator", "read")); + granted.add(new java.util.PropertyPermission("path.separator", "read")); + granted.add(new java.util.PropertyPermission("line.separator", "read")); + granted.add(new java.util.PropertyPermission("java.specification.version", "read")); + granted.add(new java.util.PropertyPermission("java.specification.vendor", "read")); + granted.add(new java.util.PropertyPermission("java.specification.name", "read")); + granted.add(new java.util.PropertyPermission("java.vm.specification.version", "read")); + granted.add(new java.util.PropertyPermission("java.vm.specification.vendor", "read")); + granted.add(new java.util.PropertyPermission("java.vm.specification.name", "read")); + granted.add(new java.util.PropertyPermission("java.vm.version", "read")); + granted.add(new java.util.PropertyPermission("java.vm.vendor", "read")); + granted.add(new java.util.PropertyPermission("java.vm.name", "read")); + } + + /** + * To be used by tasks that just finished executing the parts subject to these permissions. + */ + public void restoreSecurityManager() { + active = false; + System.setSecurityManager(origSm); + } + + /** + * This inner class implements the actual SecurityManager that can be used by tasks + * supporting Permissions. + */ + private class MySM extends SecurityManager { + + /** + * Exit is treated in a special way in order to be able to return the exit code towards tasks. + * An ExitException is thrown instead of a simple SecurityException to indicate the exit + * code. + * Overridden from java.lang.SecurityManager + * @param status The exit status requested. + */ + public void checkExit(int status) { + java.security.Permission perm = new java.lang.RuntimePermission("exitVM",null); + try { + checkPermission(perm); + } catch (SecurityException e) { + throw new ExitException(e.getMessage(), status); + } + } + + /** + * The central point in checking permissions. + * Overridden from java.lang.SecurityManager + * + * @parem perm The permission requested. + */ + public void checkPermission(java.security.Permission perm) { + if (active) { + if (!granted.implies(perm)) { + throw new SecurityException("Permission " + perm +" was not granted."); + } + for (Iterator i = revokedPermissions.listIterator(); i.hasNext();) { + if (((Permissions.Permission)i.next()).matches(perm)) { + throw new SecurityException("Permission " + perm +" was revoked."); + } + } + } + } + } + + /** Represents a permission. */ + public static class Permission { + private String className; + private String name; + private String actionString; + private Set actions; + + /** + * Sets the class, mandatory. + * @param aClass The class name of the permission. + */ + public void setClass(String aClass) { + className = aClass.trim(); + } + + /** Get the class of the permission + * @return The class name of the permission. + */ + public String getClassName() { + return className; + } + + /** + * Sets the name of the permission. + * @param aName The name of the permission. + */ + public void setName(String aName) { + name = aName.trim(); + } + + /** + * Get the name of the permission. + * @return The name of the permission. + */ + public String getName() { + return name; + } + + /** + * Sets the actions. + * @param actions The actions of the permission. + */ + public void setActions(String actions) { + actionString = actions; + if (actions.length() > 0) { + this.actions = parseActions(actions); + } + } + + /** + * Gets the actions. + * @return The actions of the permission. + */ + public String getActions() { + return actionString; + } + + /** + * Checks if the permission matches in case of a revoked permission. + * @param perm The permission to check against. + */ + boolean matches(java.security.Permission perm) { + + if (!className.equals(perm.getClass().getName())) { + return false; + } + + if (name != null) { + if (name.endsWith("*")) { + if (!perm.getName().startsWith(name.substring(0,name.length()-1))) { + return false; + } + } else { + if (!name.equals(perm.getName())) { + return false; + } + } + } + + if (actions != null) { + Set as = parseActions(perm.getActions()); + int size = as.size(); + as.removeAll(actions); + if (as.size() == size) { + // None of the actions revoked, so all allowed. + return false; + } + } + + return true; + } + + /** + * Parses the actions into a set of separate strings. + * @param action The actions to be parsed. + */ + private Set parseActions(String actions) { + Set result = new HashSet(); + StringTokenizer tk = new StringTokenizer(actions, ","); + while (tk.hasMoreTokens()) { + String item = tk.nextToken().trim(); + if (!item.equals("")) { + result.add(item); + } + } + return result; + } + + public String toString() { + return ("Permission: " + className + " (\""+name+"\", \""+actions+"\")"); + } + } +} \ No newline at end of file diff --git a/src/testcases/org/apache/tools/ant/taskdefs/JavaTest.java b/src/testcases/org/apache/tools/ant/taskdefs/JavaTest.java index 8797215db..d7d75e36d 100644 --- a/src/testcases/org/apache/tools/ant/taskdefs/JavaTest.java +++ b/src/testcases/org/apache/tools/ant/taskdefs/JavaTest.java @@ -64,6 +64,7 @@ import org.apache.tools.ant.util.FileUtils; * @author steve loughran * @author Stephane Bailliez * @author Donal Quinlan + * @author Martijn Kruithof * */ public class JavaTest extends BuildFileTest { @@ -185,6 +186,16 @@ public class JavaTest extends BuildFileTest { assertEquals("2",project.getProperty("exitcode")); } + public void testResultPropertyZeroNoFork() { + executeTarget("testResultPropertyZeroNoFork"); + assertEquals("0",project.getProperty("exitcode")); + } + + public void testResultPropertyNonZeroNoFork() { + executeTarget("testResultPropertyNonZeroNoFork"); + assertEquals("-1",project.getProperty("exitcode")); + } + public void testSpawn() { FileUtils fileutils = FileUtils.newFileUtils(); File logFile = fileutils.createTempFile("spawn","log", project.getBaseDir()); diff --git a/src/testcases/org/apache/tools/ant/types/PermissionsTest.java b/src/testcases/org/apache/tools/ant/types/PermissionsTest.java new file mode 100644 index 000000000..f7320607d --- /dev/null +++ b/src/testcases/org/apache/tools/ant/types/PermissionsTest.java @@ -0,0 +1,187 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "Ant" and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ + +package org.apache.tools.ant.types; + +import junit.framework.TestCase; + +import org.apache.tools.ant.ExitException; + +/** + * JUnit 3 testcases for org.apache.tools.ant.types.Permissions. + * + * @author