/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.xacml.extensions; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.regex.Pattern; import com.sun.xacml.EvaluationCtx; import com.sun.xacml.attr.AnyURIAttribute; import com.sun.xacml.attr.AttributeValue; import com.sun.xacml.attr.BooleanAttribute; import com.sun.xacml.attr.DNSNameAttribute; import com.sun.xacml.attr.IPAddressAttribute; import com.sun.xacml.attr.RFC822NameAttribute; import com.sun.xacml.attr.StringAttribute; import com.sun.xacml.attr.X500NameAttribute; import com.sun.xacml.cond.EvaluationResult; import com.sun.xacml.cond.Expression; import com.sun.xacml.cond.FunctionBase; /** * XACML Function implementing wildcard matching * * @author Christian Mueller * */ public class WildCardFunction extends FunctionBase { /** * geotools identifier for the string-wildcard-match function. NOTE: this is a geotools specific * extension */ public static final String GEOTOOLS_FUNCTION_NS = "org:geotools:function:"; public static final String NAME_STRING_WILDCARD_MATCH = GEOTOOLS_FUNCTION_NS + "string-wildcard-match"; /** * Geotools identifier for the anyURI-wildcard-match function. */ public static final String NAME_ANYURI_WILDCARD_MATCH = GEOTOOLS_FUNCTION_NS + "anyURI-wildcard-match"; /** * Geotools identifier for the ipAddress-wildcard-match function. */ public static final String NAME_IPADDRESS_WILDCARD_MATCH = GEOTOOLS_FUNCTION_NS + "ipAddress-wildcard-match"; /** * Geotools identifier for the dnsName-wildcard-match function. */ public static final String NAME_DNSNAME_WILDCARD_MATCH = GEOTOOLS_FUNCTION_NS + "dnsName-wildcard-match"; /** * Geotools identifier for the rfc822Name-wildcard-match function. */ public static final String NAME_RFC822NAME_WILDCARD_MATCH = GEOTOOLS_FUNCTION_NS + "rfc822Name-wildcard-match"; /** * Geotools identifier for the x500Name-wildcard-match function. */ public static final String NAME_X500NAME_WILDCARD_MATCH = GEOTOOLS_FUNCTION_NS + "x500Name-wildcard-match"; // private identifiers for the supported functions private static final int ID_STRING_WILDCARD_MATCH = 0; private static final int ID_ANYURI_WILDCARD_MATCH = 1; private static final int ID_IPADDRESS_WILDCARD_MATCH = 2; private static final int ID_DNSNAME_WILDCARD_MATCH = 3; private static final int ID_RFC822NAME_WILDCARD_MATCH = 4; private static final int ID_X500NAME_WILDCARD_MATCH = 5; // private mappings for the input arguments private static final String stringWildcardParams[] = { StringAttribute.identifier, StringAttribute.identifier }; private static final String anyURIWildcardParams[] = { StringAttribute.identifier, AnyURIAttribute.identifier }; private static final String ipAddressWildcardParams[] = { StringAttribute.identifier, IPAddressAttribute.identifier }; private static final String dnsNameWildcardParams[] = { StringAttribute.identifier, DNSNameAttribute.identifier }; private static final String rfc822NameWildcardParams[] = { StringAttribute.identifier, RFC822NameAttribute.identifier }; private static final String x500NameWildcardParams[] = { StringAttribute.identifier, X500NameAttribute.identifier }; // private mapping for bag input options private static final boolean bagParams[] = { false, false }; /** * Creates a new <code>WildCardFunction</code> based on the given name. * * @param functionName * the name of the standard match function, including the complete namespace * * @throws IllegalArgumentException * if the function is unknown */ public WildCardFunction(String functionName) { super(functionName, getId(functionName), getArgumentTypes(functionName), bagParams, BooleanAttribute.identifier, false); } /** * Private helper that returns the internal identifier used for the given standard function. */ private static int getId(String functionName) { if (functionName.equals(NAME_STRING_WILDCARD_MATCH)) return ID_STRING_WILDCARD_MATCH; else if (functionName.equals(NAME_ANYURI_WILDCARD_MATCH)) return ID_ANYURI_WILDCARD_MATCH; else if (functionName.equals(NAME_IPADDRESS_WILDCARD_MATCH)) return ID_IPADDRESS_WILDCARD_MATCH; else if (functionName.equals(NAME_DNSNAME_WILDCARD_MATCH)) return ID_DNSNAME_WILDCARD_MATCH; else if (functionName.equals(NAME_RFC822NAME_WILDCARD_MATCH)) return ID_RFC822NAME_WILDCARD_MATCH; else if (functionName.equals(NAME_X500NAME_WILDCARD_MATCH)) return ID_X500NAME_WILDCARD_MATCH; throw new IllegalArgumentException("unknown match function: " + functionName); } /** * Private helper that returns the types used for the given standard function. Note that this * doesn't check on the return value since the method always is called after getId, so we assume * that the function is present. */ private static String[] getArgumentTypes(String functionName) { if (functionName.equals(NAME_STRING_WILDCARD_MATCH)) return stringWildcardParams; else if (functionName.equals(NAME_ANYURI_WILDCARD_MATCH)) return anyURIWildcardParams; else if (functionName.equals(NAME_IPADDRESS_WILDCARD_MATCH)) return ipAddressWildcardParams; else if (functionName.equals(NAME_DNSNAME_WILDCARD_MATCH)) return dnsNameWildcardParams; else if (functionName.equals(NAME_RFC822NAME_WILDCARD_MATCH)) return rfc822NameWildcardParams; else if (functionName.equals(NAME_X500NAME_WILDCARD_MATCH)) return x500NameWildcardParams; return null; } /** * Returns a <code>Set</code> containing all the function identifiers supported by this class. * * @return a <code>Set</code> of <code>String</code>s */ public static Set<String> getSupportedIdentifiers() { Set<String> set = new HashSet<String>(); set.add(NAME_STRING_WILDCARD_MATCH); set.add(NAME_ANYURI_WILDCARD_MATCH); set.add(NAME_IPADDRESS_WILDCARD_MATCH); set.add(NAME_DNSNAME_WILDCARD_MATCH); set.add(NAME_RFC822NAME_WILDCARD_MATCH); set.add(NAME_X500NAME_WILDCARD_MATCH); return set; } /** * Evaluate the function, using the specified parameters. * * @param inputs * a <code>List</code> of <code>Evaluatable</code> objects representing the arguments * passed to the function * @param context * an <code>EvaluationCtx</code> so that the <code>Evaluatable</code> objects can be * evaluated * @return an <code>EvaluationResult</code> representing the function's result */ public EvaluationResult evaluate(List<? extends Expression> inputs, EvaluationCtx context) { // Evaluate the arguments AttributeValue[] argValues = new AttributeValue[inputs.size()]; EvaluationResult result = evalArgs(inputs, context, argValues); // make sure we didn't get an error in processing the args if (result != null) return result; // now that we're setup, we can do the matching operations boolean boolResult = false; switch (getFunctionId()) { case ID_STRING_WILDCARD_MATCH: { // arg0 is a regular expression; arg1 is a general string String arg0 = ((StringAttribute) (argValues[0])).getValue(); String arg1 = ((StringAttribute) (argValues[1])).getValue(); boolResult = wildCardMatch(arg0, arg1); break; } case ID_ANYURI_WILDCARD_MATCH: { // arg0 is a regular expression; arg1 is a general string String arg0 = ((StringAttribute) (argValues[0])).getValue(); String arg1 = ((AnyURIAttribute) (argValues[1])).encode(); boolResult = wildCardMatch(arg0, arg1); break; } case ID_IPADDRESS_WILDCARD_MATCH: { // arg0 is a regular expression; arg1 is a general string String arg0 = ((StringAttribute) (argValues[0])).getValue(); String arg1 = ((IPAddressAttribute) (argValues[1])).encode(); boolResult = wildCardMatch(arg0, arg1); break; } case ID_DNSNAME_WILDCARD_MATCH: { // arg0 is a regular expression; arg1 is a general string String arg0 = ((StringAttribute) (argValues[0])).getValue(); String arg1 = ((DNSNameAttribute) (argValues[1])).encode(); boolResult = wildCardMatch(arg0, arg1); break; } case ID_RFC822NAME_WILDCARD_MATCH: { // arg0 is a regular expression; arg1 is a general string String arg0 = ((StringAttribute) (argValues[0])).getValue(); String arg1 = ((RFC822NameAttribute) (argValues[1])).encode(); boolResult = wildCardMatch(arg0, arg1); break; } case ID_X500NAME_WILDCARD_MATCH: { // arg0 is a regular expression; arg1 is a general string String arg0 = ((StringAttribute) (argValues[0])).getValue(); String arg1 = ((X500NameAttribute) (argValues[1])).encode(); boolResult = wildCardMatch(arg0, arg1); break; } } // Return the result as a BooleanAttribute. return EvaluationResult.getInstance(boolResult); } private boolean wildCardMatch(String wildcard, String testString) { String regexp = wildcardToRegex(wildcard); return Pattern.matches(regexp, testString); } private String wildcardToRegex(String wildcard) { StringBuffer s = new StringBuffer(wildcard.length()); s.append('^'); for (int i = 0, is = wildcard.length(); i < is; i++) { char c = wildcard.charAt(i); switch (c) { case '*': s.append(".*"); break; case '?': s.append("."); break; // escape special regexp-characters case '(': case ')': case '[': case ']': case '$': case '^': case '.': case '{': case '}': case '|': case '\\': s.append("\\"); s.append(c); break; default: s.append(c); break; } } s.append('$'); return (s.toString()); } }