org.ow2.easybeans.security.jacc.provider.JPolicy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of easybeans-jacc-provider Show documentation
Show all versions of easybeans-jacc-provider Show documentation
Implementation of JACC provider
/**
* EasyBeans
* Copyright (C) 2006 Bull S.A.S.
* Contact: [email protected]
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* --------------------------------------------------------------------------
* $Id: JPolicy.java 5369 2010-02-24 14:58:19Z benoitf $
* --------------------------------------------------------------------------
*/
package org.ow2.easybeans.security.jacc.provider;
import java.io.FilePermission;
import java.lang.reflect.ReflectPermission;
import java.net.SocketPermission;
import java.security.CodeSource;
import java.security.Permission;
import java.security.PermissionCollection;
import java.security.Policy;
import java.security.Principal;
import java.security.ProtectionDomain;
import java.util.PropertyPermission;
import javax.management.MBeanPermission;
import javax.security.jacc.EJBMethodPermission;
import javax.security.jacc.EJBRoleRefPermission;
import javax.security.jacc.PolicyConfiguration;
import javax.security.jacc.PolicyConfigurationFactory;
import javax.security.jacc.PolicyContext;
import javax.security.jacc.PolicyContextException;
import javax.security.jacc.WebResourcePermission;
import javax.security.jacc.WebRoleRefPermission;
import javax.security.jacc.WebUserDataPermission;
import org.ow2.util.log.Log;
import org.ow2.util.log.LogFactory;
/**
* Defines the "delegating Policy provider" / JACC 2.5 In J2SE 1.4 new methods
* can be used for dynamic permissions implies() and getPermissions() methods on
* Policy class were added. A replacement Policy object may accomplish this by
* delegating non-javax.security.jacc policy decisions to the corresponding
* default system Policy implementation class. A replacement Policy object that
* relies in this way on the corresponding default Policy implementation class
* must identify itself in its installation instructions as a "delegating Policy
* provider"
* EasyBeans uses delegating model
* @author Florent Benoit
*/
public final class JPolicy extends Policy {
/**
* Logger.
*/
private static Log logger = LogFactory.getLog(JPolicy.class);
/**
* Unique instance of JPolicy.
*/
private static JPolicy unique = null;
/**
* Bootstrap Policy provider use for delegating non-jacc decisions.
*/
private static Policy initialPolicy = null;
/**
* Reference to the EasyBeans PolicyConfigurationFactory. Used for retrieve
* parameters with interfaces not in
* javax.security.jacc.PolicyConfigurationFactory
*/
private static PolicyConfigurationFactory policyConfigurationFactory = null;
/**
* Constructor : build a policy which manage JACC permissions. The non-jacc
* permissions are delegated to the initial Policy class
*/
private JPolicy() {
// Retrieve existing policy
initialPolicy = Policy.getPolicy();
}
/**
* Init the PolicyConfiguration factory object used in Policy configuration.
* @throws JPolicyException if some methods on PolicyConfigurationFactory
* fail
*/
private void initPolicyConfigurationFactory() throws JPolicyException {
// Check that factory is the EasyBeans policy configuration factory
try {
policyConfigurationFactory = PolicyConfigurationFactory.getPolicyConfigurationFactory();
} catch (ClassNotFoundException cnfe) {
throw new JPolicyException("PolicyConfigurationFactory class implementation was not found", cnfe);
} catch (PolicyContextException pce) {
throw new JPolicyException("PolicyContextException in PolicyConfigurationFactory", pce);
}
// Check that the object is initialized
if (policyConfigurationFactory == null) {
throw new JPolicyException("policyConfigurationFactory object hasn't be initialized");
}
}
/**
* Gets the unique instance of the JACC delegating policy provider.
* @return unique instance of the JACC delegating policy provider
*/
public static JPolicy getInstance() {
if (unique == null) {
unique = new JPolicy();
}
return unique;
}
// Section 4.8
// J2EE 1.4 container can call Policy.implies or Policy.getPermissions
// with an argument ProtectionDomain that was constructed with the
// principals of the caller.
// Then the caller must call implies method on the returned
// PermissionCollection
/**
* Evaluates the global policy for the permissions granted to the
* ProtectionDomain and tests whether the permission is granted.
* @param domain the ProtectionDomain to test.
* @param permission the Permission object to be tested for implication.
* @return true if "permission" is a proper subset of a permission granted
* to this ProtectionDomain.
*/
@Override
public boolean implies(final ProtectionDomain domain, final Permission permission) {
// See 2.5 of JACC. A replacement Policy object may accomplish this
// by delegating non-javax.security.jacc policy decisions to the
// corresponding default system Policy implementation class.
// Something has reset the policy object, avoid NPE
if (initialPolicy == null) {
return false;
}
if (permission instanceof RuntimePermission || permission instanceof SocketPermission
|| permission instanceof PropertyPermission || permission instanceof FilePermission
|| permission instanceof MBeanPermission || permission instanceof ReflectPermission) {
return initialPolicy.implies(domain, permission);
}
// check with context ID
String contextID = PolicyContext.getContextID();
// No context, use existing
if (contextID == null) {
return initialPolicy.implies(domain, permission);
}
if (!(permission instanceof EJBMethodPermission || permission instanceof EJBRoleRefPermission
|| permission instanceof WebUserDataPermission || permission instanceof WebRoleRefPermission
|| permission instanceof WebResourcePermission)) {
return initialPolicy.implies(domain, permission);
}
logger.debug("Permission being checked = ''{0}''", permission);
// configuration was committed ?
try {
if (policyConfigurationFactory == null) {
initPolicyConfigurationFactory();
}
if (!policyConfigurationFactory.inService(contextID)) {
logger.debug("Policy configuration factory not in service, return false");
return false;
}
} catch (JPolicyException jpe) {
logger.error("JPolicy.implies.canNotCheck", jpe);
return false;
} catch (PolicyContextException pce) {
logger.error("JPolicy.implies.canNotCheck", pce);
return false;
}
JPolicyConfiguration jPolicyConfiguration = null;
try {
PolicyConfiguration pc = policyConfigurationFactory.getPolicyConfiguration(contextID, false);
if (pc instanceof JPolicyConfiguration) {
jPolicyConfiguration = (JPolicyConfiguration) pc;
} else {
// Maybe it's a delegating policy configuration and we have a
// configuration for this object
jPolicyConfiguration = JPolicyConfigurationKeeper.getConfiguration(contextID);
if (jPolicyConfiguration == null) {
throw new RuntimeException("This policy provider can only manage JPolicyConfiguration objects");
}
}
} catch (PolicyContextException pce) {
logger.error("JPolicy.implies.canNotRetrieve", contextID, pce);
return false;
}
/*
* JACC 3.2 The provider must ensure that excluded policy statements
* take precedence over overlapping unchecked policy statements, and
* that both excluded and unchecked policy statements take precedence
* over overlapping role based policy statements.
*/
PermissionCollection excludedPermissions = jPolicyConfiguration.getExcludedPermissions();
PermissionCollection uncheckedPermissions = jPolicyConfiguration.getUncheckedPermissions();
// debug info.
if (logger.isDebugEnabled()) {
logger.debug("Check permission");
logger.debug("Excluded permissions = " + excludedPermissions);
logger.debug("unchecked permissions = " + uncheckedPermissions);
}
// excluded ?
if (excludedPermissions.implies(permission)) {
logger.debug("Permission ''{0}'' is excluded, return false", permission);
return false;
} else if (uncheckedPermissions.implies(permission)) { // unchecked
logger.debug("Permission ''{0}'' is unchecked, return true", permission);
return true;
} else {
// per role if any or false
if (domain.getPrincipals().length > 0) {
logger.debug("There are principals, checking principals...");
// check roles
return isImpliedPermissionForPrincipals(jPolicyConfiguration, permission, domain.getPrincipals());
}
// permission not found
logger.debug("Principals length = 0, there is no principal on this domain");
logger.debug("Permission ''{0}'' not found, return false", permission);
return false;
}
}
/**
* Evaluates the global policy and returns a PermissionCollection object
* specifying the set of permissions allowed given the characteristics of
* the protection domain.
* @param domain the ProtectionDomain associated with the caller.
* @return the set of permissions allowed for the domain according to the
* policy.The returned set of permissions must be a new mutable
* instance and it must support heterogeneous Permission types.
*/
@Override
public PermissionCollection getPermissions(final ProtectionDomain domain) {
// Always use delegating model
return initialPolicy.getPermissions(domain);
}
/**
* Evaluates the global policy and returns a PermissionCollection object
* specifying the set of permissions allowed for code from the specified
* code source.
* @param codeSource the CodeSource associated with the caller. This
* encapsulates the original location of the code (where the code
* came from) and the public key(s) of its signer.
* @return the set of permissions allowed for code from codesource according
* to the policy.The returned set of permissions must be a new
* mutable instance and it must support heterogeneous Permission
* types.
*/
@Override
public PermissionCollection getPermissions(final CodeSource codeSource) {
// Always use delegating model
return initialPolicy.getPermissions(codeSource);
}
/**
* Refreshes/reloads the policy configuration.
*/
@Override
public void refresh() {
initialPolicy.refresh();
}
/**
* Check for each principal permission if the given permission is implied.
* @param jPolicyConfiguration EasyBeans JACC PolicyConfiguration object
* @param permission the permission to check
* @param principals the array of principals on which we must retrieve
* permissions
* @return true if the given permission is implied by a role's permission
*/
private boolean isImpliedPermissionForPrincipals(final JPolicyConfiguration jPolicyConfiguration,
final Permission permission, final Principal[] principals) {
// if (logger.isLoggable(BasicLevel.DEBUG)) {
// logger.log(BasicLevel.DEBUG, "");
// }
PermissionCollection permissions = null;
int i = 0;
boolean implied = false;
// for each principal's permissions check if the given permission is
// implied
while (i < principals.length && !implied) {
if (logger.isDebugEnabled()) {
logger.debug("Checking permission ''{0}'' with permissions of Principal ''{1}''.", permission, principals[i]
.getName());
}
permissions = jPolicyConfiguration.getPermissionsForPrincipal(principals[i]);
if (permissions.implies(permission)) {
if (logger.isDebugEnabled()) {
logger.debug("Permission implied with principal ''{0}''.", principals[i].getName());
}
implied = true;
}
i++;
}
if (!implied) {
logger.debug("Permission ''{0}'' was not found in each permissions of the given roles, return false", permission);
}
return implied;
}
}