Started working on a HostFilter. Not yet complete.

git-svn-id: https://svn.apache.org/repos/asf/incubator/jsecurity/trunk@762587 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/core/src/main/java/org/apache/ki/util/RegExPatternMatcher.java b/core/src/main/java/org/apache/ki/util/RegExPatternMatcher.java
new file mode 100644
index 0000000..c7c4253
--- /dev/null
+++ b/core/src/main/java/org/apache/ki/util/RegExPatternMatcher.java
@@ -0,0 +1,53 @@
+/*

+ * 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.

+ */

+package org.apache.ki.util;

+

+import java.util.regex.Pattern;

+import java.util.regex.Matcher;

+

+/**

+ * {@code PatternMatcher} implementation that uses standard {@link java.util.regex} objects.

+ *

+ * @see Pattern

+ * @author Les Hazlewood

+ * @since 1.0

+ */

+public class RegExPatternMatcher implements PatternMatcher {

+

+    /**

+     * Simple implementation that merely uses the default pattern comparison logic provided by the

+     * JDK.

+     * <p/>This implementation essentially executes the following:

+     * <pre>

+     * Pattern p = Pattern.compile(pattern);

+     * Matcher m = p.matcher(source);

+     * return m.matches();</pre>

+     * @param pattern the pattern to match against

+     * @param source  the source to match

+     * @return {@code true} if the source matches the required pattern, {@code false} otherwise.

+     */

+    public boolean matches(String pattern, String source) {

+        if (pattern == null) {

+            throw new IllegalArgumentException("pattern argument cannot be null.");

+        }

+        Pattern p = Pattern.compile(pattern);

+        Matcher m = p.matcher(source);

+        return m.matches();

+    }

+}

diff --git a/core/src/test/java/org/apache/ki/util/RegExPatternMatcherTest.java b/core/src/test/java/org/apache/ki/util/RegExPatternMatcherTest.java
new file mode 100644
index 0000000..704987d
--- /dev/null
+++ b/core/src/test/java/org/apache/ki/util/RegExPatternMatcherTest.java
@@ -0,0 +1,43 @@
+/*

+ * 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.

+ */

+package org.apache.ki.util;

+

+import org.junit.Test;

+import static org.junit.Assert.*;

+

+import java.util.regex.Pattern;

+

+/**

+ * Unit tests for the {@link RegExPatternMatcher}.

+ *

+ * @since 1.0

+ */

+public class RegExPatternMatcherTest {

+

+    @Test

+    public void testSimplePattern() {

+        PatternMatcher pm = new RegExPatternMatcher();

+        String pattern = "a*b";

+        String test = "aaaaaaab";

+        //not necessary for the test, but Idea performs auto validation when it sees this:

+        Pattern.compile(pattern);

+        assertTrue(pm.matches(pattern, test));

+    }

+

+}

diff --git a/web/src/main/java/org/apache/ki/web/filter/AccessControlFilter.java b/web/src/main/java/org/apache/ki/web/filter/AccessControlFilter.java
index f35ef30..386caa2 100644
--- a/web/src/main/java/org/apache/ki/web/filter/AccessControlFilter.java
+++ b/web/src/main/java/org/apache/ki/web/filter/AccessControlFilter.java
@@ -161,7 +161,6 @@
      * @throws Exception if an error occurs.
      */
     public boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
-        //mapped value is ignored - not needed for most (if not all) authc Filters.
         return isAccessAllowed(request, response, mappedValue) || onAccessDenied(request, response, mappedValue);
     }
 
diff --git a/web/src/main/java/org/apache/ki/web/filter/authz/HostFilter.java b/web/src/main/java/org/apache/ki/web/filter/authz/HostFilter.java
new file mode 100644
index 0000000..8b59a79
--- /dev/null
+++ b/web/src/main/java/org/apache/ki/web/filter/authz/HostFilter.java
@@ -0,0 +1,106 @@
+/*

+ * 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.

+ */

+package org.apache.ki.web.filter.authz;

+

+import org.apache.ki.util.StringUtils;

+

+import javax.servlet.ServletRequest;

+import javax.servlet.ServletResponse;

+import java.util.regex.Pattern;

+import java.util.Map;

+

+/**

+ * A Filter that can allow or deny access based on the host that sent the request.

+ *

+ * <b>WARNING:</b> NOT YET FULLY IMPLEMENTED!!!  Work in progress.

+ *

+ * @since 1.0

+ */

