001: /**
002: * EasyBeans
003: * Copyright (C) 2006 Bull S.A.S.
004: * Contact: easybeans@ow2.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * --------------------------------------------------------------------------
022: * $Id: JPolicy.java 1970 2007-10-16 11:49:25Z benoitf $
023: * --------------------------------------------------------------------------
024: */package org.ow2.easybeans.security.jacc.provider;
025:
026: import java.net.SocketPermission;
027: import java.security.CodeSource;
028: import java.security.Permission;
029: import java.security.PermissionCollection;
030: import java.security.Policy;
031: import java.security.Principal;
032: import java.security.ProtectionDomain;
033:
034: import javax.security.jacc.EJBMethodPermission;
035: import javax.security.jacc.EJBRoleRefPermission;
036: import javax.security.jacc.PolicyConfiguration;
037: import javax.security.jacc.PolicyConfigurationFactory;
038: import javax.security.jacc.PolicyContext;
039: import javax.security.jacc.PolicyContextException;
040: import javax.security.jacc.WebResourcePermission;
041: import javax.security.jacc.WebRoleRefPermission;
042: import javax.security.jacc.WebUserDataPermission;
043:
044: import org.ow2.util.log.Log;
045: import org.ow2.util.log.LogFactory;
046:
047: /**
048: * Defines the "delegating Policy provider" / JACC 2.5 In J2SE 1.4 new methods
049: * can be used for dynamic permissions implies() and getPermissions() methods on
050: * Policy class were added. A replacement Policy object may accomplish this by
051: * delegating non-javax.security.jacc policy decisions to the corresponding
052: * default system Policy implementation class. A replacement Policy object that
053: * relies in this way on the corresponding default Policy implementation class
054: * must identify itself in its installation instructions as a "delegating Policy
055: * provider"<br>
056: * EasyBeans uses delegating model
057: * @author Florent Benoit
058: */
059: public final class JPolicy extends Policy {
060:
061: /**
062: * Logger.
063: */
064: private static Log logger = LogFactory.getLog(JPolicy.class);
065:
066: /**
067: * Unique instance of JPolicy.
068: */
069: private static JPolicy unique = null;
070:
071: /**
072: * Bootstrap Policy provider use for delegating non-jacc decisions.
073: */
074: private static Policy initialPolicy = null;
075:
076: /**
077: * Reference to the EasyBeans PolicyConfigurationFactory. Used for retrieve
078: * parameters with interfaces not in
079: * javax.security.jacc.PolicyConfigurationFactory
080: */
081: private static PolicyConfigurationFactory policyConfigurationFactory = null;
082:
083: /**
084: * Constructor : build a policy which manage JACC permissions. The non-jacc
085: * permissions are delegated to the initial Policy class
086: */
087: private JPolicy() {
088: // Retrieve existing policy
089: initialPolicy = Policy.getPolicy();
090:
091: }
092:
093: /**
094: * Init the PolicyConfiguration factory object used in Policy configuration.
095: * @throws JPolicyException if some methods on PolicyConfigurationFactory
096: * fail
097: */
098: private void initPolicyConfigurationFactory()
099: throws JPolicyException {
100: // Check that factory is the EasyBeans policy configuration factory
101: try {
102: policyConfigurationFactory = PolicyConfigurationFactory
103: .getPolicyConfigurationFactory();
104: } catch (ClassNotFoundException cnfe) {
105: throw new JPolicyException(
106: "PolicyConfigurationFactory class implementation was not found",
107: cnfe);
108: } catch (PolicyContextException pce) {
109: throw new JPolicyException(
110: "PolicyContextException in PolicyConfigurationFactory",
111: pce);
112: }
113:
114: // Check that the object is initialized
115: if (policyConfigurationFactory == null) {
116: throw new JPolicyException(
117: "policyConfigurationFactory object hasn't be initialized");
118: }
119:
120: }
121:
122: /**
123: * Gets the unique instance of the JACC delegating policy provider.
124: * @return unique instance of the JACC delegating policy provider
125: */
126: public static JPolicy getInstance() {
127: if (unique == null) {
128: unique = new JPolicy();
129: }
130: return unique;
131: }
132:
133: // Section 4.8
134: // J2EE 1.4 container can call Policy.implies or Policy.getPermissions
135: // with an argument ProtectionDomain that was constructed with the
136: // principals of the caller.
137: // Then the caller must call implies method on the returned
138: // PermissionCollection
139:
140: /**
141: * Evaluates the global policy for the permissions granted to the
142: * ProtectionDomain and tests whether the permission is granted.
143: * @param domain the ProtectionDomain to test.
144: * @param permission the Permission object to be tested for implication.
145: * @return true if "permission" is a proper subset of a permission granted
146: * to this ProtectionDomain.
147: */
148: @Override
149: public boolean implies(final ProtectionDomain domain,
150: final Permission permission) {
151: // See 2.5 of JACC. A replacement Policy object may accomplish this
152: // by delegating non-javax.security.jacc policy decisions to the
153: // corresponding default system Policy implementation class.
154:
155: if (permission instanceof RuntimePermission
156: || permission instanceof SocketPermission) {
157: return initialPolicy.implies(domain, permission);
158: }
159:
160: // check with context ID
161: String contextID = PolicyContext.getContextID();
162: // No context, use existing
163: if (contextID == null) {
164: return initialPolicy.implies(domain, permission);
165: }
166:
167: if (!(permission instanceof EJBMethodPermission
168: || permission instanceof EJBRoleRefPermission
169: || permission instanceof WebUserDataPermission
170: || permission instanceof WebRoleRefPermission || permission instanceof WebResourcePermission)) {
171: return initialPolicy.implies(domain, permission);
172: }
173:
174: logger.debug("Permission being checked = ''{0}''", permission);
175:
176: // configuration was committed ?
177: try {
178: if (policyConfigurationFactory == null) {
179: initPolicyConfigurationFactory();
180: }
181:
182: if (!policyConfigurationFactory.inService(contextID)) {
183: logger
184: .debug("Policy configuration factory not in service, return false");
185: return false;
186: }
187: } catch (JPolicyException jpe) {
188: logger.error("JPolicy.implies.canNotCheck", jpe);
189: return false;
190: } catch (PolicyContextException pce) {
191: logger.error("JPolicy.implies.canNotCheck", pce);
192: return false;
193: }
194:
195: JPolicyConfiguration jPolicyConfiguration = null;
196: try {
197: PolicyConfiguration pc = policyConfigurationFactory
198: .getPolicyConfiguration(contextID, false);
199: if (pc instanceof JPolicyConfiguration) {
200: jPolicyConfiguration = (JPolicyConfiguration) pc;
201: } else {
202: // Maybe it's a delegating policy configuration and we have a
203: // configuration for this object
204: jPolicyConfiguration = JPolicyConfigurationKeeper
205: .getConfiguration(contextID);
206: if (jPolicyConfiguration == null) {
207: throw new RuntimeException(
208: "This policy provider can only manage JPolicyConfiguration objects");
209: }
210: }
211: } catch (PolicyContextException pce) {
212: logger.error("JPolicy.implies.canNotRetrieve", contextID,
213: pce);
214: return false;
215: }
216:
217: /*
218: * JACC 3.2 The provider must ensure that excluded policy statements
219: * take precedence over overlapping unchecked policy statements, and
220: * that both excluded and unchecked policy statements take precedence
221: * over overlapping role based policy statements.
222: */
223: PermissionCollection excludedPermissions = jPolicyConfiguration
224: .getExcludedPermissions();
225: PermissionCollection uncheckedPermissions = jPolicyConfiguration
226: .getUncheckedPermissions();
227:
228: // debug info.
229: if (logger.isDebugEnabled()) {
230: logger.debug("Check permission");
231: logger.debug("Excluded permissions = "
232: + excludedPermissions);
233: logger.debug("unchecked permissions = "
234: + uncheckedPermissions);
235: }
236:
237: // excluded ?
238: if (excludedPermissions.implies(permission)) {
239: logger.debug(
240: "Permission ''{0}'' is excluded, return false",
241: permission);
242: return false;
243: } else if (uncheckedPermissions.implies(permission)) { // unchecked
244: logger.debug(
245: "Permission ''{0}'' is unchecked, return true",
246: permission);
247: return true;
248: } else {
249: // per role if any or false
250: if (domain.getPrincipals().length > 0) {
251: logger
252: .debug("There are principals, checking principals...");
253: // check roles
254: return isImpliedPermissionForPrincipals(
255: jPolicyConfiguration, permission, domain
256: .getPrincipals());
257: }
258: // permission not found
259: logger
260: .debug("Principals length = 0, there is no principal on this domain");
261: logger.debug("Permission ''{0}'' not found, return false",
262: permission);
263: return false;
264: }
265: }
266:
267: /**
268: * Evaluates the global policy and returns a PermissionCollection object
269: * specifying the set of permissions allowed given the characteristics of
270: * the protection domain.
271: * @param domain the ProtectionDomain associated with the caller.
272: * @return the set of permissions allowed for the domain according to the
273: * policy.The returned set of permissions must be a new mutable
274: * instance and it must support heterogeneous Permission types.
275: */
276: @Override
277: public PermissionCollection getPermissions(
278: final ProtectionDomain domain) {
279:
280: // Always use delegating model
281: return initialPolicy.getPermissions(domain);
282: }
283:
284: /**
285: * Evaluates the global policy and returns a PermissionCollection object
286: * specifying the set of permissions allowed for code from the specified
287: * code source.
288: * @param codeSource the CodeSource associated with the caller. This
289: * encapsulates the original location of the code (where the code
290: * came from) and the public key(s) of its signer.
291: * @return the set of permissions allowed for code from codesource according
292: * to the policy.The returned set of permissions must be a new
293: * mutable instance and it must support heterogeneous Permission
294: * types.
295: */
296: @Override
297: public PermissionCollection getPermissions(
298: final CodeSource codeSource) {
299:
300: // Always use delegating model
301: return initialPolicy.getPermissions(codeSource);
302: }
303:
304: /**
305: * Refreshes/reloads the policy configuration.
306: */
307: @Override
308: public void refresh() {
309: initialPolicy.refresh();
310: }
311:
312: /**
313: * Check for each principal permission if the given permission is implied.
314: * @param jPolicyConfiguration EasyBeans JACC PolicyConfiguration object
315: * @param permission the permission to check
316: * @param principals the array of principals on which we must retrieve
317: * permissions
318: * @return true if the given permission is implied by a role's permission
319: */
320: private boolean isImpliedPermissionForPrincipals(
321: final JPolicyConfiguration jPolicyConfiguration,
322: final Permission permission, final Principal[] principals) {
323: // if (logger.isLoggable(BasicLevel.DEBUG)) {
324: // logger.log(BasicLevel.DEBUG, "");
325: // }
326: PermissionCollection permissions = null;
327: int i = 0;
328: boolean implied = false;
329: // for each principal's permissions check if the given permission is
330: // implied
331: while (i < principals.length && !implied) {
332: if (logger.isDebugEnabled()) {
333: logger
334: .debug(
335: "Checking permission ''{0}'' with permissions of Principal ''{1}''.",
336: permission, principals[i].getName());
337: }
338: permissions = jPolicyConfiguration
339: .getPermissionsForPrincipal(principals[i]);
340:
341: if (permissions.implies(permission)) {
342: if (logger.isDebugEnabled()) {
343: logger
344: .debug(
345: "Permission implied with principal ''{0}''.",
346: principals[i].getName());
347: }
348: implied = true;
349: }
350: i++;
351: }
352: if (!implied) {
353: logger
354: .debug(
355: "Permission ''{0}'' was not found in each permissions of the given roles, return false",
356: permission);
357: }
358: return implied;
359: }
360:
361: }
|