You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by rj...@apache.org on 2014/11/30 19:30:48 UTC

svn commit: r1642595 - in /tomcat/trunk: java/org/apache/catalina/valves/RequestFilterValve.java test/org/apache/catalina/valves/TestRequestFilterValve.java webapps/docs/config/valve.xml

Author: rjung
Date: Sun Nov 30 18:30:47 2014
New Revision: 1642595

URL: http://svn.apache.org/r1642595
Log:
Allow RemoteAddreValve and RemoteHostValve to
trigger authentication instead of denying a
request with a status code.

This only works in combination with preemptiveAuthentication
on the application context.

It can be used to add an additional authentication
without touching the application war.

Example:

<Context preemptiveAuthentication="true">
  <Valve className="org.apache.catalina.valves.RequestFilterValve"
         allow=".*,8009"
         addLocalPort="true"
         invalidAuthenticationWhenDeny="true"/>
  <Valve className="org.apache.catalina.authenticator.BasicAuthenticator" />
</Context>

This will allow normal access via the port 8009 connector (AJP)
but will trigger basic auth when accessed via any other connector.
An administrator can use an http port to check whether the app
works but public access will still be restricted to the AJP port.

Modified:
    tomcat/trunk/java/org/apache/catalina/valves/RequestFilterValve.java
    tomcat/trunk/test/org/apache/catalina/valves/TestRequestFilterValve.java
    tomcat/trunk/webapps/docs/config/valve.xml

Modified: tomcat/trunk/java/org/apache/catalina/valves/RequestFilterValve.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/valves/RequestFilterValve.java?rev=1642595&r1=1642594&r2=1642595&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/valves/RequestFilterValve.java (original)
+++ tomcat/trunk/java/org/apache/catalina/valves/RequestFilterValve.java Sun Nov 30 18:30:47 2014
@@ -23,6 +23,7 @@ import java.util.regex.Pattern;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.catalina.Context;
 import org.apache.catalina.LifecycleException;
 import org.apache.catalina.connector.Request;
 import org.apache.catalina.connector.Response;
@@ -52,6 +53,11 @@ import org.apache.catalina.connector.Res
  * <li>The request will be rejected with a "Forbidden" HTTP response.</li>
  * </ul>
  * <p>
+ * As an option the valve can generate an invalid <code>authenticate</code>
+ * header instead of denying the request. This can be combined with the
+ * context attribute <code>preemptiveAuthentication="true"</code> and an
+ * authenticator to force authentication instead of denial.
+ * <p>
  * This Valve may be attached to any Container, depending on the granularity
  * of the filtering you wish to perform.
  *
@@ -117,6 +123,14 @@ public abstract class RequestFilterValve
      */
     protected int denyStatus = HttpServletResponse.SC_FORBIDDEN;
 
+    /**
+     * <p>If <code>invalidAuthenticationWhenDeny</code> is true
+     * and the context has <code>preemptiveAuthentication</code>
+     * set, set an invalid authorization header to trigger basic auth
+     * instead of denying the request..
+     */
+    private boolean invalidAuthenticationWhenDeny = false;
+
     // ------------------------------------------------------------- Properties
 
 
@@ -221,6 +235,23 @@ public abstract class RequestFilterValve
         this.denyStatus = denyStatus;
     }
 
+
+    /**
+     * Return true if a deny is handled by setting an invalid auth header.
+     */
+    public boolean getInvalidAuthenticationWhenDeny() {
+        return invalidAuthenticationWhenDeny;
+    }
+
+
+    /**
+     * Set invalidAuthenticationWhenDeny property.
+     */
+    public void setInvalidAuthenticationWhenDeny(boolean value) {
+        invalidAuthenticationWhenDeny = value;
+    }
+
+
     // --------------------------------------------------------- Public Methods
 
     /**
@@ -290,6 +321,9 @@ public abstract class RequestFilterValve
 
     /**
      * Reject the request that was denied by this valve.
+     * <p>If <code>invalidAuthenticationWhenDeny</code> is true
+     * and the context has <code>preemptiveAuthentication</code>
+     * set, set an invalid authorization header to trigger basic auth.
      *
      * @param request The servlet request to be processed
      * @param response The servlet response to be processed
@@ -298,6 +332,16 @@ public abstract class RequestFilterValve
      */
     protected void denyRequest(Request request, Response response)
             throws IOException, ServletException {
+        if (invalidAuthenticationWhenDeny) {
+            Context context = request.getContext();
+            if (context != null && context.getPreemptiveAuthentication()) {
+                if (request.getCoyoteRequest().getMimeHeaders().getValue("authorization") == null) {
+                    request.getCoyoteRequest().getMimeHeaders().addValue("authorization").setString("invalid");
+                }
+                getNext().invoke(request, response);
+                return;
+            }
+        }
         response.sendError(denyStatus);
     }
 

