You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jetspeed-dev@portals.apache.org by rw...@apache.org on 2014/12/23 16:30:16 UTC

svn commit: r1647594 - in /portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src: main/java/org/apache/jetspeed/pipeline/valve/ main/java/org/apache/jetspeed/pipeline/valve/impl/ test/java/org/apache/jetspeed/container/state/ test/java/org/apa...

Author: rwatler
Date: Tue Dec 23 15:30:15 2014
New Revision: 1647594

URL: http://svn.apache.org/r1647594
Log:
JS2-1309: New request filtering and security utility valves.

Added:
    portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/main/java/org/apache/jetspeed/pipeline/valve/RequestFilterValve.java
    portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/main/java/org/apache/jetspeed/pipeline/valve/impl/AbstractFilterValveImpl.java
    portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/main/java/org/apache/jetspeed/pipeline/valve/impl/RequestFilterValveImpl.java
    portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/main/java/org/apache/jetspeed/pipeline/valve/impl/SimpleSecurityValveImpl.java
    portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/test/java/org/apache/jetspeed/pipeline/valve/
    portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/test/java/org/apache/jetspeed/pipeline/valve/TestRequestFilterValve.java
    portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/test/java/org/apache/jetspeed/pipeline/valve/TestSimpleSecurityValve.java
Modified:
    portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/test/java/org/apache/jetspeed/container/state/MockRequestContext.java

Added: portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/main/java/org/apache/jetspeed/pipeline/valve/RequestFilterValve.java
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/main/java/org/apache/jetspeed/pipeline/valve/RequestFilterValve.java?rev=1647594&view=auto
==============================================================================
--- portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/main/java/org/apache/jetspeed/pipeline/valve/RequestFilterValve.java (added)
+++ portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/main/java/org/apache/jetspeed/pipeline/valve/RequestFilterValve.java Tue Dec 23 15:30:15 2014
@@ -0,0 +1,28 @@
+/*
+ * 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.jetspeed.pipeline.valve;
+
+/**
+ * This valve filters incoming requests, sending a NOT_FOUND response
+ * to requests that are filtered.
+ *
+ * @author <a href="mailto:rwatler@apache.org">Randy Watler</a>
+ * @version $Id:$
+ */
+public interface RequestFilterValve extends Valve {
+}

