| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| // |
| // This source code implements specifications defined by the Java |
| // Community Process. In order to remain compliant with the specification |
| // DO NOT add / change / or delete method signatures! |
| // |
| |
| package javax.security.jacc; |
| |
| import java.io.IOException; |
| import java.io.ObjectInputStream; |
| import java.io.ObjectOutputStream; |
| import java.io.Serializable; |
| import java.lang.reflect.Method; |
| import java.security.AccessController; |
| import java.security.Permission; |
| import java.security.PermissionCollection; |
| import java.security.PrivilegedAction; |
| import java.util.LinkedList; |
| import java.util.HashMap; |
| import java.util.Enumeration; |
| import java.util.Collections; |
| import java.util.HashSet; |
| |
| /** |
| * @version $Rev$ $Date$ |
| */ |
| public final class EJBMethodPermission extends Permission implements Serializable { |
| |
| private static final long serialVersionUID = 1L; |
| |
| private final static String NEW_METHOD_INTERFACES = "org.apache.security.jacc.EJBMethodPermission.methodInterfaces"; |
| private static String[] methodInterfaces; |
| |
| static { |
| String newMethodInterfaces = AccessController.doPrivileged(new |
| PrivilegedAction<String>() { |
| public String run() { |
| return System.getProperty(NEW_METHOD_INTERFACES); |
| } |
| }); |
| |
| if (newMethodInterfaces != null) { |
| newMethodInterfaces = newMethodInterfaces + ",Home,LocalHome,Remote,Local,ServiceEndpoint"; |
| } else { |
| newMethodInterfaces = "Home,LocalHome,Remote,Local,ServiceEndpoint"; |
| } |
| |
| methodInterfaces = newMethodInterfaces.split(",", -1); |
| } |
| |
| private transient int cachedHashCode; |
| private transient MethodSpec methodSpec; |
| |
| public EJBMethodPermission(String name, String spec) { |
| super(name); |
| |
| methodSpec = new MethodSpec(spec); |
| } |
| |
| public EJBMethodPermission(String EJBName, String methodName, String methodInterface, String[] methodParams) { |
| super(EJBName); |
| |
| methodSpec = new MethodSpec(methodName, methodInterface, methodParams); |
| } |
| |
| public EJBMethodPermission(String EJBName, String methodInterface, Method method) { |
| super(EJBName); |
| |
| if (method == null) throw new IllegalArgumentException("Parameter method must not be null"); |
| |
| methodSpec = new MethodSpec(methodInterface, method); |
| } |
| |
| public boolean equals(Object o) { |
| if (o == null || !(o instanceof EJBMethodPermission)) return false; |
| |
| EJBMethodPermission other = (EJBMethodPermission) o; |
| return getName().equals(other.getName()) && methodSpec.equals(other.methodSpec); |
| } |
| |
| public String getActions() { |
| return methodSpec.getActions(); |
| } |
| |
| public int hashCode() { |
| if (cachedHashCode == 0) { |
| cachedHashCode = getName().hashCode() ^ methodSpec.hashCode(); |
| } |
| return cachedHashCode; |
| } |
| |
| public boolean implies(Permission permission) { |
| if (permission == null || !(permission instanceof EJBMethodPermission)) return false; |
| |
| EJBMethodPermission other = (EJBMethodPermission) permission; |
| return getName().equals(other.getName()) && methodSpec.implies(other.methodSpec); |
| } |
| |
| public PermissionCollection newPermissionCollection() { |
| return new EJBMethodPermissionCollection(); |
| } |
| |
| private synchronized void readObject(ObjectInputStream in) throws IOException { |
| methodSpec = new MethodSpec(in.readUTF()); |
| } |
| |
| private synchronized void writeObject(ObjectOutputStream out) throws IOException { |
| out.writeUTF(methodSpec.getActions()); |
| } |
| |
| private static class MethodSpec { |
| protected String methodName; |
| protected String methodInterface; |
| protected String methodParams; |
| protected String actions; |
| |
| public MethodSpec(String actionString) { |
| if (actionString == null || actionString.length() == 0) { |
| methodName = null; |
| methodInterface = null; |
| methodParams = null; |
| actions = ""; |
| } else { |
| String[] tokens = actionString.split(",", 3); |
| |
| switch (tokens.length) { |
| case 1: |
| { |
| methodName = emptyNullCheck(tokens[0]); |
| methodInterface = null; |
| methodParams = null; |
| break; |
| } |
| case 2: |
| { |
| if (tokens[1].length() == 0) throw new IllegalArgumentException("This format of actions requires a method interface"); |
| checkMethodInterface(tokens[1]); |
| |
| methodName = emptyNullCheck(tokens[0]); |
| methodInterface = emptyNullCheck(tokens[1]); |
| methodParams = null; |
| break; |
| } |
| case 3: |
| { |
| checkMethodInterface(tokens[1]); |
| if (tokens[2].indexOf(',') > -1) { |
| String[] test = tokens[2].split(",", -1); |
| for (String aTest : test) { |
| if (aTest.length() == 0) throw new IllegalArgumentException("Invalid type name"); |
| } |
| } |
| |
| methodName = emptyNullCheck(tokens[0]); |
| methodInterface = emptyNullCheck(tokens[1]); |
| methodParams = tokens[2]; |
| } |
| } |
| actions = actionString; |
| } |
| } |
| |
| public MethodSpec(String mthdName, String mthdInterface, String[] methodParamsArray) { |
| checkMethodInterface(mthdInterface); |
| |
| methodName = emptyNullCheck(mthdName); |
| methodInterface = emptyNullCheck(mthdInterface); |
| |
| if (methodParamsArray == null) { |
| methodParams = null; |
| } else if (methodParamsArray.length == 0) { |
| methodParams = ""; |
| } else { |
| if (methodParamsArray[0] == null || methodParamsArray[0].length() == 0) throw new IllegalArgumentException("Invalid type name"); |
| |
| StringBuilder buffer = new StringBuilder(methodParamsArray[0]); |
| for (int i = 1; i < methodParamsArray.length; i++) { |
| if (methodParamsArray[i] == null || methodParamsArray[i].length() == 0) throw new IllegalArgumentException("Invalid type name"); |
| |
| buffer.append(","); |
| buffer.append(methodParamsArray[i]); |
| } |
| methodParams = buffer.toString(); |
| } |
| |
| initActions(); |
| } |
| |
| public MethodSpec(String mthdInterface, Method method) { |
| checkMethodInterface(mthdInterface); |
| |
| methodName = method.getName(); |
| methodInterface = emptyNullCheck(mthdInterface); |
| |
| Class[] paramTypes = method.getParameterTypes(); |
| if (paramTypes.length == 0) { |
| methodParams = ""; |
| } else { |
| StringBuilder buffer = new StringBuilder(paramTypes[0].getName()); |
| for (int i = 1; i < paramTypes.length; i++) { |
| buffer.append(","); |
| getName(paramTypes[i], buffer); |
| } |
| methodParams = buffer.toString(); |
| } |
| |
| initActions(); |
| } |
| |
| private static void getName(Class<?> paramType, StringBuilder buffer){ |
| if(paramType.isArray()){ |
| getName(paramType.getComponentType(), buffer); |
| buffer.append("[]"); |
| }else{ |
| buffer.append(paramType.getName()); |
| } |
| } |
| |
| |
| public boolean equals(MethodSpec spec) { |
| return implies(spec) && spec.implies(this); |
| } |
| |
| public String getActions() { |
| return actions; |
| } |
| |
| public int hashCode() { |
| return actions.hashCode(); |
| } |
| |
| public boolean implies(MethodSpec methodSpec) { |
| if (methodName == null || methodName.equals(methodSpec.methodName)) { |
| if (methodInterface == null || methodInterface.equals(methodSpec.methodInterface)) { |
| if (methodParams == null || methodParams.equals(methodSpec.methodParams)) { |
| return true; |
| } else |
| return false; |
| } else |
| return false; |
| } else |
| return false; |
| } |
| |
| private void initActions() { |
| if (methodParams == null) { |
| if (methodInterface == null) { |
| if (methodName == null) { |
| actions = ""; |
| } else { |
| |
| actions = methodName; |
| } |
| } else { |
| if (methodName == null) { |
| actions = "," + methodInterface; |
| } else { |
| actions = methodName + "," + methodInterface; |
| } |
| } |
| } else { |
| if (methodInterface == null) { |
| if (methodName == null) { |
| actions = ",," + methodParams; |
| } else { |
| actions = methodName + ",," + methodParams; |
| } |
| } else { |
| if (methodName == null) { |
| actions = "," + methodInterface + "," + methodParams; |
| } else { |
| actions = methodName + "," + methodInterface + "," + methodParams; |
| } |
| } |
| } |
| } |
| |
| private void checkMethodInterface(String methodInterface) { |
| if (methodInterface == null || methodInterface.length() == 0) return; |
| |
| for (int i = 0; i < methodInterfaces.length; i++) { |
| if (methodInterfaces[i].equals(methodInterface)) return; |
| } |
| throw new IllegalArgumentException("Invalid method interface: " + methodInterface); |
| } |
| |
| /** |
| * For the method name, method interface, and method parameters, a |
| * value of <CODE>null</CODE> indicates a wildcard value. This |
| * function is used to check if we are passed a <CODE>null</CODE> |
| * or empty string, which indicates a wildcard. |
| * |
| * @param name The name to be checked. |
| * @return <CODE>null</CODE> if we are passed a <CODE>null</CODE> or empty string else |
| * we return the name. |
| */ |
| private String emptyNullCheck(String name) { |
| if (name != null && name.length() == 0) { |
| return null; |
| } else { |
| return name; |
| } |
| } |
| } |
| |
| private static final class EJBMethodPermissionCollection extends PermissionCollection { |
| |
| private static final long serialVersionUID = -3557818912959683053L; |
| |
| private static final String WILDCARD = "$WILDCARD"; |
| private static final HashMap<String, HashMap<String, HashSet<String>>> ALL_METHODS = new HashMap<String, HashMap<String, HashSet<String>>>(); |
| private LinkedList<Permission> collection = new LinkedList<Permission>(); |
| private transient HashMap<String, HashMap<String, HashMap<String, HashSet<String>>>> permissions = new HashMap<String, HashMap<String, HashMap<String, HashSet<String>>>>(); |
| |
| /** |
| * Adds a permission object to the current collection of permission objects. |
| * |
| * @param permission the Permission object to add. |
| * |
| * @exception SecurityException - if this PermissionCollection object |
| * has been marked readonly |
| */ |
| |
| public void add(Permission permission) { |
| |
| if (isReadOnly()) throw new IllegalArgumentException("Read only collection"); |
| |
| if (!(permission instanceof EJBMethodPermission)) throw new IllegalArgumentException("Wrong permission type"); |
| |
| EJBMethodPermission p = (EJBMethodPermission)permission; |
| if (collection.contains(p)) return; |
| else collection.add(p); |
| |
| addEJBMethodPermission(p); |
| |
| } |
| |
| private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { |
| in.defaultReadObject(); |
| permissions = new HashMap<String, HashMap<String, HashMap<String, HashSet<String>>>>(); |
| for (Permission p: collection) { |
| addEJBMethodPermission((EJBMethodPermission)p); |
| } |
| } |
| |
| private void addEJBMethodPermission(EJBMethodPermission p) { |
| MethodSpec spec = p.methodSpec; |
| HashMap<String, HashMap<String, HashSet<String>>> methods = permissions.get(p.getName()); |
| |
| if (methods == ALL_METHODS) return; |
| |
| if (spec.methodName == null && spec.methodInterface == null && spec.methodParams == null) { |
| permissions.put(p.getName(), ALL_METHODS); |
| return; |
| } |
| |
| if (methods == null) { |
| methods = new HashMap<String, HashMap<String, HashSet<String>>>(); |
| permissions.put(p.getName(), methods); |
| } |
| |
| String methodKey = (spec.methodName == null || spec.methodName.length() == 0? WILDCARD:spec.methodName); |
| HashMap<String, HashSet<String>> interfaces = methods.get(methodKey); |
| if (interfaces == null) { |
| interfaces = new HashMap<String, HashSet<String>>(); |
| methods.put(methodKey, interfaces); |
| } |
| |
| String interfaceKey = (spec.methodInterface == null || spec.methodInterface.length() == 0? WILDCARD:spec.methodInterface); |
| HashSet<String> parameters = interfaces.get(interfaceKey); |
| if (parameters == null) { |
| parameters = new HashSet<String>(); |
| interfaces.put(interfaceKey, parameters); |
| } |
| |
| |
| // an empty string for a parameter spec indicates a method w/ no parameters |
| String parametersKey = (spec.methodParams == null? WILDCARD:spec.methodParams); |
| if (!parameters.contains(parametersKey)) { |
| parameters.add(parametersKey); |
| } |
| } |
| |
| /** |
| * Checks to see if the specified permission is implied by |
| * the collection of Permission objects held in this PermissionCollection. |
| * |
| * @param permission the Permission object to compare. |
| * |
| * @return true if "permission" is implied by the permissions in |
| * the collection, false if not. |
| */ |
| public boolean implies(Permission permission) { |
| |
| if (!(permission instanceof EJBMethodPermission)) return false; |
| |
| EJBMethodPermission p = (EJBMethodPermission)permission; |
| |
| EJBMethodPermission.MethodSpec spec = p.methodSpec; |
| HashMap<String, HashMap<String, HashSet<String>>> methods = permissions.get(p.getName()); |
| |
| if (methods == null) return false; |
| if (methods == ALL_METHODS) return true; |
| |
| String methodKey = (spec.methodName == null || spec.methodName.length() == 0? WILDCARD:spec.methodName); |
| HashMap<String, HashSet<String>> interfaces = methods.get(methodKey); |
| |
| if (methodImplies(interfaces, spec)) return true; |
| if (methodKey != WILDCARD) { |
| return methodImplies(methods.get(WILDCARD), spec); |
| } |
| |
| return false; |
| } |
| |
| |
| |
| protected boolean methodImplies(HashMap<String, HashSet<String>> interfaces, EJBMethodPermission.MethodSpec spec) { |
| |
| if (interfaces == null) return false; |
| |
| String interfaceKey = (spec.methodInterface == null || spec.methodInterface.length() == 0? WILDCARD:spec.methodInterface); |
| HashSet<String> parameters = interfaces.get(interfaceKey); |
| |
| if (interfaceImplies(parameters, spec)) return true; |
| if (interfaceKey != WILDCARD) { |
| return interfaceImplies(interfaces.get(WILDCARD), spec); |
| } |
| |
| return false; |
| } |
| |
| |
| |
| protected boolean interfaceImplies(HashSet<String> parameters, EJBMethodPermission.MethodSpec spec) { |
| |
| if (parameters == null) return false; |
| |
| // An empty string for a parameter spec indicates a method w/ no parameters |
| // so we won't convert an empty string to a wildcard. |
| String parametersKey = (spec.methodParams == null? WILDCARD:spec.methodParams); |
| |
| if (parameters.contains(parametersKey)) return true; |
| if (parametersKey != WILDCARD) { |
| return parameters.contains(WILDCARD); |
| } |
| |
| return false; |
| } |
| |
| |
| |
| /** |
| * Returns an enumeration of all the Permission objects in the collection. |
| * |
| * @return an enumeration of all the Permissions. |
| */ |
| public Enumeration<Permission> elements() { |
| return Collections.enumeration(collection); |
| } |
| } |
| } |
| |