Modified: tomcat/trunk/test/org/apache/catalina/valves/TestRequestFilterValve.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/valves/TestRequestFilterValve.java?rev=1642595&r1=1642594&r2=1642595&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/catalina/valves/TestRequestFilterValve.java (original)
+++ tomcat/trunk/test/org/apache/catalina/valves/TestRequestFilterValve.java Sun Nov 30 18:30:47 2014
@@ -26,9 +26,11 @@ import static org.junit.Assert.fail;
 
 import org.junit.Test;
 
+import org.apache.catalina.Context;
 import org.apache.catalina.connector.Connector;
 import org.apache.catalina.connector.Request;
 import org.apache.catalina.connector.Response;
+import org.apache.catalina.core.StandardContext;
 
 /**
  * {@link RequestFilterValve} Tests
@@ -79,11 +81,12 @@ public class TestRequestFilterValve {
     }
 
     private void oneTest(String allow, String deny, boolean denyStatus,
-                         boolean addLocalPort,
+                         boolean addLocalPort, boolean auth,
                          String property, String type, boolean allowed) {
         // PREPARE
         RequestFilterValve valve = null;
         Connector connector = new Connector();
+        Context context = new StandardContext();
         Request request = new Request();
         Response response = new MockResponse();
         StringBuilder msg = new StringBuilder();
@@ -91,6 +94,8 @@ public class TestRequestFilterValve {
 
         connector.setPort(PORT);
         request.setConnector(connector);
+        request.setContext(context);
+        request.setCoyoteRequest(new org.apache.coyote.Request());
 
         if (type == null) {
             fail("Invalid test with null type");
@@ -135,6 +140,11 @@ public class TestRequestFilterValve {
             }
             msg.append(" addLocalPort='true'");
         }
+        if (auth) {
+            context.setPreemptiveAuthentication(true);
+            valve.setInvalidAuthenticationWhenDeny(true);
+            msg.append(" auth='true'");
+        }
 
         // TEST
         try {
@@ -146,169 +156,174 @@ public class TestRequestFilterValve {
         }
 
         // VERIFY
-        assertEquals(msg.toString(), expected, response.getStatus());
+        if (!allowed && auth) {
+            assertEquals(msg.toString(), OK, response.getStatus());
+            assertEquals(msg.toString(), "invalid", request.getHeader("authorization"));
+        } else {
+            assertEquals(msg.toString(), expected, response.getStatus());
+        }
     }
 
     private void standardTests(String allow_pat, String deny_pat,
                                String OnlyAllow, String OnlyDeny,
                                String AllowAndDeny, String NoAllowNoDeny,
-                               String type) {
+                               boolean auth, String type) {
         String apat;
         String dpat;
 
         // Test without ports
         apat = allow_pat;
         dpat = deny_pat;
-        oneTest(null, null, false, false, AllowAndDeny,  type, false);
-        oneTest(null, null, true,  false, AllowAndDeny,  type, false);
-        oneTest(apat, null, false, false, AllowAndDeny,  type, true);
-        oneTest(apat, null, false, false, NoAllowNoDeny, type, false);
-        oneTest(apat, null, true,  false, AllowAndDeny,  type, true);
-        oneTest(apat, null, true,  false, NoAllowNoDeny, type, false);
-        oneTest(null, dpat, false, false, AllowAndDeny,  type, false);
-        oneTest(null, dpat, false, false, NoAllowNoDeny, type, true);
-        oneTest(null, dpat, true,  false, AllowAndDeny,  type, false);
-        oneTest(null, dpat, true,  false, NoAllowNoDeny, type, true);
-        oneTest(apat, dpat, false, false, NoAllowNoDeny, type, false);
-        oneTest(apat, dpat, false, false, OnlyAllow,     type, true);
-        oneTest(apat, dpat, false, false, OnlyDeny,      type, false);
-        oneTest(apat, dpat, false, false, AllowAndDeny,  type, false);
-        oneTest(apat, dpat, true,  false, NoAllowNoDeny, type, false);
-        oneTest(apat, dpat, true,  false, OnlyAllow,     type, true);
-        oneTest(apat, dpat, true,  false, OnlyDeny,      type, false);
-        oneTest(apat, dpat, true,  false, AllowAndDeny,  type, false);
+        oneTest(null, null, false, false, auth, AllowAndDeny,  type, false);
+        oneTest(null, null, true,  false, auth, AllowAndDeny,  type, false);
+        oneTest(apat, null, false, false, auth, AllowAndDeny,  type, true);
+        oneTest(apat, null, false, false, auth, NoAllowNoDeny, type, false);
+        oneTest(apat, null, true,  false, auth, AllowAndDeny,  type, true);
+        oneTest(apat, null, true,  false, auth, NoAllowNoDeny, type, false);
+        oneTest(null, dpat, false, false, auth, AllowAndDeny,  type, false);
+        oneTest(null, dpat, false, false, auth, NoAllowNoDeny, type, true);
+        oneTest(null, dpat, true,  false, auth, AllowAndDeny,  type, false);
+        oneTest(null, dpat, true,  false, auth, NoAllowNoDeny, type, true);
+        oneTest(apat, dpat, false, false, auth, NoAllowNoDeny, type, false);
+        oneTest(apat, dpat, false, false, auth, OnlyAllow,     type, true);
+        oneTest(apat, dpat, false, false, auth, OnlyDeny,      type, false);
+        oneTest(apat, dpat, false, false, auth, AllowAndDeny,  type, false);
+        oneTest(apat, dpat, true,  false, auth, NoAllowNoDeny, type, false);
+        oneTest(apat, dpat, true,  false, auth, OnlyAllow,     type, true);
+        oneTest(apat, dpat, true,  false, auth, OnlyDeny,      type, false);
+        oneTest(apat, dpat, true,  false, auth, AllowAndDeny,  type, false);
 
         // Test with port in pattern but forgotten "addLocalPort"
         apat = allow_pat + PORT_MATCH_PATTERN;
         dpat = deny_pat + PORT_MATCH_PATTERN;
-        oneTest(null, null, false, false, AllowAndDeny,  type, false);
-        oneTest(null, null, true,  false, AllowAndDeny,  type, false);
-        oneTest(apat, null, false, false, AllowAndDeny,  type, false);
-        oneTest(apat, null, false, false, NoAllowNoDeny, type, false);
-        oneTest(apat, null, true,  false, AllowAndDeny,  type, false);
-        oneTest(apat, null, true,  false, NoAllowNoDeny, type, false);
-        oneTest(null, dpat, false, false, AllowAndDeny,  type, true);
-        oneTest(null, dpat, false, false, NoAllowNoDeny, type, true);
-        oneTest(null, dpat, true,  false, AllowAndDeny,  type, true);
-        oneTest(null, dpat, true,  false, NoAllowNoDeny, type, true);
-        oneTest(apat, dpat, false, false, NoAllowNoDeny, type, false);
-        oneTest(apat, dpat, false, false, OnlyAllow,     type, false);
-        oneTest(apat, dpat, false, false, OnlyDeny,      type, false);
-        oneTest(apat, dpat, false, false, AllowAndDeny,  type, false);
-        oneTest(apat, dpat, true,  false, NoAllowNoDeny, type, false);
-        oneTest(apat, dpat, true,  false, OnlyAllow,     type, false);
-        oneTest(apat, dpat, true,  false, OnlyDeny,      type, false);
-        oneTest(apat, dpat, true,  false, AllowAndDeny,  type, false);
+        oneTest(null, null, false, false, auth, AllowAndDeny,  type, false);
+        oneTest(null, null, true,  false, auth, AllowAndDeny,  type, false);
+        oneTest(apat, null, false, false, auth, AllowAndDeny,  type, false);
+        oneTest(apat, null, false, false, auth, NoAllowNoDeny, type, false);
+        oneTest(apat, null, true,  false, auth, AllowAndDeny,  type, false);
+        oneTest(apat, null, true,  false, auth, NoAllowNoDeny, type, false);
+        oneTest(null, dpat, false, false, auth, AllowAndDeny,  type, true);
+        oneTest(null, dpat, false, false, auth, NoAllowNoDeny, type, true);
+        oneTest(null, dpat, true,  false, auth, AllowAndDeny,  type, true);
+        oneTest(null, dpat, true,  false, auth, NoAllowNoDeny, type, true);
+        oneTest(apat, dpat, false, false, auth, NoAllowNoDeny, type, false);
+        oneTest(apat, dpat, false, false, auth, OnlyAllow,     type, false);
+        oneTest(apat, dpat, false, false, auth, OnlyDeny,      type, false);
+        oneTest(apat, dpat, false, false, auth, AllowAndDeny,  type, false);
+        oneTest(apat, dpat, true,  false, auth, NoAllowNoDeny, type, false);
+        oneTest(apat, dpat, true,  false, auth, OnlyAllow,     type, false);
+        oneTest(apat, dpat, true,  false, auth, OnlyDeny,      type, false);
+        oneTest(apat, dpat, true,  false, auth, AllowAndDeny,  type, false);
 
         // Test with "addLocalPort" but port not in pattern
         apat = allow_pat;
         dpat = deny_pat;
-        oneTest(null, null, false, true, AllowAndDeny,  type, false);
-        oneTest(null, null, true,  true, AllowAndDeny,  type, false);
-        oneTest(apat, null, false, true, AllowAndDeny,  type, false);
-        oneTest(apat, null, false, true, NoAllowNoDeny, type, false);
-        oneTest(apat, null, true,  true, AllowAndDeny,  type, false);
-        oneTest(apat, null, true,  true, NoAllowNoDeny, type, false);
-        oneTest(null, dpat, false, true, AllowAndDeny,  type, true);
-        oneTest(null, dpat, false, true, NoAllowNoDeny, type, true);
-        oneTest(null, dpat, true,  true, AllowAndDeny,  type, true);
-        oneTest(null, dpat, true,  true, NoAllowNoDeny, type, true);
-        oneTest(apat, dpat, false, true, NoAllowNoDeny, type, false);
-        oneTest(apat, dpat, false, true, OnlyAllow,     type, false);
-        oneTest(apat, dpat, false, true, OnlyDeny,      type, false);
-        oneTest(apat, dpat, false, true, AllowAndDeny,  type, false);
-        oneTest(apat, dpat, true,  true, NoAllowNoDeny, type, false);
-        oneTest(apat, dpat, true,  true, OnlyAllow,     type, false);
-        oneTest(apat, dpat, true,  true, OnlyDeny,      type, false);
-        oneTest(apat, dpat, true,  true, AllowAndDeny,  type, false);
+        oneTest(null, null, false, true, auth, AllowAndDeny,  type, false);
+        oneTest(null, null, true,  true, auth, AllowAndDeny,  type, false);
+        oneTest(apat, null, false, true, auth, AllowAndDeny,  type, false);
+        oneTest(apat, null, false, true, auth, NoAllowNoDeny, type, false);
+        oneTest(apat, null, true,  true, auth, AllowAndDeny,  type, false);
+        oneTest(apat, null, true,  true, auth, NoAllowNoDeny, type, false);
+        oneTest(null, dpat, false, true, auth, AllowAndDeny,  type, true);
+        oneTest(null, dpat, false, true, auth, NoAllowNoDeny, type, true);
+        oneTest(null, dpat, true,  true, auth, AllowAndDeny,  type, true);
+        oneTest(null, dpat, true,  true, auth, NoAllowNoDeny, type, true);
+        oneTest(apat, dpat, false, true, auth, NoAllowNoDeny, type, false);
+        oneTest(apat, dpat, false, true, auth, OnlyAllow,     type, false);
+        oneTest(apat, dpat, false, true, auth, OnlyDeny,      type, false);
+        oneTest(apat, dpat, false, true, auth, AllowAndDeny,  type, false);
+        oneTest(apat, dpat, true,  true, auth, NoAllowNoDeny, type, false);
+        oneTest(apat, dpat, true,  true, auth, OnlyAllow,     type, false);
+        oneTest(apat, dpat, true,  true, auth, OnlyDeny,      type, false);
+        oneTest(apat, dpat, true,  true, auth, AllowAndDeny,  type, false);
 
         // Test "addLocalPort" and with port matching in both patterns
         apat = allow_pat + PORT_MATCH_PATTERN;
         dpat = deny_pat + PORT_MATCH_PATTERN;
-        oneTest(null, null, false, true, AllowAndDeny,  type, false);
-        oneTest(null, null, true,  true, AllowAndDeny,  type, false);
-        oneTest(apat, null, false, true, AllowAndDeny,  type, true);
-        oneTest(apat, null, false, true, NoAllowNoDeny, type, false);
-        oneTest(apat, null, true,  true, AllowAndDeny,  type, true);
-        oneTest(apat, null, true,  true, NoAllowNoDeny, type, false);
-        oneTest(null, dpat, false, true, AllowAndDeny,  type, false);
-        oneTest(null, dpat, false, true, NoAllowNoDeny, type, true);
-        oneTest(null, dpat, true,  true, AllowAndDeny,  type, false);
-        oneTest(null, dpat, true,  true, NoAllowNoDeny, type, true);
-        oneTest(apat, dpat, false, true, NoAllowNoDeny, type, false);
-        oneTest(apat, dpat, false, true, OnlyAllow,     type, true);
-        oneTest(apat, dpat, false, true, OnlyDeny,      type, false);
-        oneTest(apat, dpat, false, true, AllowAndDeny,  type, false);
-        oneTest(apat, dpat, true,  true, NoAllowNoDeny, type, false);
-        oneTest(apat, dpat, true,  true, OnlyAllow,     type, true);
-        oneTest(apat, dpat, true,  true, OnlyDeny,      type, false);
-        oneTest(apat, dpat, true,  true, AllowAndDeny,  type, false);
+        oneTest(null, null, false, true, auth, AllowAndDeny,  type, false);
+        oneTest(null, null, true,  true, auth, AllowAndDeny,  type, false);
+        oneTest(apat, null, false, true, auth, AllowAndDeny,  type, true);
+        oneTest(apat, null, false, true, auth, NoAllowNoDeny, type, false);
+        oneTest(apat, null, true,  true, auth, AllowAndDeny,  type, true);
+        oneTest(apat, null, true,  true, auth, NoAllowNoDeny, type, false);
+        oneTest(null, dpat, false, true, auth, AllowAndDeny,  type, false);
+        oneTest(null, dpat, false, true, auth, NoAllowNoDeny, type, true);
+        oneTest(null, dpat, true,  true, auth, AllowAndDeny,  type, false);
+        oneTest(null, dpat, true,  true, auth, NoAllowNoDeny, type, true);
+        oneTest(apat, dpat, false, true, auth, NoAllowNoDeny, type, false);
+        oneTest(apat, dpat, false, true, auth, OnlyAllow,     type, true);
+        oneTest(apat, dpat, false, true, auth, OnlyDeny,      type, false);
+        oneTest(apat, dpat, false, true, auth, AllowAndDeny,  type, false);
+        oneTest(apat, dpat, true,  true, auth, NoAllowNoDeny, type, false);
+        oneTest(apat, dpat, true,  true, auth, OnlyAllow,     type, true);
+        oneTest(apat, dpat, true,  true, auth, OnlyDeny,      type, false);
+        oneTest(apat, dpat, true,  true, auth, AllowAndDeny,  type, false);
 
         // Test "addLocalPort" and with port not matching in both patterns
         apat = allow_pat + PORT_NO_MATCH_PATTERN;
         dpat = deny_pat + PORT_NO_MATCH_PATTERN;
-        oneTest(null, null, false, true, AllowAndDeny,  type, false);
-        oneTest(null, null, true,  true, AllowAndDeny,  type, false);
-        oneTest(apat, null, false, true, AllowAndDeny,  type, false);
-        oneTest(apat, null, false, true, NoAllowNoDeny, type, false);
-        oneTest(apat, null, true,  true, AllowAndDeny,  type, false);
-        oneTest(apat, null, true,  true, NoAllowNoDeny, type, false);
-        oneTest(null, dpat, false, true, AllowAndDeny,  type, true);
-        oneTest(null, dpat, false, true, NoAllowNoDeny, type, true);
-        oneTest(null, dpat, true,  true, AllowAndDeny,  type, true);
-        oneTest(null, dpat, true,  true, NoAllowNoDeny, type, true);
-        oneTest(apat, dpat, false, true, NoAllowNoDeny, type, false);
-        oneTest(apat, dpat, false, true, OnlyAllow,     type, false);
-        oneTest(apat, dpat, false, true, OnlyDeny,      type, false);
-        oneTest(apat, dpat, false, true, AllowAndDeny,  type, false);
-        oneTest(apat, dpat, true,  true, NoAllowNoDeny, type, false);
-        oneTest(apat, dpat, true,  true, OnlyAllow,     type, false);
-        oneTest(apat, dpat, true,  true, OnlyDeny,      type, false);
-        oneTest(apat, dpat, true,  true, AllowAndDeny,  type, false);
+        oneTest(null, null, false, true, auth, AllowAndDeny,  type, false);
+        oneTest(null, null, true,  true, auth, AllowAndDeny,  type, false);
+        oneTest(apat, null, false, true, auth, AllowAndDeny,  type, false);
+        oneTest(apat, null, false, true, auth, NoAllowNoDeny, type, false);
+        oneTest(apat, null, true,  true, auth, AllowAndDeny,  type, false);
+        oneTest(apat, null, true,  true, auth, NoAllowNoDeny, type, false);
+        oneTest(null, dpat, false, true, auth, AllowAndDeny,  type, true);
+        oneTest(null, dpat, false, true, auth, NoAllowNoDeny, type, true);
+        oneTest(null, dpat, true,  true, auth, AllowAndDeny,  type, true);
+        oneTest(null, dpat, true,  true, auth, NoAllowNoDeny, type, true);
+        oneTest(apat, dpat, false, true, auth, NoAllowNoDeny, type, false);
+        oneTest(apat, dpat, false, true, auth, OnlyAllow,     type, false);
+        oneTest(apat, dpat, false, true, auth, OnlyDeny,      type, false);
+        oneTest(apat, dpat, false, true, auth, AllowAndDeny,  type, false);
+        oneTest(apat, dpat, true,  true, auth, NoAllowNoDeny, type, false);
+        oneTest(apat, dpat, true,  true, auth, OnlyAllow,     type, false);
+        oneTest(apat, dpat, true,  true, auth, OnlyDeny,      type, false);
+        oneTest(apat, dpat, true,  true, auth, AllowAndDeny,  type, false);
 
         // Test "addLocalPort" and with port matching only in allow
         apat = allow_pat + PORT_MATCH_PATTERN;
         dpat = deny_pat + PORT_NO_MATCH_PATTERN;
-        oneTest(null, null, false, true, AllowAndDeny,  type, false);
-        oneTest(null, null, true,  true, AllowAndDeny,  type, false);
-        oneTest(apat, null, false, true, AllowAndDeny,  type, true);
-        oneTest(apat, null, false, true, NoAllowNoDeny, type, false);
-        oneTest(apat, null, true,  true, AllowAndDeny,  type, true);
-        oneTest(apat, null, true,  true, NoAllowNoDeny, type, false);
-        oneTest(null, dpat, false, true, AllowAndDeny,  type, true);
-        oneTest(null, dpat, false, true, NoAllowNoDeny, type, true);
-        oneTest(null, dpat, true,  true, AllowAndDeny,  type, true);
-        oneTest(null, dpat, true,  true, NoAllowNoDeny, type, true);
-        oneTest(apat, dpat, false, true, NoAllowNoDeny, type, false);
-        oneTest(apat, dpat, false, true, OnlyAllow,     type, true);
-        oneTest(apat, dpat, false, true, OnlyDeny,      type, false);
-        oneTest(apat, dpat, false, true, AllowAndDeny,  type, true);
-        oneTest(apat, dpat, true,  true, NoAllowNoDeny, type, false);
-        oneTest(apat, dpat, true,  true, OnlyAllow,     type, true);
-        oneTest(apat, dpat, true,  true, OnlyDeny,      type, false);
-        oneTest(apat, dpat, true,  true, AllowAndDeny,  type, true);
+        oneTest(null, null, false, true, auth, AllowAndDeny,  type, false);
+        oneTest(null, null, true,  true, auth, AllowAndDeny,  type, false);
+        oneTest(apat, null, false, true, auth, AllowAndDeny,  type, true);
+        oneTest(apat, null, false, true, auth, NoAllowNoDeny, type, false);
+        oneTest(apat, null, true,  true, auth, AllowAndDeny,  type, true);
+        oneTest(apat, null, true,  true, auth, NoAllowNoDeny, type, false);
+        oneTest(null, dpat, false, true, auth, AllowAndDeny,  type, true);
+        oneTest(null, dpat, false, true, auth, NoAllowNoDeny, type, true);
+        oneTest(null, dpat, true,  true, auth, AllowAndDeny,  type, true);
+        oneTest(null, dpat, true,  true, auth, NoAllowNoDeny, type, true);
+        oneTest(apat, dpat, false, true, auth, NoAllowNoDeny, type, false);
+        oneTest(apat, dpat, false, true, auth, OnlyAllow,     type, true);
+        oneTest(apat, dpat, false, true, auth, OnlyDeny,      type, false);
+        oneTest(apat, dpat, false, true, auth, AllowAndDeny,  type, true);
+        oneTest(apat, dpat, true,  true, auth, NoAllowNoDeny, type, false);
+        oneTest(apat, dpat, true,  true, auth, OnlyAllow,     type, true);
+        oneTest(apat, dpat, true,  true, auth, OnlyDeny,      type, false);
+        oneTest(apat, dpat, true,  true, auth, AllowAndDeny,  type, true);
 
         // Test "addLocalPort" and with port matching only in deny
         apat = allow_pat + PORT_NO_MATCH_PATTERN;
         dpat = deny_pat + PORT_MATCH_PATTERN;
-        oneTest(null, null, false, true, AllowAndDeny,  type, false);
-        oneTest(null, null, true,  true, AllowAndDeny,  type, false);
-        oneTest(apat, null, false, true, AllowAndDeny,  type, false);
-        oneTest(apat, null, false, true, NoAllowNoDeny, type, false);
-        oneTest(apat, null, true,  true, AllowAndDeny,  type, false);
-        oneTest(apat, null, true,  true, NoAllowNoDeny, type, false);
-        oneTest(null, dpat, false, true, AllowAndDeny,  type, false);
-        oneTest(null, dpat, false, true, NoAllowNoDeny, type, true);
-        oneTest(null, dpat, true,  true, AllowAndDeny,  type, false);
-        oneTest(null, dpat, true,  true, NoAllowNoDeny, type, true);
-        oneTest(apat, dpat, false, true, NoAllowNoDeny, type, false);
-        oneTest(apat, dpat, false, true, OnlyAllow,     type, false);
-        oneTest(apat, dpat, false, true, OnlyDeny,      type, false);
-        oneTest(apat, dpat, false, true, AllowAndDeny,  type, false);
-        oneTest(apat, dpat, true,  true, NoAllowNoDeny, type, false);
-        oneTest(apat, dpat, true,  true, OnlyAllow,     type, false);
-        oneTest(apat, dpat, true,  true, OnlyDeny,      type, false);
-        oneTest(apat, dpat, true,  true, AllowAndDeny,  type, false);
+        oneTest(null, null, false, true, auth, AllowAndDeny,  type, false);
+        oneTest(null, null, true,  true, auth, AllowAndDeny,  type, false);
+        oneTest(apat, null, false, true, auth, AllowAndDeny,  type, false);
+        oneTest(apat, null, false, true, auth, NoAllowNoDeny, type, false);
+        oneTest(apat, null, true,  true, auth, AllowAndDeny,  type, false);
+        oneTest(apat, null, true,  true, auth, NoAllowNoDeny, type, false);
+        oneTest(null, dpat, false, true, auth, AllowAndDeny,  type, false);
+        oneTest(null, dpat, false, true, auth, NoAllowNoDeny, type, true);
+        oneTest(null, dpat, true,  true, auth, AllowAndDeny,  type, false);
+        oneTest(null, dpat, true,  true, auth, NoAllowNoDeny, type, true);
+        oneTest(apat, dpat, false, true, auth, NoAllowNoDeny, type, false);
+        oneTest(apat, dpat, false, true, auth, OnlyAllow,     type, false);
+        oneTest(apat, dpat, false, true, auth, OnlyDeny,      type, false);
+        oneTest(apat, dpat, false, true, auth, AllowAndDeny,  type, false);
+        oneTest(apat, dpat, true,  true, auth, NoAllowNoDeny, type, false);
+        oneTest(apat, dpat, true,  true, auth, OnlyAllow,     type, false);
+        oneTest(apat, dpat, true,  true, auth, OnlyDeny,      type, false);
+        oneTest(apat, dpat, true,  true, auth, AllowAndDeny,  type, false);
     }
 
     @Test
@@ -316,7 +331,11 @@ public class TestRequestFilterValve {
         standardTests(ADDR_ALLOW_PAT, ADDR_DENY_PAT,
                       ADDR_ONLY_ALLOW, ADDR_ONLY_DENY,
                       ADDR_ALLOW_AND_DENY, ADDR_NO_ALLOW_NO_DENY,
-                      "Addr");
+                      false, "Addr");
+        standardTests(ADDR_ALLOW_PAT, ADDR_DENY_PAT,
+                      ADDR_ONLY_ALLOW, ADDR_ONLY_DENY,
+                      ADDR_ALLOW_AND_DENY, ADDR_NO_ALLOW_NO_DENY,
+                      true, "Addr");
     }
 
     @Test
@@ -324,6 +343,10 @@ public class TestRequestFilterValve {
         standardTests(HOST_ALLOW_PAT, HOST_DENY_PAT,
                       HOST_ONLY_ALLOW, HOST_ONLY_DENY,
                       HOST_ALLOW_AND_DENY, HOST_NO_ALLOW_NO_DENY,
-                      "Host");
+                      false, "Host");
+        standardTests(HOST_ALLOW_PAT, HOST_DENY_PAT,
+                      HOST_ONLY_ALLOW, HOST_ONLY_DENY,
+                      HOST_ALLOW_AND_DENY, HOST_NO_ALLOW_NO_DENY,
+                      true, "Host");
     }
 }

Modified: tomcat/trunk/webapps/docs/config/valve.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/valve.xml?rev=1642595&r1=1642594&r2=1642595&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/valve.xml (original)
+++ tomcat/trunk/webapps/docs/config/valve.xml Sun Nov 30 18:30:47 2014
@@ -476,6 +476,11 @@
     <p>Optionally one can append the local server port separated with a
     comma (",") to allow different expressions for each connector.</p>
 
+    <p>The behavior when a request is refused can be changed
+    to not deny but instead set an invalid <code>authentication</code>
+    header. This is useful in combination with the context attribute
+    <code>preemptiveAuthentication="true"</code>.</p>
+
     <p><strong>Note:</strong> There is a caveat when using this valve with
     IPv6 addresses. Format of the IP address that this valve is processing
     depends on the API that was used to obtain it. If the address was obtained
@@ -533,6 +538,17 @@
         request. The default value is <code>false</code>.</p>
       </attribute>
 
+      <attribute name="invalidAuthenticationWhenDeny" required="false">
+        <p>When a request should be denied, do not deny but instead
+        set an invalid <code>authentication</code> header. This only works
+        if the context has the attribute <code>preemptiveAuthentication="true"</code>
+        set. An already existing <code>authentication</code> header will not be
+        overwritten. In effect this will trigger authentication instead of deny
+        even if the application does not have a security constraint configured.</p>
+        <p>This can be combined with <code>addLocalPort</code> to trigger authentication
+        depending on the client and the port that is used to access an application.</p>
+      </attribute>
+
     </attributes>
 
   </subsection>
@@ -575,6 +591,11 @@
     <p>Optionally one can append the local server port separated with a
     comma (",") to allow different expressions for each connector.</p>
 
+    <p>The behavior when a request is refused can be changed
+    to not deny but instead set an invalid <code>authentication</code>
+    header. This is useful in combination with the context attribute
+    <code>preemptiveAuthentication="true"</code>.</p>
+
     <p><strong>Note:</strong> This filter processes the value returned by
     method <code>ServletRequest.getRemoteHost()</code>. To allow the method
     to return proper host names, you have to enable "DNS lookups" feature on
@@ -629,6 +650,17 @@
         request. The default value is <code>false</code>.</p>
       </attribute>
 
+      <attribute name="invalidAuthenticationWhenDeny" required="false">
+        <p>When a request should be denied, do not deny but instead
+        set an invalid <code>authentication</code> header. This only works
+        if the context has the attribute <code>preemptiveAuthentication="true"</code>
+        set. An already existing <code>authentication</code> header will not be
+        overwritten. In effect this will trigger authentication instead of deny
+        even if the application does not have a security constraint configured.</p>
+        <p>This can be combined with <code>addLocalPort</code> to trigger authentication
+        depending on the client and the port that is used to access an application.</p>
+      </attribute>
+
     </attributes>
 
   </subsection>



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


Re: svn commit: r1642595 - in /tomcat/trunk: java/org/apache/catalina/valves/RequestFilterValve.java test/org/apache/catalina/valves/TestRequestFilterValve.java webapps/docs/config/valve.xml

Posted by Rainer Jung <ra...@kippdata.de>.
Am 30.11.2014 um 21:13 schrieb Konstantin Kolinko:
> 2014-11-30 21:30 GMT+03:00  <rj...@apache.org>:
>> Author: rjung
>> Date: Sun Nov 30 18:30:47 2014
>> New Revision: 1642595
>>
>> URL: http://svn.apache.org/r1642595
>> Log:
>> Allow RemoteAddreValve and RemoteHostValve to
>> trigger authentication instead of denying a
>> request with a status code.
>>
>> This only works in combination with preemptiveAuthentication
>> on the application context.
>>
>> It can be used to add an additional authentication
>> without touching the application war.
>>
>> Example:
>>
>> <Context preemptiveAuthentication="true">
>>    <Valve className="org.apache.catalina.valves.RequestFilterValve"
>
> RequestFilterValve is an abstract class...

Oups, yes, it would be either RequestAddrValve or RequestHostValve.

I should add an explicit working example to the docs-

>>           allow=".*,8009"
>
> 1) If you ever plan to backport this to Tomcat 6, then comma (',') is
> a wrong choice, because in Tomcat 6 it cannot be used in a regular
> expression, as it is treated as a separator between several regular
> expressions.

Thanks for the hint. I had originally used "-", but didn't like it 
because it can show up in host names.

> If colon is no good (as part of ipv6 address), I propose to use semicolon (';').

ACK, will adjust.

>>           addLocalPort="true"
>
> 2) "local port" usually means request.getServerPort() (that is what
> means "%p" in AccessLogValve) or request.getLocalPort().
>
> Your request.getConnector().getPort() in r1642564 is different from
> either of them, because it can return "-1" if Tomcat is configured to
> autoselect a port number, while none of the above methods can do that.
> (See Connector.getPort() vs. connector.getLocalPort())
>
> The Connector.getPort() value is good for this task of identifying connectors.
> Maybe name this feature "addConnectorPort" instead of "addLocalPort"?

Good point, thanks.

>>           invalidAuthenticationWhenDeny="true"/>
>>    <Valve className="org.apache.catalina.authenticator.BasicAuthenticator" />
>> </Context>
>>
>> This will allow normal access via the port 8009 connector (AJP)
>> but will trigger basic auth when accessed via any other connector.
>> An administrator can use an http port to check whether the app
>> works but public access will still be restricted to the AJP port.
>
>
> 3) Expose the new properties via JMX = ?

ACK

Thanks a bunch for your review!

Regards,

Rainer

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


Re: svn commit: r1642595 - in /tomcat/trunk: java/org/apache/catalina/valves/RequestFilterValve.java test/org/apache/catalina/valves/TestRequestFilterValve.java webapps/docs/config/valve.xml

Posted by Konstantin Kolinko <kn...@gmail.com>.
2014-11-30 21:30 GMT+03:00  <rj...@apache.org>:
> Author: rjung
> Date: Sun Nov 30 18:30:47 2014
> New Revision: 1642595
>
> URL: http://svn.apache.org/r1642595
> Log:
> Allow RemoteAddreValve and RemoteHostValve to
> trigger authentication instead of denying a
> request with a status code.
>
> This only works in combination with preemptiveAuthentication
> on the application context.
>
> It can be used to add an additional authentication
> without touching the application war.
>
> Example:
>
> <Context preemptiveAuthentication="true">
>   <Valve className="org.apache.catalina.valves.RequestFilterValve"

RequestFilterValve is an abstract class...

>          allow=".*,8009"

1) If you ever plan to backport this to Tomcat 6, then comma (',') is
a wrong choice, because in Tomcat 6 it cannot be used in a regular
expression, as it is treated as a separator between several regular
expressions.

If colon is no good (as part of ipv6 address), I propose to use semicolon (';').

>          addLocalPort="true"

2) "local port" usually means request.getServerPort() (that is what
means "%p" in AccessLogValve) or request.getLocalPort().

Your request.getConnector().getPort() in r1642564 is different from
either of them, because it can return "-1" if Tomcat is configured to
autoselect a port number, while none of the above methods can do that.
(See Connector.getPort() vs. connector.getLocalPort())

The Connector.getPort() value is good for this task of identifying connectors.
Maybe name this feature "addConnectorPort" instead of "addLocalPort"?

>          invalidAuthenticationWhenDeny="true"/>
>   <Valve className="org.apache.catalina.authenticator.BasicAuthenticator" />
> </Context>
>
> This will allow normal access via the port 8009 connector (AJP)
> but will trigger basic auth when accessed via any other connector.
> An administrator can use an http port to check whether the app
> works but public access will still be restricted to the AJP port.


3) Expose the new properties via JMX = ?

> Modified:
>     tomcat/trunk/java/org/apache/catalina/valves/RequestFilterValve.java
>     tomcat/trunk/test/org/apache/catalina/valves/TestRequestFilterValve.java
>     tomcat/trunk/webapps/docs/config/valve.xml
>

Best regards,
Konstantin Kolinko

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