Package com.sun.enterprise.security

Source Code of com.sun.enterprise.security.PermissionCache

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code.  If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.enterprise.security;

import java.security.CodeSource;
import java.security.AllPermission;
import java.security.Permission;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.security.Policy;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
import java.util.Enumeration;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import javax.security.jacc.PolicyContext;
import com.sun.enterprise.security.CachedPermissionImpl.Epoch;
import com.sun.enterprise.security.AppservAccessController;

import com.sun.logging.LogDomains;

/**
* This class is
* @author Ron Monzillo
*/

public class PermissionCache extends Object {

    private static Logger _logger =
    LogDomains.getLogger(LogDomains.SECURITY_LOGGER);
    private static Policy policy = Policy.getPolicy();
    private static AllPermission allPermission = new AllPermission();

    private Permissions cache;
    private CodeSource codesource;
    private Permission[] protoPerms;
    private Class[] classes;
    private String name;
    private String pcID;
    private final Integer factoryKey;
    private volatile int epoch;
    private volatile boolean loading;
    private ReadWriteLock rwLock;
    private Lock rLock;
    private Lock wLock;
    /*
     * USE OF THIS CONSTRUCTOR WITH IS DISCOURAGED PLEASE USE THE Permission
     * (object) based CONSTRUCTOR.
     * @param key -  Integer that uniquely identifies the cache at the factory
     * @param pcID - a string identifying the policy context and which must
     *     be set when getPermissions is called (internally). this value may be
     *     null, in which case the permisions of the default policy context
     *     will be cached.
     * @param codesource - the codesource argument to be used in the call to
     *     getPermissions. this value may be null.
     * @param class - a single Class object that identifies the permission
     *     type that will be managed by the cache. This value may be
     *     null. When this argument is not null, only permissions of the
     *     identified type  or that resolve to the identified type,
     *     will be managed within the cache. When null is passed to this
     *     argument, permission type will not be a factor in determining
     *     the cached permissions.
     * @param name - a string corresponding to a value returned by
     *     Permission.getName(). Only permissions whose getName() value
     *     matches the name parameter will be included in the cache. This value
     *     may be null, in which case permission name does not factor into
     *     the permission caching.
     */
    public PermissionCache(Integer key, String pcID, CodeSource codesource,
         Class clazz, String name){
    if (codesource == null) {
       this.codesource =
     new CodeSource(null,
              (java.security.cert.Certificate[])null);
    } else {
        this.codesource = codesource;
    }
   this.factoryKey = key;
    this.cache  = null;
    this.pcID = pcID;
   this.protoPerms = null;
   if (clazz != null) {
       this.classes = new Class[] {clazz};
   } else {
       this.classes = null;
   }
    this.name = name;
   this.epoch = 1;
   this.loading = false;
   this.rwLock = new ReentrantReadWriteLock(true);
   this.rLock = rwLock.readLock();
   this.wLock = rwLock.writeLock();
    }
 
    /*
     * @param key -  Integer that uniquely identifies the cache at the factory
     * @param pcID - a string identifying the policy context and which must
     *     be set when getPermissions is called (internally). this value may be
     *     null, in which case the permisions of the default policy context
     *     will be cached.
     * @param codesource - the codesource argument to be used in the call to
     *     getPermissions. this value may be null.
     * @param perms - an array of permission objects identifying the
     *     permission types that will be managed by the cache. This value may be
     *     null. When this argument is not null, only permissions of the types
     *     passed in the array or that resolve to the types identified in the
     *     will be managed within the cache. When null is passed to this
     *     argument, permission type will not be a factor in determining the
     *     cached permissions.
     * @param name - a string corresponding to a value returned by
     *     Permission.getName(). Only permissions whose getName() value
     *     matches the name parameter will be included in the cache. This value
     *     may be null, in which case permission name does not factor into
     *     the permission caching.
     */
    public PermissionCache(Integer key, String pcID, CodeSource codesource,
         Permission[] perms, String name){
   if (codesource == null) {
       this.codesource =
     new CodeSource(null,
              (java.security.cert.Certificate[])null);
   } else {
       this.codesource = codesource;
   }
   this.factoryKey = key;
   this.cache  = null;
   this.pcID = pcID;
   this.protoPerms = perms;
   if (perms != null && perms.length>0) {
       this.classes = new Class[perms.length];
       for (int i=0; i<perms.length; i++) {
     this.classes[i] = perms[i].getClass();
       }
   } else {
       this.classes = null;
   }
   this.name = name;
   this.epoch = 1;
   this.loading = false;
   this.rwLock = new ReentrantReadWriteLock(true);
   this.rLock = rwLock.readLock();
   this.wLock = rwLock.writeLock();
    }
    public Integer getFactoryKey() {
  return this.factoryKey;
    }

