From 639d9712bc1d16b35ad64bffe5b0cea5e385ed00 Mon Sep 17 00:00:00 2001 From: Jesse McConnell Date: Tue, 30 Jun 2009 21:23:49 +0000 Subject: [PATCH] [BUG-27751] refactor property evaluator into PolicyContext and add support for resolving special cases ${{self}} and ${{alias:data}} git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@447 7e9141cc-0065-0410-87d8-b60c137991c4 --- .../org/eclipse/jetty/policy/JettyPolicy.java | 2 +- .../eclipse/jetty/policy/PolicyContext.java | 172 ++++++++++++++++-- .../jetty/policy/PropertyEvaluator.java | 10 +- .../jetty/policy/component/GrantNode.java | 25 ++- .../jetty/policy/component/KeystoreNode.java | 2 +- .../policy/component/PermissionNode.java | 10 +- .../jetty/policy/component/PrincipalNode.java | 2 +- .../policy/loader/DefaultPolicyLoader.java | 6 +- .../jetty/policy/TestPolicyContext.java | 102 +++++++++++ .../context/jetty-certificate-alias.policy | 6 + .../context/jetty-certificate.policy | 6 + 11 files changed, 308 insertions(+), 35 deletions(-) create mode 100644 jetty-policy/src/test/java/org/eclipse/jetty/policy/TestPolicyContext.java create mode 100644 jetty-policy/src/test/resources/context/jetty-certificate-alias.policy create mode 100644 jetty-policy/src/test/resources/context/jetty-certificate.policy diff --git a/jetty-policy/src/main/java/org/eclipse/jetty/policy/JettyPolicy.java b/jetty-policy/src/main/java/org/eclipse/jetty/policy/JettyPolicy.java index 2517aaee47a..e54857e080d 100644 --- a/jetty-policy/src/main/java/org/eclipse/jetty/policy/JettyPolicy.java +++ b/jetty-policy/src/main/java/org/eclipse/jetty/policy/JettyPolicy.java @@ -67,7 +67,7 @@ public class JettyPolicy extends Policy public JettyPolicy( Set policies, Map properties ) { _policies = policies; - _context.setEvaluator( new PropertyEvaluator( properties ) ); + _context.setProperties( properties ); // we have the policies we need and an evaluator to reference, lets refresh and save the user a call. refresh(); diff --git a/jetty-policy/src/main/java/org/eclipse/jetty/policy/PolicyContext.java b/jetty-policy/src/main/java/org/eclipse/jetty/policy/PolicyContext.java index 05eab9af794..84c90463b4b 100644 --- a/jetty-policy/src/main/java/org/eclipse/jetty/policy/PolicyContext.java +++ b/jetty-policy/src/main/java/org/eclipse/jetty/policy/PolicyContext.java @@ -1,31 +1,31 @@ package org.eclipse.jetty.policy; import java.security.KeyStore; +import java.security.Principal; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.eclipse.jetty.policy.component.GrantNode; +import org.eclipse.jetty.policy.component.PrincipalNode; public class PolicyContext { - private PropertyEvaluator evaluator; + private Map properties = new HashMap(); + private Principal[] principals; private KeyStore keystore; - - public PolicyContext() + + public void addProperty( String name, String value ) { - + this.properties.put( name, value ); } - public PolicyContext( PropertyEvaluator evaluator ) + public void setProperties( Map properties ) { - this.evaluator = evaluator; - } - - public PropertyEvaluator getEvaluator() - { - return evaluator; - } - - public void setEvaluator( PropertyEvaluator evaluator ) - { - this.evaluator = evaluator; + this.properties = properties; } public KeyStore getKeystore() @@ -33,8 +33,146 @@ public class PolicyContext return keystore; } - public void setKeystore( KeyStore keystores ) + public void setKeystore( KeyStore keystore ) { this.keystore = keystore; } + + public Principal[] getPrincipals() + { + return principals; + } + + public void setPrincipals( Principal[] principals ) + { + this.principals = principals; + } + + public String evaluate(String s) throws PolicyException + { + s = processProtocols( 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 property=getProperty(s.substring(i1+2,i2)); + + s=s.substring(0,i1)+property+s.substring(i2+1); + } + + return s; + } + + private String processProtocols( String s ) throws PolicyException + { + 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 property; + String target = s.substring(i1+3,i2); + + if ( target.indexOf( ":" ) >= 0 ) + { + String[] resolve = target.split( ":" ); + property = resolve(resolve[0], resolve[1] ); + } + else + { + property = resolve( target, null ); + } + s=s.substring(0,i1)+property+s.substring(i2+2); + } + + return s; + } + + + private String getProperty(String name) + { + if (properties.containsKey(name)) + { + return properties.get(name); + } + + return System.getProperty(name); + } + + private String resolve( String protocol, String data ) throws PolicyException + { + + if ( "self".equals( protocol ) ) { //$NON-NLS-1$ + // need expanding to list of principals in grant clause + if ( principals != null && principals.length != 0 ) + { + StringBuilder sb = new StringBuilder(); + for ( int i = 0; i < principals.length; ++i ) + { + sb.append( principals[i].getClass().getName() ); + sb.append( " \"" ); + sb.append( principals[i].getName() ); + sb.append( "\" " ); + } + return sb.toString(); + } + else + { + throw new PolicyException( "self can not be expanded, missing principals" ); + } + } + if ( "alias".equals( protocol ) ) + { + try + { + Certificate cert = keystore.getCertificate(data); + + if ( cert instanceof X509Certificate ) + { + Principal principal = ((X509Certificate) cert).getSubjectX500Principal(); + StringBuilder sb = new StringBuilder(); + sb.append( principal.getClass().getName() ); + sb.append( " \"" ); + sb.append( principal.getName() ); + sb.append( "\" " ); + return sb.toString(); + } + else + { + throw new PolicyException( "alias can not be expanded, bad cert" ); + } + } + catch ( Exception e ) + { + throw new PolicyException( "alias can not be expanded: " + data ); + } + } + throw new PolicyException( "unknown protocol: " + protocol ); + } } diff --git a/jetty-policy/src/main/java/org/eclipse/jetty/policy/PropertyEvaluator.java b/jetty-policy/src/main/java/org/eclipse/jetty/policy/PropertyEvaluator.java index 02e1e660371..9134db8430b 100644 --- a/jetty-policy/src/main/java/org/eclipse/jetty/policy/PropertyEvaluator.java +++ b/jetty-policy/src/main/java/org/eclipse/jetty/policy/PropertyEvaluator.java @@ -15,6 +15,7 @@ package org.eclipse.jetty.policy; import java.io.File; +import java.security.Principal; import java.util.HashMap; import java.util.Map; @@ -44,11 +45,11 @@ public class PropertyEvaluator extends HashMap */ public String getSystemProperty(String name) { - - //System.out.println("Prop: " + name + " " + System.getProperty(name)); - if (containsKey(name)) + { return get(name); + } + return System.getProperty(name); } @@ -95,4 +96,7 @@ public class PropertyEvaluator extends HashMap return s; } + + + } diff --git a/jetty-policy/src/main/java/org/eclipse/jetty/policy/component/GrantNode.java b/jetty-policy/src/main/java/org/eclipse/jetty/policy/component/GrantNode.java index 71e294a9162..7a39a95964f 100644 --- a/jetty-policy/src/main/java/org/eclipse/jetty/policy/component/GrantNode.java +++ b/jetty-policy/src/main/java/org/eclipse/jetty/policy/component/GrantNode.java @@ -63,21 +63,25 @@ public class GrantNode extends AbstractNode public void expand( PolicyContext context ) throws PolicyException { - signerArray = resolveToCertificates( context.getKeystore(), signers ); // TODO alter to support self:: etc - codebase = context.getEvaluator().evaluate( codebase ); + if ( signers != null ) + { + signerArray = resolveToCertificates( context.getKeystore(), signers ); // TODO alter to support self:: etc + } + codebase = context.evaluate( codebase ); if ( principalNodes != null ) { - Set principalSet = new HashSet(); // TODO address this not being accurate ( missing prinicipals in codestore) - for ( Iterator i = principalNodes.iterator(); i.hasNext(); ) - { - PrincipalNode node = i.next(); - node.expand( context ); - principalSet.add( node.toPrincipal( context ) ); - } - principals = principalSet.toArray( new Principal[principalSet.size()] ); + Set principalSet = new HashSet(); + for ( Iterator i = principalNodes.iterator(); i.hasNext(); ) + { + PrincipalNode node = i.next(); + node.expand( context ); + principalSet.add( node.toPrincipal( context ) ); + } + principals = principalSet.toArray( new Principal[principalSet.size()] ); } + context.setPrincipals( principals ); permissions = new Permissions(); for ( Iterator i = permissionNodes.iterator(); i.hasNext(); ) { @@ -85,6 +89,7 @@ public class GrantNode extends AbstractNode node.expand( context ); permissions.add( node.toPermission() ); } + context.setPrincipals( null ); setExpanded( true ); } diff --git a/jetty-policy/src/main/java/org/eclipse/jetty/policy/component/KeystoreNode.java b/jetty-policy/src/main/java/org/eclipse/jetty/policy/component/KeystoreNode.java index 6a841cd778b..1ea381fab05 100644 --- a/jetty-policy/src/main/java/org/eclipse/jetty/policy/component/KeystoreNode.java +++ b/jetty-policy/src/main/java/org/eclipse/jetty/policy/component/KeystoreNode.java @@ -48,7 +48,7 @@ public class KeystoreNode extends AbstractNode public void expand( PolicyContext context ) throws PolicyException { - url = context.getEvaluator().evaluate( url ); + url = context.evaluate( url ); setExpanded( true ); } diff --git a/jetty-policy/src/main/java/org/eclipse/jetty/policy/component/PermissionNode.java b/jetty-policy/src/main/java/org/eclipse/jetty/policy/component/PermissionNode.java index b0912ae5b9e..1a306105701 100644 --- a/jetty-policy/src/main/java/org/eclipse/jetty/policy/component/PermissionNode.java +++ b/jetty-policy/src/main/java/org/eclipse/jetty/policy/component/PermissionNode.java @@ -75,7 +75,15 @@ public class PermissionNode extends AbstractNode public void expand( PolicyContext context ) throws PolicyException { - name = context.getEvaluator().evaluate( name ); + if ( name != null ) + { + name = context.evaluate( name ).trim(); + } + + if ( actions != null ) + { + actions = context.evaluate( actions ).trim(); + } if ( signers != null ) { diff --git a/jetty-policy/src/main/java/org/eclipse/jetty/policy/component/PrincipalNode.java b/jetty-policy/src/main/java/org/eclipse/jetty/policy/component/PrincipalNode.java index 1f07fcb58b7..33647842529 100644 --- a/jetty-policy/src/main/java/org/eclipse/jetty/policy/component/PrincipalNode.java +++ b/jetty-policy/src/main/java/org/eclipse/jetty/policy/component/PrincipalNode.java @@ -67,7 +67,7 @@ public class PrincipalNode extends AbstractNode public void expand( PolicyContext context ) throws PolicyException { - name = context.getEvaluator().evaluate( name ); + name = context.evaluate( name ); setExpanded(true); } diff --git a/jetty-policy/src/main/java/org/eclipse/jetty/policy/loader/DefaultPolicyLoader.java b/jetty-policy/src/main/java/org/eclipse/jetty/policy/loader/DefaultPolicyLoader.java index 837c2c0ab4a..74325da1a5d 100644 --- a/jetty-policy/src/main/java/org/eclipse/jetty/policy/loader/DefaultPolicyLoader.java +++ b/jetty-policy/src/main/java/org/eclipse/jetty/policy/loader/DefaultPolicyLoader.java @@ -72,7 +72,6 @@ public class DefaultPolicyLoader for ( Iterator i = grantEntries.iterator(); i.hasNext(); ) { GrantNode grant = i.next(); - grant.expand( context ); PolicyEntry policy = new PolicyEntry(); @@ -92,3 +91,8 @@ public class DefaultPolicyLoader } } } + + + + + diff --git a/jetty-policy/src/test/java/org/eclipse/jetty/policy/TestPolicyContext.java b/jetty-policy/src/test/java/org/eclipse/jetty/policy/TestPolicyContext.java new file mode 100644 index 00000000000..4c2499ac7a3 --- /dev/null +++ b/jetty-policy/src/test/java/org/eclipse/jetty/policy/TestPolicyContext.java @@ -0,0 +1,102 @@ +package org.eclipse.jetty.policy; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.security.Permission; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jetty.policy.component.GrantNode; +import org.eclipse.jetty.policy.component.KeystoreNode; +import org.eclipse.jetty.policy.loader.PolicyFileScanner; + +import junit.framework.TestCase; + +public class TestPolicyContext + extends TestCase +{ + public static final String __PRINCIPAL = "javax.security.auth.x500.X500Principal \"CN=Jetty Policy,OU=Artifact,O=Jetty Project,L=Earth,ST=Internet,C=US\""; + + + + + @Override + protected void setUp() + throws Exception + { + + System.setProperty( "basedir", getWorkingDirectory() ); + + super.setUp(); + } + + public void testSelfPropertyExpansion() throws Exception + { + + PolicyContext context = new PolicyContext(); + PolicyFileScanner loader = new PolicyFileScanner(); + List grantEntries = new ArrayList(); + List keystoreEntries = new ArrayList(); + + File policyFile = new File( getWorkingDirectory() + "/src/test/resources/context/jetty-certificate.policy" ); + + loader.scanStream( new InputStreamReader( new FileInputStream( policyFile ) ), grantEntries, keystoreEntries ); + + for ( Iterator i = keystoreEntries.iterator(); i.hasNext();) + { + KeystoreNode node = i.next(); + node.expand( context ); + + context.setKeystore( node.toKeyStore() ); + } + + GrantNode grant = grantEntries.get( 0 ); + grant.expand( context ); + + Permission perm = grant.getPermissions().elements().nextElement(); + + assertEquals( __PRINCIPAL, perm.getName() ); + } + + public void testAliasPropertyExpansion() throws Exception + { + + PolicyContext context = new PolicyContext(); + PolicyFileScanner loader = new PolicyFileScanner(); + List grantEntries = new ArrayList(); + List keystoreEntries = new ArrayList(); + + File policyFile = new File( getWorkingDirectory() + "/src/test/resources/context/jetty-certificate-alias.policy" ); + + loader.scanStream( new InputStreamReader( new FileInputStream( policyFile ) ), grantEntries, keystoreEntries ); + + for ( Iterator i = keystoreEntries.iterator(); i.hasNext();) + { + KeystoreNode node = i.next(); + node.expand( context ); + + context.setKeystore( node.toKeyStore() ); + } + + GrantNode grant = grantEntries.get( 0 ); + grant.expand( context ); + + Permission perm = grant.getPermissions().elements().nextElement(); + + assertEquals( __PRINCIPAL, perm.getName() ); + } + + private String getWorkingDirectory() + { + String cwd = System.getProperty( "basedir" ); + + if ( cwd == null ) + { + cwd = System.getProperty( "user.dir" ); + } + return cwd; + } + +} diff --git a/jetty-policy/src/test/resources/context/jetty-certificate-alias.policy b/jetty-policy/src/test/resources/context/jetty-certificate-alias.policy new file mode 100644 index 00000000000..d8f4ded62f5 --- /dev/null +++ b/jetty-policy/src/test/resources/context/jetty-certificate-alias.policy @@ -0,0 +1,6 @@ +keystore "file://${basedir}/target/test-policy/jetty-policy.keystore", "jks"; + +grant signedBy "jetty-policy-bad", codeBase "file://${basedir}/target/test-policy/jetty-test-policy-1.0-SNAPSHOT.jar" +{ + permission java.util.PropertyPermission "${{alias:jetty-policy}}", "read"; +}; diff --git a/jetty-policy/src/test/resources/context/jetty-certificate.policy b/jetty-policy/src/test/resources/context/jetty-certificate.policy new file mode 100644 index 00000000000..87bf7917e3a --- /dev/null +++ b/jetty-policy/src/test/resources/context/jetty-certificate.policy @@ -0,0 +1,6 @@ +keystore "file://${basedir}/target/test-policy/jetty-policy.keystore", "jks"; + +grant principal "jetty-policy" +{ + permission java.util.PropertyPermission "${{self}}", "read"; +};