FileDocCategorySizeDatePackage
DefaultPolicyParser.javaAPI DocAndroid 1.5 API21219Wed May 06 22:41:06 BST 2009org.apache.harmony.security.fortress

DefaultPolicyParser

public class DefaultPolicyParser extends Object
This is a basic loader of policy files. It delegates lexical analysis to a pluggable scanner and converts received tokens to a set of {@link org.apache.harmony.security.PolicyEntry PolicyEntries}. For details of policy format, see the {@link org.apache.harmony.security.fortress.DefaultPolicy default policy description}.
For ordinary uses, this class has just one public method parse(), which performs the main task. Extensions of this parser may redefine specific operations separately, by overriding corresponding protected methods.
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).
see
org.apache.harmony.security.fortress.DefaultPolicy
see
org.apache.harmony.security.DefaultPolicyScanner
see
org.apache.harmony.security.PolicyEntry

Fields Summary
private final org.apache.harmony.security.DefaultPolicyScanner
scanner
Constructors Summary
public DefaultPolicyParser()
Default constructor, {@link org.apache.harmony.security.DefaultPolicyScanner DefaultPolicyScanner} is used.

        scanner = new DefaultPolicyScanner();
    
public DefaultPolicyParser(org.apache.harmony.security.DefaultPolicyScanner s)
Extension constructor for plugging-in custom scanner.

        this.scanner = s;
    
Methods Summary
protected java.security.PrincipalgetPrincipalByAlias(java.security.KeyStore ks, java.lang.String alias)
Returns a subject's X500Principal of an X509Certificate, which is associated with the specified keystore alias.

param
ks KeyStore for resolving Certificate, may be null
param
alias alias to a certificate
return
X500Principal with a subject distinguished name
throws
KeyStoreException if KeyStore is null or if it failed to provide a certificate
throws
CertificateException if found certificate is not an X509Certificate


        if (ks == null) {
            throw new KeyStoreException(
                    Messages.getString("security.147", alias)); //$NON-NLS-1$
        }
        //XXX cache found certs ??
        Certificate x509 = ks.getCertificate(alias);
        if (x509 instanceof X509Certificate) {
            return ((X509Certificate) x509).getSubjectX500Principal();
        } else {
            throw new CertificateException(Messages.getString("security.148", //$NON-NLS-1$
                    alias, x509));
        }
    
protected java.security.KeyStoreinitKeyStore(java.util.List keystores, java.net.URL base, java.util.Properties system, boolean resolve)
Returns the first successfully loaded KeyStore, from the specified list of possible locations. This method iterates over the list of KeystoreEntries; for each entry expands url and type, tries to construct instances of specified URL and KeyStore and to load the keystore. If it is loaded, returns the keystore, otherwise proceeds to the next KeystoreEntry.
Note: an url may be relative to the policy file location or absolute.

param
keystores list of available KeystoreEntries
param
base the policy file location
param
system system properties, used for property expansion
param
resolve flag enabling/disabling property expansion
return
the first successfully loaded KeyStore or null


        for (int i = 0; i < keystores.size(); i++) {
            try {
                DefaultPolicyScanner.KeystoreEntry ke = keystores
                        .get(i);
                if (resolve) {
                    ke.url = PolicyUtils.expandURL(ke.url, system);
                    if (ke.type != null) {
                        ke.type = PolicyUtils.expand(ke.type, system);
                    }
                }
                if (ke.type == null || ke.type.length() == 0) {
                    ke.type = KeyStore.getDefaultType();
                }
                KeyStore ks = KeyStore.getInstance(ke.type);
                URL location = new URL(base, ke.url);
                InputStream is = AccessController
                        .doPrivileged(new PolicyUtils.URLLoader(location));
                try {
                    ks.load(is, null);
                }
                finally {
                    is.close();
                }
                return ks;
            }
            catch (Exception e) {
                // TODO: log warning
            }
        }
        return null;
    