    private boolean checkLoadedCache(Permission p, Epoch e) {
  if (e == null) {
      return cache.implies(p);
  } else {
      if (e.epoch != epoch) {
    e.granted = cache.implies(p);
    e.epoch = epoch;
      }
      return e.granted;
  }
    }

    private boolean checkCache(Permission p, Epoch e) {

   // test-and-set to guard critical section
   rLock.lock();
  try {
      if (loading) {
    return false;
      } else if (cache != null) {
    // cache is loaded and readlock is held
    // check permission and return
    return checkLoadedCache(p,e);
      }
  } finally {
      rLock.unlock();
  }

  wLock.lock();
  if (loading) {
      // another thread started the load
      // release the writelock and return
      wLock.unlock();
      return false;
  } else if (cache != null) {
      // another thread loaded the cache
      // get readlock inside writelock.
      // check permission and return
      rLock.lock();
      wLock.unlock();
      try {
    // cache is loaded and readlock is held
    // check permission and return
    return checkLoadedCache(p,e);
      } finally {
    rLock.unlock();
      }
  } else {
      // set the load indicators so that readers will
      // bypass the cache until it is loaded
      // release the writelock and return
      cache = null;
      loading = true;
      wLock.unlock();
  }
 
  // cache will be null if we proceed past this point
  // NO LOCKS ARE HELD AT THIS POINT

  Permissions nextCache = new Permissions();

  boolean setPc = false;
  String oldpcID = null;
  try {
      oldpcID = PolicyContext.getContextID();
      if (this.pcID != oldpcID &&
    (this.pcID == null || !this.pcID.equals(oldpcID))) {
    setPc = true;
      }
  } catch (Exception ex) {
      _logger.log(Level.SEVERE,"JACC: Unexpected security exception on access decision"
      , ex);
      return false;
  }

  PermissionCollection pc = null;
  try {
      if (setPc) {
    setPolicyContextID(this.pcID);
      }
   
      pc = this.policy.getPermissions(this.codesource);
  } catch(Exception ex) {
      _logger.log(Level.SEVERE,"JACC: Unexpected security exception on access decision"
      , ex);
      return false;
  } finally {
      if (setPc) {
    try {
        setPolicyContextID(oldpcID);
    } catch(Exception ex) {
        _logger.log(Level.SEVERE,"JACC: Unexpected security exception on access decision", ex);
        return false;
    }
      }
  }

   // force resolution of unresolved permissions
   // so that we can filter out all but the permissions
   // that are supposed to be in the cache.
   resolvePermissions(pc,p);

  Enumeration granted = pc.elements();
  while (granted.hasMoreElements()) {
      Permission i = (Permission) granted.nextElement();
      if (i.equals(allPermission)) {
    nextCache.add(i);
      } else {
    boolean classMatch = true;
    if (this.classes != null) {
        classMatch = false;
        Class iClazz = i.getClass();
        for (int j=0; j<this.classes.length; j++) {
      if (this.classes[j].equals(iClazz)) {
          classMatch = true;
          break;
      }
        }
    }
    if (classMatch) {
        if (this.name != null) {
      String name = i.getName();
      if (name != null && this.name.equals(name)) {
          nextCache.add(i);
      }
        } else {
      nextCache.add(i);
        }
    }
      }
  }

  // get the writelock to mark cache as loaded
   wLock.lock();
  cache = nextCache;
  loading = false;
  try {
      // get readlock inside writelock.
      rLock.lock();
      wLock.unlock();
      // cache is loaded and readlock is held
      // check permission and return
      return checkLoadedCache(p,e);
  } finally {
      rLock.unlock();
  }
    }
   
    public boolean checkPermission(Permission p, Epoch e) {
   return checkCache(p,e);
    }
 
    public boolean checkPermission(Permission p) {
   return checkCache(p,null);
    }
  
    public synchronized void reset() {
   wLock.lock();
   try {
        if (cache != null) {
      // since cache is non-null, we know we are NOT loading
      // setting cache to null will force a (re)load
    cache = null;
    epoch = (epoch + 1 == 0) ? 1 : epoch + 1;
      }
  } finally {
       wLock.unlock();
    }
    }

    private void setPolicyContextID(final String newID)
            throws PrivilegedActionException {
        AppservAccessController.doPrivileged(new PrivilegedExceptionAction(){
            public java.lang.Object run() throws Exception{
                PolicyContext.setContextID(newID);
                return null;
            }
        });
    }

    // use implies to resolve unresolved permissions
    private void resolvePermissions(PermissionCollection pc, Permission p) {
   // each call to implies will resolve permissions of the
   // argument permission type
   if (this.protoPerms != null && this.protoPerms.length > 0) {
       for (int i=0; i<this.protoPerms.length; i++) {     
     pc.implies(this.protoPerms[i]);
        }
   } else {
       pc.implies(p);
   }
    }
}
TOP

Related Classes of com.sun.enterprise.security.PermissionCache

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.