1 /**
2 *
3 * Copyright 2003-2004 The Apache Software Foundation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18
19
20
21
22
23
24 package javax.security.jacc;
25
26 import java.io.IOException;
27 import java.io.ObjectInputStream;
28 import java.io.ObjectOutputStream;
29 import java.io.Serializable;
30 import java.lang.reflect.Method;
31 import java.security.AccessController;
32 import java.security.Permission;
33 import java.security.PermissionCollection;
34 import java.security.PrivilegedAction;
35 import java.util.LinkedList;
36 import java.util.HashMap;
37 import java.util.Enumeration;
38 import java.util.Collections;
39
40 /**
41 * @version $Rev: 209985 $ $Date: 2005-07-09 20:22:20 -0700 (Sat, 09 Jul 2005) $
42 */
43 public final class EJBMethodPermission extends Permission implements Serializable {
44
45 private final static String NEW_METHOD_INTERFACES = "org.apache.security.jacc.EJBMethodPermission.methodInterfaces";
46 private static String[] methodInterfaces;
47
48 static {
49 String newMethodInterfaces = (String) AccessController.doPrivileged(new
50 PrivilegedAction() {
51 public Object run() {
52 return System.getProperty(NEW_METHOD_INTERFACES);
53 }
54 });
55
56 if (newMethodInterfaces != null) {
57 newMethodInterfaces = newMethodInterfaces + ",Home,LocalHome,Remote,Local,ServiceEndpoint";
58 } else {
59 newMethodInterfaces = "Home,LocalHome,Remote,Local,ServiceEndpoint";
60 }
61
62 methodInterfaces = newMethodInterfaces.split(",", -1);
63 }
64
65 private transient int cachedHashCode;
66 private transient MethodSpec methodSpec;
67
68 public EJBMethodPermission(String name, String spec) {
69 super(name);
70
71 methodSpec = new MethodSpec(spec);
72 }
73
74 public EJBMethodPermission(String EJBName, String methodName, String methodInterface, String[] methodParams) {
75 super(EJBName);
76
77 methodSpec = new MethodSpec(methodName, methodInterface, methodParams);
78 }
79
80 public EJBMethodPermission(String EJBName, String methodInterface, Method method) {
81 super(EJBName);
82
83 if (method == null) throw new IllegalArgumentException("Parameter method must not be null");
84
85 methodSpec = new MethodSpec(methodInterface, method);
86 }
87
88 public boolean equals(Object o) {
89 if (o == null || !(o instanceof EJBMethodPermission)) return false;
90
91 EJBMethodPermission other = (EJBMethodPermission) o;
92 return getName().equals(other.getName()) && methodSpec.equals(other.methodSpec);
93 }
94
95 public String getActions() {
96 return methodSpec.getActions();
97 }
98
99 public int hashCode() {
100 if (cachedHashCode == 0) {
101 cachedHashCode = getName().hashCode() ^ methodSpec.hashCode();
102 }
103 return cachedHashCode;
104 }
105
106 public boolean implies(Permission permission) {
107 if (permission == null || !(permission instanceof EJBMethodPermission)) return false;
108
109 EJBMethodPermission other = (EJBMethodPermission) permission;
110 return getName().equals(other.getName()) && methodSpec.implies(other.methodSpec);
111 }
112
113 public PermissionCollection newPermissionCollection() {
114 return new EJBMethodPermissionCollection();
115 }
116
117 private synchronized void readObject(ObjectInputStream in) throws IOException {
118 methodSpec = new MethodSpec(in.readUTF());
119 }
120
121 private synchronized void writeObject(ObjectOutputStream out) throws IOException {
122 out.writeUTF(methodSpec.getActions());
123 }
124
125 private static class MethodSpec {
126 protected String methodName;
127 protected String methodInterface;
128 protected String methodParams;
129 protected String actions;
130
131 public MethodSpec(String actionString) {
132 if (actionString == null || actionString.length() == 0) {
133 methodName = null;
134 methodInterface = null;
135 methodParams = null;
136 actions = "";
137 } else {
138 String[] tokens = actionString.split(",", 3);
139
140 switch (tokens.length) {
141 case 1:
142 {
143 methodName = emptyNullCheck(tokens[0]);
144 methodInterface = null;
145 methodParams = null;
146 break;
147 }
148 case 2:
149 {
150 if (tokens[1].length() == 0) throw new IllegalArgumentException("This format of actions requires a method interface");
151 checkMethodInterface(tokens[1]);
152
153 methodName = emptyNullCheck(tokens[0]);
154 methodInterface = emptyNullCheck(tokens[1]);
155 methodParams = null;
156 break;
157 }
158 case 3:
159 {
160 checkMethodInterface(tokens[1]);
161 if (tokens[2].indexOf(',') > -1) {
162 String[] test = tokens[2].split(",", -1);
163 for (int i = 0; i < test.length; i++) {
164 if (test[i].length() == 0) throw new IllegalArgumentException("Invalid type name");
165 }
166 }
167
168 methodName = emptyNullCheck(tokens[0]);
169 methodInterface = emptyNullCheck(tokens[1]);
170 methodParams = tokens[2];
171 }
172 }
173 actions = actionString;
174 }
175 }
176
177 public MethodSpec(String mthdName, String mthdInterface, String[] methodParamsArray) {
178 checkMethodInterface(mthdInterface);
179
180 methodName = emptyNullCheck(mthdName);
181 methodInterface = emptyNullCheck(mthdInterface);
182
183 if (methodParamsArray == null) {
184 methodParams = null;
185 } else if (methodParamsArray.length == 0) {
186 methodParams = "";
187 } else {
188 if (methodParamsArray[0] == null || methodParamsArray[0].length() == 0) throw new IllegalArgumentException("Invalid type name");
189
190 StringBuffer buffer = new StringBuffer(methodParamsArray[0]);
191 for (int i = 1; i < methodParamsArray.length; i++) {
192 if (methodParamsArray[i] == null || methodParamsArray[i].length() == 0) throw new IllegalArgumentException("Invalid type name");
193
194 buffer.append(",");
195 buffer.append(methodParamsArray[i]);
196 }
197 methodParams = buffer.toString();
198 }
199
200 initActions();
201 }
202
203 public MethodSpec(String mthdInterface, Method method) {
204 checkMethodInterface(mthdInterface);
205
206 methodName = method.getName();
207 methodInterface = emptyNullCheck(mthdInterface);
208
209 Class[] paramTypes = method.getParameterTypes();
210 if (paramTypes.length == 0) {
211 methodParams = "";
212 } else {
213 StringBuffer buffer = new StringBuffer(paramTypes[0].getName());
214 for (int i = 1; i < paramTypes.length; i++) {
215 buffer.append(",");
216 buffer.append(paramTypes[i].getName());
217 }
218 methodParams = buffer.toString();
219 }
220
221 initActions();
222 }
223
224 public boolean equals(MethodSpec spec) {
225 return implies(spec) && spec.implies(this);
226 }
227
228 public String getActions() {
229 return actions;
230 }
231
232 public int hashCode() {
233 return actions.hashCode();
234 }
235
236 public boolean implies(MethodSpec methodSpec) {
237 if (methodName == null || methodName.equals(methodSpec.methodName)) {
238 if (methodInterface == null || methodInterface.equals(methodSpec.methodInterface)) {
239 if (methodParams == null || methodParams.equals(methodSpec.methodParams)) {
240 return true;
241 } else
242 return false;
243 } else
244 return false;
245 } else
246 return false;
247 }
248
249 private void initActions() {
250 if (methodParams == null) {
251 if (methodInterface == null) {
252 if (methodName == null) {
253 actions = "";
254 } else {
255
256 actions = methodName;
257 }
258 } else {
259 if (methodName == null) {
260 actions = "," + methodInterface;
261 } else {
262 actions = methodName + "," + methodInterface;
263 }
264 }
265 } else {
266 if (methodInterface == null) {
267 if (methodName == null) {
268 actions = ",," + methodParams;
269 } else {
270 actions = methodName + ",," + methodParams;
271 }
272 } else {
273 if (methodName == null) {
274 actions = "," + methodInterface + "," + methodParams;
275 } else {
276 actions = methodName + "," + methodInterface + "," + methodParams;
277 }
278 }
279 }
280 }
281
282 private void checkMethodInterface(String methodInterface) {
283 if (methodInterface == null || methodInterface.length() == 0) return;
284
285 for (int i = 0; i < methodInterfaces.length; i++) {
286 if (methodInterfaces[i].equals(methodInterface)) return;
287 }
288 throw new IllegalArgumentException("Invalid method interface");
289 }
290
291 /**
292 * For the method name, method interface, and method parameters, a
293 * value of <CODE>null</CODE> indicates a wildcard value. This
294 * function is used to check if we are passed a <CODE>null</CODE>
295 * or empty string, which indicates a wildcard.
296 *
297 * @param name The name to be checked.
298 * @return <CODE>null</CODE> if we are passed a <CODE>null</CODE> or empty string else
299 * we return the name.
300 */
301 private String emptyNullCheck(String name) {
302 if (name != null && name.length() == 0) {
303 return null;
304 } else {
305 return name;
306 }
307 }
308 }
309
310 private static final class EJBMethodPermissionCollection extends PermissionCollection {
311
312 private LinkedList collection = new LinkedList();
313 private HashMap permissions = new HashMap();
314 private static final String WILDCARD = new String("$WILDCARD");
315
316 /**
317 * Adds a permission object to the current collection of permission objects.
318 *
319 * @param permission the Permission object to add.
320 *
321 * @exception SecurityException - if this PermissionCollection object
322 * has been marked readonly
323 */
324
325 public void add(Permission permission) {
326
327 if (isReadOnly()) throw new IllegalArgumentException("Read only collection");
328
329 if (!(permission instanceof EJBMethodPermission)) throw new IllegalArgumentException("Wrong permission type");
330
331 if (collection.contains(permission)) return;
332 else collection.add(permission);
333
334 EJBMethodPermission p = (EJBMethodPermission)permission;
335 EJBMethodPermission.MethodSpec spec = p.methodSpec;
336 Object test = permissions.get(p.getName());
337
338 if (test instanceof Boolean) return;
339
340 if (spec.methodName == null && spec.methodInterface == null && spec.methodParams == null) {
341 permissions.put(p.getName(), new Boolean(true));
342 return;
343 }
344
345 HashMap methods = (HashMap)test;
346 if (methods == null) {
347 methods = new HashMap();
348 permissions.put(p.getName(), methods);
349 }
350
351 Object methodKey = (spec.methodName == null || spec.methodName.length() == 0? WILDCARD:spec.methodName);
352 HashMap interfaces = (HashMap)methods.get(methodKey);
353 if (interfaces == null) {
354 interfaces = new HashMap();
355 methods.put(methodKey, interfaces);
356 }
357
358 Object interfaceKey = (spec.methodInterface == null || spec.methodInterface.length() == 0? WILDCARD:spec.methodInterface);
359 HashMap parameters = (HashMap)interfaces.get(interfaceKey);
360 if (parameters == null) {
361 parameters = new HashMap();
362 interfaces.put(interfaceKey, parameters);
363 }
364
365
366
367
368 Object parametersKey = (spec.methodParams == null? WILDCARD:spec.methodParams);
369 Object parameter = parameters.get(parametersKey);
370 if (parameter == null) {
371 parameter = new Boolean(true);
372 parameters.put(parametersKey, parameter);
373 }
374
375 }
376
377 /**
378 * Checks to see if the specified permission is implied by
379 * the collection of Permission objects held in this PermissionCollection.
380 *
381 * @param permission the Permission object to compare.
382 *
383 * @return true if "permission" is implied by the permissions in
384 * the collection, false if not.
385 */
386 public boolean implies(Permission permission) {
387
388 if (!(permission instanceof EJBMethodPermission)) return false;
389
390 EJBMethodPermission p = (EJBMethodPermission)permission;
391
392 EJBMethodPermission.MethodSpec spec = p.methodSpec;
393 Object test = permissions.get(p.getName());
394
395 if (test == null) return false;
396 if (test instanceof Boolean) return true;
397
398 HashMap methods = (HashMap)test;
399
400 Object methodKey = (spec.methodName == null || spec.methodName.length() == 0? WILDCARD:spec.methodName);
401 HashMap interfaces = (HashMap)methods.get(methodKey);
402
403 if (methodImplies(interfaces, spec)) return true;
404 if (methodKey != WILDCARD) {
405 return methodImplies((HashMap)methods.get(WILDCARD), spec);
406 }
407
408 return false;
409 }
410
411
412
413 protected boolean methodImplies(HashMap interfaces, EJBMethodPermission.MethodSpec spec) {
414
415 if (interfaces == null) return false;
416
417 Object interfaceKey = (spec.methodInterface == null || spec.methodInterface.length() == 0? WILDCARD:spec.methodInterface);
418 HashMap parameters = (HashMap)interfaces.get(interfaceKey);
419
420 if (interfaceImplies(parameters, spec)) return true;
421 if (interfaceKey != WILDCARD) {
422 return interfaceImplies((HashMap)interfaces.get(WILDCARD), spec);
423 }
424
425 return false;
426 }
427
428
429
430 protected boolean interfaceImplies(HashMap parameters, EJBMethodPermission.MethodSpec spec) {
431
432 if (parameters == null) return false;
433
434
435
436 Object parametersKey = (spec.methodParams == null? WILDCARD:spec.methodParams);
437 Object parameter = parameters.get(parametersKey);
438
439 if (parameter != null) return true;
440 if (parametersKey != WILDCARD) {
441 return parameters.containsKey(WILDCARD);
442 }
443
444 return false;
445 }
446
447
448
449 /**
450 * Returns an enumeration of all the Permission objects in the collection.
451 *
452 * @return an enumeration of all the Permissions.
453 */
454 public Enumeration elements() {
455 return Collections.enumeration(collection);
456 }
457 }
458 }
459