[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
This commit is contained in:
parent
d0e514f192
commit
639d9712bc
|
@ -67,7 +67,7 @@ public class JettyPolicy extends Policy
|
|||
public JettyPolicy( Set<String> policies, Map<String,String> 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();
|
||||
|
|
|
@ -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<String, String> properties = new HashMap<String, String>();
|
||||
|
||||
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<String,String> 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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<String,String>
|
|||
*/
|
||||
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<String,String>
|
|||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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<Principal> principalSet = new HashSet<Principal>(); // TODO address this not being accurate ( missing prinicipals in codestore)
|
||||
for ( Iterator<PrincipalNode> 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<Principal> principalSet = new HashSet<Principal>();
|
||||
for ( Iterator<PrincipalNode> 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<PermissionNode> 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 );
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -72,7 +72,6 @@ public class DefaultPolicyLoader
|
|||
for ( Iterator<GrantNode> i = grantEntries.iterator(); i.hasNext(); )
|
||||
{
|
||||
GrantNode grant = i.next();
|
||||
|
||||
grant.expand( context );
|
||||
|
||||
PolicyEntry policy = new PolicyEntry();
|
||||
|
@ -92,3 +91,8 @@ public class DefaultPolicyLoader
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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<GrantNode> grantEntries = new ArrayList<GrantNode>();
|
||||
List<KeystoreNode> keystoreEntries = new ArrayList<KeystoreNode>();
|
||||
|
||||
File policyFile = new File( getWorkingDirectory() + "/src/test/resources/context/jetty-certificate.policy" );
|
||||
|
||||
loader.scanStream( new InputStreamReader( new FileInputStream( policyFile ) ), grantEntries, keystoreEntries );
|
||||
|
||||
for ( Iterator<KeystoreNode> 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<GrantNode> grantEntries = new ArrayList<GrantNode>();
|
||||
List<KeystoreNode> keystoreEntries = new ArrayList<KeystoreNode>();
|
||||
|
||||
File policyFile = new File( getWorkingDirectory() + "/src/test/resources/context/jetty-certificate-alias.policy" );
|
||||
|
||||
loader.scanStream( new InputStreamReader( new FileInputStream( policyFile ) ), grantEntries, keystoreEntries );
|
||||
|
||||
for ( Iterator<KeystoreNode> 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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";
|
||||
};
|
|
@ -0,0 +1,6 @@
|
|||
keystore "file://${basedir}/target/test-policy/jetty-policy.keystore", "jks";
|
||||
|
||||
grant principal "jetty-policy"
|
||||
{
|
||||
permission java.util.PropertyPermission "${{self}}", "read";
|
||||
};
|
Loading…
Reference in New Issue