Author: markt Date: Fri Apr 1 10:49:43 2011 New Revision: 1087643 URL: http://svn.apache.org/viewvc?rev=1087643&view=rev Log: Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=12428 Add optional support for preemptive authentication on a per context basis Based on a patch suggested by Werner Donn
Added: tomcat/trunk/test/webapp-3.0-servletsecurity2/ tomcat/trunk/test/webapp-3.0-servletsecurity2/WEB-INF/ tomcat/trunk/test/webapp-3.0-servletsecurity2/WEB-INF/web.xml (with props) tomcat/trunk/test/webapp-3.0-servletsecurity2/protected.jsp (with props) tomcat/trunk/test/webapp-3.0-servletsecurity2/unprotected.jsp (with props) Modified: tomcat/trunk/java/org/apache/catalina/Context.java tomcat/trunk/java/org/apache/catalina/authenticator/AuthenticatorBase.java tomcat/trunk/java/org/apache/catalina/core/StandardContext.java tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java tomcat/trunk/test/org/apache/catalina/core/TestStandardWrapper.java tomcat/trunk/webapps/docs/changelog.xml tomcat/trunk/webapps/docs/config/context.xml Modified: tomcat/trunk/java/org/apache/catalina/Context.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/Context.java?rev=1087643&r1=1087642&r2=1087643&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/Context.java (original) +++ tomcat/trunk/java/org/apache/catalina/Context.java Fri Apr 1 10:49:43 2011 @@ -1349,5 +1349,18 @@ public interface Context extends Contain */ public boolean getFireRequestListenersOnForwards(); + /** + * Configures if a user presents authentication credentials, whether the + * context will process them when the request is for a non-protected + * resource. + */ + public void setPreemptiveAuthentication(boolean enable); + + /** + * Determines if a user presents authentication credentials, will the + * context will process them when the request is for a non-protected + * resource. + */ + public boolean getPreemptiveAuthentication(); } Modified: tomcat/trunk/java/org/apache/catalina/authenticator/AuthenticatorBase.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/authenticator/AuthenticatorBase.java?rev=1087643&r1=1087642&r2=1087643&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/authenticator/AuthenticatorBase.java (original) +++ tomcat/trunk/java/org/apache/catalina/authenticator/AuthenticatorBase.java Fri Apr 1 10:49:43 2011 @@ -21,6 +21,7 @@ package org.apache.catalina.authenticato import java.io.IOException; import java.security.Principal; +import java.security.cert.X509Certificate; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; @@ -32,6 +33,7 @@ import javax.servlet.http.HttpServletRes import org.apache.catalina.Authenticator; import org.apache.catalina.Container; import org.apache.catalina.Context; +import org.apache.catalina.Globals; import org.apache.catalina.LifecycleException; import org.apache.catalina.Manager; import org.apache.catalina.Realm; @@ -454,8 +456,7 @@ public abstract class AuthenticatorBase SecurityConstraint [] constraints = realm.findSecurityConstraints(request, this.context); - if ((constraints == null) /* && - (!Constants.FORM_METHOD.equals(config.getAuthMethod())) */ ) { + if (constraints == null && !context.getPreemptiveAuthentication()) { if (log.isDebugEnabled()) log.debug(" Not subject to any constraint"); getNext().invoke(request, response); @@ -464,7 +465,7 @@ public abstract class AuthenticatorBase // Make sure that constrained resources are not cached by web proxies // or browsers as caching can provide a security hole - if (disableProxyCaching && + if (constraints != null && disableProxyCaching && // FIXME: Disabled for Mozilla FORM support over SSL // (improper caching issue) //!request.isSecure() && @@ -482,36 +483,55 @@ public abstract class AuthenticatorBase } int i; - // Enforce any user data constraint for this security constraint - if (log.isDebugEnabled()) { - log.debug(" Calling hasUserDataPermission()"); - } - if (!realm.hasUserDataPermission(request, response, - constraints)) { + if (constraints != null) { + // Enforce any user data constraint for this security constraint if (log.isDebugEnabled()) { - log.debug(" Failed hasUserDataPermission() test"); + log.debug(" Calling hasUserDataPermission()"); + } + if (!realm.hasUserDataPermission(request, response, + constraints)) { + if (log.isDebugEnabled()) { + log.debug(" Failed hasUserDataPermission() test"); + } + /* + * ASSERT: Authenticator already set the appropriate + * HTTP status code, so we do not have to do anything special + */ + return; } - /* - * ASSERT: Authenticator already set the appropriate - * HTTP status code, so we do not have to do anything special - */ - return; } // Since authenticate modifies the response on failure, // we have to check for allow-from-all first. - boolean authRequired = true; - for(i=0; i < constraints.length && authRequired; i++) { - if(!constraints[i].getAuthConstraint()) { - authRequired = false; - } else if(!constraints[i].getAllRoles()) { - String [] roles = constraints[i].findAuthRoles(); - if(roles == null || roles.length == 0) { + boolean authRequired; + if (constraints == null) { + authRequired = false; + } else { + authRequired = true; + for(i=0; i < constraints.length && authRequired; i++) { + if(!constraints[i].getAuthConstraint()) { authRequired = false; + } else if(!constraints[i].getAllRoles()) { + String [] roles = constraints[i].findAuthRoles(); + if(roles == null || roles.length == 0) { + authRequired = false; + } } } } - + + if (!authRequired) { + authRequired = + request.getCoyoteRequest().getMimeHeaders().getValue( + "authorization") != null; + } + + if (!authRequired) { + X509Certificate[] certs = (X509Certificate[]) request.getAttribute( + Globals.CERTIFICATES_ATTR); + authRequired = certs != null && certs.length > 0; + } + if(authRequired) { if (log.isDebugEnabled()) { log.debug(" Calling authenticate()"); @@ -530,21 +550,23 @@ public abstract class AuthenticatorBase } - if (log.isDebugEnabled()) { - log.debug(" Calling accessControl()"); - } - if (!realm.hasResourcePermission(request, response, - constraints, - this.context)) { + if (constraints != null) { if (log.isDebugEnabled()) { - log.debug(" Failed accessControl() test"); + log.debug(" Calling accessControl()"); + } + if (!realm.hasResourcePermission(request, response, + constraints, + this.context)) { + if (log.isDebugEnabled()) { + log.debug(" Failed accessControl() test"); + } + /* + * ASSERT: AccessControl method has already set the + * appropriate HTTP status code, so we do not have to do + * anything special + */ + return; } - /* - * ASSERT: AccessControl method has already set the - * appropriate HTTP status code, so we do not have to do - * anything special - */ - return; } // Any and all specified constraints have been satisfied Modified: tomcat/trunk/java/org/apache/catalina/core/StandardContext.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/StandardContext.java?rev=1087643&r1=1087642&r2=1087643&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/core/StandardContext.java (original) +++ tomcat/trunk/java/org/apache/catalina/core/StandardContext.java Fri Apr 1 10:49:43 2011 @@ -849,10 +849,24 @@ public class StandardContext extends Con */ private Set<Servlet> createdServlets = new HashSet<Servlet>(); + private boolean preemptiveAuthentication = false; + // ----------------------------------------------------- Context Properties @Override + public boolean getPreemptiveAuthentication() { + return preemptiveAuthentication; + } + + + @Override + public void setPreemptiveAuthentication(boolean preemptiveAuthentication) { + this.preemptiveAuthentication = preemptiveAuthentication; + } + + + @Override public void setFireRequestListenersOnForwards(boolean enable) { fireRequestListenersOnForwards = enable; } Modified: tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java?rev=1087643&r1=1087642&r2=1087643&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java (original) +++ tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java Fri Apr 1 10:49:43 2011 @@ -367,12 +367,17 @@ public class ContextConfig protected synchronized void authenticatorConfig() { LoginConfig loginConfig = context.getLoginConfig(); - if (loginConfig == null) { - if (context.getIgnoreAnnotations()) { - return; - } else { - // Not metadata-complete, need an authenticator to support - // @ServletSecurity annotations + + SecurityConstraint constraints[] = context.findConstraints(); + if (context.getIgnoreAnnotations() && + (constraints == null || constraints.length ==0) && + !context.getPreemptiveAuthentication()) { + return; + } else { + if (loginConfig == null) { + // Not metadata-complete or security constraints present, need + // an authenticator to support @ServletSecurity annotations + // and/or constraints loginConfig = DUMMY_LOGIN_CONFIG; context.setLoginConfig(loginConfig); } Modified: tomcat/trunk/test/org/apache/catalina/core/TestStandardWrapper.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/core/TestStandardWrapper.java?rev=1087643&r1=1087642&r2=1087643&view=diff ============================================================================== --- tomcat/trunk/test/org/apache/catalina/core/TestStandardWrapper.java (original) +++ tomcat/trunk/test/org/apache/catalina/core/TestStandardWrapper.java Fri Apr 1 10:49:43 2011 @@ -143,6 +143,30 @@ public class TestStandardWrapper extends assertEquals(403, rc); } + public void testSecurityAnnotationsNoWebXmlLoginConfig() throws Exception { + // Setup Tomcat instance + Tomcat tomcat = getTomcatInstance(); + + File appDir = new File("test/webapp-3.0-servletsecurity2"); + tomcat.addWebapp(null, "", appDir.getAbsolutePath()); + + tomcat.start(); + + ByteChunk bc = new ByteChunk(); + int rc; + rc = getUrl("http://localhost:" + getPort() + "/protected.jsp", + bc, null, null); + + assertNull(bc.toString()); + assertEquals(403, rc); + + rc = getUrl("http://localhost:" + getPort() + "/unprotected.jsp", + bc, null, null); + + assertEquals(200, rc); + assertTrue(bc.toString().contains("00-OK")); + } + private void doTestSecurityAnnotationsAddServlet(boolean useCreateServlet) throws Exception { Added: tomcat/trunk/test/webapp-3.0-servletsecurity2/WEB-INF/web.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/test/webapp-3.0-servletsecurity2/WEB-INF/web.xml?rev=1087643&view=auto ============================================================================== --- tomcat/trunk/test/webapp-3.0-servletsecurity2/WEB-INF/web.xml (added) +++ tomcat/trunk/test/webapp-3.0-servletsecurity2/WEB-INF/web.xml Fri Apr 1 10:49:43 2011 @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<!-- + 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. +--> +<web-app xmlns="http://java.sun.com/xml/ns/javaee" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee + http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" + version="3.0" + metadata-complete="true"> + + <!-- + WARNING: + For the unit tests to work correctly, no login-config may be configured in + the web.xml. + --> + + <display-name>Tomcat Test Application</display-name> + <description> + Used as part of the Tomcat unit tests when a full web application is + required. + </description> + + <security-constraint> + <auth-constraint/> + <web-resource-collection> + <url-pattern>/protected.jsp</url-pattern> + </web-resource-collection> + </security-constraint> +</web-app> \ No newline at end of file Propchange: tomcat/trunk/test/webapp-3.0-servletsecurity2/WEB-INF/web.xml ------------------------------------------------------------------------------ svn:eol-style = native Added: tomcat/trunk/test/webapp-3.0-servletsecurity2/protected.jsp URL: http://svn.apache.org/viewvc/tomcat/trunk/test/webapp-3.0-servletsecurity2/protected.jsp?rev=1087643&view=auto ============================================================================== --- tomcat/trunk/test/webapp-3.0-servletsecurity2/protected.jsp (added) +++ tomcat/trunk/test/webapp-3.0-servletsecurity2/protected.jsp Fri Apr 1 10:49:43 2011 @@ -0,0 +1,23 @@ +<%-- + 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. +--%> +<html> + <head><title>Protected page</title></head> + <body> + <p>00-OK</p> + </body> +</html> + Propchange: tomcat/trunk/test/webapp-3.0-servletsecurity2/protected.jsp ------------------------------------------------------------------------------ svn:eol-style = native Added: tomcat/trunk/test/webapp-3.0-servletsecurity2/unprotected.jsp URL: http://svn.apache.org/viewvc/tomcat/trunk/test/webapp-3.0-servletsecurity2/unprotected.jsp?rev=1087643&view=auto ============================================================================== --- tomcat/trunk/test/webapp-3.0-servletsecurity2/unprotected.jsp (added) +++ tomcat/trunk/test/webapp-3.0-servletsecurity2/unprotected.jsp Fri Apr 1 10:49:43 2011 @@ -0,0 +1,23 @@ +<%-- + 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. +--%> +<html> + <head><title>Unprotected page</title></head> + <body> + <p>00-OK</p> + </body> +</html> + Propchange: tomcat/trunk/test/webapp-3.0-servletsecurity2/unprotected.jsp ------------------------------------------------------------------------------ svn:eol-style = native Modified: tomcat/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1087643&r1=1087642&r2=1087643&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/changelog.xml (original) +++ tomcat/trunk/webapps/docs/changelog.xml Fri Apr 1 10:49:43 2011 @@ -73,6 +73,11 @@ When using parallel deployment, correctly handle the scenario when the client sends multiple JSESSIONID cookies. (markt) </fix> + <add> + <bug>12428</bug>: Add support (disabled by default) for preemptive + authentication. This can be configured per context. Based on a patch + suggested by Werner Donn. (markt) + </add> <fix> <bug>50929</bug>: When wrapping an exception, include the root cause. Patch provided by sebb. (markt) Modified: tomcat/trunk/webapps/docs/config/context.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/context.xml?rev=1087643&r1=1087642&r2=1087643&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/config/context.xml (original) +++ tomcat/trunk/webapps/docs/config/context.xml Fri Apr 1 10:49:43 2011 @@ -312,6 +312,16 @@ filenames used for either the .xml context file or the docBase.</p> </attribute> + <attribute name="preemptiveAuthentication" required="false"> + <p>When set to <code>true</code> and the user presents credentials for a + resource that is not protected by a security constraint, if the + authenticator supports preemptive authentication (the standard + authenticators provided with Tomcat do) then the user' credentials + will be processed. If not specified, the default of <code>false</code>is + used. + </p> + </attribute> + <attribute name="privileged" required="false"> <p>Set to <code>true</code> to allow this context to use container servlets, like the manager servlet. Use of the <code>privileged</code> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org