001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.openejb.assembler.classic;
017:
018: import org.apache.openejb.DeploymentInfo;
019: import org.apache.openejb.InterfaceType;
020: import org.apache.openejb.OpenEJBException;
021: import org.apache.openejb.core.CoreDeploymentInfo;
022:
023: import javax.security.jacc.EJBMethodPermission;
024: import javax.security.jacc.EJBRoleRefPermission;
025: import javax.security.jacc.PolicyConfiguration;
026: import javax.security.jacc.PolicyConfigurationFactory;
027: import javax.security.jacc.PolicyContextException;
028: import java.security.Permission;
029: import java.security.PermissionCollection;
030: import java.security.Permissions;
031: import java.util.Enumeration;
032: import java.util.HashMap;
033: import java.util.List;
034: import java.util.Map;
035:
036: /**
037: * @version $Rev: 602704 $ $Date: 2007-12-09 09:58:22 -0800 $
038: */
039: public class JaccPermissionsBuilder {
040:
041: static {
042: System
043: .setProperty(
044: "org.apache.security.jacc.EJBMethodPermission.methodInterfaces",
045: "BusinessLocalHome,BusinessRemoteHome,BusinessRemote,BusinessLocal");
046: }
047:
048: public void install(PolicyContext policyContext)
049: throws OpenEJBException {
050: try {
051: PolicyConfigurationFactory factory = PolicyConfigurationFactory
052: .getPolicyConfigurationFactory();
053:
054: PolicyConfiguration policy = factory
055: .getPolicyConfiguration(policyContext
056: .getContextID(), false);
057:
058: policy.addToExcludedPolicy(policyContext
059: .getExcludedPermissions());
060:
061: policy.addToUncheckedPolicy(policyContext
062: .getUncheckedPermissions());
063:
064: for (Map.Entry<String, PermissionCollection> entry : policyContext
065: .getRolePermissions().entrySet()) {
066: policy.addToRole(entry.getKey(), entry.getValue());
067: }
068:
069: policy.commit();
070: } catch (ClassNotFoundException e) {
071: throw new OpenEJBException(
072: "PolicyConfigurationFactory class not found", e);
073: } catch (PolicyContextException e) {
074: throw new OpenEJBException(
075: "JACC PolicyConfiguration failed: ContextId="
076: + policyContext.getContextID(), e);
077: }
078: }
079:
080: public PolicyContext build(EjbJarInfo ejbJar,
081: HashMap<String, DeploymentInfo> deployments)
082: throws OpenEJBException {
083:
084: PolicyContext policyContext = new PolicyContext(ejbJar.moduleId);
085:
086: for (EnterpriseBeanInfo enterpriseBean : ejbJar.enterpriseBeans) {
087: CoreDeploymentInfo deployment = (CoreDeploymentInfo) deployments
088: .get(enterpriseBean.ejbDeploymentId);
089:
090: Permissions permissions = new Permissions();
091:
092: String ejbName = enterpriseBean.ejbName;
093:
094: for (InterfaceType type : InterfaceType.values()) {
095: if (type == InterfaceType.UNKNOWN)
096: continue;
097:
098: for (Class interfce : deployment.getInterfaces(type)) {
099: addPossibleEjbMethodPermissions(permissions,
100: ejbName, type.getSpecName(), interfce);
101: }
102: }
103: addPossibleEjbMethodPermissions(permissions, ejbName, null,
104: deployment.getBeanClass());
105:
106: addDeclaredEjbPermissions(ejbJar, enterpriseBean, null,
107: permissions, policyContext);
108:
109: }
110:
111: return policyContext;
112: }
113:
114: private void addDeclaredEjbPermissions(EjbJarInfo ejbJar,
115: EnterpriseBeanInfo beanInfo, String defaultRole,
116: Permissions notAssigned, PolicyContext policyContext)
117: throws OpenEJBException {
118:
119: PermissionCollection uncheckedPermissions = policyContext
120: .getUncheckedPermissions();
121: PermissionCollection excludedPermissions = policyContext
122: .getExcludedPermissions();
123: Map<String, PermissionCollection> rolePermissions = policyContext
124: .getRolePermissions();
125:
126: String ejbName = beanInfo.ejbName;
127:
128: //this can occur in an ear when one ejb module has security and one doesn't. In this case we still need
129: //to make the non-secure one completely unchecked.
130: /**
131: * JACC v1.0 section 3.1.5.1
132: */
133: for (MethodPermissionInfo methodPermission : ejbJar.methodPermissions) {
134: List<String> roleNames = methodPermission.roleNames;
135: boolean unchecked = methodPermission.unchecked;
136:
137: for (MethodInfo method : methodPermission.methods) {
138:
139: if (!ejbName.equals(method.ejbName)) {
140: continue;
141: }
142:
143: // method name
144: String methodName = method.methodName;
145: if ("*".equals(methodName)) {
146: // jacc uses null instead of *
147: methodName = null;
148: }
149:
150: // method interface
151: String methodIntf = method.methodIntf;
152:
153: // method parameters
154: String[] methodParams;
155: if (method.methodParams != null) {
156: List<String> paramList = method.methodParams;
157: methodParams = paramList
158: .toArray(new String[paramList.size()]);
159: } else {
160: methodParams = null;
161: }
162:
163: // create the permission object
164: EJBMethodPermission permission = new EJBMethodPermission(
165: ejbName, methodName, methodIntf, methodParams);
166: notAssigned = cullPermissions(notAssigned, permission);
167:
168: // if this is unchecked, mark it as unchecked; otherwise assign the roles
169: if (unchecked) {
170: uncheckedPermissions.add(permission);
171: } else {
172: for (String roleName : roleNames) {
173: Permissions permissions = (Permissions) rolePermissions
174: .get(roleName);
175: if (permissions == null) {
176: permissions = new Permissions();
177: rolePermissions.put(roleName, permissions);
178: }
179: permissions.add(permission);
180: }
181: }
182: }
183:
184: }
185:
186: /**
187: * JACC v1.0 section 3.1.5.2
188: */
189: for (MethodInfo method : ejbJar.excludeList) {
190: if (!ejbName.equals(method.ejbName)) {
191: continue;
192: }
193:
194: // method name
195: String methodName = method.methodName;
196: // method interface
197: String methodIntf = method.methodIntf;
198:
199: // method parameters
200: String[] methodParams;
201: if (method.methodParams != null) {
202: List<String> paramList = method.methodParams;
203: methodParams = paramList.toArray(new String[paramList
204: .size()]);
205: } else {
206: methodParams = null;
207: }
208:
209: // create the permission object
210: EJBMethodPermission permission = new EJBMethodPermission(
211: ejbName, methodName, methodIntf, methodParams);
212:
213: excludedPermissions.add(permission);
214: notAssigned = cullPermissions(notAssigned, permission);
215: }
216:
217: /**
218: * JACC v1.0 section 3.1.5.3
219: */
220: for (SecurityRoleReferenceInfo securityRoleRef : beanInfo.securityRoleReferences) {
221:
222: if (securityRoleRef.roleLink == null) {
223: throw new OpenEJBException("Missing role-link");
224: }
225:
226: String roleLink = securityRoleRef.roleLink;
227:
228: PermissionCollection roleLinks = (PermissionCollection) rolePermissions
229: .get(roleLink);
230: if (roleLinks == null) {
231: roleLinks = new Permissions();
232: rolePermissions.put(roleLink, roleLinks);
233:
234: }
235: roleLinks.add(new EJBRoleRefPermission(ejbName,
236: securityRoleRef.roleName));
237: }
238:
239: /**
240: * EJB v2.1 section 21.3.2
241: * <p/>
242: * It is possible that some methods are not assigned to any security
243: * roles nor contained in the <code>exclude-list</code> element. In
244: * this case, it is the responsibility of the Deployer to assign method
245: * permissions for all of the unspecified methods, either by assigning
246: * them to security roles, or by marking them as <code>unchecked</code>.
247: */
248: PermissionCollection permissions;
249: if (defaultRole == null) {
250: permissions = uncheckedPermissions;
251: } else {
252: permissions = (PermissionCollection) rolePermissions
253: .get(defaultRole);
254: if (permissions == null) {
255: permissions = new Permissions();
256: rolePermissions.put(defaultRole, permissions);
257: }
258: }
259:
260: Enumeration e = notAssigned.elements();
261: while (e.hasMoreElements()) {
262: Permission p = (Permission) e.nextElement();
263: permissions.add(p);
264: }
265:
266: }
267:
268: /**
269: * Generate all the possible permissions for a bean's interface.
270: * <p/>
271: * Method permissions are defined in the deployment descriptor as a binary
272: * relation from the set of security roles to the set of methods of the
273: * home, component, and/or web service endpoint interfaces of session and
274: * entity beans, including all their superinterfaces (including the methods
275: * of the <code>EJBHome</code> and <code>EJBObject</code> interfaces and/or
276: * <code>EJBLocalHome</code> and <code>EJBLocalObject</code> interfaces).
277: *
278: * @param permissions the permission set to be extended
279: * @param ejbName the name of the EJB
280: * @param methodInterface the EJB method interface
281: * @throws org.apache.openejb.OpenEJBException
282: * in case a class could not be found
283: */
284: public void addPossibleEjbMethodPermissions(
285: Permissions permissions, String ejbName,
286: String methodInterface, Class clazz)
287: throws OpenEJBException {
288: if (clazz == null)
289: return;
290: for (java.lang.reflect.Method method : clazz.getMethods()) {
291: permissions.add(new EJBMethodPermission(ejbName,
292: methodInterface, method));
293: }
294: }
295:
296: /**
297: * Removes permissions from <code>toBeChecked</code> that are implied by
298: * <code>permission</code>.
299: *
300: * @param toBeChecked the permissions that are to be checked and possibly culled
301: * @param permission the permission that is to be used for culling
302: * @return the culled set of permissions that are not implied by <code>permission</code>
303: */
304: private Permissions cullPermissions(Permissions toBeChecked,
305: Permission permission) {
306: Permissions result = new Permissions();
307:
308: for (Enumeration e = toBeChecked.elements(); e
309: .hasMoreElements();) {
310: Permission test = (Permission) e.nextElement();
311: if (!permission.implies(test)) {
312: result.add(test);
313: }
314: }
315:
316: return result;
317: }
318: }
|