+public class HostFilter extends AuthorizationFilter {

+

+    public static final String IPV4_QUAD_REGEX = "(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2(?:[0-4][0-9]|5[0-5]))";

+

+    public static final String IPV4_REGEX = "(?:" + IPV4_QUAD_REGEX + "\\.){3}" + IPV4_QUAD_REGEX + "$";

+    public static final Pattern IPV4_PATTERN = Pattern.compile(IPV4_REGEX);

+

+    public static final String PRIVATE_CLASS_B_SUBSET = "(?:1[6-9]|2[0-9]|3[0-1])";

+

+    public static final String PRIVATE_CLASS_A_REGEX = "10\\.(?:" + IPV4_QUAD_REGEX + "\\.){2}" + IPV4_QUAD_REGEX + "$";

+

+    public static final String PRIVATE_CLASS_B_REGEX =

+            "172\\." + PRIVATE_CLASS_B_SUBSET + "\\." + IPV4_QUAD_REGEX + "\\." + IPV4_QUAD_REGEX + "$";

+

+    public static final String PRIVATE_CLASS_C_REGEX = "192\\.168\\." + IPV4_QUAD_REGEX + "\\." + IPV4_QUAD_REGEX + "$";

+

+    Map<String, String> authorizedIps; //user-configured IP (which can be wildcarded) to constructed regex mapping

+    Map<String, String> deniedIps;

+    Map<String, String> authorizedHostnames;

+    Map<String, String> deniedHostnames;

+

+

+    public void setAuthorizedHosts(String authorizedHosts) {

+        if (!StringUtils.hasText(authorizedHosts)) {

+            throw new IllegalArgumentException("authorizedHosts argument cannot be null or empty.");

+        }

+        String[] hosts = StringUtils.tokenizeToStringArray(authorizedHosts, ", \t");

+

+        for (String host : hosts) {

+            //replace any periods with \\. to ensure the regex works:

+            String periodsReplaced = host.replace(".", "\\.");

+            //check for IPv4:

+            String wildcardsReplaced = periodsReplaced.replace("*", IPV4_QUAD_REGEX);

+

+            if (IPV4_PATTERN.matcher(wildcardsReplaced).matches()) {

+                authorizedIps.put(host, wildcardsReplaced);

+            } else {

+

+            }

+

+

+        }

+

+    }

+

+    public void setDeniedHosts(String deniedHosts) {

+        if (!StringUtils.hasText(deniedHosts)) {

+            throw new IllegalArgumentException("deniedHosts argument cannot be null or empty.");

+        }

+    }

+

+    protected boolean isIpv4Candidate(String host) {

+        String[] quads = StringUtils.tokenizeToStringArray(host, ".");

+        if (quads == null || quads.length != 4) {

+            return false;

+        }

+        for (String quad : quads) {

+            if (!quad.equals("*")) {

+                try {

+                    Integer.parseInt(quad);

+                } catch (NumberFormatException nfe) {

+                    return false;

+                }

+            }

+        }

+        return true;

+    }

+

+    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {

+        throw new UnsupportedOperationException("Not yet fully implemented!!!" );

+    }

+}

diff --git a/web/src/test/java/org/apache/ki/web/filter/authz/HostFilterTest.java b/web/src/test/java/org/apache/ki/web/filter/authz/HostFilterTest.java
new file mode 100644
index 0000000..91e7fcf
--- /dev/null
+++ b/web/src/test/java/org/apache/ki/web/filter/authz/HostFilterTest.java
@@ -0,0 +1,81 @@
+/*

+ * 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.

+ */

+package org.apache.ki.web.filter.authz;

+

+import org.junit.Test;

+import static org.junit.Assert.*;

+

+import java.util.regex.Pattern;

+

+/** @since 1.0 */

+public class HostFilterTest {

+

+    @Test

+    public void testPrivateClassC() {

+        Pattern p = Pattern.compile(HostFilter.PRIVATE_CLASS_C_REGEX);

+

+        String base = "192.168.";

+

+        for (int i = 0; i < 256; i++) {

+            String ibase = base + i;

+            for (int j = 0; j < 256; j++) {

+                String ip = ibase + "." + j;

+                assertTrue(p.matcher(ip).matches());

+            }

+        }

+    }

+

+    @Test

+    public void testPrivateClassB() {

+        Pattern p = Pattern.compile(HostFilter.PRIVATE_CLASS_B_REGEX);

+

+        String base = "172.";

+

+        for (int i = 16; i < 32; i++) {

+            String ibase = base + i;

+            for (int j = 0; j < 256; j++) {

+                String jBase = ibase + "." + j;

+                for (int k = 0; k < 256; k++) {

+                    String ip = jBase + "." + k;

+                    assertTrue(p.matcher(ip).matches());

+                }

+            }

+        }

+    }

+

+    /* Takes a long time (20+ seconds?) - only enable when testing explicitly:

+    @Test

+    public void testPrivateClassA() {

+        Pattern p = Pattern.compile(HostFilter.PRIVATE_CLASS_A_REGEX);

+

+        String base = "10.";

+

+        for (int i = 0; i < 256; i++) {

+            String ibase = base + i;

+            for (int j = 0; j < 256; j++) {

+                String jBase = ibase + "." + j;

+                for (int k = 0; k < 256; k++) {

+                    String ip = jBase + "." + k;

+                    assertTrue(p.matcher(ip).matches());

+                }

+            }

+        }

+    } */

+

+}