001: /**
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright (C) 2004-2005 Bull S.A.
004: * Contact: jonas-team@objectweb.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 6686 2005-05-03 12:55:05Z benoitf $
023: * --------------------------------------------------------------------------
024: */package org.objectweb.jonas_lib.security.jacc;
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.objectweb.common.TraceCore;
045:
046: import org.objectweb.jonas_lib.I18n;
047:
048: import org.objectweb.util.monolog.api.BasicLevel;
049: import org.objectweb.util.monolog.api.Logger;
050:
051: /**
052: * Defines the "delegating Policy provider" / JACC 2.5
053: * In J2SE 1.4 new methods can be used for dynamic permissions
054: * implies() and getPermissions() methods on Policy class were added.
055: *
056: * A replacement Policy object may accomplish this by delegating
057: * non-javax.security.jacc policy decisions to the corresponding
058: * default system Policy implementation class. A replacement
059: * Policy object that relies in this way on the corresponding
060: * default Policy implementation class must identify itself in
061: * its installation instructions as a "delegating Policy provider"
062: *
063: * JOnAS uses delegating model
064: * @author Florent Benoit
065: */
066: public class JPolicy extends Policy {
067:
068: /**
069: * Logger
070: */
071: private static Logger logger = null;
072:
073: /**
074: * Unique instance of JPolicy
075: */
076: private static JPolicy unique = null;
077:
078: /**
079: * Bootstrap Policy provider use for delegating non-jacc decisions
080: */
081: private static Policy initialPolicy = null;
082:
083: /**
084: * I18n
085: */
086: private static I18n i18n = I18n.getInstance(JPolicy.class);
087:
088: /**
089: * Reference to the JOnAS PolicyConfigurationFactory
090: * Used for retrieve parameters with interfaces not
091: * in javax.security.jacc.PolicyConfigurationFactory
092: */
093: private static PolicyConfigurationFactory policyConfigurationFactory = null;
094:
095: /**
096: * Constructor : build a policy which manage JACC permissions
097: * The non-jacc permissions are delegated to the initial Policy class
098: */
099: public JPolicy() {
100: // Retrieve existing policy
101: initialPolicy = Policy.getPolicy();
102:
103: // init logger
104: logger = TraceCore.sec;
105: }
106:
107: /**
108: * Init the PolicyConfiguration factory object used in Policy configuration
109: * @throws JPolicyException if some methods on PolicyConfigurationFactory fail
110: */
111: private void initPolicyConfigurationFactory()
112: throws JPolicyException {
113: // Check that factory is the JOnAS policy configuration factory
114: try {
115: policyConfigurationFactory = PolicyConfigurationFactory
116: .getPolicyConfigurationFactory();
117: } catch (ClassNotFoundException cnfe) {
118: throw new JPolicyException(
119: "PolicyConfigurationFactory class implementation was not found : '"
120: + cnfe.getMessage() + "'.");
121: } catch (PolicyContextException pce) {
122: throw new JPolicyException(
123: "PolicyContextException in PolicyConfigurationFactory : '"
124: + pce.getMessage() + "'.");
125: }
126:
127: }
128:
129: /**
130: * Gets the unique instance of the JACC delegating policy provider
131: * @return unique instance of the JACC delegating policy provider
132: */
133: public static JPolicy getInstance() {
134: if (unique == null) {
135: unique = new JPolicy();
136: }
137: return unique;
138: }
139:
140: // Section 4.8
141: // J2EE 1.4 container can call Policy.implies or Policy.getPermissions
142: // with an argument ProtectionDomain that was constructed with the
143: // principals of the caller.
144: // Then the caller must call implies method on the returned PermissionCollection
145:
146: /**
147: * Evaluates the global policy for the permissions granted
148: * to the ProtectionDomain and tests whether the permission is granted.
149: * @param domain the ProtectionDomain to test.
150: * @param permission the Permission object to be tested for implication.
151: * @return true if "permission" is a proper subset of a permission
152: * granted to this ProtectionDomain.
153: */
154: public boolean implies(ProtectionDomain domain,
155: Permission permission) {
156: // See 2.5 of JACC. A replacement Policy object may accomplish this
157: // by delegating non-javax.security.jacc policy decisions to the
158: // corresponding default system Policy implementation class.
159:
160: if (permission instanceof RuntimePermission
161: || permission instanceof SocketPermission) {
162: return initialPolicy.implies(domain, permission);
163: }
164:
165: // check with context ID
166: String contextID = PolicyContext.getContextID();
167: // No context, use existing
168: if (contextID == null) {
169: return initialPolicy.implies(domain, permission);
170: }
171:
172: if (!(permission instanceof EJBMethodPermission
173: || permission instanceof EJBRoleRefPermission
174: || permission instanceof WebUserDataPermission
175: || permission instanceof WebRoleRefPermission || permission instanceof WebResourcePermission)) {
176: return initialPolicy.implies(domain, permission);
177: }
178:
179: if (logger.isLoggable(BasicLevel.DEBUG)) {
180: logger
181: .log(BasicLevel.DEBUG,
182: "!= null, Permission being checked = "
183: + permission);
184: }
185:
186: // configuration was committed ?
187: try {
188: if (policyConfigurationFactory == null) {
189: initPolicyConfigurationFactory();
190: }
191:
192: if (!policyConfigurationFactory.inService(contextID)) {
193: if (logger.isLoggable(BasicLevel.DEBUG)) {
194: logger.log(BasicLevel.DEBUG,
195: "Not in service, return false");
196: }
197: return false;
198: }
199: } catch (JPolicyException jpe) {
200: if (logger.isLoggable(BasicLevel.ERROR)) {
201: logger.log(BasicLevel.ERROR, i18n
202: .getMessage("JPolicy.implies.canNotCheck", jpe
203: .getMessage()));
204: }
205: return false;
206: } catch (PolicyContextException pce) {
207: if (logger.isLoggable(BasicLevel.ERROR)) {
208: logger.log(BasicLevel.ERROR, i18n
209: .getMessage("JPolicy.implies.canNotCheck", pce
210: .getMessage()));
211: }
212: return false;
213: }
214:
215: JPolicyConfiguration jPolicyConfiguration = null;
216: try {
217: PolicyConfiguration pc = policyConfigurationFactory
218: .getPolicyConfiguration(contextID, false);
219: if (pc instanceof JPolicyConfiguration) {
220: jPolicyConfiguration = (JPolicyConfiguration) pc;
221: } else {
222: //Maybe it's a delegating policy configuration and we have a configuration for this object
223: jPolicyConfiguration = JPolicyConfigurationKeeper
224: .getConfiguration(contextID);
225: if (jPolicyConfiguration == null) {
226: throw new RuntimeException(
227: "This policy provider can only manage JPolicyConfiguration objects");
228: }
229: }
230: } catch (PolicyContextException pce) {
231: if (logger.isLoggable(BasicLevel.ERROR)) {
232: logger.log(BasicLevel.ERROR, i18n.getMessage(
233: "JPolicy.implies.canNotRetrieve", contextID,
234: pce.getMessage()));
235: }
236: return false;
237: }
238:
239: /* JACC 3.2
240: The provider must ensure that excluded policy statements take precedence
241: over overlapping unchecked policy statements, and that both excluded and
242: unchecked policy statements take precedence over overlapping role based policy
243: statements.
244: */
245: PermissionCollection excludedPermissions = jPolicyConfiguration
246: .getExcludedPermissions();
247: PermissionCollection uncheckedPermissions = jPolicyConfiguration
248: .getUncheckedPermissions();
249:
250: if (logger.isLoggable(BasicLevel.DEBUG)) {
251: logger.log(BasicLevel.DEBUG, "Check permission");
252: logger.log(BasicLevel.DEBUG, "Excluded permissions = "
253: + excludedPermissions);
254: logger.log(BasicLevel.DEBUG, "unchecked permissions = "
255: + uncheckedPermissions);
256: }
257:
258: // excluded ?
259: if (excludedPermissions.implies(permission)) {
260: if (logger.isLoggable(BasicLevel.DEBUG)) {
261: logger.log(BasicLevel.DEBUG, "Permission '"
262: + permission + "' is excluded, return false");
263: }
264: return false;
265: } else if (uncheckedPermissions.implies(permission)) { // unchecked
266: if (logger.isLoggable(BasicLevel.DEBUG)) {
267: logger.log(BasicLevel.DEBUG, "Permission '"
268: + permission + "' is unchecked, return true");
269: }
270: return true;
271: } else {
272: // per role if any or false
273: if (domain.getPrincipals().length > 0) {
274: if (logger.isLoggable(BasicLevel.DEBUG)) {
275: logger
276: .log(BasicLevel.DEBUG,
277: "There are principals, checking principals...");
278: }
279: // check roles
280: return isImpliedPermissionForPrincipals(
281: jPolicyConfiguration, permission, domain
282: .getPrincipals());
283: } else {
284: if (logger.isLoggable(BasicLevel.DEBUG)) {
285: logger
286: .log(BasicLevel.DEBUG,
287: "Principals length = 0, there is no principal on this domain");
288: }
289: // permission not found
290: if (logger.isLoggable(BasicLevel.DEBUG)) {
291: logger.log(BasicLevel.DEBUG, "Permission '"
292: + permission + "' not found, return false");
293: }
294: return false;
295: }
296: }
297: }
298:
299: /**
300: * Evaluates the global policy and returns a PermissionCollection
301: * object specifying the set of permissions allowed given the
302: * characteristics of the protection domain.
303: * @param domain the ProtectionDomain associated with the caller.
304: * @return the set of permissions allowed for the domain according
305: * to the policy.The returned set of permissions must be a
306: * new mutable instance and it must support heterogeneous
307: * Permission types.
308: */
309: public PermissionCollection getPermissions(ProtectionDomain domain) {
310:
311: // Always use delegating model
312: return initialPolicy.getPermissions(domain);
313:
314: //TODO : retrieve all permissions for a given ProtectionDomain
315: //JPolicyConfiguration jPolicyConfiguration = policyConfigurationFactory.getPolicyConfiguration(contextID);
316: //return jPolicyConfiguration.getPermissionsForDomain(domain);
317: // String contextID = PolicyContext.getContextID();
318: // // Delegating model
319: // if (contextID == null) {
320: // return initialPolicy.getPermissions(domain);
321: // } else {
322: // // not implemented as not recommended in section 4.8
323: // throw new UnsupportedOperationException("Method getPermissions with a given protection domain is not supported");
324: // }
325:
326: }
327:
328: /**
329: * Evaluates the global policy and returns a PermissionCollection
330: * object specifying the set of permissions allowed for code from
331: * the specified code source.
332: * @param codeSource the CodeSource associated with the caller.
333: * This encapsulates the original location of the code
334: * (where the code came from) and the public key(s)
335: * of its signer.
336: * @return the set of permissions allowed for code from
337: * codesource according to the policy.The returned
338: * set of permissions must be a new mutable instance
339: * and it must support heterogeneous Permission types.
340: */
341: public PermissionCollection getPermissions(CodeSource codeSource) {
342:
343: // Always use delegating model
344: return initialPolicy.getPermissions(codeSource);
345:
346: //TODO : retrieve all permissions for a given codesource
347: // String contextID = PolicyContext.getContextID();
348: // if (contextID == null) {
349: // return initialPolicy.getPermissions(codeSource);
350: // } else {
351: // // not implemented
352: // throw new UnsupportedOperationException("Method getPermissions with a given codeSource is not implemented");
353: // }
354: }
355:
356: /**
357: * Refreshes/reloads the policy configuration.
358: */
359: public void refresh() {
360: initialPolicy.refresh();
361: }
362:
363: /**
364: * Check for each principal permission if the given permission is implied
365: * @param jPolicyConfiguration JOnAS JACC PolicyConfiguration object
366: * @param permission the permission to check
367: * @param principals the array of principals on which we must retrieve permissions
368: * @return true if the given permission is implied by a role's permission
369: */
370: private boolean isImpliedPermissionForPrincipals(
371: JPolicyConfiguration jPolicyConfiguration,
372: Permission permission, Principal[] principals) {
373: //if (logger.isLoggable(BasicLevel.DEBUG)) {
374: // logger.log(BasicLevel.DEBUG, "");
375: //}
376: PermissionCollection permissions = null;
377: int i = 0;
378: boolean implied = false;
379: // for each principal's permissions check if the given permission is implied
380: while (i < principals.length && !implied) {
381: if (logger.isLoggable(BasicLevel.DEBUG)) {
382: logger.log(BasicLevel.DEBUG, "Checking permission '"
383: + permission
384: + "' with permissions of Principal '"
385: + principals[i].getName() + "'.");
386: }
387: permissions = jPolicyConfiguration
388: .getPermissionsForPrincipal(principals[i]);
389:
390: if (permissions.implies(permission)) {
391: if (logger.isLoggable(BasicLevel.DEBUG)) {
392: logger.log(BasicLevel.DEBUG,
393: "Permission implied with principal '"
394: + principals[i].getName() + "'.");
395: }
396: implied = true;
397: }
398: i++;
399: }
400: if (logger.isLoggable(BasicLevel.DEBUG)) {
401: if (!implied) {
402: logger
403: .log(
404: BasicLevel.DEBUG,
405: "Permission '"
406: + permission
407: + "' was not found in each permissions of the given roles, return false");
408: }
409: }
410: return implied;
411: }
412:
413: }
|