Package com.sun.jini.start

Source Code of com.sun.jini.start.AggregatePolicyProvider$AggregateSecurityContext

/*
* 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.
*/

package com.sun.jini.start;

import com.sun.jini.collection.WeakIdentityMap;
import java.lang.reflect.Method;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.AllPermission;
import java.security.CodeSource;
import java.security.Permission;
import java.security.Permissions;
import java.security.PermissionCollection;
import java.security.Principal;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.security.Policy;
import java.security.ProtectionDomain;
import java.security.Security;
import java.security.SecurityPermission;
import java.util.Map;
import java.util.WeakHashMap;
import net.jini.security.SecurityContext;
import net.jini.security.policy.DynamicPolicy;
import net.jini.security.policy.PolicyInitializationException;
import net.jini.security.policy.SecurityContextSource;

/**
* Security policy provider which supports associating security sub-policies
* with context class loaders.  Permission queries and grants (if supported),
* as well as <code>implies</code> and <code>refresh</code> operations are
* delegated to the currently active sub-policy.
* <p>
* The currently active sub-policy is determined as follows: if the current
* thread does not override the {@link Thread#getContextClassLoader
* getContextClassLoader} method, then that method is called to obtain the
* context class loader.  If the context class loader is associated with a
* sub-policy (via a previous call to <code>setPolicy</code>), then that
* sub-policy is the currently active sub-policy.  If no such association
* exists, then the same check is performed on each non-<code>null</code>
* parent of the context class loader, proceeding up the chain of class loader
* delegation, until a sub-policy association is found, in which case the
* associated sub-policy is the currently active sub-policy.  If no sub-policy
* association is found for the context class loader or any of its parents,
* then a fallback sub-policy, the main policy, is the currently active
* sub-policy.  Also, if the current thread overrides the
* <code>getContextClassLoader</code> method, then
* <code>getContextClassLoader</code> is not called and the main policy is the
* currently active sub-policy.
*
* @author Sun Microsystems, Inc.
*
* @since 2.0
*/
public class AggregatePolicyProvider
    extends Policy implements DynamicPolicy, SecurityContextSource
{
    private static final String mainPolicyClassProperty =
  "com.sun.jini.start.AggregatePolicyProvider.mainPolicyClass";
    private static final String defaultMainPolicyClass =
  "net.jini.security.policy.DynamicPolicyProvider";

    private static final Map trustGetCCL = new WeakHashMap();
    private static final ProtectionDomain myDomain = (ProtectionDomain)
  AccessController.doPrivileged(new PrivilegedAction() {
      public Object run() {
    return AggregatePolicyProvider.class.getProtectionDomain();
      }
  });

    private WeakIdentityMap subPolicies = new WeakIdentityMap();
    private WeakIdentityMap subPolicyCache = new WeakIdentityMap();
    private Policy mainPolicy;

    /**
     * Creates a new <code>AggregatePolicyProvider</code> instance, containing
     * a main policy created as follows: if the
     * <code>com.sun.jini.start.AggregatePolicyProvider.mainPolicyClass</code>
     * security property is set, then its value is interpreted as the class
     * name of the main policy provider; otherwise, a default class name of
     * <code>"net.jini.security.policy.DynamicPolicyProvider"</code>
     * is used.  The main policy is then instantiated using the no-arg public
     * constructor of the named class.  If the main policy class is not found,
     * is not instantiable via a public no-arg constructor, or if invocation of
     * its constructor fails, then a <code>PolicyInitializationException</code>
     * is thrown.
     * <p>
     * Note that this constructor requires the appropriate
     * <code>"getProperty"</code> {@link SecurityPermission} to read the
     * <code>com.sun.jini.start.AggregatePolicyProvider.mainPolicyClass</code>
     * security property, and may require <code>"accessClassInPackage.*"</code>
     * {@link RuntimePermission}s, depending on the package of the main policy
     * class.
     *
     * @throws  PolicyInitializationException if unable to construct the main
     *          policy
     * @throws  SecurityException if there is a security manager and the
     *          calling context does not have <code>SecurityPermission</code>
     *          for reading the
     *          <code>com.sun.jini.start.AggregatePolicyProvider.mainPolicy</code>
     *          security property, or if the calling context does not have
     *          adequate permissions to access the main policy class
     */
    public AggregatePolicyProvider() throws PolicyInitializationException {
  String cname = Security.getProperty(mainPolicyClassProperty);
  if (cname == null) {
      cname = defaultMainPolicyClass;
  }
  try {
      mainPolicy = (Policy) Class.forName(cname).newInstance();
  } catch (SecurityException e) {
      throw e;
  } catch (Exception e) {
      throw new PolicyInitializationException(
    "unable to construct main policy", e);
  }
  ensureDependenciesResolved();
    }

    /**
     * Creates a new <code>AggregatePolicyProvider</code> instance with the
     * given main policy, which must be non-<code>null</code>.
     *
     * @param   mainPolicy main policy
     * @throws  NullPointerException if main policy is <code>null</code>
     */
    public AggregatePolicyProvider(Policy mainPolicy) {
  if (mainPolicy == null) {
      throw new NullPointerException();
  }
  this.mainPolicy = mainPolicy;
  ensureDependenciesResolved();
    }

    /**
     * Delegates to the corresponding <code>getPermissions</code> method of the
     * currently active sub-policy to return the set of permissions allowed for
     * code from the specified code source, as a newly-created mutable
     * <code>PermissionCollection</code> which supports heterogeneous
     * permission types.
     *
     * @param  source code source for which to look up permissions
     * @return  set of permissions allowed for the given code source
     */
    public PermissionCollection getPermissions(CodeSource source) {
  return getCurrentSubPolicy().getPermissions(source);
    }

    /**
     * If the given protection domain is the protection domain of this class,
     * then a newly-created <code>PermissionCollection</code> containing {@link
     * AllPermission} is returned.  Otherwise, delegates to the corresponding
     * <code>getPermissions</code> method of the currently active sub-policy to
     * return the set of permissions allowed for code in the specified
     * protection domain, as a newly-created mutable
     * <code>PermissionCollection</code> which supports heterogeneous
     * permission types.
     *
     * @param  domain protection domain for which to look up permissions
     * @return  set of permissions allowed for given protection domain
     */
    public PermissionCollection getPermissions(ProtectionDomain domain) {
  if (domain == myDomain) {
      PermissionCollection pc = new Permissions();
      pc.add(new AllPermission());
      return pc;
  } else {
      return getCurrentSubPolicy().getPermissions(domain);
  }
    }

    /**
     * If the given protection domain is the protection domain of this class,
     * then <code>true</code> is returned.  Otherwise, delegates to the
     * <code>implies</code> method of the currently active sub-policy to
     * determine if the given permission is implied by the permissions for the
     * specified protection domain.
     *
     * @param  domain protection domain in which to check implication
     * @param  permission permission to test implication of
     * @return  <code>true</code> if permission is implied by permissions of
     *     given protection domain, <code>false</code> otherwise
     */
    public boolean implies(ProtectionDomain domain, Permission permission) {
  return (domain == myDomain) ||
         getCurrentSubPolicy().implies(domain, permission);
    }

    /**
     * Refreshes the currently active sub-policy by delegating to its
     * <code>refresh</code> method.
     */
    public void refresh() {
  getCurrentSubPolicy().refresh();
    }

    /**
     * Changes sub-policy association with given class loader.  If
     * <code>subPolicy</code> is non-<code>null</code>, then it is used as a
     * new sub-policy to associate with the given class loader, overriding any
     * previous sub-policy associated with the loader.  If
     * <code>subPolicy</code> is <code>null</code>, then any previous
     * association between a sub-policy and the given class loader is removed.
     * If loader is <code>null</code>, then <code>subPolicy</code> is used as
     * the new main policy, and must be non-<code>null</code>.  If there is a
     * security manager, its <code>checkPermission</code> method is called with
     * the <code>"setPolicy"</code> {@link SecurityPermission}.
     *
     * @param   loader class loader with which to associate sub-policy, or
     *     <code>null</code> if setting main policy
     * @param   subPolicy sub-policy to associate with given class loader, or
     *          <code>null</code> if removing sub-policy association
     * @throws  NullPointerException if both <code>loader</code> and
     *     <code>subPolicy</code> are <code>null</code>
     * @throws  SecurityException if there is a security manager and the
     *     calling context does not have the <code>"setPolicy"
     *     SecurityPermission</code>
     */
    public void setPolicy(ClassLoader loader, Policy subPolicy) {
  SecurityManager sm = System.getSecurityManager();
  if (sm != null) {
      sm.checkPermission(new SecurityPermission("setPolicy"));
  }
  synchronized (subPolicies) {
      subPolicyCache.clear();
      if (loader != null) {
    if (subPolicy != null) {
        subPolicies.put(loader, subPolicy);
        subPolicyCache.put(loader, subPolicy);
    } else {
        subPolicies.remove(loader);
    }
      } else {
    if (subPolicy == null) {
        throw new NullPointerException();
    }
    mainPolicy = subPolicy;
      }
  }
    }

    /**
     * Returns <code>true</code> if the currently active sub-policy supports
     * dynamic grants; this is determined by delegating to the
     * <code>grantSupported</code> method of the currently active sub-policy if
     * it implements the {@link DynamicPolicy} interface.  If the currently
     * active sub-policy does not implement <code>DynamicPolicy</code>, then
     * <code>false</code> is returned.
     *
     * @return <code>true</code> if the currently active sub-policy supports
     * dynamic grants, or <code>false</code> otherwise
     */
    public boolean grantSupported() {
  Policy p = getCurrentSubPolicy();
  return (p instanceof DynamicPolicy &&
    ((DynamicPolicy) p).grantSupported());
    }

    /**
     * If the currently active sub-policy supports dynamic permission grants,
     * delegates to the corresponding <code>grant</code> method of the
     * currently active sub-policy to grant the specified permissions to all
     * protection domains (including ones not yet created) which are associated
     * with the class loader of the given class and possess at least the given
     * set of principals.
     *
     * @param   cl {@inheritDoc}
     * @param  principals {@inheritDoc}
     * @param  permissions {@inheritDoc}
     * @throws  UnsupportedOperationException {@inheritDoc}
     * @throws  SecurityException {@inheritDoc}
     * @throws  NullPointerException {@inheritDoc}
     */
    public void grant(Class cl,
                      Principal[] principals,
                      Permission[] permissions)
    {
  Policy p = getCurrentSubPolicy();
  if (p instanceof DynamicPolicy) {
      ((DynamicPolicy) p).grant(cl, principals, permissions);
  } else {
      throw new UnsupportedOperationException("grants not supported");
  }
    }

    /**
     * If the currently active sub-policy supports dynamic permission grants,
     * delegates to the corresponding <code>getGrants</code> method of the
     * currently active sub-policy to return a new array containing the set of
     * permissions dynamically granted to protection domains which are
     * associated with the class loader of the given class and possess at least
     * the given set of principals.
     *
     * @param   cl {@inheritDoc}
     * @param   principals {@inheritDoc}
     * @return  {@inheritDoc}
     * @throws  UnsupportedOperationException {@inheritDoc}
     * @throws  NullPointerException {@inheritDoc}
     */
    public Permission[] getGrants(Class cl, Principal[] principals) {
  Policy p = getCurrentSubPolicy();
  if (p instanceof DynamicPolicy) {
      return ((DynamicPolicy) p).getGrants(cl, principals);
  } else {
      throw new UnsupportedOperationException("grants not supported");
  }
    }

    /**
     * Returns a snapshot of the current security context, which can be used to
     * restore the context at a later time.
     * <p>
     * The security context returned by this method contains the security
     * context of the currently active sub-policy (or an equivalent of the
     * default security context described in the documentation for {@link
     * net.jini.security.Security#getContext
     * Security.getContext}, if the currently active sub-policy does not
     * implement {@link SecurityContextSource}), as well as the current context
     * class loader.  The privileged action wrappers it creates restore the
     * saved context class loader before delegating to the action wrappers of
     * the underlying sub-policy security context.  The
     * <code>getAccessControlContext</code> method of the returned security
     * context delegates to the corresponding method of the sub-policy security
     * context.
     *
     * @return  {@inheritDoc}
     */
    public SecurityContext getContext() {
  Policy p = getCurrentSubPolicy();
  SecurityContext sc = (p instanceof SecurityContextSource) ?
      ((SecurityContextSource) p).getContext() :
      new DefaultSecurityContext();
  return new AggregateSecurityContext(sc);
    }

    /**
     * Ensures that any classes depended on by this policy provider are
     * resolved.  This is to preclude lazy resolution of such classes during
     * operation of the provider, which can result in deadlock as described by
     * bug 4911907.
     */
    private void ensureDependenciesResolved() {
  // get any non-null class loader
  ClassLoader ldr = getClass().getClassLoader();
  if (ldr == null) {
      ldr = ClassLoader.getSystemClassLoader();
  }

  // force class resolution by pre-invoking methods called by implies()
  trustGetContextClassLoader0(Thread.class);
  getContextClassLoader();
  synchronized (subPolicies) {
      lookupSubPolicy(ldr);
  }
    }

    /**
     * Returns currently active sub-policy.
     */
    private Policy getCurrentSubPolicy() {
  final Thread t = Thread.currentThread();
  if (!trustGetContextClassLoader(t)) {
      return mainPolicy;
  }
  ClassLoader ccl = getContextClassLoader();
  synchronized (subPolicies) {
      Policy policy = (Policy) subPolicyCache.get(ccl);
      if (policy == null) {
    policy = lookupSubPolicy(ccl);
    subPolicyCache.put(ccl, policy);
      }
      return policy;
  }
    }

    /**
     * Returns sub-policy associated with the given class loader.  This method
     * should only be called when already synchronized on subPolicies.
     */
    private Policy lookupSubPolicy(final ClassLoader ldr) {
  assert Thread.holdsLock(subPolicies);
  return (Policy) AccessController.doPrivileged(
      new PrivilegedAction() {
    public Object run() {
        for (ClassLoader l = ldr; l != null; l = l.getParent()) {
      Policy p = (Policy) subPolicies.get(l);
      if (p != null) {
          return p;
      }
        }
        return mainPolicy;
    }
      });
    }

    /**
     * Returns current context class loader.
     */
    static ClassLoader getContextClassLoader() {
  return (ClassLoader) AccessController.doPrivileged(
      new PrivilegedAction() {
    public Object run() {
        return Thread.currentThread().getContextClassLoader();
    }
      });
    }

    /**
     * Returns true if the given thread does not override
     * Thread.getContextClassLoader(), false otherwise.
     */
    private static boolean trustGetContextClassLoader(Thread t) {
  Class cl = t.getClass();
  if (cl == Thread.class) {
      return true;
  }
 
  Boolean b;
  synchronized (trustGetCCL) {
      b = (Boolean) trustGetCCL.get(cl);
  }
  if (b == null) {
      b = trustGetContextClassLoader0(cl);
      synchronized (trustGetCCL) {
    trustGetCCL.put(cl, b);
      }
  }
  return b.booleanValue();
    }

    private static Boolean trustGetContextClassLoader0(final Class cl) {
  return (Boolean) AccessController.doPrivileged(new PrivilegedAction() {
      public Object run() {
    try {
        Method m = cl.getMethod(
      "getContextClassLoader", new Class[0]);
        return Boolean.valueOf(m.getDeclaringClass() == Thread.class);
    } catch (NoSuchMethodException ex) {
        throw new InternalError(
      "Thread.getContextClassLoader() not found");
    }
      }
  });
    }

    /**
     * Stand-in "default" security context for sub-policies that do not
     * implement SecurityContextSource.
     */
    private static class DefaultSecurityContext implements SecurityContext {

  private final AccessControlContext acc =
      AccessController.getContext();

  public PrivilegedAction wrap(PrivilegedAction a) {
      if (a == null) {
    throw new NullPointerException();
      }
      return a;
  }

  public PrivilegedExceptionAction wrap(PrivilegedExceptionAction a) {
      if (a == null) {
    throw new NullPointerException();
      }
      return a;
  }

  public AccessControlContext getAccessControlContext() {
      return acc;
  }
    }

    /**
     * Security context that produces privileged action wrappers which restore
     * the context class loader before delegating to the sub-policy context's
     * wrapped action.
     */
    private static class AggregateSecurityContext implements SecurityContext {

  private final ClassLoader ccl = getContextClassLoader();
  private final SecurityContext sc;

  AggregateSecurityContext(SecurityContext sc) {
      if (sc == null) {
    throw new NullPointerException();
      }
      this.sc = sc;
  }

  public PrivilegedAction wrap(PrivilegedAction a) {
      final PrivilegedAction wa = sc.wrap(a);
      return new PrivilegedAction() {
    public Object run() {
        ClassLoader sccl = setCCL(ccl, false);
        try {
      return wa.run();
        } finally {
      setCCL(sccl, sccl != ccl);
        }
    }
      };
  }

  public PrivilegedExceptionAction wrap(PrivilegedExceptionAction a) {
      final PrivilegedExceptionAction wa = sc.wrap(a);
      return new PrivilegedExceptionAction() {
    public Object run() throws Exception {
        ClassLoader sccl = setCCL(ccl, false);
        try {
      return wa.run();
        } finally {
      setCCL(sccl, sccl != ccl);
        }
    }
      };
  }

  public AccessControlContext getAccessControlContext() {
      return sc.getAccessControlContext();
  }

  private ClassLoader setCCL(final ClassLoader ldr, final boolean force) {
      return (ClassLoader) AccessController.doPrivileged(
    new PrivilegedAction() {
        public Object run() {
      Thread t = Thread.currentThread();
      ClassLoader old = null;
      if (force || ldr != (old = t.getContextClassLoader())) {
          t.setContextClassLoader(ldr);
      }
      return old;
        }
    });
  }
    }
}
TOP

Related Classes of com.sun.jini.start.AggregatePolicyProvider$AggregateSecurityContext

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.