001 /** 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one or more 004 * contributor license agreements. See the NOTICE file distributed with 005 * this work for additional information regarding copyright ownership. 006 * The ASF licenses this file to You under the Apache License, Version 2.0 007 * (the "License"); you may not use this file except in compliance with 008 * the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 package org.apache.geronimo.openejb.deployment; 019 020 import java.security.Permission; 021 import java.security.PermissionCollection; 022 import java.security.Permissions; 023 import java.util.Enumeration; 024 import java.util.List; 025 import java.util.Map; 026 027 import javax.security.jacc.EJBMethodPermission; 028 import javax.security.jacc.EJBRoleRefPermission; 029 030 import org.apache.geronimo.common.DeploymentException; 031 import org.apache.geronimo.security.jacc.ComponentPermissions; 032 import org.apache.openejb.jee.AssemblyDescriptor; 033 import org.apache.openejb.jee.ExcludeList; 034 import org.apache.openejb.jee.Method; 035 import org.apache.openejb.jee.MethodPermission; 036 import org.apache.openejb.jee.SecurityRoleRef; 037 038 public class SecurityBuilder { 039 /** 040 * Fill the container moduleBuilder with the security information that it needs 041 * to create the proper interceptors. A <code>SecurityConfiguration</code> 042 * is also filled with permissions that need to be used to fill the JACC 043 * policy configuration. 044 * 045 * @param defaultRole default role for otherwise unassigned permissions 046 * @param notAssigned the set of all possible permissions. These will be 047 * culled so that all that are left are those that have 048 * not been assigned roles. 049 * @param assemblyDescriptor the assembly descriptor 050 * @param ejbName the name of the EJB 051 * @param securityRoleRefs the EJB's role references 052 * @param componentPermissions the holder for the ejb's permissions 053 * @throws DeploymentException if any constraints are violated 054 */ 055 public void addComponentPermissions(String defaultRole, 056 PermissionCollection notAssigned, 057 AssemblyDescriptor assemblyDescriptor, 058 String ejbName, 059 List<SecurityRoleRef> securityRoleRefs, 060 ComponentPermissions componentPermissions) throws DeploymentException { 061 062 PermissionCollection uncheckedPermissions = componentPermissions.getUncheckedPermissions(); 063 PermissionCollection excludedPermissions = componentPermissions.getExcludedPermissions(); 064 Map<String, PermissionCollection> rolePermissions = componentPermissions.getRolePermissions(); 065 066 //this can occur in an ear when one ejb module has security and one doesn't. In this case we still need 067 //to make the non-secure one completely unchecked. 068 if (assemblyDescriptor != null) { 069 /** 070 * JACC v1.0 section 3.1.5.1 071 */ 072 for (MethodPermission methodPermission : assemblyDescriptor.getMethodPermission()) { 073 List<String> roleNames = methodPermission.getRoleName(); 074 boolean unchecked = methodPermission.getUnchecked(); 075 076 for (Method method : methodPermission.getMethod()) { 077 if (!ejbName.equals(method.getEjbName())) { 078 continue; 079 } 080 081 // method name 082 String methodName = method.getMethodName(); 083 if ("*".equals(methodName)) { 084 // jacc uses null instead of * 085 methodName = null; 086 } 087 // method interface 088 String methodIntf = method.getMethodIntf() == null? null: method.getMethodIntf().toString(); 089 090 // method parameters 091 String[] methodParams; 092 if (method.getMethodParams() != null) { 093 List<String> paramList = method.getMethodParams().getMethodParam(); 094 methodParams = paramList.toArray(new String[paramList.size()]); 095 } else { 096 methodParams = null; 097 } 098 099 // create the permission object 100 EJBMethodPermission permission = new EJBMethodPermission(ejbName, methodName, methodIntf, methodParams); 101 notAssigned = cullPermissions(notAssigned, permission); 102 103 // if this is unchecked, mark it as unchecked; otherwise assign the roles 104 if (unchecked) { 105 uncheckedPermissions.add(permission); 106 } else { 107 for (String roleName : roleNames) { 108 Permissions permissions = (Permissions) rolePermissions.get(roleName); 109 if (permissions == null) { 110 permissions = new Permissions(); 111 rolePermissions.put(roleName, permissions); 112 } 113 permissions.add(permission); 114 } 115 } 116 } 117 118 } 119 120 /** 121 * JACC v1.0 section 3.1.5.2 122 */ 123 ExcludeList excludeList = assemblyDescriptor.getExcludeList(); 124 if (excludeList != null) { 125 for (Method method : excludeList.getMethod()) { 126 if (!ejbName.equals(method.getEjbName())) { 127 continue; 128 } 129 130 // method name 131 String methodName = method.getMethodName(); 132 // method interface 133 String methodIntf = method.getMethodIntf() == null? null: method.getMethodIntf().toString(); 134 135 // method parameters 136 String[] methodParams; 137 if (method.getMethodParams() != null) { 138 List<String> paramList = method.getMethodParams().getMethodParam(); 139 methodParams = paramList.toArray(new String[paramList.size()]); 140 } else { 141 methodParams = null; 142 } 143 144 // create the permission object 145 EJBMethodPermission permission = new EJBMethodPermission(ejbName, methodName, methodIntf, methodParams); 146 147 excludedPermissions.add(permission); 148 notAssigned = cullPermissions(notAssigned, permission); 149 } 150 } 151 152 /** 153 * JACC v1.0 section 3.1.5.3 154 */ 155 for (SecurityRoleRef securityRoleRef : securityRoleRefs) { 156 157 String roleLink = securityRoleRef.getRoleLink() == null? securityRoleRef.getRoleName(): securityRoleRef.getRoleLink(); 158 159 PermissionCollection roleLinks = rolePermissions.get(roleLink); 160 if (roleLinks == null) { 161 roleLinks = new Permissions(); 162 rolePermissions.put(roleLink, roleLinks); 163 164 } 165 roleLinks.add(new EJBRoleRefPermission(ejbName, securityRoleRef.getRoleName())); 166 } 167 } 168 169 /** 170 * EJB v2.1 section 21.3.2 171 * <p/> 172 * It is possible that some methods are not assigned to any security 173 * roles nor contained in the <code>exclude-list</code> element. In 174 * this case, it is the responsibility of the Deployer to assign method 175 * permissions for all of the unspecified methods, either by assigning 176 * them to security roles, or by marking them as <code>unchecked</code>. 177 */ 178 PermissionCollection permissions; 179 if (defaultRole == null) { 180 permissions = uncheckedPermissions; 181 } else { 182 permissions = rolePermissions.get(defaultRole); 183 if (permissions == null) { 184 permissions = new Permissions(); 185 rolePermissions.put(defaultRole, permissions); 186 } 187 } 188 189 Enumeration e = notAssigned.elements(); 190 while (e.hasMoreElements()) { 191 Permission p = (Permission) e.nextElement(); 192 permissions.add(p); 193 } 194 195 } 196 197 /** 198 * Generate all the possible permissions for a bean's interface. 199 * <p/> 200 * Method permissions are defined in the deployment descriptor as a binary 201 * relation from the set of security roles to the set of methods of the 202 * home, component, and/or web service endpoint interfaces of session and 203 * entity beans, including all their superinterfaces (including the methods 204 * of the <code>EJBHome</code> and <code>EJBObject</code> interfaces and/or 205 * <code>EJBLocalHome</code> and <code>EJBLocalObject</code> interfaces). 206 * 207 * @param permissions the permission set to be extended 208 * @param ejbName the name of the EJB 209 * @param methodInterface the EJB method interface 210 * @param interfaceClass the class name of the interface to be used to generate the permissions 211 * @param classLoader the class loader to be used in obtaining the interface class 212 * @throws org.apache.geronimo.common.DeploymentException in case a class could not be found 213 */ 214 public void addToPermissions(PermissionCollection permissions, 215 String ejbName, 216 String methodInterface, 217 String interfaceClass, 218 ClassLoader classLoader) throws DeploymentException { 219 220 if (interfaceClass == null) { 221 return; 222 } 223 224 try { 225 Class clazz = Class.forName(interfaceClass, false, classLoader); 226 for (java.lang.reflect.Method method : clazz.getMethods()) { 227 permissions.add(new EJBMethodPermission(ejbName, methodInterface, method)); 228 } 229 } catch (ClassNotFoundException e) { 230 throw new DeploymentException(e); 231 } 232 233 } 234 235 /** 236 * Removes permissions from <code>toBeChecked</code> that are implied by 237 * <code>permission</code>. 238 * 239 * @param toBeChecked the permissions that are to be checked and possibly culled 240 * @param permission the permission that is to be used for culling 241 * @return the culled set of permissions that are not implied by <code>permission</code> 242 */ 243 private Permissions cullPermissions(PermissionCollection toBeChecked, Permission permission) { 244 Permissions result = new Permissions(); 245 246 for (Enumeration e = toBeChecked.elements(); e.hasMoreElements();) { 247 Permission test = (Permission) e.nextElement(); 248 if (!permission.implies(test)) { 249 result.add(test); 250 } 251 } 252 253 return result; 254 } 255 }