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 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.
+
+
+ Attribute |
+ Description |
+ Required |
+
+
+ class |
+ The fully qualified name of the Permission class. |
+ Yes |
+
+
+ name |
+ The name of the Permission. The actual contents depends on the
+ Permission class. |
+ No |
+
+
+ actions |
+ The 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.
+
+
+ Attribute |
+ Description |
+ Required |
+
+
+ class |
+ The fully qualified name of the Permission class. |
+ Yes |
+
+
+ name |
+ The name of the Permission. The actual contents depends on the
+ Permission class. |
+ No |
+
+
+ actions |
+ The 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.
+
+
+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