You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@river.apache.org by pe...@apache.org on 2010/03/28 14:57:05 UTC
svn commit: r928394 [4/6] - in /incubator/river/jtsk/trunk: ./ qa/
qa/harness/policy/ qa/jtreg/net/jini/jeri/kerberos/UnitTests/
qa/jtreg/net/jini/jeri/transport/multihomed/ qa/jtreg/unittestlib/
qa/src/com/sun/jini/qa/harness/ qa/src/com/sun/jini/qa/r...
Added: incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/DefaultPolicyParser.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/DefaultPolicyParser.java?rev=928394&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/DefaultPolicyParser.java (added)
+++ incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/DefaultPolicyParser.java Sun Mar 28 12:57:03 2010
@@ -0,0 +1,478 @@
+/*
+ * 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.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @version $Revision$
+*/
+
+package org.apache.river.security.policy.util;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.URL;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.security.AccessController;
+import java.security.CodeSource;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.Permission;
+import java.security.Principal;
+import java.security.UnresolvedPermission;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import org.apache.river.security.policy.util.DefaultPolicyScanner.GrantEntry;
+import org.apache.river.security.policy.util.DefaultPolicyScanner.KeystoreEntry;
+import org.apache.river.security.policy.util.DefaultPolicyScanner.PermissionEntry;
+import org.apache.river.security.policy.util.DefaultPolicyScanner.PrincipalEntry;
+
+
+/**
+ * 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.DefaultPolicy default policy description}.
+ * <br>
+ * For ordinary uses, this class has just one public method <code>parse()</code>,
+ * which performs the main task.
+ * Extensions of this parser may redefine specific operations separately,
+ * by overriding corresponding protected methods.
+ * <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).
+ *
+ * @see org.apache.harmony.security.DefaultPolicy
+ * @see org.apache.harmony.security.DefaultPolicyScanner
+ * @see org.apache.harmony.security.PolicyEntry
+ */
+public class DefaultPolicyParser implements PolicyParser {
+
+ // Pluggable scanner for a specific file format
+ private final DefaultPolicyScanner scanner;
+
+ /**
+ * Default constructor,
+ * {@link org.apache.harmony.security.DefaultPolicyScanner DefaultPolicyScanner}
+ * is used.
+ */
+ public DefaultPolicyParser() {
+ scanner = new DefaultPolicyScanner();
+ }
+
+ /**
+ * Extension constructor for plugging-in custom scanner.
+ */
+ public DefaultPolicyParser(DefaultPolicyScanner s) {
+ this.scanner = s;
+ }
+
+ /**
+ * 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.
+ * <br>
+ * 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
+ */
+ public Collection<PolicyEntry> parse(URL location, Properties system)
+ throws Exception {
+ boolean resolve = PolicyUtils.canExpandProperties();
+ Reader r = new BufferedReader(new InputStreamReader(
+ AccessController
+ .doPrivileged(new PolicyUtils.URLLoader(location))));
+
+ Collection<GrantEntry> grantEntries = new HashSet<GrantEntry>();
+ List<KeystoreEntry> keystores = new ArrayList<KeystoreEntry>();
+
+ try {
+ scanner.scanStream(r, grantEntries, keystores); // modifies 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;
+ }
+
+ /**
+ * Translates GrantEntry token to PolicyEntry object. It goes step by step,
+ * trying to resolve each component of the GrantEntry:
+ * <ul>
+ * <li> If <code>codebase</code> is specified, expand it and construct an URL.
+ * <li> If <code>signers</code> is specified, expand it and obtain
+ * corresponding Certificates.
+ * <li> If <code>principals</code> 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.
+ * <li> Iterate over <code>permissions</code> 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.
+ * </ul>
+ * In fact, property expansion in the steps above is conditional and is ruled by
+ * the parameter <i>resolve</i>.
+ * <br>
+ * 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 <code>null</code>
+ * @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.PolicyUtils
+ */
+ protected PolicyEntry resolveGrant(DefaultPolicyScanner.GrantEntry ge,
+ KeyStore ks, Properties system, boolean resolve) throws Exception {
+
+ 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);
+ }
+ 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);
+ }
+
+ /**
+ * Translates PermissionEntry token to Permission object.
+ * First, it performs general expansion for non-null <code>name</code> and
+ * properties expansion for non-null <code>name</code>, <code>action</code>
+ * and <code>signers</code>.
+ * Then, it obtains signing Certificates(if any), tries to find a class specified by
+ * <code>klass</code> 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 <code>null</code>
+ * @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
+ */
+ protected Permission resolvePermission(
+ DefaultPolicyScanner.PermissionEntry pe,
+ DefaultPolicyScanner.GrantEntry ge, KeyStore ks, Properties system,
+ boolean resolve) throws Exception {
+ 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);
+ }
+
+ /**
+ * Specific handler for expanding <i>self</i> and <i>alias</i> protocols.
+ */
+ class PermissionExpander implements PolicyUtils.GeneralExpansionHandler {
+
+ // Store KeyStore
+ private KeyStore ks;
+
+ // Store GrantEntry
+ private DefaultPolicyScanner.GrantEntry ge;
+
+ /**
+ * Combined setter of all required fields.
+ */
+ public PermissionExpander configure(DefaultPolicyScanner.GrantEntry ge,
+ KeyStore ks) {
+ this.ge = ge;
+ this.ks = ks;
+ return this;
+ }
+
+ /**
+ * Resolves the following protocols:
+ * <dl>
+ * <dt>self
+ * <dd>Denotes substitution to a principal information of the parental
+ * GrantEntry. Returns a space-separated list of resolved Principals
+ * (including wildcarded), formatting each as <b>class "name"</b>.
+ * If parental GrantEntry has no Principals, throws ExpansionFailedException.
+ * <dt>alias:<i>name</i>
+ * <dd>Denotes substitution of a KeyStore alias. Namely, if a KeyStore has
+ * an X.509 certificate associated with the specified name, then returns
+ * <b>javax.security.auth.x500.X500Principal "<i>DN</i>"</b> string,
+ * where <i>DN</i> is a certificate's subject distinguished name.
+ * </dl>
+ * @throws ExpansionFailedException - if protocol is other than
+ * <i>self</i> or <i>alias</i>, or if data resolution failed
+ */
+ public String resolve(String protocol, String data)
+ throws PolicyUtils.ExpansionFailedException {
+
+ if ("self".equals(protocol)) { //$NON-NLS-1$
+ //need expanding to list of principals in grant clause
+ if (ge.principals != null && ge.principals.size() != 0) {
+ StringBuilder sb = new StringBuilder();
+ for (Iterator<PrincipalEntry> iter = ge.principals.iterator(); iter
+ .hasNext();) {
+ DefaultPolicyScanner.PrincipalEntry pr = iter
+ .next();
+ if (pr.klass == null) {
+ // aliased X500Principal
+ try {
+ sb.append(pc2str(getPrincipalByAlias(ks,
+ pr.name)));
+ }
+ catch (Exception e) {
+ throw new PolicyUtils.ExpansionFailedException(
+ Messages.getString("security.143", pr.name), e); //$NON-NLS-1$
+ }
+ } else {
+ sb.append(pr.klass).append(" \"").append(pr.name) //$NON-NLS-1$
+ .append("\" "); //$NON-NLS-1$
+ }
+ }
+ return sb.toString();
+ } else {
+ throw new PolicyUtils.ExpansionFailedException(
+ Messages.getString("security.144")); //$NON-NLS-1$
+ }
+ }
+ if ("alias".equals(protocol)) { //$NON-NLS-1$
+ try {
+ return pc2str(getPrincipalByAlias(ks, data));
+ }
+ catch (Exception e) {
+ throw new PolicyUtils.ExpansionFailedException(
+ Messages.getString("security.143", data), e); //$NON-NLS-1$
+ }
+ }
+ throw new PolicyUtils.ExpansionFailedException(
+ Messages.getString("security.145", protocol)); //$NON-NLS-1$
+ }
+
+ // Formats a string describing the passed Principal.
+ private String pc2str(Principal pc) {
+ String klass = pc.getClass().getName();
+ String name = pc.getName();
+ StringBuilder sb = new StringBuilder(klass.length() + name.length()
+ + 5);
+ return sb.append(klass).append(" \"").append(name).append("\"") //$NON-NLS-1$ //$NON-NLS-2$
+ .toString();
+ }
+ }
+
+ /**
+ * Takes a comma-separated list of aliases and obtains corresponding
+ * certificates.
+ * @param ks KeyStore for resolving Certificates, may be <code>null</code>
+ * @param signers comma-separated list of certificate aliases,
+ * must be not <code>null</code>
+ * @return an array of signing Certificates
+ * @throws Exception if KeyStore is <code>null</code>
+ * or if it failed to provide a certificate
+ */
+ protected Certificate[] resolveSigners(KeyStore ks, String signers)
+ throws Exception {
+ 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()]);
+ }
+
+ /**
+ * Returns a subject's X500Principal of an X509Certificate,
+ * which is associated with the specified keystore alias.
+ * @param ks KeyStore for resolving Certificate, may be <code>null</code>
+ * @param alias alias to a certificate
+ * @return X500Principal with a subject distinguished name
+ * @throws KeyStoreException if KeyStore is <code>null</code>
+ * or if it failed to provide a certificate
+ * @throws CertificateException if found certificate is not
+ * an X509Certificate
+ */
+ protected Principal getPrincipalByAlias(KeyStore ks, String alias)
+ throws KeyStoreException, CertificateException {
+
+ 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));
+ }
+ }
+
+ /**
+ * 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 <code>url</code> and <code>type</code>,
+ * 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.
+ * <br>
+ * <b>Note:</b> 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 <code>null</code>
+ */
+ protected KeyStore initKeyStore(List<KeystoreEntry>keystores,
+ URL base, Properties system, boolean resolve) {
+
+ 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;
+ }
+}
Propchange: incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/DefaultPolicyParser.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/DefaultPolicyScanner.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/DefaultPolicyScanner.java?rev=928394&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/DefaultPolicyScanner.java (added)
+++ incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/DefaultPolicyScanner.java Sun Mar 28 12:57:03 2010
@@ -0,0 +1,519 @@
+/*
+ * 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.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @version $Revision$
+*/
+
+package org.apache.river.security.policy.util;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StreamTokenizer;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+
+
+/**
+ * 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).
+ *
+ * @see org.apache.harmony.security.fortress.DefaultPolicyParser
+ */
+public class DefaultPolicyScanner {
+
+ /**
+ * 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, Messages.getString("security.89")); //$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, Messages.getString("security.8A")); //$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, Messages.getString("security.8B")); //$NON-NLS-1$
+ }
+ } else if (Util.equalsIgnoreCase("codebase", st.sval)) { //$NON-NLS-1$
+ if (st.nextToken() == '"') {
+ ge.codebase = st.sval;
+ } else {
+ handleUnexpectedToken(st, Messages.getString("security.8C")); //$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, Messages.getString("security.8D")); //$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, Messages.getString("security.8E")); //$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(Messages.getString("security.8F", //$NON-NLS-1$
+ 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(Messages.getString("security.90", //$NON-NLS-1$
+ composeStatus(st)));
+ }
+
+ /**
+ * 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;
+ }
+}
Propchange: incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/DefaultPolicyScanner.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/Messages.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/Messages.java?rev=928394&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/Messages.java (added)
+++ incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/Messages.java Sun Mar 28 12:57:03 2010
@@ -0,0 +1,250 @@
+/*
+ * 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.
+ */
+
+/*
+ * THE FILE HAS BEEN AUTOGENERATED BY MSGTOOL TOOL.
+ * All changes made to this file manually will be overwritten
+ * if this tool runs again. Better make changes in the template file.
+ */
+
+package org.apache.river.security.policy.util;
+
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+
+
+/**
+ * This class retrieves strings from a resource bundle and returns them,
+ * formatting them with MessageFormat when required.
+ * <p>
+ * It is used by the system classes to provide national language support, by
+ * looking up messages in the <code>
+ * org.apache.harmony.security.internal.nls.messages
+ * </code>
+ * resource bundle. Note that if this file is not available, or an invalid key
+ * is looked up, or resource bundle support is not available, the key itself
+ * will be returned as the associated message. This means that the <em>KEY</em>
+ * should a reasonable human-readable (english) string.
+ *
+ */
+public class Messages {
+
+ // ResourceBundle holding the system messages.
+ static private ResourceBundle bundle = null;
+
+ /**
+ * Retrieves a message which has no arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg) {
+ if (bundle == null) {
+ return msg;
+ }
+ try {
+ return bundle.getString(msg);
+ } catch (MissingResourceException e) {
+ return "Missing message: " + msg; //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Retrieves a message which takes 1 argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * Object the object to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object arg) {
+ return getString(msg, new Object[] { arg });
+ }
+
+ /**
+ * Retrieves a message which takes 1 integer argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * int the integer to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, int arg) {
+ return getString(msg, new Object[] { Integer.toString(arg) });
+ }
+
+ /**
+ * Retrieves a message which takes 1 character argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * char the character to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, char arg) {
+ return getString(msg, new Object[] { String.valueOf(arg) });
+ }
+
+ /**
+ * Retrieves a message which takes 2 arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg1
+ * Object an object to insert in the formatted output.
+ * @param arg2
+ * Object another object to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object arg1, Object arg2) {
+ return getString(msg, new Object[] { arg1, arg2 });
+ }
+
+ /**
+ * Retrieves a message which takes several arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param args
+ * Object[] the objects to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object[] args) {
+ String format = msg;
+
+ if (bundle != null) {
+ try {
+ format = bundle.getString(msg);
+ } catch (MissingResourceException e) {
+ }
+ }
+
+ return format(format, args);
+ }
+
+ /**
+ * Generates a formatted text string given a source string containing
+ * "argument markers" of the form "{argNum}" where each argNum must be in
+ * the range 0..9. The result is generated by inserting the toString of each
+ * argument into the position indicated in the string.
+ * <p>
+ * To insert the "{" character into the output, use a single backslash
+ * character to escape it (i.e. "\{"). The "}" character does not need to be
+ * escaped.
+ *
+ * @param format
+ * String the format to use when printing.
+ * @param args
+ * Object[] the arguments to use.
+ * @return String the formatted message.
+ */
+ public static String format(String format, Object[] args) {
+ StringBuilder answer = new StringBuilder(format.length()
+ + (args.length * 20));
+ String[] argStrings = new String[args.length];
+ for (int i = 0; i < args.length; ++i) {
+ if (args[i] == null) {
+ argStrings[i] = "<null>";
+ } //$NON-NLS-1$
+ else {
+ argStrings[i] = args[i].toString();
+ }
+ }
+ int lastI = 0;
+ for (int i = format.indexOf('{', 0); i >= 0; i = format.indexOf('{',
+ lastI)) {
+ if (i != 0 && format.charAt(i - 1) == '\\') {
+ // It's escaped, just print and loop.
+ if (i != 1) {
+ answer.append(format.substring(lastI, i - 1));
+ }
+ answer.append('{');
+ lastI = i + 1;
+ } else {
+ // It's a format character.
+ if (i > format.length() - 3) {
+ // Bad format, just print and loop.
+ answer.append(format.substring(lastI, format.length()));
+ lastI = format.length();
+ } else {
+ int argnum = (byte) Character.digit(format.charAt(i + 1),
+ 10);
+ if (argnum < 0 || format.charAt(i + 2) != '}') {
+ // Bad format, just print and loop.
+ answer.append(format.substring(lastI, i + 1));
+ lastI = i + 1;
+ } else {
+ // Got a good one!
+ answer.append(format.substring(lastI, i));
+ if (argnum >= argStrings.length) {
+ answer.append("<missing argument>");
+ } //$NON-NLS-1$
+ else {
+ answer.append(argStrings[argnum]);
+ }
+ lastI = i + 3;
+ }
+ }
+ }
+ }
+ if (lastI < format.length()) {
+ answer.append(format.substring(lastI, format.length()));
+ }
+ return answer.toString();
+ }
+
+ /**
+ * Changes the locale of the messages.
+ *
+ * @param locale
+ * Locale the locale to change to.
+ */
+ static public ResourceBundle setLocale(final Locale locale,
+ final String resource) {
+ try {
+ final ClassLoader loader = null;
+ return (ResourceBundle) AccessController
+ .doPrivileged(new PrivilegedAction<Object>() {
+ public Object run() {
+ return ResourceBundle.getBundle(resource, locale,
+ loader != null ? loader : ClassLoader.getSystemClassLoader());
+ }
+ });
+ } catch (MissingResourceException e) {
+ }
+ return null;
+ }
+
+ static {
+ // Attempt to load the messages.
+ try {
+ bundle = setLocale(Locale.getDefault(),
+ "org.apache.harmony.security.internal.nls.messages"); //$NON-NLS-1$
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+}
Propchange: incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/Messages.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/NullPolicyParser.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/NullPolicyParser.java?rev=928394&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/NullPolicyParser.java (added)
+++ incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/NullPolicyParser.java Sun Mar 28 12:57:03 2010
@@ -0,0 +1,24 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.apache.river.security.policy.util;
+
+import java.net.URL;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Properties;
+
+/**
+ * A null PolicyParser.
+ * Just in case you don't want to utilise any policy files, for whatever reason.
+ * @author Peter Firmstone.
+ */
+public class NullPolicyParser implements PolicyParser{
+
+ public Collection<PolicyEntry> parse(URL location, Properties system) throws Exception {
+ return new HashSet<PolicyEntry>();
+ }
+
+}
Propchange: incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/NullPolicyParser.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/PolicyEntry.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/PolicyEntry.java?rev=928394&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/PolicyEntry.java (added)
+++ incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/PolicyEntry.java Sun Mar 28 12:57:03 2010
@@ -0,0 +1,163 @@
+/*
+ * 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.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @author Peter Firmstone.
+* @version $Revision$
+*/
+
+package org.apache.river.security.policy.util;
+
+import java.net.URL;
+import java.security.CodeSigner;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+
+/**
+ * This class represents an elementary block of a security policy. It associates
+ * a CodeSource of an executable code, Principals allowed to execute the code,
+ * and a set of granted Permissions.
+ *
+ * Immutable
+ *
+ *
+ */
+public class PolicyEntry {
+
+ // Store CodeSource
+ private final CodeSource cs;
+
+ // Array of principals
+ private final List<Principal> principals;
+
+ // Permissions collection
+ private final Collection<Permission> permissions;
+
+ private transient final int hashcode;
+
+ /**
+ * Constructor with initialization parameters. Passed collections are not
+ * referenced directly, but copied.
+ */
+ public PolicyEntry(CodeSource cs, Collection<? extends Principal> prs,
+ Collection<? extends Permission> permissions) {
+ this.cs = (cs != null) ? normalizeCodeSource(cs) : null;
+ if ( prs == null || prs.isEmpty()) {
+ this.principals = null;
+ }else{
+ this.principals = new ArrayList<Principal>();
+ this.principals.addAll(prs);
+ }
+ if (permissions == null || permissions.isEmpty()) {
+ this.permissions = null;
+ }else{
+ Set<Permission> perm = new HashSet<Permission>();
+ perm.addAll(permissions);
+ this.permissions = Collections.unmodifiableCollection(perm);
+ }
+ /* Effectively immutable, this will make any hash this is contained in perform.
+ * May need to consider Serializable for this class yet, we'll see.
+ */
+ hashcode = (this.cs.hashCode() + principals.hashCode() + this.permissions.hashCode())/3;
+ }
+
+ /**
+ * Checks if passed CodeSource matches this PolicyEntry. Null CodeSource of
+ * PolicyEntry implies any CodeSource; non-null CodeSource forwards to its
+ * imply() method.
+ */
+ public boolean impliesCodeSource(CodeSource codeSource) {
+ if (cs == null) {
+ return true;
+ }
+
+ if (codeSource == null) {
+ return false;
+ }
+ return cs.implies(normalizeCodeSource(codeSource));
+ }
+
+ private CodeSource normalizeCodeSource(CodeSource codeSource) {
+ URL codeSourceURL = PolicyUtils.normalizeURL(codeSource.getLocation());
+ CodeSource result = codeSource;
+
+ if (codeSourceURL != codeSource.getLocation()) {
+ // URL was normalized - recreate codeSource with new URL
+ CodeSigner[] signers = codeSource.getCodeSigners();
+ if (signers == null) {
+ result = new CodeSource(codeSourceURL, codeSource
+ .getCertificates());
+ } else {
+ result = new CodeSource(codeSourceURL, signers);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Checks if specified Principals match this PolicyEntry. Null or empty set
+ * of Principals of PolicyEntry implies any Principals; otherwise specified
+ * array must contain all Principals of this PolicyEntry.
+ */
+ public boolean impliesPrincipals(Principal[] prs) {
+ // return PolicyUtils.matchSubset(principals, prs);
+ if ( principals == null || principals.isEmpty()) return true;
+ if ( prs == null || prs.length == 0 ) return false;
+ List<Principal> princp = Arrays.asList(prs);
+ return princp.containsAll(principals);
+ }
+
+ /**
+ * Returns unmodifiable collection of permissions defined by this
+ * PolicyEntry, may be <code>null</code>.
+ */
+ public Collection<Permission> getPermissions() {
+ return permissions;
+ }
+
+ /**
+ * Returns true if this PolicyEntry defines no Permissions, false otherwise.
+ */
+ public boolean isVoid() {
+ return permissions == null || permissions.size() == 0;
+ }
+
+ @Override
+ public boolean equals(Object o){
+ if (this == o) return true;
+ if ( !(o instanceof PolicyEntry)) return false;
+ PolicyEntry pe = (PolicyEntry) o;
+ if (cs.equals(pe.cs) && principals.equals(pe.principals)
+ && permissions.equals(pe.permissions) ) return true;
+ return false;
+ }
+
+ @Override
+ public int hashCode(){
+ return hashcode;
+ }
+}
Propchange: incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/PolicyEntry.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/PolicyParser.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/PolicyParser.java?rev=928394&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/PolicyParser.java (added)
+++ incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/PolicyParser.java Sun Mar 28 12:57:03 2010
@@ -0,0 +1,35 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.apache.river.security.policy.util;
+
+import java.net.URL;
+import java.util.Collection;
+import java.util.Properties;
+
+/**
+ *
+ * @author peter
+ */
+public interface PolicyParser {
+
+ /**
+ * 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.
+ * <br>
+ * 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
+ */
+ Collection<PolicyEntry> parse(URL location, Properties system) throws Exception;
+
+}
Propchange: incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/PolicyParser.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/PolicyUtils.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/PolicyUtils.java?rev=928394&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/PolicyUtils.java (added)
+++ incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/PolicyUtils.java Sun Mar 28 12:57:03 2010
@@ -0,0 +1,663 @@
+/*
+ * 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.
+ */
+
+/**
+* @author Alexey V. Varlamov
+ * @author Peter Firmstone
+* @version $Revision$
+*/
+
+package org.apache.river.security.policy.util;
+
+import java.io.File;
+import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
+import java.security.Security;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.river.security.concurrent.ConcurrentPermissions;
+
+/**
+ * This class consist of a number of static methods, which provide a common functionality
+ * for various policy and configuration providers.
+ *
+ */
+public class PolicyUtils {
+
+ // No reason to instantiate
+ private PolicyUtils() {}
+
+ /**
+ * Auxiliary action for opening InputStream from specified location.
+ */
+ public static class URLLoader implements PrivilegedExceptionAction<InputStream> {
+
+ /**
+ * URL of target location.
+ */
+ public URL location;
+
+ /**
+ * Constructor with target URL parameter.
+ */
+ public URLLoader(URL location) {
+ this.location = location;
+ }
+
+ /**
+ * Returns InputStream from the target URL.
+ */
+ public InputStream run() throws Exception {
+ return location.openStream();
+ }
+ }
+
+ /**
+ * Auxiliary action for accessing system properties in a bundle.
+ */
+ public static class SystemKit implements PrivilegedAction<Properties> {
+
+ /**
+ * Returns system properties.
+ */
+ public Properties run() {
+ return System.getProperties();
+ }
+ }
+
+ /**
+ * Auxiliary action for accessing specific system property.
+ */
+ public static class SystemPropertyAccessor implements PrivilegedAction<String> {
+
+ /**
+ * A key of a required system property.
+ */
+ public String key;
+
+ /**
+ * Constructor with a property key parameter.
+ */
+ public SystemPropertyAccessor(String key) {
+ this.key = key;
+ }
+
+ /**
+ * Handy one-line replacement of
+ * "provide key and supply action" code block,
+ * for reusing existing action instance.
+ */
+ public PrivilegedAction<String> key(String key) {
+ this.key = key;
+ return this;
+ }
+
+ /**
+ * Returns specified system property.
+ */
+ public String run() {
+ return System.getProperty(key);
+ }
+ }
+
+ /**
+ * Auxiliary action for accessing specific security property.
+ */
+ public static class SecurityPropertyAccessor implements PrivilegedAction<String> {
+
+ private String key;
+
+ /**
+ * Constructor with a property key parameter.
+ */
+ public SecurityPropertyAccessor(String key) {
+ super();
+ this.key = key;
+ }
+
+ public PrivilegedAction<String> key(String key) {
+ this.key = key;
+ return this;
+ }
+
+ /**
+ * Returns specified security property.
+ */
+ public String run() {
+ return Security.getProperty(key);
+ }
+ }
+
+ /**
+ * Auxiliary action for loading a provider by specific security property.
+ */
+ public static class ProviderLoader<T> implements PrivilegedAction<T> {
+
+ private String key;
+
+ /**
+ * Acceptable provider superclass.
+ */
+ private Class<T> expectedType;
+
+ /**
+ * Constructor taking property key and acceptable provider
+ * superclass parameters.
+ */
+ public ProviderLoader(String key, Class<T> expected) {
+ super();
+ this.key = key;
+ this.expectedType = expected;
+ }
+
+ /**
+ * Returns provider instance by specified security property.
+ * The <code>key</code> should map to a fully qualified classname.
+ *
+ * @throws SecurityException if no value specified for the key
+ * in security properties or if an Exception has occurred
+ * during classloading and instantiating.
+ */
+ public T run() {
+ String klassName = Security.getProperty(key);
+ if (klassName == null || klassName.length() == 0) {
+ throw new SecurityException(Messages.getString("security.14C", //$NON-NLS-1$
+ key));
+ }
+ // TODO accurate classloading
+ try {
+ Class<?> klass = Class.forName(klassName, true,
+ Thread.currentThread().getContextClassLoader());
+ if (expectedType != null && klass.isAssignableFrom(expectedType)){
+ throw new SecurityException(Messages.getString("security.14D", //$NON-NLS-1$
+ klassName, expectedType.getName()));
+ }
+ //FIXME expectedType.cast(klass.newInstance());
+ return (T)klass.newInstance();
+ }
+ catch (SecurityException se){
+ throw se;
+ }
+ catch (Exception e) {
+ // TODO log error ??
+ SecurityException se = new SecurityException(
+ Messages.getString("security.14E", klassName)); //$NON-NLS-1$
+ se.initCause(e);
+ throw se;
+ }
+ }
+ }
+
+ /**
+ * Specific exception to signal that property expansion failed
+ * due to unknown key.
+ */
+ public static class ExpansionFailedException extends Exception {
+
+ /**
+ * @serial
+ */
+ private static final long serialVersionUID = 2869748055182612000L;
+
+ /**
+ * Constructor with user-friendly message parameter.
+ */
+ public ExpansionFailedException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructor with user-friendly message and causing error.
+ */
+ public ExpansionFailedException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ }
+
+ /**
+ * Substitutes all entries like ${some.key}, found in specified string,
+ * for specified values.
+ * If some key is unknown, throws ExpansionFailedException.
+ * @param str the string to be expanded
+ * @param properties available key-value mappings
+ * @return expanded string
+ * @throws ExpansionFailedException
+ */
+ public static String expand(String str, Properties properties)
+ throws ExpansionFailedException {
+ final String START_MARK = "${"; //$NON-NLS-1$
+ final String END_MARK = "}"; //$NON-NLS-1$
+ final int START_OFFSET = START_MARK.length();
+ final int END_OFFSET = END_MARK.length();
+
+ StringBuilder result = new StringBuilder(str);
+ int start = result.indexOf(START_MARK);
+ while (start >= 0) {
+ int end = result.indexOf(END_MARK, start);
+ if (end >= 0) {
+ String key = result.substring(start + START_OFFSET, end);
+ String value = properties.getProperty(key);
+ if (value != null) {
+ result.replace(start, end + END_OFFSET, value);
+ start += value.length();
+ } else {
+ throw new ExpansionFailedException(Messages.getString("security.14F", key)); //$NON-NLS-1$
+ }
+ }
+ start = result.indexOf(START_MARK, start);
+ }
+ return result.toString();
+ }
+
+ /**
+ * Handy shortcut for
+ * <code>expand(str, properties).replace(File.separatorChar, '/')</code>.
+ * @see #expand(String, Properties)
+ */
+ public static String expandURL(String str, Properties properties)
+ throws ExpansionFailedException {
+ return expand(str, properties).replace(File.separatorChar, '/');
+ }
+
+ /**
+ * Normalizes URLs to standard ones, eliminating pathname symbols.
+ *
+ * @param codebase -
+ * the original URL.
+ * @return - the normalized URL.
+ */
+ public static URL normalizeURL(URL codebase) {
+ if (codebase != null && "file".equals(codebase.getProtocol())) { //$NON-NLS-1$
+ try {
+ if (codebase.getHost().length() == 0) {
+ String path = codebase.getFile();
+
+ if (path.length() == 0) {
+ // codebase is "file:"
+ path = "*";
+ }
+ return filePathToURI(new File(path)
+ .getAbsolutePath()).normalize().toURL();
+ } else {
+ // codebase is "file://<smth>"
+ return codebase.toURI().normalize().toURL();
+ }
+ } catch (Exception e) {
+ // Ignore
+ }
+ }
+ return codebase;
+ }
+
+ /**
+ * Converts a file path to URI without accessing file system
+ * (like {File#toURI()} does).
+ *
+ * @param path -
+ * file path.
+ * @return - the resulting URI.
+ * @throw URISyntaxException
+ */
+ public static URI filePathToURI(String path) throws URISyntaxException {
+ path = path.replace(File.separatorChar, '/');
+
+ if (!path.startsWith("/")) { //$NON-NLS-1$
+ return new URI("file", null, //$NON-NLS-1$
+ new StringBuilder(path.length() + 1).append('/')
+ .append(path).toString(), null, null);
+ }
+ return new URI("file", null, path, null, null); //$NON-NLS-1$
+ }
+
+ /**
+ * Instances of this interface are intended for resolving
+ * generalized expansion expressions, of the form ${{protocol:data}}.
+ * Such functionality is applicable to security policy files, for example.
+ * @see org.apache.harmony.security.PolicyUtils#expandGeneral(String, GeneralExpansionHandler)
+ */
+ public static interface GeneralExpansionHandler {
+
+ /**
+ * Resolves general expansion expressions of the form ${{protocol:data}}.
+ * @param protocol denotes type of resolution
+ * @param data data to be resolved, optional (may be null)
+ * @return resolved value, must not be null
+ * @throws PolicyUtils.ExpansionFailedException if expansion is impossible
+ */
+ String resolve(String protocol, String data)
+ throws ExpansionFailedException;
+ }
+
+ /**
+ * Substitutes all entries like ${{protocol:data}}, found in specified string,
+ * for values resolved by passed handler.
+ * The data part may be empty, and in this case expression
+ * may have simplified form, as ${{protocol}}.
+ * If some entry cannot be resolved, throws ExpansionFailedException;
+ * @param str the string to be expanded
+ * @param handler the handler to resolve data denoted by protocol
+ * @return expanded string
+ * @throws ExpansionFailedException
+ */
+ public static String expandGeneral(String str,
+ GeneralExpansionHandler handler) throws ExpansionFailedException {
+ final String START_MARK = "${{"; //$NON-NLS-1$
+ final String END_MARK = "}}"; //$NON-NLS-1$
+ final int START_OFFSET = START_MARK.length();
+ final int END_OFFSET = END_MARK.length();
+
+ StringBuilder result = new StringBuilder(str);
+ int start = result.indexOf(START_MARK);
+ while (start >= 0) {
+ int end = result.indexOf(END_MARK, start);
+ if (end >= 0) {
+ String key = result.substring(start + START_OFFSET, end);
+ int separator = key.indexOf(':');
+ String protocol = (separator >= 0) ? key
+ .substring(0, separator) : key;
+ String data = (separator >= 0) ? key.substring(separator + 1)
+ : null;
+ String value = handler.resolve(protocol, data);
+ result.replace(start, end + END_OFFSET, value);
+ start += value.length();
+ }
+ start = result.indexOf(START_MARK, start);
+ }
+ return result.toString();
+ }
+
+ /**
+ * A key to security properties, deciding whether usage of
+ * dynamic policy location via system properties is allowed.
+ * @see #getPolicyURLs(Properties, String, String)
+ */
+ public static final String POLICY_ALLOW_DYNAMIC = "policy.allowSystemProperty"; //$NON-NLS-1$
+
+ /**
+ * A key to security properties, deciding whether expansion of
+ * system properties is allowed
+ * (in security properties values, policy files, etc).
+ * @see #expand(String, Properties)
+ */
+ public static final String POLICY_EXPAND = "policy.expandProperties"; //$NON-NLS-1$
+
+ /**
+ * Positive value of switching properties.
+ */
+ public static final String TRUE = "true"; //$NON-NLS-1$
+
+ /**
+ * Negative value of switching properties.
+ */
+ public static final String FALSE = "false"; //$NON-NLS-1$
+
+ /**
+ * Returns false if current security settings disable to perform
+ * properties expansion, true otherwise.
+ * @see #expand(String, Properties)
+ */
+ public static boolean canExpandProperties() {
+ return !Util.equalsIgnoreCase(FALSE,AccessController
+ .doPrivileged(new SecurityPropertyAccessor(POLICY_EXPAND)));
+ }
+
+ /**
+ * Obtains a list of locations for a policy or configuration provider.
+ * The search algorithm is as follows:
+ * <ol>
+ * <li> Look in security properties for keys of form <code>prefix + n</code>,
+ * where <i>n</i> is an integer and <i>prefix</i> is a passed parameter.
+ * Sequence starts with <code>n=1</code>, and keeps incrementing <i>n</i>
+ * until next key is not found. <br>
+ * For each obtained key, try to construct an URL instance. On success,
+ * add the URL to the list; otherwise ignore it.
+ * <li>
+ * If security settings do not prohibit (through
+ * {@link #POLICY_ALLOW_DYNAMIC the "policy.allowSystemProperty" property})
+ * to use additional policy location, read the system property under the
+ * passed key parameter. If property exists, it may designate a file or
+ * an absolute URL. Thus, first check if there is a file with that name,
+ * and if so, convert the pathname to URL. Otherwise, try to instantiate
+ * an URL directly. If succeeded, append the URL to the list
+ * <li>
+ * If the additional location from the step above was specified to the
+ * system via "==" (i.e. starts with '='), discard all URLs above
+ * and use this only URL.
+ * </ol>
+ * <b>Note:</b> all property values (both security and system) related to URLs are
+ * subject to {@link #expand(String, Properties) property expansion}, regardless
+ * of the "policy.expandProperties" security setting.
+ *
+ * @param system system properties
+ * @param systemUrlKey key to additional policy location
+ * @param securityUrlPrefix prefix to numbered locations in security properties
+ * @return array of URLs to provider's configuration files, may be empty.
+ */
+ public static URL[] getPolicyURLs(final Properties system,
+ final String systemUrlKey, final String securityUrlPrefix) {
+
+ final SecurityPropertyAccessor security = new SecurityPropertyAccessor(
+ null);
+ final List<URL> urls = new ArrayList<URL>();
+ boolean dynamicOnly = false;
+ URL dynamicURL = null;
+
+ //first check if policy is set via system properties
+ if (!Util.equalsIgnoreCase(FALSE, AccessController
+ .doPrivileged(security.key(POLICY_ALLOW_DYNAMIC)))) {
+ String location = system.getProperty(systemUrlKey);
+ if (location != null) {
+ if (location.startsWith("=")) { //$NON-NLS-1$
+ //overrides all other urls
+ dynamicOnly = true;
+ location = location.substring(1);
+ }
+ try {
+ location = expandURL(location, system);
+ // location can be a file, but we need an url...
+ final File f = new File(location);
+ dynamicURL = AccessController
+ .doPrivileged(new PrivilegedExceptionAction<URL>() {
+
+ public URL run() throws Exception {
+ if (f.exists()) {
+ return f.toURI().toURL();
+ } else {
+ return null;
+ }
+ }
+ });
+ if (dynamicURL == null) {
+ dynamicURL = new URL(location);
+ }
+ }
+ catch (Exception e) {
+ // TODO: log error
+ // System.err.println("Error detecting system policy location: "+e);
+ }
+ }
+ }
+ //next read urls from security.properties
+ if (!dynamicOnly) {
+ int i = 1;
+ while (true) {
+ String location = AccessController
+ .doPrivileged(security.key(new StringBuilder(
+ securityUrlPrefix).append(i++).toString()));
+ if (location == null) {
+ break;
+ }
+ try {
+ location = expandURL(location, system);
+ URL anURL = new URL(location);
+ if (anURL != null) {
+ urls.add(anURL);
+ }
+ }
+ catch (Exception e) {
+ // TODO: log error
+ // System.err.println("Error detecting security policy location: "+e);
+ }
+ }
+ }
+ if (dynamicURL != null) {
+ urls.add(dynamicURL);
+ }
+ return urls.toArray(new URL[urls.size()]);
+ }
+
+ /**
+ * Converts common-purpose collection of Permissions to PermissionCollection.
+ *
+ * @param perms a collection containing arbitrary permissions, may be null
+ * @return mutable heterogeneous PermissionCollection containing all Permissions
+ * from the specified collection
+ */
+ public static PermissionCollection
+ toPermissionCollection(Collection<Permission> perms) {
+ PermissionCollection pc = new ConcurrentPermissions();
+ if (perms != null) {
+ for (Iterator<Permission> iter = perms.iterator(); iter.hasNext();) {
+ Permission element = iter.next();
+ pc.add(element);
+ }
+ }
+ return pc;
+ }
+
+ /**
+ * Converts common-purpose homegeneous or heterogeneous PermissionCollection
+ * to a hetergeneous PermissionCollection.
+ *
+ * @param perms a PermissionCollection containing arbitrary permissions.
+ * @return mutable heterogeneous PermissionCollection containing all Permissions
+ * from the specified PermissionCollection
+ */
+ public static PermissionCollection
+ toConcurrentPermissions(PermissionCollection perms) {
+ if (perms instanceof ConcurrentPermissions) return perms;
+ PermissionCollection pc = new ConcurrentPermissions();
+ if (perms != null) {
+ Enumeration<Permission> iter = perms.elements();
+ while ( iter.hasMoreElements() ) {
+ Permission element = iter.nextElement();
+ pc.add(element);
+ }
+ }
+ return pc;
+ }
+
+ // Empty set of arguments to default constructor of a Permission.
+ private static final Class[] NO_ARGS = {};
+
+ // One-arg set of arguments to default constructor of a Permission.
+ private static final Class[] ONE_ARGS = { String.class };
+
+ // Two-args set of arguments to default constructor of a Permission.
+ private static final Class[] TWO_ARGS = { String.class, String.class };
+
+ /**
+ * Tries to find a suitable constructor and instantiate a new Permission
+ * with specified parameters.
+ *
+ * @param targetType class of expected Permission instance
+ * @param targetName name of expected Permission instance
+ * @param targetActions actions of expected Permission instance
+ * @return a new Permission instance
+ * @throws IllegalArgumentException if no suitable constructor found
+ * @throws Exception any exception thrown by Constructor.newInstance()
+ */
+ public static Permission instantiatePermission(Class<?> targetType,
+ String targetName, String targetActions) throws Exception {
+
+ // let's guess the best order for trying constructors
+ Class[][] argTypes = null;
+ Object[][] args = null;
+ if (targetActions != null) {
+ argTypes = new Class[][] { TWO_ARGS, ONE_ARGS, NO_ARGS };
+ args = new Object[][] { { targetName, targetActions },
+ { targetName }, {} };
+ } else if (targetName != null) {
+ argTypes = new Class[][] { ONE_ARGS, TWO_ARGS, NO_ARGS };
+ args = new Object[][] { { targetName },
+ { targetName, targetActions }, {} };
+ } else {
+ argTypes = new Class[][] { NO_ARGS, ONE_ARGS, TWO_ARGS };
+ args = new Object[][] { {}, { targetName },
+ { targetName, targetActions } };
+ }
+
+ // finally try to instantiate actual permission
+ for (int i = 0; i < argTypes.length; i++) {
+ try {
+ Constructor<?> ctor = targetType.getConstructor(argTypes[i]);
+ return (Permission)ctor.newInstance(args[i]);
+ }
+ catch (NoSuchMethodException ignore) {}
+ }
+ throw new IllegalArgumentException(
+ Messages.getString("security.150", targetType));//$NON-NLS-1$
+ }
+
+ /**
+ * Checks whether the objects from <code>what</code> array are all
+ * presented in <code>where</code> array.
+ *
+ * @param what first array, may be <code>null</code>
+ * @param where second array, may be <code>null</code>
+ * @return <code>true</code> if the first array is <code>null</code>
+ * or if each and every object (ignoring null values)
+ * from the first array has a twin in the second array; <code>false</code> otherwise
+ */
+ public static boolean matchSubset(Object[] what, Object[] where) {
+ if (what == null) {
+ return true;
+ }
+
+ for (int i = 0; i < what.length; i++) {
+ if (what[i] != null) {
+ if (where == null) {
+ return false;
+ }
+ boolean found = false;
+ for (int j = 0; j < where.length; j++) {
+ if (what[i].equals(where[j])) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+}
Propchange: incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/PolicyUtils.java
------------------------------------------------------------------------------
svn:eol-style = native