public java.util.Collectionparse(java.net.URL location, java.util.Properties system)
This is the main business method. It manages loading process as follows: the associated scanner is used to parse the stream to a set of {@link org.apache.harmony.security.DefaultPolicyScanner.GrantEntry composite tokens}, then this set is iterated and each token is translated to a PolicyEntry. Semantically invalid tokens are ignored, the same as void PolicyEntries.
A policy file may refer to some KeyStore(s), and in this case the first valid reference is initialized and used in processing tokens.

param
location an URL of a policy file to be loaded
param
system system properties, used for property expansion
return
a collection of PolicyEntry objects, may be empty
throws
Exception IO error while reading location or file syntax error


        boolean resolve = PolicyUtils.canExpandProperties();
        // BEGIN android-modified
        Reader r =
            new BufferedReader(
                    new InputStreamReader(
                            AccessController.doPrivileged(
                                    new PolicyUtils.URLLoader(location))),
                    8192);
        // END android-modified

        Collection<GrantEntry> grantEntries = new HashSet<GrantEntry>();
        List<KeystoreEntry> keystores = new ArrayList<KeystoreEntry>();

        try {
            scanner.scanStream(r, grantEntries, keystores);
        }
        finally {
            r.close();
        }

        //XXX KeyStore could be loaded lazily...
        KeyStore ks = initKeyStore(keystores, location, system, resolve);

        Collection<PolicyEntry> result = new HashSet<PolicyEntry>();
        for (Iterator<GrantEntry> iter = grantEntries.iterator(); iter.hasNext();) {
            DefaultPolicyScanner.GrantEntry ge = iter
                    .next();
            try {
                PolicyEntry pe = resolveGrant(ge, ks, system, resolve);
                if (!pe.isVoid()) {
                    result.add(pe);
                }
            }
            catch (Exception e) {
                // TODO: log warning
            }
        }

        return result;
    