Added: portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/main/java/org/apache/jetspeed/pipeline/valve/impl/AbstractFilterValveImpl.java
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/main/java/org/apache/jetspeed/pipeline/valve/impl/AbstractFilterValveImpl.java?rev=1647594&view=auto
==============================================================================
--- portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/main/java/org/apache/jetspeed/pipeline/valve/impl/AbstractFilterValveImpl.java (added)
+++ portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/main/java/org/apache/jetspeed/pipeline/valve/impl/AbstractFilterValveImpl.java Tue Dec 23 15:30:15 2014
@@ -0,0 +1,117 @@
+/*
+ * 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.jetspeed.pipeline.valve.impl;
+
+import org.apache.jetspeed.pipeline.valve.AbstractValve;
+import org.springframework.util.AntPathMatcher;
+
+import java.util.List;
+
+/**
+ * Abstract valve implementation supporting request path includes
+ * and excludes.
+ *
+ * @author <a href="mailto:rwatler@apache.org">Randy Watler</a>
+ * @version $Id:$
+ */
+public abstract class AbstractFilterValveImpl extends AbstractValve {
+
+    private static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
+
+    /** List of Ant style expression include request path patterns. */
+    private List<String> includes;
+
+    /** List of Ant style expression exclude request path patterns. */
+    private List<String> excludes;
+
+    /**
+     * Test request path against includes.
+     *
+     * @param requestPath request path
+     * @return included result
+     */
+    protected boolean includesRequestPath(String requestPath) {
+        // assume request included if no includes are specified
+        if ((includes == null) || includes.isEmpty()) {
+            return true;
+        }
+        // test includes
+        for (String include : includes) {
+            if (PATH_MATCHER.match(include, requestPath)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Test request path against excludes.
+     *
+     * @param requestPath request path
+     * @return excluded result
+     */
+    protected boolean excludesRequestPath(String requestPath) {
+        // assume request not excluded if no excludes are specified
+        if ((excludes == null) || excludes.isEmpty()) {
+            return false;
+        }
+        // test excludes
+        for (String exclude : excludes) {
+            if (PATH_MATCHER.match(exclude, requestPath)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Get list of include request path patterns.
+     *
+     * @return list of Ant style expression include patterns
+     */
+    public List<String> getIncludes() {
+        return includes;
+    }
+
+    /**
+     * Set list of include request path patterns.
+     *
+     * @param includes list of Ant style expression include patterns
+     */
+    public void setIncludes(List<String> includes) {
+        this.includes = includes;
+    }
+
+    /**
+     * Get list of exclude request path patterns.
+     *
+     * @return list of Ant style expression exclude patterns
+     */
+    public List<String> getExcludes() {
+        return excludes;
+    }
+
+    /**
+     * Set list of exclude request path patterns.
+     *
+     * @param excludes list of Ant style expression exclude patterns
+     */
+    public void setExcludes(List<String> excludes) {
+        this.excludes = excludes;
+    }
+}

Added: portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/main/java/org/apache/jetspeed/pipeline/valve/impl/RequestFilterValveImpl.java
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/main/java/org/apache/jetspeed/pipeline/valve/impl/RequestFilterValveImpl.java?rev=1647594&view=auto
==============================================================================
--- portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/main/java/org/apache/jetspeed/pipeline/valve/impl/RequestFilterValveImpl.java (added)
+++ portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/main/java/org/apache/jetspeed/pipeline/valve/impl/RequestFilterValveImpl.java Tue Dec 23 15:30:15 2014
@@ -0,0 +1,86 @@
+/*
+ * 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.jetspeed.pipeline.valve.impl;
+
+import org.apache.jetspeed.pipeline.PipelineException;
+import org.apache.jetspeed.pipeline.valve.RequestFilterValve;
+import org.apache.jetspeed.pipeline.valve.ValveContext;
+import org.apache.jetspeed.request.RequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * This valve implementation filters incoming requests, sending a NOT_FOUND
+ * response to requests that are filtered.
+ *
+ * @author <a href="mailto:rwatler@apache.org">Randy Watler</a>
+ * @version $Id:$
+ */
+public class RequestFilterValveImpl extends AbstractFilterValveImpl implements RequestFilterValve {
+
+    private static final Logger log = LoggerFactory.getLogger(RequestFilterValveImpl.class);
+
+    /** Valve name. */
+    private String name;
+
+    /**
+     * Named valve constructor.
+     *
+     * @param name name of valve
+     */
+    public RequestFilterValveImpl(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public void invoke(RequestContext request, ValveContext context) throws PipelineException {
+
+        // get request path relative to pipeline/servlet path
+        String requestPath = request.getRequest().getPathInfo();
+
+        // test request path includes and excludes
+        if (!includesRequestPath(requestPath) || excludesRequestPath(requestPath)) {
+            if (log.isDebugEnabled()) {
+                log.debug("Request filtered by " + request.getPipeline().getName() + "." + name + " request path: " + requestPath);
+            }
+            try {
+                request.getResponse().sendError(HttpServletResponse.SC_NOT_FOUND);
+            } catch (IOException ioe) {
+                if (log.isDebugEnabled()) {
+                    log.error("Unexpected exception sending error for filtered request, (" + requestPath + "): " + ioe, ioe);
+                }
+            }
+            return;
+        }
+
+        // continue valve execution on pipeline
+        context.invokeNext(request);
+    }
+
+    /**
+     * Get valve name.
+     *
+     * @return valve name
+     */
+    public String getName() {
+        return name;
+    }
+}

Added: portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/main/java/org/apache/jetspeed/pipeline/valve/impl/SimpleSecurityValveImpl.java
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/main/java/org/apache/jetspeed/pipeline/valve/impl/SimpleSecurityValveImpl.java?rev=1647594&view=auto
==============================================================================
--- portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/main/java/org/apache/jetspeed/pipeline/valve/impl/SimpleSecurityValveImpl.java (added)
+++ portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/main/java/org/apache/jetspeed/pipeline/valve/impl/SimpleSecurityValveImpl.java Tue Dec 23 15:30:15 2014
@@ -0,0 +1,305 @@
+/*
+ * 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.jetspeed.pipeline.valve.impl;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.jetspeed.pipeline.PipelineException;
+import org.apache.jetspeed.pipeline.valve.SecurityValve;
+import org.apache.jetspeed.pipeline.valve.ValveContext;
+import org.apache.jetspeed.request.RequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This valve implementation filters incoming requests based on simple HTTP Basic
+ * Authentication and/or Remote IP Address.
+ *
+ * @author <a href="mailto:rwatler@apache.org">Randy Watler</a>
+ * @version $Id:$
+ */
+public class SimpleSecurityValveImpl extends AbstractFilterValveImpl implements SecurityValve {
+
+    private static final Logger log = LoggerFactory.getLogger(SimpleSecurityValveImpl.class);
+
+    public static final String HTTP_AUTHORIZATION_HEADER = "Authorization";
+    public static final String HTTP_WWW_AUTHENTICATE_HEADER = "WWW-Authenticate";
+
+    private static final String DEFAULT_AUTHENTICATION_REALM = "Jetspeed Portal";
+
+    /** Valve name. */
+    private String name;
+
+    /** HTTP Basic Authentication realm. */
+    private String authenticationRealm;
+
+    /** HTTP Basic Authentication username. */
+    private String authenticationUser;
+
+    /** HTTP Basic Authentication password MD5 HEX hash. */
+    private String authenticationPasswordHash;
+
+    /** Valid IP addresses and/or subnets. */
+    private List<String> validIPAddresses;
+
+    /** Parsed valid IP addresses. */
+    private List<ValidIPAddress> parsedValidIPAddresses = new ArrayList<ValidIPAddress>();
+
+    /**
+     * Named valve constructor.
+     *
+     * @param name name of valve
+     */
+    public SimpleSecurityValveImpl(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public void invoke(RequestContext request, ValveContext context) throws PipelineException {
+
+        // get request path relative to pipeline/servlet path
+        String requestPath = request.getRequest().getPathInfo();
+
+        // test request path includes and excludes
+        if (includesRequestPath(requestPath) && !excludesRequestPath(requestPath)) {
+
+            // check HTTP Basic Authentication
+            if (authenticationRealm != null) {
+                boolean authorized = false;
+                String authorizationHeader = request.getRequest().getHeader(HTTP_AUTHORIZATION_HEADER);
+                if ((authorizationHeader != null) && (authorizationHeader.startsWith("Basic "))) {
+                    authorizationHeader = authorizationHeader.substring(6);
+                    try {
+                        authorizationHeader = new String(Base64.decodeBase64(authorizationHeader), "UTF-8");
+                    } catch (Exception e) {
+                        authorizationHeader = null;
+                    }
+                    if ((authorizationHeader != null) && !authorizationHeader.isEmpty()) {
+                        String[] authorizationCredentials = authorizationHeader.split(":");
+                        if ((authorizationCredentials.length == 2) && authenticationUser.equals(authorizationCredentials[0])) {
+                            String authorizationCredentialsPasswordHash = DigestUtils.md5Hex(authorizationCredentials[1]);
+                            authorized = authorizationCredentialsPasswordHash.equalsIgnoreCase(authenticationPasswordHash);
+                        }
+                    }
+                }
+                if (!authorized) {
+                    if (log.isDebugEnabled()) {
+                        log.debug("Request filtered by " + request.getPipeline().getName() + "." + name + " authorization: " + authorizationHeader);
+                    }
+                    try {
+                        request.getResponse().setHeader(HTTP_WWW_AUTHENTICATE_HEADER, "Basic realm=\"" + authenticationRealm + "\"");
+                        request.getResponse().sendError(HttpServletResponse.SC_UNAUTHORIZED);
+                    } catch (IOException ioe) {
+                        if (log.isDebugEnabled()) {
+                            log.error("Unexpected exception sending error for filtered request, (" + request.getRequest().getPathInfo() + "): " + ioe, ioe);
+                        }
+                    }
+                    return;
+                }
+            }
+
+            // check valid remote IP address
+            if (!parsedValidIPAddresses.isEmpty()) {
+                String remoteIPAddress = request.getRequest().getRemoteAddr();
+                boolean valid = false;
+                try {
+                    int remoteIP = getIP(remoteIPAddress);
+                    for (ValidIPAddress validIPAddress : parsedValidIPAddresses) {
+                        if (validIPAddress.matchIP(remoteIP)) {
+                            valid = true;
+                            break;
+                        }
+                    }
+                } catch (Exception e) {
+                }
+                if (!valid) {
+                    if (log.isDebugEnabled()) {
+                        log.debug("Request filtered by " + request.getPipeline().getName() + "." + name + " IP address: " + remoteIPAddress);
+                    }
+                    try {
+                        request.getResponse().sendError(HttpServletResponse.SC_FORBIDDEN);
+                    } catch (IOException ioe) {
+                        if (log.isDebugEnabled()) {
+                            log.error("Unexpected exception sending error for filtered request, (" + request.getRequest().getPathInfo() + "): " + ioe, ioe);
+                        }
+                    }
+                    return;
+                }
+            }
+        }
+
+        // continue valve execution on pipeline
+        context.invokeNext(request);
+    }
+
+    @Override
+    public void initialize() throws PipelineException {
+
+        // validate HTTP Basic Authentication configuration
+        if ((authenticationUser != null) && !authenticationUser.isEmpty() && (authenticationPasswordHash != null) && !authenticationPasswordHash.isEmpty()) {
+            if ((authenticationRealm == null) || authenticationRealm.isEmpty()) {
+                authenticationRealm = DEFAULT_AUTHENTICATION_REALM;
+            }
+        } else {
+            authenticationRealm = null;
+            authenticationUser = null;
+            authenticationPasswordHash = null;
+        }
+
+        // setup valid IP addresses configuration
+        if ((validIPAddresses != null) && !validIPAddresses.isEmpty()) {
+            for (String validIPAddress : validIPAddresses) {
+                try {
+                    parsedValidIPAddresses.add(new ValidIPAddress(validIPAddress));
+                } catch (Exception e) {
+                    log.error("SimpleSecurityValve: unable to parse valid IP address '"+validIPAddress+"': " + e, e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Get valve name.
+     *
+     * @return valve name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Get HTTP Basic Authentication realm.
+     *
+     * @return HTTP Basic Authentication realm
+     */
+    public String getAuthenticationRealm() {
+        return authenticationRealm;
+    }
+
+    /**
+     * Set HTTP Basic Authentication realm.
+     *
+     * @param authenticationRealm HTTP Basic Authentication realm
+     */
+    public void setAuthenticationRealm(String authenticationRealm) {
+        this.authenticationRealm = authenticationRealm;
+    }
+
+    /**
+     * Get HTTP Basic Authentication username.
+     *
+     * @return HTTP Basic Authentication username
+     */
+    public String getAuthenticationUser() {
+        return authenticationUser;
+    }
+
+    /**
+     * Set HTTP Basic Authentication username.
+     *
+     * @param authenticationUser HTTP Basic Authentication username
+     */
+    public void setAuthenticationUser(String authenticationUser) {
+        this.authenticationUser = authenticationUser;
+    }
+
+    /**
+     * Get HTTP Basic Authentication password MD5 HEX hash.
+     *
+     * @return HTTP Basic Authentication password MD5 HEX hash
+     */
+    public String getAuthenticationPasswordHash() {
+        return authenticationPasswordHash;
+    }
+
+    /**
+     * Set HTTP Basic Authentication password MD5 HEX hash.
+     *
+     * @param authenticationPasswordHash HTTP Basic Authentication password MD5 HEX hash
+     */
+    public void setAuthenticationPasswordHash(String authenticationPasswordHash) {
+        this.authenticationPasswordHash = authenticationPasswordHash;
+    }
+
+    /**
+     * Get valid IP addresses and/or subnets.
+     *
+     * @return list of valid IP addresses and/or subnets
+     */
+    public List<String> getValidIPAddresses() {
+        return validIPAddresses;
+    }
+
+    /**
+     * Set valid IP addresses and/or subnets.
+     *
+     * @param validIPAddresses list of valid IP addresses and/or subnets
+     */
+    public void setValidIPAddresses(List<String> validIPAddresses) {
+        this.validIPAddresses = validIPAddresses;
+    }
+
+    /**
+     * Class used to capture IPV4 addresses and subnets for matching tests.
+     */
+    private static class ValidIPAddress {
+        private int mask;
+        private int ip;
+
+        private ValidIPAddress(String validIPAddress) throws UnknownHostException {
+            int bitsIndex = validIPAddress.indexOf("/");
+            if (bitsIndex != -1) {
+                int bits = Integer.parseInt(validIPAddress.substring(bitsIndex+1));
+                this.mask = -1 << (32 - bits);
+                validIPAddress = validIPAddress.substring(0, bitsIndex);
+            } else {
+                this.mask = -1;
+            }
+            this.ip = getIP(validIPAddress) & this.mask;
+        }
+
+        private boolean matchIP(int testIP) {
+            return ((testIP & mask) == ip);
+        }
+    }
+
+    /**
+     * Convert string IPV4 address to int representation which is easier to mask.
+     *
+     * @param ipAddress String IPV4 address
+     * @return int address
+     * @throws UnknownHostException
+     */
+    private static int getIP(String ipAddress) throws UnknownHostException {
+        InetAddress inetAddress = InetAddress.getByName(ipAddress);
+        if (inetAddress instanceof Inet4Address) {
+            byte [] bytes = ((Inet4Address)inetAddress).getAddress();
+            return ((bytes[0] & 0xFF) << 24) | ((bytes[1] & 0xFF) << 16) | ((bytes[2] & 0xFF) << 8) | ((bytes[3] & 0xFF) << 0);
+        } else {
+            throw new UnknownHostException(ipAddress);
+        }
+    }
+}

Modified: portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/test/java/org/apache/jetspeed/container/state/MockRequestContext.java
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/test/java/org/apache/jetspeed/container/state/MockRequestContext.java?rev=1647594&r1=1647593&r2=1647594&view=diff
==============================================================================
--- portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/test/java/org/apache/jetspeed/container/state/MockRequestContext.java (original)
+++ portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/test/java/org/apache/jetspeed/container/state/MockRequestContext.java Tue Dec 23 15:30:15 2014
@@ -17,18 +17,6 @@
 
 package org.apache.jetspeed.container.state;
 
-import java.security.Principal;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
-import javax.security.auth.Subject;
-import javax.servlet.ServletConfig;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
 import org.apache.jetspeed.capabilities.CapabilityMap;
 import org.apache.jetspeed.container.PortletWindow;
 import org.apache.jetspeed.container.url.PortalURL;
@@ -44,6 +32,17 @@ import org.apache.jetspeed.request.Reque
 import org.apache.jetspeed.util.KeyValue;
 import org.apache.jetspeed.window.MockPortletWindow;
 
+import javax.security.auth.Subject;
+import javax.servlet.ServletConfig;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.security.Principal;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
 /**
  * @version $Id$
  *
@@ -52,6 +51,7 @@ public class MockRequestContext implemen
 {
     
     private HttpServletRequest request;
+    private HttpServletResponse response;
     private final Map<String, PortletWindow> portletWindows = new HashMap<String, PortletWindow>();
     
     public void addPortletWindow(PortletWindow window)
@@ -269,8 +269,7 @@ public class MockRequestContext implemen
      */
     public HttpServletResponse getResponse()
     {
-        // TODO Auto-generated method stub
-        return null;
+        return response;
     }
 
     /* (non-Javadoc)
@@ -453,7 +452,7 @@ public class MockRequestContext implemen
      */
     public void setResponse(HttpServletResponse response)
     {
-        // TODO Auto-generated method stub
+        this.response = response;
     }
 
     /* (non-Javadoc)

Added: portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/test/java/org/apache/jetspeed/pipeline/valve/TestRequestFilterValve.java
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/test/java/org/apache/jetspeed/pipeline/valve/TestRequestFilterValve.java?rev=1647594&view=auto
==============================================================================
--- portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/test/java/org/apache/jetspeed/pipeline/valve/TestRequestFilterValve.java (added)
+++ portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/test/java/org/apache/jetspeed/pipeline/valve/TestRequestFilterValve.java Tue Dec 23 15:30:15 2014
@@ -0,0 +1,121 @@
+/*
+ * 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.jetspeed.pipeline.valve;
+
+import com.mockrunner.mock.web.MockHttpServletRequest;
+import com.mockrunner.mock.web.MockHttpServletResponse;
+import junit.framework.TestCase;
+import org.apache.jetspeed.container.state.MockRequestContext;
+import org.apache.jetspeed.pipeline.PipelineException;
+import org.apache.jetspeed.pipeline.valve.impl.RequestFilterValveImpl;
+import org.apache.jetspeed.request.RequestContext;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.Arrays;
+
+/**
+ * Test for RequestFilterValve implementation.
+ *
+ * @author <a href="mailto:rwatler@apache.org">Randy Watler</a>
+ * @version $Id:$
+ */
+public class TestRequestFilterValve extends TestCase {
+
+    /**
+     * Test RequestFilterValveImpl implementation.
+     *
+     * @throws Exception on unexpected exception
+     */
+    public void testRequestFilterValve() throws Exception {
+
+        // test default filtering
+        RequestFilterValve valve = new RequestFilterValveImpl("test-valve");
+        RequestContext requestContext = createRequestContext("/include");
+        StubValveContext valveContext = new StubValveContext();
+        valve.invoke(requestContext, valveContext);
+        assertFalse(((MockHttpServletResponse) requestContext.getResponse()).wasErrorSent());
+        assertTrue(valveContext.nextInvoked);
+
+        // test include/exclude filtering
+        valve = new RequestFilterValveImpl("test-valve");
+        ((RequestFilterValveImpl)valve).setIncludes(Arrays.asList(new String[]{"/include/**"}));
+        ((RequestFilterValveImpl)valve).setExcludes(Arrays.asList(new String[]{"/include/exclude/**"}));
+        requestContext = createRequestContext("/include/include");
+        valveContext = new StubValveContext();
+        valve.invoke(requestContext, valveContext);
+        assertFalse(((MockHttpServletResponse) requestContext.getResponse()).wasErrorSent());
+        assertTrue(valveContext.nextInvoked);
+        requestContext = createRequestContext("/exclude");
+        valveContext = new StubValveContext();
+        valve.invoke(requestContext, valveContext);
+        assertTrue(((MockHttpServletResponse) requestContext.getResponse()).wasErrorSent());
+        assertEquals(HttpServletResponse.SC_NOT_FOUND, ((MockHttpServletResponse) requestContext.getResponse()).getErrorCode());
+        assertFalse(valveContext.nextInvoked);
+        requestContext = createRequestContext("/include/exclude/exclude");
+        valveContext = new StubValveContext();
+        valve.invoke(requestContext, valveContext);
+        assertTrue(((MockHttpServletResponse) requestContext.getResponse()).wasErrorSent());
+        assertEquals(HttpServletResponse.SC_NOT_FOUND, ((MockHttpServletResponse) requestContext.getResponse()).getErrorCode());
+        assertFalse(valveContext.nextInvoked);
+
+        // test exclude filtering
+        valve = new RequestFilterValveImpl("test-valve");
+        ((RequestFilterValveImpl)valve).setIncludes(null);
+        ((RequestFilterValveImpl)valve).setExcludes(Arrays.asList(new String[]{"/exclude/**"}));
+        requestContext = createRequestContext("/include");
+        valveContext = new StubValveContext();
+        valve.invoke(requestContext, valveContext);
+        assertFalse(((MockHttpServletResponse) requestContext.getResponse()).wasErrorSent());
+        assertTrue(valveContext.nextInvoked);
+        requestContext = createRequestContext("/exclude");
+        valveContext = new StubValveContext();
+        valve.invoke(requestContext, valveContext);
+        assertTrue(((MockHttpServletResponse) requestContext.getResponse()).wasErrorSent());
+        assertEquals(HttpServletResponse.SC_NOT_FOUND, ((MockHttpServletResponse) requestContext.getResponse()).getErrorCode());
+        assertFalse(valveContext.nextInvoked);
+    }
+
+    /**
+     * Create mock RequestContext with the specified HttpServletRequest pathInfo.
+     *
+     * @param pathInfo request pathInfo
+     * @return mock RequestContext
+     */
+    private RequestContext createRequestContext(String pathInfo) {
+        MockHttpServletRequest servletRequest = new MockHttpServletRequest();
+        servletRequest.setPathInfo(pathInfo);
+        MockHttpServletResponse servletResponse = new MockHttpServletResponse();
+        RequestContext requestContext = new MockRequestContext();
+        requestContext.setRequest(servletRequest);
+        requestContext.setResponse(servletResponse);
+        return requestContext;
+    }
+
+    /**
+     * Stub ValveContext implementation that tracks ValveContext.invokeNext() invocations.
+     */
+    private class StubValveContext implements ValveContext {
+
+        private boolean nextInvoked;
+
+        @Override
+        public void invokeNext(RequestContext request) throws PipelineException {
+            nextInvoked = true;
+        }
+    }
+}

Added: portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/test/java/org/apache/jetspeed/pipeline/valve/TestSimpleSecurityValve.java
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/test/java/org/apache/jetspeed/pipeline/valve/TestSimpleSecurityValve.java?rev=1647594&view=auto
==============================================================================
--- portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/test/java/org/apache/jetspeed/pipeline/valve/TestSimpleSecurityValve.java (added)
+++ portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/test/java/org/apache/jetspeed/pipeline/valve/TestSimpleSecurityValve.java Tue Dec 23 15:30:15 2014
@@ -0,0 +1,170 @@
+/*
+ * 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.jetspeed.pipeline.valve;
+
+import com.mockrunner.mock.web.MockHttpServletRequest;
+import com.mockrunner.mock.web.MockHttpServletResponse;
+import junit.framework.TestCase;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.jetspeed.container.state.MockRequestContext;
+import org.apache.jetspeed.pipeline.PipelineException;
+import org.apache.jetspeed.pipeline.valve.impl.SimpleSecurityValveImpl;
+import org.apache.jetspeed.request.RequestContext;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+
+/**
+ * Test for simple SecurityValve implementation.
+ *
+ * @author <a href="mailto:rwatler@apache.org">Randy Watler</a>
+ * @version $Id:$
+ */
+public class TestSimpleSecurityValve extends TestCase {
+
+    /**
+     * Test SimpleSecurityValveImpl implementation.
+     *
+     * @throws Exception on unexpected exception
+     */
+    public void testRequestFilterValve() throws Exception {
+
+        // test default configuration
+        SecurityValve valve = new SimpleSecurityValveImpl("test-valve");
+        valve.initialize();
+        RequestContext requestContext = createRequestContext("/test", "127.0.0.1", null, null);
+        StubValveContext valveContext = new StubValveContext();
+        valve.invoke(requestContext, valveContext);
+        assertNull(((MockHttpServletResponse) requestContext.getResponse()).getHeader(SimpleSecurityValveImpl.HTTP_WWW_AUTHENTICATE_HEADER));
+        assertFalse(((MockHttpServletResponse) requestContext.getResponse()).wasErrorSent());
+        assertTrue(valveContext.nextInvoked);
+
+        // test HTTP Basic Authentication configuration
+        valve = new SimpleSecurityValveImpl("test-valve");
+        ((SimpleSecurityValveImpl)valve).setIncludes(Arrays.asList(new String[]{"/include/**"}));
+        ((SimpleSecurityValveImpl)valve).setAuthenticationRealm("test-realm");
+        ((SimpleSecurityValveImpl)valve).setAuthenticationUser("test-user");
+        ((SimpleSecurityValveImpl)valve).setAuthenticationPasswordHash(DigestUtils.md5Hex("test-password"));
+        valve.initialize();
+        requestContext = createRequestContext("/include/test", "127.0.0.1", "test-user", "test-password");
+        valveContext = new StubValveContext();
+        valve.invoke(requestContext, valveContext);
+        assertNull(((MockHttpServletResponse) requestContext.getResponse()).getHeader(SimpleSecurityValveImpl.HTTP_WWW_AUTHENTICATE_HEADER));
+        assertFalse(((MockHttpServletResponse) requestContext.getResponse()).wasErrorSent());
+        assertTrue(valveContext.nextInvoked);
+        requestContext = createRequestContext("/include/test", "127.0.0.1", null, null);
+        valveContext = new StubValveContext();
+        valve.invoke(requestContext, valveContext);
+        assertEquals("Basic realm=\"test-realm\"", ((MockHttpServletResponse) requestContext.getResponse()).getHeader(SimpleSecurityValveImpl.HTTP_WWW_AUTHENTICATE_HEADER));
+        assertTrue(((MockHttpServletResponse) requestContext.getResponse()).wasErrorSent());
+        assertEquals(HttpServletResponse.SC_UNAUTHORIZED, ((MockHttpServletResponse) requestContext.getResponse()).getErrorCode());
+        assertFalse(valveContext.nextInvoked);
+        requestContext = createRequestContext("/include/test", "127.0.0.1", "not-test-user", "not-test-password");
+        valveContext = new StubValveContext();
+        valve.invoke(requestContext, valveContext);
+        assertEquals("Basic realm=\"test-realm\"", ((MockHttpServletResponse) requestContext.getResponse()).getHeader(SimpleSecurityValveImpl.HTTP_WWW_AUTHENTICATE_HEADER));
+        assertTrue(((MockHttpServletResponse) requestContext.getResponse()).wasErrorSent());
+        assertEquals(HttpServletResponse.SC_UNAUTHORIZED, ((MockHttpServletResponse) requestContext.getResponse()).getErrorCode());
+        assertFalse(valveContext.nextInvoked);
+        requestContext = createRequestContext("/exclude/test", "127.0.0.1", null, null);
+        valveContext = new StubValveContext();
+        valve.invoke(requestContext, valveContext);
+        assertNull(((MockHttpServletResponse) requestContext.getResponse()).getHeader(SimpleSecurityValveImpl.HTTP_WWW_AUTHENTICATE_HEADER));
+        assertFalse(((MockHttpServletResponse) requestContext.getResponse()).wasErrorSent());
+        assertTrue(valveContext.nextInvoked);
+
+        // test valid IP Address configuration
+        valve = new SimpleSecurityValveImpl("test-valve");
+        ((SimpleSecurityValveImpl)valve).setIncludes(Arrays.asList(new String[]{"/include/**"}));
+        ((SimpleSecurityValveImpl)valve).setExcludes(Arrays.asList(new String[]{"/include/exclude/**"}));
+        ((SimpleSecurityValveImpl)valve).setValidIPAddresses(Arrays.asList(new String[]{"127.0.0.1", "10.0.0.0/8"}));
+        valve.initialize();
+        requestContext = createRequestContext("/include/test", "127.0.0.1", null, null);
+        valveContext = new StubValveContext();
+        valve.invoke(requestContext, valveContext);
+        assertNull(((MockHttpServletResponse) requestContext.getResponse()).getHeader(SimpleSecurityValveImpl.HTTP_WWW_AUTHENTICATE_HEADER));
+        assertFalse(((MockHttpServletResponse) requestContext.getResponse()).wasErrorSent());
+        assertTrue(valveContext.nextInvoked);
+        requestContext = createRequestContext("/include/test", "10.0.0.23", null, null);
+        valveContext = new StubValveContext();
+        valve.invoke(requestContext, valveContext);
+        assertNull(((MockHttpServletResponse) requestContext.getResponse()).getHeader(SimpleSecurityValveImpl.HTTP_WWW_AUTHENTICATE_HEADER));
+        assertFalse(((MockHttpServletResponse) requestContext.getResponse()).wasErrorSent());
+        assertTrue(valveContext.nextInvoked);
+        requestContext = createRequestContext("/include/test", "173.194.79.105", null, null);
+        valveContext = new StubValveContext();
+        valve.invoke(requestContext, valveContext);
+        assertNull(((MockHttpServletResponse) requestContext.getResponse()).getHeader(SimpleSecurityValveImpl.HTTP_WWW_AUTHENTICATE_HEADER));
+        assertTrue(((MockHttpServletResponse) requestContext.getResponse()).wasErrorSent());
+        assertEquals(HttpServletResponse.SC_FORBIDDEN, ((MockHttpServletResponse) requestContext.getResponse()).getErrorCode());
+        assertFalse(valveContext.nextInvoked);
+        requestContext = createRequestContext("/include/exclude/test", "173.194.79.105", null, null);
+        valveContext = new StubValveContext();
+        valve.invoke(requestContext, valveContext);
+        assertNull(((MockHttpServletResponse) requestContext.getResponse()).getHeader(SimpleSecurityValveImpl.HTTP_WWW_AUTHENTICATE_HEADER));
+        assertFalse(((MockHttpServletResponse) requestContext.getResponse()).wasErrorSent());
+        assertTrue(valveContext.nextInvoked);
+    }
+
+
+
+    /**
+     * Create mock RequestContext with the specified HttpServletRequest pathInfo,
+     * remoteAddr, and HTTP Basic Authorization header.
+     *
+     * @param pathInfo request pathInfo
+     * @param remoteAddr request remoteAddr
+     * @param user request HTTP Basic Authentication user or null
+     * @param password request HTTP Basic Authentication password or null
+     * @return mock RequestContext
+     */
+    private RequestContext createRequestContext(String pathInfo, String remoteAddr, String user, String password) {
+        MockHttpServletRequest servletRequest = new MockHttpServletRequest();
+        servletRequest.setPathInfo(pathInfo);
+        servletRequest.setRemoteAddr(remoteAddr);
+        if ((user != null) && (password != null)) {
+            String authorization = user+":"+password;
+            try {
+                authorization = "Basic " + Base64.encodeBase64String(authorization.getBytes("UTF-8"));
+            } catch (UnsupportedEncodingException uee) {
+            }
+            servletRequest.setHeader(SimpleSecurityValveImpl.HTTP_AUTHORIZATION_HEADER, authorization);
+        }
+        MockHttpServletResponse servletResponse = new MockHttpServletResponse();
+        RequestContext requestContext = new MockRequestContext();
+        requestContext.setRequest(servletRequest);
+        requestContext.setResponse(servletResponse);
+        return requestContext;
+    }
+
+    /**
+     * Stub ValveContext implementation that tracks ValveContext.invokeNext() invocations.
+     */
+    private class StubValveContext implements ValveContext {
+
+        private boolean nextInvoked;
+
+        @Override
+        public void invokeNext(RequestContext request) throws PipelineException {
+            nextInvoked = true;
+        }
+    }
+
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: jetspeed-dev-unsubscribe@portals.apache.org
For additional commands, e-mail: jetspeed-dev-help@portals.apache.org