[BUG-277551] promote to trunk so we can review in full context if this implemenation is the way to go
git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@365 7e9141cc-0065-0410-87d8-b60c137991c4
This commit is contained in:
parent
b9b14e438e
commit
eea741beb8
|
@ -0,0 +1,40 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>7.0.0.M3-SNAPSHOT</version>
|
||||
</parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-policy</artifactId>
|
||||
<name>Jetty :: Policy Tool</name>
|
||||
<packaging>jar</packaging>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>config.xml</descriptor>
|
||||
</descriptors>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,107 @@
|
|||
// basic policy file for jetty
|
||||
|
||||
// TODO update with greg's latest property changes and set better reasonable defaults for various jetty codeBases
|
||||
|
||||
grant codeBase "file:${jetty.home}${/}-" {
|
||||
permission java.io.FilePermission "${jetty.home}${/}-", "read";
|
||||
|
||||
permission java.io.FilePermission "${jetty.home}${/}logs${/}-", "read, write";
|
||||
|
||||
permission java.lang.RuntimePermission "createClassLoader";
|
||||
permission java.lang.RuntimePermission "setContextClassLoader";
|
||||
|
||||
permission java.security.SecurityPermission "getPolicy";
|
||||
permission java.lang.RuntimePermission "accessDeclaredMembers";
|
||||
|
||||
// makes everything work as a crutch to work on startup
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
// default permissions granted to all domains
|
||||
grant {
|
||||
|
||||
// Allows any thread to stop itself using the java.lang.Thread.stop()
|
||||
// method that takes no argument.
|
||||
// Note that this permission is granted by default only to remain
|
||||
// backwards compatible.
|
||||
// It is strongly recommended that you either remove this permission
|
||||
// from this policy file or further restrict it to code sources
|
||||
// that you specify, because Thread.stop() is potentially unsafe.
|
||||
// See "http://java.sun.com/notes" for more information.
|
||||
permission java.lang.RuntimePermission "stopThread";
|
||||
|
||||
// allows anyone to listen on un-privileged ports
|
||||
permission java.net.SocketPermission "localhost:1024-", "listen";
|
||||
|
||||
// "standard" properties that can be read by anyone
|
||||
|
||||
permission java.util.PropertyPermission "java.version", "read";
|
||||
permission java.util.PropertyPermission "java.vendor", "read";
|
||||
permission java.util.PropertyPermission "java.vendor.url", "read";
|
||||
permission java.util.PropertyPermission "java.class.version", "read";
|
||||
permission java.util.PropertyPermission "os.name", "read";
|
||||
permission java.util.PropertyPermission "os.version", "read";
|
||||
permission java.util.PropertyPermission "os.arch", "read";
|
||||
permission java.util.PropertyPermission "file.separator", "read";
|
||||
permission java.util.PropertyPermission "path.separator", "read";
|
||||
permission java.util.PropertyPermission "line.separator", "read";
|
||||
|
||||
permission java.util.PropertyPermission "java.specification.version", "read";
|
||||
permission java.util.PropertyPermission "java.specification.vendor", "read";
|
||||
permission java.util.PropertyPermission "java.specification.name", "read";
|
||||
|
||||
permission java.util.PropertyPermission "java.vm.specification.version", "read";
|
||||
permission java.util.PropertyPermission "java.vm.specification.vendor", "read";
|
||||
permission java.util.PropertyPermission "java.vm.specification.name", "read";
|
||||
permission java.util.PropertyPermission "java.vm.version", "read";
|
||||
permission java.util.PropertyPermission "java.vm.vendor", "read";
|
||||
permission java.util.PropertyPermission "java.vm.name", "read";
|
||||
|
||||
// jetty specific properties
|
||||
permission java.util.PropertyPermission "org.eclipse.jetty.util.log.DEBUG", "read";
|
||||
permission java.util.PropertyPermission "START", "read";
|
||||
permission java.util.PropertyPermission "org.eclipse.jetty.util.log.VERBOSE", "read";
|
||||
permission java.util.PropertyPermission "STOP.PORT", "read";
|
||||
permission java.util.PropertyPermission "STOP.KEY", "read";
|
||||
permission java.util.PropertyPermission "org.eclipse.jetty.util.log.IGNORED", "read";
|
||||
permission java.util.PropertyPermission "CLASSPATH", "read";
|
||||
permission java.util.PropertyPermission "OPTIONS", "read";
|
||||
permission java.util.PropertyPermission "JETTY_NO_SHUTDOWN_HOOK", "read";
|
||||
permission java.util.PropertyPermission "ISO_8859_1", "read";
|
||||
permission java.util.PropertyPermission "jetty.home", "read, write";
|
||||
|
||||
permission java.util.PropertyPermission "user.home", "read";
|
||||
|
||||
permission java.util.PropertyPermission "jetty.class.path", "read, write";
|
||||
permission java.util.PropertyPermission "java.class.path", "read, write";
|
||||
|
||||
permission java.util.PropertyPermission "repository", "read, write";
|
||||
|
||||
permission java.util.PropertyPermission "jetty.lib", "read";
|
||||
permission java.util.PropertyPermission "jetty.server", "read";
|
||||
permission java.util.PropertyPermission "jetty.host", "read";
|
||||
permission java.util.PropertyPermission "jetty.port", "read";
|
||||
permission java.util.PropertyPermission "start.class", "read";
|
||||
|
||||
permission java.util.PropertyPermission "main.class", "read";
|
||||
|
||||
permission java.util.PropertyPermission "org.eclipse.jetty.util.log.class", "read";
|
||||
|
||||
permission java.util.PropertyPermission "org.eclipse.jetty.util.URI.charset", "read";
|
||||
|
||||
permission java.util.PropertyPermission "org.eclipse.jetty.util.FileResource.checkAliases", "read";
|
||||
|
||||
permission java.util.PropertyPermission "org.eclipse.jetty.xml.XmlParser.Validating", "read";
|
||||
|
||||
permission java.util.PropertyPermission "org.eclipse.jetty.io.nio.JVMBUG_THRESHHOLD", "read, write";
|
||||
|
||||
permission java.util.PropertyPermission "org.eclipse.jetty.util.TypeUtil.IntegerCacheSize", "read, write";
|
||||
|
||||
permission java.util.PropertyPermission "org.eclipse.jetty.util.TypeUtil.LongCacheSize", "read";
|
||||
|
||||
// provides access to webapps
|
||||
permission java.io.FilePermission "${jetty.home}${/}webapps${/}-", "read"; // Ought to go up a specific codebase
|
||||
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
package org.eclipse.jetty.policy;
|
||||
|
||||
//========================================================================
|
||||
//Copyright (c) 2003-2009 Mort Bay Consulting Pty. Ltd.
|
||||
//------------------------------------------------------------------------
|
||||
//All rights reserved. This program and the accompanying materials
|
||||
//are made available under the terms of the Eclipse Public License v1.0
|
||||
//and Apache License v2.0 which accompanies this distribution.
|
||||
//The Eclipse Public License is available at
|
||||
//http://www.eclipse.org/legal/epl-v10.html
|
||||
//The Apache License v2.0 is available at
|
||||
//http://www.opensource.org/licenses/apache2.0.php
|
||||
//You may elect to redistribute this code under either of these licenses.
|
||||
//========================================================================
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.security.CodeSource;
|
||||
import java.security.Permission;
|
||||
import java.security.PermissionCollection;
|
||||
import java.security.Permissions;
|
||||
import java.security.Policy;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.policy.loader.DefaultPolicyLoader;
|
||||
|
||||
/**
|
||||
* Policy implementation that will load a set of policy files and manage the mapping of permissions and protection domains
|
||||
*
|
||||
* The reason I created this class and added this mechanism are:
|
||||
*
|
||||
* 1) I wanted a way to be able to follow the startup mechanic that jetty uses with jetty-start using OPTIONS=policy,default
|
||||
* to be able to startup a security manager and policy implementation without have to rely on the existing JVM cli options
|
||||
* 2) establish a starting point to add on further functionality to permissions based security with jetty like jmx enabled
|
||||
* permission tweaking or runtime creation and specification of policies for specific webapps
|
||||
* 3) I wanted to have support for specifying multiple policy files to source permissions from
|
||||
*
|
||||
* Possible additions are:
|
||||
* - jmx enabled a la #2 above
|
||||
* - proxying of system security policy where we can proxy access to the system policy should the jvm have been started with
|
||||
* one, I had support for this but ripped it out to add in again later
|
||||
* - merging of protection domains if process multiple policy files that declare permissions for the same codebase
|
||||
* - an xml policy file parser, had originally added this using modello but tore it out since it would have been
|
||||
* a nightmare to get its dependencies through IP validation, could do this with jvm xml parser instead sometime
|
||||
* - check performance of the synch'd map I am using for the protection domain mapping
|
||||
*/
|
||||
public class JettyPolicy extends Policy
|
||||
{
|
||||
// Policy files that are actively managed by the aggregate policy mechanism
|
||||
private Set<String> _policies;
|
||||
|
||||
private PropertyEvaluator _evaluator;
|
||||
|
||||
private Map<ProtectionDomain, PermissionCollection> pdMapping =
|
||||
Collections.synchronizedMap( new HashMap<ProtectionDomain, PermissionCollection>() );
|
||||
|
||||
public JettyPolicy( Set<String> policies, Map<String,String> properties )
|
||||
{
|
||||
_policies = policies;
|
||||
_evaluator = new PropertyEvaluator( properties );
|
||||
|
||||
// we have the policies we need and an evaluator to reference, lets refresh and save the user a call.
|
||||
refresh();
|
||||
}
|
||||
|
||||
public PermissionCollection getPermissions( ProtectionDomain domain )
|
||||
{
|
||||
PermissionCollection perms = new Permissions();
|
||||
|
||||
for ( Iterator<ProtectionDomain> i = pdMapping.keySet().iterator(); i.hasNext(); )
|
||||
{
|
||||
ProtectionDomain pd = (ProtectionDomain) i.next();
|
||||
|
||||
if ( pd.getCodeSource() == null || pd.getCodeSource().implies( domain.getCodeSource() ) )
|
||||
{
|
||||
// gather dynamic permissions
|
||||
if ( pdMapping.get( pd ) != null )
|
||||
{
|
||||
for ( Enumeration<Permission> e = pdMapping.get( pd ).elements(); e.hasMoreElements(); )
|
||||
{
|
||||
perms.add( e.nextElement() );
|
||||
}
|
||||
}
|
||||
|
||||
// gather static permissions
|
||||
if ( pd.getPermissions() != null )
|
||||
{
|
||||
for ( Enumeration<Permission> e = pd.getPermissions().elements(); e.hasMoreElements(); )
|
||||
{
|
||||
perms.add( e.nextElement() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return perms;
|
||||
}
|
||||
|
||||
public PermissionCollection getPermissions( CodeSource codesource )
|
||||
{
|
||||
PermissionCollection perms = new Permissions();
|
||||
|
||||
for ( Iterator<ProtectionDomain> i = pdMapping.keySet().iterator(); i.hasNext(); )
|
||||
{
|
||||
ProtectionDomain pd = (ProtectionDomain) i.next();
|
||||
|
||||
if ( pd.getCodeSource() == null || pd.getCodeSource().implies( codesource ) )
|
||||
{
|
||||
// gather dynamic permissions
|
||||
if ( pdMapping.get( pd ) != null )
|
||||
{
|
||||
for ( Enumeration<Permission> e = pdMapping.get( pd ).elements(); e.hasMoreElements(); )
|
||||
{
|
||||
perms.add( e.nextElement() );
|
||||
}
|
||||
}
|
||||
|
||||
// gather static permissions
|
||||
if ( pd.getPermissions() != null )
|
||||
{
|
||||
for ( Enumeration<Permission> e = pd.getPermissions().elements(); e.hasMoreElements(); )
|
||||
{
|
||||
perms.add( e.nextElement() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return perms;
|
||||
}
|
||||
|
||||
public void refresh()
|
||||
{
|
||||
try
|
||||
{
|
||||
pdMapping.clear();
|
||||
|
||||
for ( Iterator<String> i = _policies.iterator(); i.hasNext(); )
|
||||
{
|
||||
File policyFile = new File( i.next() );
|
||||
pdMapping.putAll( DefaultPolicyLoader.load( new FileInputStream( policyFile ), _evaluator ) );
|
||||
}
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package org.eclipse.jetty.policy;
|
||||
|
||||
//========================================================================
|
||||
//Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
|
||||
//------------------------------------------------------------------------
|
||||
//All rights reserved. This program and the accompanying materials
|
||||
//are made available under the terms of the Eclipse Public License v1.0
|
||||
//and Apache License v2.0 which accompanies this distribution.
|
||||
//The Eclipse Public License is available at
|
||||
//http://www.eclipse.org/legal/epl-v10.html
|
||||
//The Apache License v2.0 is available at
|
||||
//http://www.opensource.org/licenses/apache2.0.php
|
||||
//You may elect to redistribute this code under either of these licenses.
|
||||
//========================================================================
|
||||
|
||||
|
||||
public class PolicyException extends Exception
|
||||
{
|
||||
|
||||
public PolicyException()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public PolicyException( final String message, final Throwable cause)
|
||||
{
|
||||
super( message, cause );
|
||||
}
|
||||
|
||||
public PolicyException( final String message )
|
||||
{
|
||||
super( message );
|
||||
}
|
||||
|
||||
public PolicyException( final Throwable cause )
|
||||
{
|
||||
super( cause );
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
package org.eclipse.jetty.policy;
|
||||
|
||||
//========================================================================
|
||||
//Copyright (c) 2003-2009 Mort Bay Consulting Pty. Ltd.
|
||||
//------------------------------------------------------------------------
|
||||
//All rights reserved. This program and the accompanying materials
|
||||
//are made available under the terms of the Eclipse Public License v1.0
|
||||
//and Apache License v2.0 which accompanies this distribution.
|
||||
//The Eclipse Public License is available at
|
||||
//http://www.eclipse.org/legal/epl-v10.html
|
||||
//The Apache License v2.0 is available at
|
||||
//http://www.opensource.org/licenses/apache2.0.php
|
||||
//You may elect to redistribute this code under either of these licenses.
|
||||
//========================================================================
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/*
|
||||
* Property evaluator to provide common reference object for property access and evaluation
|
||||
*
|
||||
* The origin of this class was in the Main.class of the jetty-start package where is where
|
||||
* it picks up the convention of $() properties and ${} system properties
|
||||
*
|
||||
* Not exactly sun convention but a jetty convention none the less
|
||||
*/
|
||||
public class PropertyEvaluator extends HashMap<String,String>
|
||||
{
|
||||
private static final long serialVersionUID = -7745629868268683553L;
|
||||
|
||||
public PropertyEvaluator( Map<String,String> properties )
|
||||
{
|
||||
putAll( properties );
|
||||
put("/", File.separator ); // '/' is a special case when evaluated itself, resolves to File.separator as per policy parsing convention
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the value of it exists in this map, otherwise consults the System properties
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
public String getSystemProperty(String name)
|
||||
{
|
||||
if (containsKey(name))
|
||||
return get(name);
|
||||
return System.getProperty(name);
|
||||
}
|
||||
|
||||
public String getProperty(String name)
|
||||
{
|
||||
return get(name);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public String evaluate(String s)
|
||||
{
|
||||
int i1=0;
|
||||
int i2=0;
|
||||
while (s!=null)
|
||||
{
|
||||
i1=s.indexOf("$(",i2);
|
||||
if (i1<0)
|
||||
break;
|
||||
i2=s.indexOf(")",i1+2);
|
||||
if (i2<0)
|
||||
break;
|
||||
String name=s.substring(i1+2,i2);
|
||||
String property=getSystemProperty(name);
|
||||
s=s.substring(0,i1)+property+s.substring(i2+1);
|
||||
}
|
||||
|
||||
i1=0;
|
||||
i2=0;
|
||||
while (s!=null)
|
||||
{
|
||||
i1=s.indexOf("${",i2);
|
||||
if (i1<0)
|
||||
break;
|
||||
i2=s.indexOf("}",i1+2);
|
||||
if (i2<0)
|
||||
break;
|
||||
String name=s.substring(i1+2,i2);
|
||||
String property=getProperty(name);
|
||||
s=s.substring(0,i1)+property+s.substring(i2+1);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,267 @@
|
|||
package org.eclipse.jetty.policy.loader;
|
||||
|
||||
//========================================================================
|
||||
//Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
|
||||
//------------------------------------------------------------------------
|
||||
//All rights reserved. This program and the accompanying materials
|
||||
//are made available under the terms of the Eclipse Public License v1.0
|
||||
//and Apache License v2.0 which accompanies this distribution.
|
||||
//The Eclipse Public License is available at
|
||||
//http://www.eclipse.org/legal/epl-v10.html
|
||||
//The Apache License v2.0 is available at
|
||||
//http://www.opensource.org/licenses/apache2.0.php
|
||||
//You may elect to redistribute this code under either of these licenses.
|
||||
//
|
||||
//Portions of this file adapted for use from Apache Harmony code by written
|
||||
//and contributed to that project by Alexey V. Varlamov under the ASL
|
||||
//========================================================================
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.net.URL;
|
||||
import java.security.CodeSource;
|
||||
import java.security.Permission;
|
||||
import java.security.PermissionCollection;
|
||||
import java.security.Permissions;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.policy.PolicyException;
|
||||
import org.eclipse.jetty.policy.PropertyEvaluator;
|
||||
|
||||
/**
|
||||
* Load the policies within the stream and resolve into protection domains and permission collections
|
||||
*
|
||||
* TODO: currently this loading does not support keystores or certificates
|
||||
*/
|
||||
public class DefaultPolicyLoader
|
||||
{
|
||||
|
||||
public static Map<ProtectionDomain, PermissionCollection> load( InputStream policyStream, PropertyEvaluator evaluator ) throws PolicyException
|
||||
{
|
||||
Map<ProtectionDomain, PermissionCollection> pdMappings = new HashMap<ProtectionDomain, PermissionCollection>();
|
||||
|
||||
try
|
||||
{
|
||||
PolicyFileScanner loader = new PolicyFileScanner();
|
||||
|
||||
Collection<GrantEntry> grantEntries = new ArrayList<GrantEntry>();
|
||||
List<KeystoreEntry> keystoreEntries = new ArrayList<KeystoreEntry>();
|
||||
|
||||
loader.scanStream( new InputStreamReader(policyStream), grantEntries, keystoreEntries );
|
||||
|
||||
for ( Iterator<GrantEntry> i = grantEntries.iterator(); i.hasNext(); )
|
||||
{
|
||||
GrantEntry grant = i.next();
|
||||
|
||||
Permissions permissions = processPermissions( grant.permissions, evaluator );
|
||||
|
||||
ProtectionDomain pd;
|
||||
|
||||
if ( grant.codebase == null ) // these are hereby known as global permissions (no codebase associated)
|
||||
{
|
||||
pd = new ProtectionDomain( null, permissions );
|
||||
}
|
||||
else
|
||||
{
|
||||
CodeSource codeSource = resolveToCodeSource( grant.codebase, evaluator );
|
||||
pd = new ProtectionDomain( codeSource, permissions );
|
||||
}
|
||||
pdMappings.put( pd, null );
|
||||
}
|
||||
|
||||
return pdMappings;
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
throw new PolicyException( e );
|
||||
}
|
||||
}
|
||||
|
||||
private static Permissions processPermissions( Collection<PermissionEntry> collection, PropertyEvaluator evaluator ) throws PolicyException
|
||||
{
|
||||
Permissions permissions = new Permissions();
|
||||
|
||||
for ( Iterator<PermissionEntry> i = collection.iterator(); i.hasNext(); )
|
||||
{
|
||||
PermissionEntry perm = i.next();
|
||||
|
||||
Class clazz;
|
||||
try
|
||||
{
|
||||
clazz = Class.forName( perm.klass );
|
||||
|
||||
if ( perm.name == null && perm.actions == null )
|
||||
{
|
||||
permissions.add( (Permission)clazz.newInstance() );
|
||||
}
|
||||
else if ( perm.name != null && perm.actions == null )
|
||||
{
|
||||
Constructor c = clazz.getConstructor(new Class[] { String.class });
|
||||
permissions.add( (Permission)c.newInstance( evaluator.evaluate( perm.name ) ) );
|
||||
}
|
||||
else if ( perm.name != null && perm.actions != null )
|
||||
{
|
||||
Constructor c = clazz.getConstructor(new Class[] { String.class, String.class });
|
||||
permissions.add( (Permission)c.newInstance( evaluator.evaluate( perm.name ), perm.actions ) );
|
||||
}
|
||||
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
throw new PolicyException( e );
|
||||
}
|
||||
}
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
||||
private static CodeSource resolveToCodeSource( String codeBase, PropertyEvaluator evaluator ) throws PolicyException
|
||||
{
|
||||
try
|
||||
{
|
||||
URL url = new URL( evaluator.evaluate(codeBase) );
|
||||
Certificate[] cert = null;
|
||||
return new CodeSource( url, cert); //TODO support certificates
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
throw new PolicyException( e );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compound token representing <i>keystore </i> clause. See policy format
|
||||
* {@link org.apache.harmony.security.DefaultPolicy description}for details.
|
||||
*
|
||||
* @see org.apache.harmony.security.fortress.DefaultPolicyParser
|
||||
* @see org.apache.harmony.security.DefaultPolicyScanner
|
||||
*/
|
||||
public static class KeystoreEntry
|
||||
{
|
||||
|
||||
/**
|
||||
* The URL part of keystore clause.
|
||||
*/
|
||||
public String url;
|
||||
|
||||
/**
|
||||
* The typename part of keystore clause.
|
||||
*/
|
||||
public String type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compound token representing <i>grant </i> clause. See policy format
|
||||
* {@link org.apache.harmony.security.DefaultPolicy description}for details.
|
||||
*
|
||||
* @see org.apache.harmony.security.fortress.DefaultPolicyParser
|
||||
* @see org.apache.harmony.security.DefaultPolicyScanner
|
||||
*/
|
||||
public static class GrantEntry
|
||||
{
|
||||
|
||||
/**
|
||||
* The signers part of grant clause. This is a comma-separated list of certificate aliases.
|
||||
*/
|
||||
public String signers;
|
||||
|
||||
/**
|
||||
* The codebase part of grant clause. This is an URL from which code originates.
|
||||
*/
|
||||
public String codebase;
|
||||
|
||||
/**
|
||||
* Collection of PrincipalEntries of grant clause.
|
||||
*/
|
||||
public Collection<PrincipalEntry> principals;
|
||||
|
||||
/**
|
||||
* Collection of PermissionEntries of grant clause.
|
||||
*/
|
||||
public Collection<PermissionEntry> permissions;
|
||||
|
||||
/**
|
||||
* Adds specified element to the <code>principals</code> collection. If collection does not exist yet, creates a
|
||||
* new one.
|
||||
*/
|
||||
public void addPrincipal( PrincipalEntry pe )
|
||||
{
|
||||
if ( principals == null )
|
||||
{
|
||||
principals = new HashSet<PrincipalEntry>();
|
||||
}
|
||||
principals.add( pe );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Compound token representing <i>principal </i> entry of a <i>grant </i> clause. See policy format
|
||||
* {@link org.apache.harmony.security.DefaultPolicy description}for details.
|
||||
*
|
||||
* @see org.apache.harmony.security.fortress.DefaultPolicyParser
|
||||
* @see org.apache.harmony.security.DefaultPolicyScanner
|
||||
*/
|
||||
public static class PrincipalEntry
|
||||
{
|
||||
|
||||
/**
|
||||
* Wildcard value denotes any class and/or any name. Must be asterisk, for proper general expansion and
|
||||
* PrivateCredentialsPermission wildcarding
|
||||
*/
|
||||
public static final String WILDCARD = "*"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* The classname part of principal clause.
|
||||
*/
|
||||
public String klass;
|
||||
|
||||
/**
|
||||
* The name part of principal clause.
|
||||
*/
|
||||
public String name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compound token representing <i>permission </i> entry of a <i>grant </i> clause. See policy format
|
||||
* {@link org.apache.harmony.security.DefaultPolicy description}for details.
|
||||
*
|
||||
* @see org.apache.harmony.security.fortress.DefaultPolicyParser
|
||||
* @see org.apache.harmony.security.DefaultPolicyScanner
|
||||
*/
|
||||
public static class PermissionEntry
|
||||
{
|
||||
|
||||
/**
|
||||
* The classname part of permission clause.
|
||||
*/
|
||||
public String klass;
|
||||
|
||||
/**
|
||||
* The name part of permission clause.
|
||||
*/
|
||||
public String name;
|
||||
|
||||
/**
|
||||
* The actions part of permission clause.
|
||||
*/
|
||||
public String actions;
|
||||
|
||||
/**
|
||||
* The signers part of permission clause. This is a comma-separated list of certificate aliases.
|
||||
*/
|
||||
public String signers;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,469 @@
|
|||
package org.eclipse.jetty.policy.loader;
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//========================================================================
|
||||
//All rights reserved. This program and the accompanying materials
|
||||
//are made available under the terms of the Eclipse Public License v1.0
|
||||
//and Apache License v2.0 which accompanies this distribution.
|
||||
//The Eclipse Public License is available at
|
||||
//http://www.eclipse.org/legal/epl-v10.html
|
||||
//The Apache License v2.0 is available at
|
||||
//http://www.opensource.org/licenses/apache2.0.php
|
||||
//You may elect to redistribute this code under either of these licenses.
|
||||
//
|
||||
// This file adapted for use from Apache Harmony code by written and contributed
|
||||
// to that project by Alexey V. Varlamov under the ASL-2.0
|
||||
//
|
||||
// See CQ3380
|
||||
//========================================================================
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StreamTokenizer;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.policy.loader.DefaultPolicyLoader.GrantEntry;
|
||||
import org.eclipse.jetty.policy.loader.DefaultPolicyLoader.KeystoreEntry;
|
||||
import org.eclipse.jetty.policy.loader.DefaultPolicyLoader.PermissionEntry;
|
||||
import org.eclipse.jetty.policy.loader.DefaultPolicyLoader.PrincipalEntry;
|
||||
|
||||
|
||||
/**
|
||||
* This is a basic high-level tokenizer of policy files. It takes in a stream, analyzes data read from it and returns a
|
||||
* set of structured tokens. <br>
|
||||
* This implementation recognizes text files, consisting of clauses with the following syntax:
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* keystore "some_keystore_url", "keystore_type";
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* grant [SignedBy "signer_names"] [, CodeBase "URL"]
|
||||
* [, Principal [principal_class_name] "principal_name"]
|
||||
* [, Principal [principal_class_name] "principal_name"] ... {
|
||||
* permission permission_class_name [ "target_name" ] [, "action"]
|
||||
* [, SignedBy "signer_names"];
|
||||
* permission ...
|
||||
* };
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* For semantical details of this format, see the {@link org.apache.harmony.security.DefaultPolicy default policy
|
||||
* description}. <br>
|
||||
* Keywords are case-insensitive in contrast to quoted string literals. Comma-separation rule is quite forgiving, most
|
||||
* commas may be just omitted. Whitespaces, line- and block comments are ignored. Symbol-level tokenization is delegated
|
||||
* to java.io.StreamTokenizer. <br>
|
||||
* <br>
|
||||
* This implementation is effectively thread-safe, as it has no field references to data being processed (that is,
|
||||
* passes all the data as method parameters).
|
||||
*
|
||||
*/
|
||||
public class PolicyFileScanner
|
||||
{
|
||||
|
||||
/**
|
||||
* Specific exception class to signal policy file syntax error.
|
||||
*/
|
||||
public static class InvalidFormatException
|
||||
extends Exception
|
||||
{
|
||||
|
||||
/**
|
||||
* @serial
|
||||
*/
|
||||
private static final long serialVersionUID = 5789786270390222184L;
|
||||
|
||||
/**
|
||||
* Constructor with detailed message parameter.
|
||||
*/
|
||||
public InvalidFormatException( String arg0 )
|
||||
{
|
||||
super( arg0 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures passed tokenizer accordingly to supported syntax.
|
||||
*/
|
||||
protected StreamTokenizer configure( StreamTokenizer st )
|
||||
{
|
||||
st.slashSlashComments( true );
|
||||
st.slashStarComments( true );
|
||||
st.wordChars( '_', '_' );
|
||||
st.wordChars( '$', '$' );
|
||||
return st;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the main parsing loop. Starts with creating and configuring a StreamTokenizer instance; then tries to
|
||||
* recognize <i>keystore </i> or <i>grant </i> keyword. When found, invokes read method corresponding to the clause
|
||||
* and collects result to the passed collection.
|
||||
*
|
||||
* @param r policy stream reader
|
||||
* @param grantEntries a collection to accumulate parsed GrantEntries
|
||||
* @param keystoreEntries a collection to accumulate parsed KeystoreEntries
|
||||
* @throws IOException if stream reading failed
|
||||
* @throws InvalidFormatException if unexpected or unknown token encountered
|
||||
*/
|
||||
public void scanStream( Reader r, Collection<GrantEntry> grantEntries, List<KeystoreEntry> keystoreEntries )
|
||||
throws IOException, InvalidFormatException
|
||||
{
|
||||
StreamTokenizer st = configure( new StreamTokenizer( r ) );
|
||||
// main parsing loop
|
||||
parsing: while ( true )
|
||||
{
|
||||
switch ( st.nextToken() )
|
||||
{
|
||||
case StreamTokenizer.TT_EOF: // we've done the job
|
||||
break parsing;
|
||||
|
||||
case StreamTokenizer.TT_WORD:
|
||||
if ( Util.equalsIgnoreCase( "keystore", st.sval ) ) { //$NON-NLS-1$
|
||||
keystoreEntries.add( readKeystoreEntry( st ) );
|
||||
}
|
||||
else if ( Util.equalsIgnoreCase( "grant", st.sval ) ) { //$NON-NLS-1$
|
||||
grantEntries.add( readGrantEntry( st ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
handleUnexpectedToken( st, "Expected entries are : \"grant\" or \"keystore\"" ); //$NON-NLS-1$
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case ';': // just delimiter of entries
|
||||
break;
|
||||
|
||||
default:
|
||||
handleUnexpectedToken( st );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to read <i>keystore </i> clause fields. The expected syntax is
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* "some_keystore_url"[, "keystore_type"];
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @return successfully parsed KeystoreEntry
|
||||
* @throws IOException if stream reading failed
|
||||
* @throws InvalidFormatException if unexpected or unknown token encountered
|
||||
*/
|
||||
protected KeystoreEntry readKeystoreEntry( StreamTokenizer st )
|
||||
throws IOException, InvalidFormatException
|
||||
{
|
||||
KeystoreEntry ke = new KeystoreEntry();
|
||||
if ( st.nextToken() == '"' )
|
||||
{
|
||||
ke.url = st.sval;
|
||||
if ( ( st.nextToken() == '"' ) || ( ( st.ttype == ',' ) && ( st.nextToken() == '"' ) ) )
|
||||
{
|
||||
ke.type = st.sval;
|
||||
}
|
||||
else
|
||||
{ // handle token in the main loop
|
||||
st.pushBack();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
handleUnexpectedToken( st, "Expected syntax is : keystore \"url\"[, \"type\"]" ); //$NON-NLS-1$
|
||||
|
||||
}
|
||||
return ke;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to read <i>grant </i> clause. <br>
|
||||
* First, it reads <i>codebase </i>, <i>signedby </i>, <i>principal </i> entries till the '{' (opening curly brace)
|
||||
* symbol. Then it calls readPermissionEntries() method to read the permissions of this clause. <br>
|
||||
* Principal entries (if any) are read by invoking readPrincipalEntry() method, obtained PrincipalEntries are
|
||||
* accumulated. <br>
|
||||
* The expected syntax is
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* [ [codebase "url"] | [signedby "name1,...,nameN"] |
|
||||
* principal ...] ]* { ... }
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @return successfully parsed GrantEntry
|
||||
* @throws IOException if stream reading failed
|
||||
* @throws InvalidFormatException if unexpected or unknown token encountered
|
||||
*/
|
||||
protected GrantEntry readGrantEntry( StreamTokenizer st )
|
||||
throws IOException, InvalidFormatException
|
||||
{
|
||||
GrantEntry ge = new GrantEntry();
|
||||
parsing: while ( true )
|
||||
{
|
||||
switch ( st.nextToken() )
|
||||
{
|
||||
|
||||
case StreamTokenizer.TT_WORD:
|
||||
if ( Util.equalsIgnoreCase( "signedby", st.sval ) ) { //$NON-NLS-1$
|
||||
if ( st.nextToken() == '"' )
|
||||
{
|
||||
ge.signers = st.sval;
|
||||
}
|
||||
else
|
||||
{
|
||||
handleUnexpectedToken( st, "Expected syntax is : signedby \"name1,...,nameN\"" ); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
else if ( Util.equalsIgnoreCase( "codebase", st.sval ) ) { //$NON-NLS-1$
|
||||
if ( st.nextToken() == '"' )
|
||||
{
|
||||
ge.codebase = st.sval;
|
||||
}
|
||||
else
|
||||
{
|
||||
handleUnexpectedToken( st, "Expected syntax is : codebase \"url\"" ); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
else if ( Util.equalsIgnoreCase( "principal", st.sval ) ) { //$NON-NLS-1$
|
||||
ge.addPrincipal( readPrincipalEntry( st ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
handleUnexpectedToken( st );
|
||||
}
|
||||
break;
|
||||
|
||||
case ',': // just delimiter of entries
|
||||
break;
|
||||
|
||||
case '{':
|
||||
ge.permissions = readPermissionEntries( st );
|
||||
break parsing;
|
||||
|
||||
default: // handle token in the main loop
|
||||
st.pushBack();
|
||||
break parsing;
|
||||
}
|
||||
}
|
||||
|
||||
return ge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to read <i>Principal </i> entry fields. The expected syntax is
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* [ principal_class_name ] "principal_name"
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* Both class and name may be wildcards, wildcard names should not surrounded by quotes.
|
||||
*
|
||||
* @return successfully parsed PrincipalEntry
|
||||
* @throws IOException if stream reading failed
|
||||
* @throws InvalidFormatException if unexpected or unknown token encountered
|
||||
*/
|
||||
protected PrincipalEntry readPrincipalEntry( StreamTokenizer st )
|
||||
throws IOException, InvalidFormatException
|
||||
{
|
||||
PrincipalEntry pe = new PrincipalEntry();
|
||||
if ( st.nextToken() == StreamTokenizer.TT_WORD )
|
||||
{
|
||||
pe.klass = st.sval;
|
||||
st.nextToken();
|
||||
}
|
||||
else if ( st.ttype == '*' )
|
||||
{
|
||||
pe.klass = PrincipalEntry.WILDCARD;
|
||||
st.nextToken();
|
||||
}
|
||||
if ( st.ttype == '"' )
|
||||
{
|
||||
pe.name = st.sval;
|
||||
}
|
||||
else if ( st.ttype == '*' )
|
||||
{
|
||||
pe.name = PrincipalEntry.WILDCARD;
|
||||
}
|
||||
else
|
||||
{
|
||||
handleUnexpectedToken( st, "Expected syntax is : principal [class_name] \"principal_name\"" ); //$NON-NLS-1$
|
||||
}
|
||||
return pe;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to read a list of <i>permission </i> entries. The expected syntax is
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* permission permission_class_name
|
||||
* [ "target_name" ] [, "action_list"]
|
||||
* [, signedby "name1,name2,..."];
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* List is terminated by '}' (closing curly brace) symbol.
|
||||
*
|
||||
* @return collection of successfully parsed PermissionEntries
|
||||
* @throws IOException if stream reading failed
|
||||
* @throws InvalidFormatException if unexpected or unknown token encountered
|
||||
*/
|
||||
protected Collection<PermissionEntry> readPermissionEntries( StreamTokenizer st )
|
||||
throws IOException, InvalidFormatException
|
||||
{
|
||||
Collection<PermissionEntry> permissions = new HashSet<PermissionEntry>();
|
||||
parsing: while ( true )
|
||||
{
|
||||
switch ( st.nextToken() )
|
||||
{
|
||||
|
||||
case StreamTokenizer.TT_WORD:
|
||||
if ( Util.equalsIgnoreCase( "permission", st.sval ) ) { //$NON-NLS-1$
|
||||
PermissionEntry pe = new PermissionEntry();
|
||||
if ( st.nextToken() == StreamTokenizer.TT_WORD )
|
||||
{
|
||||
pe.klass = st.sval;
|
||||
if ( st.nextToken() == '"' )
|
||||
{
|
||||
pe.name = st.sval;
|
||||
st.nextToken();
|
||||
}
|
||||
if ( st.ttype == ',' )
|
||||
{
|
||||
st.nextToken();
|
||||
}
|
||||
if ( st.ttype == '"' )
|
||||
{
|
||||
pe.actions = st.sval;
|
||||
if ( st.nextToken() == ',' )
|
||||
{
|
||||
st.nextToken();
|
||||
}
|
||||
}
|
||||
if ( st.ttype == StreamTokenizer.TT_WORD && Util.equalsIgnoreCase( "signedby", st.sval ) ) { //$NON-NLS-1$
|
||||
if ( st.nextToken() == '"' )
|
||||
{
|
||||
pe.signers = st.sval;
|
||||
}
|
||||
else
|
||||
{
|
||||
handleUnexpectedToken( st );
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // handle token in the next iteration
|
||||
st.pushBack();
|
||||
}
|
||||
permissions.add( pe );
|
||||
continue parsing;
|
||||
}
|
||||
}
|
||||
handleUnexpectedToken(
|
||||
st,
|
||||
"Expected syntax is : permission permission_class_name [\"target_name\"] [, \"action_list\"] [, signedby \"name1,...,nameN\"]" ); //$NON-NLS-1$
|
||||
break;
|
||||
|
||||
case ';': // just delimiter of entries
|
||||
break;
|
||||
|
||||
case '}': // end of list
|
||||
break parsing;
|
||||
|
||||
default: // invalid token
|
||||
handleUnexpectedToken( st );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a detailed description of tokenizer status: current token, current line number, etc.
|
||||
*/
|
||||
protected String composeStatus( StreamTokenizer st )
|
||||
{
|
||||
return st.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws InvalidFormatException with detailed diagnostics.
|
||||
*
|
||||
* @param st a tokenizer holding the erroneous token
|
||||
* @param message a user-friendly comment, probably explaining expected syntax. Should not be <code>null</code>- use
|
||||
* the overloaded single-parameter method instead.
|
||||
*/
|
||||
protected final void handleUnexpectedToken( StreamTokenizer st, String message )
|
||||
throws InvalidFormatException
|
||||
{
|
||||
throw new InvalidFormatException( "Unexpected token encountered: " + composeStatus( st ) + ". " + message );
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws InvalidFormatException with error status: which token is unexpected on which line.
|
||||
*
|
||||
* @param st a tokenizer holding the erroneous token
|
||||
*/
|
||||
protected final void handleUnexpectedToken( StreamTokenizer st )
|
||||
throws InvalidFormatException
|
||||
{
|
||||
throw new InvalidFormatException( "Unexpected token encountered: " + composeStatus( st ) );
|
||||
}
|
||||
|
||||
|
||||
private static class Util
|
||||
{
|
||||
public static String toUpperCase( String s )
|
||||
{
|
||||
int len = s.length();
|
||||
StringBuilder buffer = new StringBuilder( len );
|
||||
for ( int i = 0; i < len; i++ )
|
||||
{
|
||||
char c = s.charAt( i );
|
||||
if ( 'a' <= c && c <= 'z' )
|
||||
{
|
||||
buffer.append( (char) ( c - ( 'a' - 'A' ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer.append( c );
|
||||
}
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public static boolean equalsIgnoreCase( String s1, String s2 )
|
||||
{
|
||||
s1 = toUpperCase( s1 );
|
||||
s2 = toUpperCase( s2 );
|
||||
return s1.equals( s2 );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
package org.eclipse.jetty.policy;
|
||||
//========================================================================
|
||||
//Copyright (c) 2003-2009 Mort Bay Consulting Pty. Ltd.
|
||||
//------------------------------------------------------------------------
|
||||
//All rights reserved. This program and the accompanying materials
|
||||
//are made available under the terms of the Eclipse Public License v1.0
|
||||
//and Apache License v2.0 which accompanies this distribution.
|
||||
//The Eclipse Public License is available at
|
||||
//http://www.eclipse.org/legal/epl-v10.html
|
||||
//The Apache License v2.0 is available at
|
||||
//http://www.opensource.org/licenses/apache2.0.php
|
||||
//You may elect to redistribute this code under either of these licenses.
|
||||
//========================================================================
|
||||
|
||||
import java.io.FilePermission;
|
||||
import java.net.URL;
|
||||
import java.security.CodeSource;
|
||||
import java.security.Permission;
|
||||
import java.security.PermissionCollection;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.policy.JettyPolicy;
|
||||
import org.eclipse.jetty.policy.PropertyEvaluator;
|
||||
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class TestJettyPolicy extends TestCase
|
||||
{
|
||||
PropertyEvaluator evaluator = new PropertyEvaluator( new HashMap<String,String>());
|
||||
|
||||
|
||||
@Override
|
||||
protected void setUp()
|
||||
throws Exception
|
||||
{
|
||||
super.setUp();
|
||||
|
||||
evaluator.put( "jetty.home", getWorkingDirectory() );
|
||||
}
|
||||
|
||||
public void testGlobalAllPermissionLoader()
|
||||
throws Exception
|
||||
{
|
||||
|
||||
JettyPolicy ap =
|
||||
new JettyPolicy( Collections.singleton( getWorkingDirectory() + "/src/test/resources/global-all-permission.policy" ), evaluator );
|
||||
|
||||
ap.refresh();
|
||||
|
||||
|
||||
PermissionCollection pc = ap.getPermissions( new ProtectionDomain( null, null ) );
|
||||
|
||||
assertNotNull( pc );
|
||||
|
||||
Permission testPerm = new FilePermission( "/tmp", "read" );
|
||||
|
||||
assertTrue( pc.implies( testPerm ) );
|
||||
|
||||
for ( Enumeration<Permission> e = pc.elements(); e.hasMoreElements(); )
|
||||
{
|
||||
System.out.println( "Permission: " + e.nextElement().getClass().getName() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testSingleCodebaseFilePermissionLoader()
|
||||
throws Exception
|
||||
{
|
||||
JettyPolicy ap =
|
||||
new JettyPolicy( Collections.singleton( getWorkingDirectory()
|
||||
+ "/src/test/resources/single-codebase-file-permission.policy" ), evaluator );
|
||||
|
||||
ap.refresh();
|
||||
|
||||
URL url = new URL( "file:///foo.jar" );
|
||||
CodeSource cs = new CodeSource( url, new Certificate[0]);
|
||||
|
||||
PermissionCollection pc = ap.getPermissions( cs );
|
||||
|
||||
assertNotNull( pc );
|
||||
|
||||
Permission testPerm = new FilePermission( "/tmp/*", "read" );
|
||||
|
||||
assertTrue( pc.implies( testPerm ) );
|
||||
|
||||
}
|
||||
|
||||
public void testMultipleCodebaseFilePermissionLoader()
|
||||
throws Exception
|
||||
{
|
||||
JettyPolicy ap =
|
||||
new JettyPolicy( Collections.singleton( getWorkingDirectory()
|
||||
+ "/src/test/resources/multiple-codebase-file-permission.policy" ), evaluator );
|
||||
|
||||
ap.refresh();
|
||||
|
||||
URL url = new URL( "file:///bar.jar" );
|
||||
CodeSource cs = new CodeSource( url, new Certificate[0]);
|
||||
|
||||
PermissionCollection pc = ap.getPermissions( cs );
|
||||
|
||||
assertNotNull( pc );
|
||||
|
||||
Permission testPerm = new FilePermission( "/tmp/*", "read,write" );
|
||||
Permission testPerm2 = new FilePermission( "/usr/*", "write" ); // only read was granted
|
||||
|
||||
assertTrue( pc.implies( testPerm ) );
|
||||
assertFalse( pc.implies( testPerm2 ) );
|
||||
|
||||
}
|
||||
|
||||
public void testMultipleCodebaseMixedPermissionLoader()
|
||||
throws Exception
|
||||
{
|
||||
JettyPolicy ap =
|
||||
new JettyPolicy( Collections.singleton( getWorkingDirectory()
|
||||
+ "/src/test/resources/multiple-codebase-mixed-permission.policy" ), evaluator );
|
||||
|
||||
ap.refresh();
|
||||
}
|
||||
|
||||
|
||||
public void testMultipleFilePermissionLoader()
|
||||
throws Exception
|
||||
{
|
||||
Set<String> files = new HashSet<String>();
|
||||
|
||||
files.add( getWorkingDirectory() + "/src/test/resources/single-codebase-file-permission.policy" );
|
||||
files.add( getWorkingDirectory() + "/src/test/resources/single-codebase-file-permission-2.policy" );
|
||||
|
||||
JettyPolicy ap = new JettyPolicy( files, evaluator );
|
||||
|
||||
ap.refresh();
|
||||
|
||||
URL url = new URL( "file:///bar.jar" );
|
||||
CodeSource cs = new CodeSource( url, new Certificate[0]);
|
||||
|
||||
PermissionCollection pc = ap.getPermissions( cs );
|
||||
|
||||
assertNotNull( pc );
|
||||
|
||||
Permission testPerm = new FilePermission( "/tmp/*", "read" );
|
||||
Permission testPerm2 = new FilePermission( "/usr/*", "write" ); //
|
||||
|
||||
assertTrue( pc.implies( testPerm ) );
|
||||
assertFalse( pc.implies( testPerm2 ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
private String getWorkingDirectory()
|
||||
{
|
||||
return System.getProperty( "basedir" ); // TODO work in eclipse
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
package org.eclipse.jetty.policy;
|
||||
//========================================================================
|
||||
//Copyright (c) 2003-2009 Mort Bay Consulting Pty. Ltd.
|
||||
//------------------------------------------------------------------------
|
||||
//All rights reserved. This program and the accompanying materials
|
||||
//are made available under the terms of the Eclipse Public License v1.0
|
||||
//and Apache License v2.0 which accompanies this distribution.
|
||||
//The Eclipse Public License is available at
|
||||
//http://www.eclipse.org/legal/epl-v10.html
|
||||
//The Apache License v2.0 is available at
|
||||
//http://www.opensource.org/licenses/apache2.0.php
|
||||
//You may elect to redistribute this code under either of these licenses.
|
||||
//========================================================================
|
||||
|
||||
import java.io.File;
|
||||
import java.security.AccessControlException;
|
||||
import java.security.Policy;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.eclipse.jetty.policy.JettyPolicy;
|
||||
import org.eclipse.jetty.policy.PropertyEvaluator;
|
||||
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class TestJettyPolicyRuntime extends TestCase
|
||||
{
|
||||
|
||||
PropertyEvaluator evaluator = new PropertyEvaluator( new HashMap<String,String>());
|
||||
|
||||
@Override
|
||||
protected void setUp()
|
||||
throws Exception
|
||||
{
|
||||
super.setUp();
|
||||
|
||||
evaluator.put( "jetty.home", getWorkingDirectory() );
|
||||
}
|
||||
|
||||
public void testSimplePolicyReplacement() throws Exception
|
||||
{
|
||||
JettyPolicy ap =
|
||||
new JettyPolicy( Collections.singleton( getWorkingDirectory() + "/src/test/resources/global-all-permission.policy" ), evaluator );
|
||||
|
||||
ap.refresh();
|
||||
|
||||
Policy.setPolicy( ap );
|
||||
System.setSecurityManager( new SecurityManager() );
|
||||
|
||||
File test = new File( "/tmp" );
|
||||
|
||||
assertTrue ( test.canRead() );
|
||||
|
||||
// Policy nulling must occur after Security Manager null
|
||||
System.setSecurityManager( null );
|
||||
Policy.setPolicy( null );
|
||||
}
|
||||
|
||||
public void testRepeatedPolicyReplacement() throws Exception
|
||||
{
|
||||
JettyPolicy ap =
|
||||
new JettyPolicy( Collections.singleton( getWorkingDirectory() + "/src/test/resources/global-all-permission.policy" ), evaluator );
|
||||
|
||||
ap.refresh();
|
||||
|
||||
Policy.setPolicy( ap );
|
||||
|
||||
System.setSecurityManager( new SecurityManager() );
|
||||
|
||||
// Test that the all permission policy allows us to do this
|
||||
try
|
||||
{
|
||||
File test3 = new File( "/tmp/foo/bar/do" );
|
||||
test3.mkdirs();
|
||||
test3.delete();
|
||||
assertTrue( "Under AllPermission we are allowed", true );
|
||||
}
|
||||
catch ( AccessControlException ace )
|
||||
{
|
||||
//ace.printStackTrace();
|
||||
assertFalse( "Exception was thrown which it shouldn't have been", true );
|
||||
}
|
||||
|
||||
JettyPolicy ap2 =
|
||||
new JettyPolicy( Collections.singleton( getWorkingDirectory() + "/src/test/resources/global-file-read-only-tmp-permission.policy" ), evaluator );
|
||||
|
||||
ap2.refresh();
|
||||
|
||||
Policy.setPolicy( ap2 );
|
||||
|
||||
// Test that the new policy does replace the old one and we are now now allowed
|
||||
try
|
||||
{
|
||||
File test3 = new File( "/tmp/foo/bar/do" );
|
||||
test3.mkdirs();
|
||||
assertFalse( "We should be restricted and not get here.", true );
|
||||
}
|
||||
catch ( AccessControlException ace )
|
||||
{
|
||||
//ace.printStackTrace();
|
||||
assertTrue( "Exception was thrown as it should be.", true );
|
||||
}
|
||||
|
||||
System.setSecurityManager( null );
|
||||
Policy.setPolicy( null );
|
||||
}
|
||||
|
||||
|
||||
public void testPolicyRestrictive() throws Exception
|
||||
{
|
||||
|
||||
JettyPolicy ap =
|
||||
new JettyPolicy( Collections.singleton( getWorkingDirectory() + "/src/test/resources/global-file-read-only-tmp-permission.policy" ), evaluator );
|
||||
|
||||
ap.refresh();
|
||||
|
||||
Policy.setPolicy( ap );
|
||||
|
||||
System.setSecurityManager( new SecurityManager() );
|
||||
|
||||
File test = new File( "/tmp" );
|
||||
|
||||
assertTrue ( test.canRead() );
|
||||
|
||||
File test2 = new File( "/tmp/foo" );
|
||||
assertTrue ( test2.canRead() );
|
||||
|
||||
try
|
||||
{
|
||||
File test3 = new File( "/tmp/foo/bar/do" );
|
||||
test3.mkdirs();
|
||||
assertTrue( "we should not get here", false );
|
||||
}
|
||||
catch ( AccessControlException ace )
|
||||
{
|
||||
//ace.printStackTrace();
|
||||
assertTrue( "Exception was thrown", true );
|
||||
}
|
||||
|
||||
System.setSecurityManager( null );
|
||||
Policy.setPolicy( null );
|
||||
}
|
||||
|
||||
private String getWorkingDirectory()
|
||||
{
|
||||
return System.getProperty( "basedir" ); // TODO work in eclipse
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
grant {
|
||||
permission java.security.AllPermission;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
grant {
|
||||
permission java.lang.RuntimePermission "setContextClassLoader";
|
||||
permission java.lang.RuntimePermission "setIO";
|
||||
permission java.lang.RuntimePermission "setSecurityManager";
|
||||
permission java.security.SecurityPermission "getPolicy";
|
||||
|
||||
permission java.io.FilePermission "/tmp", "read,write";
|
||||
permission java.io.FilePermission "/tmp/*", "read,write";
|
||||
permission java.io.FilePermission "/tmp/foo/bar/*", "read";
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
grant codeBase "file:///foo.jar" {
|
||||
permission java.io.FilePermission "/tmp/*", "read,write";
|
||||
}
|
||||
|
||||
grant codeBase "file:///bar.jar" {
|
||||
permission java.io.FilePermission "/tmp/*", "read,write";
|
||||
permission java.io.FilePermission "/usr/*", "read";
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
grant codeBase "file:///foo.jar" {
|
||||
permission java.io.FilePermission "/tmp/*", "read,write";
|
||||
}
|
||||
|
||||
grant codeBase "file:///bar.jar" {
|
||||
permission java.security.AllPermission;
|
||||
}
|
||||
|
||||
grant codeBase "file:///snap.jar" {
|
||||
permission java.io.FilePermission "/tmp/*", "read,write";
|
||||
permission java.io.FilePermission "/usr/*", "read,write";
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
grant codeBase "file:///bar.jar" {
|
||||
permission java.io.FilePermission "/tmp/*", "read";
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
grant codeBase "file:///foo.jar" {
|
||||
permission java.io.FilePermission "/tmp/*", "read,write";
|
||||
}
|
Loading…
Reference in New Issue