protected org.apache.harmony.security.PolicyEntryresolveGrant(org.apache.harmony.security.DefaultPolicyScanner.GrantEntry ge, java.security.KeyStore ks, java.util.Properties system, boolean resolve)
Translates GrantEntry token to PolicyEntry object. It goes step by step, trying to resolve each component of the GrantEntry:
  • If codebase is specified, expand it and construct an URL.
  • If signers is specified, expand it and obtain corresponding Certificates.
  • If principals collection is specified, iterate over it. For each PrincipalEntry, expand name and if no class specified, resolve actual X500Principal from a KeyStore certificate; otherwise keep it as UnresolvedPrincipal.
  • Iterate over permissions collection. For each PermissionEntry, try to resolve (see method {@link #resolvePermission(DefaultPolicyScanner.PermissionEntry, DefaultPolicyScanner.GrantEntry, KeyStore, Properties, boolean) resolvePermission()}) a corresponding permission. If resolution failed, ignore the PermissionEntry.
In fact, property expansion in the steps above is conditional and is ruled by the parameter resolve.
Finally a new PolicyEntry is created, which associates the trinity of resolved URL, Certificates and Principals to a set of granted Permissions.

param
ge GrantEntry token to be resolved
param
ks KeyStore for resolving Certificates, may be null
param
system system properties, used for property expansion
param
resolve flag enabling/disabling property expansion
return
resolved PolicyEntry
throws
Exception if unable to resolve codebase, signers or principals of the GrantEntry
see
DefaultPolicyScanner.PrincipalEntry
see
DefaultPolicyScanner.PermissionEntry
see
org.apache.harmony.security.fortress.PolicyUtils


        URL codebase = null;
        Certificate[] signers = null;
        Set<Principal>principals = new HashSet<Principal>();
        Set<Permission>permissions = new HashSet<Permission>();
        if (ge.codebase != null) {
            codebase = new URL(resolve ? PolicyUtils.expandURL(ge.codebase,
                    system) : ge.codebase);
            //Fix HARMONY-1963
            if ("file".equals(codebase.getProtocol())) { //$NON-NLS-1$
                File codeFile = new File(codebase.getFile());
                if (codeFile.isAbsolute()) {
                    codebase = new URL("file://" +  //$NON-NLS-1$
                            codeFile.getAbsolutePath());                    
                }
            }
        }
        if (ge.signers != null) {
            if (resolve) {
                ge.signers = PolicyUtils.expand(ge.signers, system);
            }
            signers = resolveSigners(ks, ge.signers);
        }
        if (ge.principals != null) {
            for (Iterator<PrincipalEntry> iter = ge.principals.iterator(); iter.hasNext();) {
                DefaultPolicyScanner.PrincipalEntry pe = iter
                        .next();
                if (resolve) {
                    pe.name = PolicyUtils.expand(pe.name, system);
                }
                if (pe.klass == null) {
                    principals.add(getPrincipalByAlias(ks, pe.name));
                } else {
                    principals.add(new UnresolvedPrincipal(pe.klass, pe.name));
                }
            }
        }
        if (ge.permissions != null) {
            for (Iterator<PermissionEntry> iter = ge.permissions.iterator(); iter.hasNext();) {
                DefaultPolicyScanner.PermissionEntry pe = iter
                        .next();
                try {
                    permissions.add(resolvePermission(pe, ge, ks, system,
                            resolve));
                }
                catch (Exception e) {
                    // TODO: log warning
                }
            }
        }
        return new PolicyEntry(new CodeSource(codebase, signers), principals,
                permissions);
    
protected java.security.PermissionresolvePermission(org.apache.harmony.security.DefaultPolicyScanner.PermissionEntry pe, org.apache.harmony.security.DefaultPolicyScanner.GrantEntry ge, java.security.KeyStore ks, java.util.Properties system, boolean resolve)
Translates PermissionEntry token to Permission object. First, it performs general expansion for non-null name and properties expansion for non-null name, action and signers. Then, it obtains signing Certificates(if any), tries to find a class specified by klass name and instantiate a corresponding permission object. If class is not found or it is signed improperly, returns UnresolvedPermission.

param
pe PermissionEntry token to be resolved
param
ge parental GrantEntry of the PermissionEntry
param
ks KeyStore for resolving Certificates, may be null
param
system system properties, used for property expansion
param
resolve flag enabling/disabling property expansion
return
resolved Permission object, either of concrete class or UnresolvedPermission
throws
Exception if failed to expand properties, or to get a Certificate, or to create an instance of a successfully found class

        if (pe.name != null) {
            pe.name = PolicyUtils.expandGeneral(pe.name,
                    new PermissionExpander().configure(ge, ks));
        }
        if (resolve) {
            if (pe.name != null) {
                pe.name = PolicyUtils.expand(pe.name, system);
            }
            if (pe.actions != null) {
                pe.actions = PolicyUtils.expand(pe.actions, system);
            }
            if (pe.signers != null) {
                pe.signers = PolicyUtils.expand(pe.signers, system);
            }
        }
        Certificate[] signers = (pe.signers == null) ? null : resolveSigners(
                ks, pe.signers);
        try {
            Class<?> klass = Class.forName(pe.klass);
            if (PolicyUtils.matchSubset(signers, klass.getSigners())) {
                return PolicyUtils.instantiatePermission(klass, pe.name,
                        pe.actions);
            }
        }
        catch (ClassNotFoundException cnfe) {}
        //maybe properly signed class will be loaded later
        return new UnresolvedPermission(pe.klass, pe.name, pe.actions, signers);
    
protected java.security.cert.Certificate[]resolveSigners(java.security.KeyStore ks, java.lang.String signers)
Takes a comma-separated list of aliases and obtains corresponding certificates.

param
ks KeyStore for resolving Certificates, may be null
param
signers comma-separated list of certificate aliases, must be not null
return
an array of signing Certificates
throws
Exception if KeyStore is null or if it failed to provide a certificate

        if (ks == null) {
            throw new KeyStoreException(Messages.getString("security.146", //$NON-NLS-1$
                    signers));
        }

        Collection<Certificate> certs = new HashSet<Certificate>();
        StringTokenizer snt = new StringTokenizer(signers, ","); //$NON-NLS-1$
        while (snt.hasMoreTokens()) {
            //XXX cache found certs ??
            certs.add(ks.getCertificate(snt.nextToken().trim()));
        }
        return certs.toArray(new Certificate[certs.size()]);