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 }