Index: java/org/apache/catalina/core/ApplicationServletRegistration.java =================================================================== --- java/org/apache/catalina/core/ApplicationServletRegistration.java (revision 1001832) +++ java/org/apache/catalina/core/ApplicationServletRegistration.java (revision 1001833) @@ -117,10 +117,12 @@ // Have to add in a separate loop since spec requires no updates at all // if there is an issue - for (Map.Entry entry : initParameters.entrySet()) { - setInitParameter(entry.getKey(), entry.getValue()); + if (conflicts.isEmpty()) { + for (Map.Entry entry : initParameters.entrySet()) { + setInitParameter(entry.getKey(), entry.getValue()); + } } - + return conflicts; } @@ -158,53 +160,7 @@ getName(), context.getPath())); } - Set conflicts = new HashSet(); - - Collection urlPatterns = getMappings(); - for (String urlPattern : urlPatterns) { - boolean foundConflict = false; - - SecurityConstraint[] securityConstraints = - context.findConstraints(); - for (SecurityConstraint securityConstraint : securityConstraints) { - - SecurityCollection[] collections = - securityConstraint.findCollections(); - for (SecurityCollection collection : collections) { - if (collection.findPattern(urlPattern)) { - // First pattern found will indicate if there is a - // conflict since for any given pattern all matching - // constraints will be from either the descriptor or - // not. It is not permitted to have a mixture - if (collection.isFromDescriptor()) { - // Skip this pattern - foundConflict = true; - } else { - // Need to overwrite constraint for this pattern - // so remove every pattern found - context.removeConstraint(securityConstraint); - } - } - if (foundConflict) { - break; - } - } - if (foundConflict) { - break; - } - } - if (!foundConflict) { - SecurityConstraint[] newSecurityConstraints = - SecurityConstraint.createConstraints(constraint, - urlPattern); - for (SecurityConstraint securityConstraint : - newSecurityConstraints) { - context.addConstraint(securityConstraint); - } - } - } - - return conflicts; + return context.addServletSecurity(this, constraint); } Index: java/org/apache/catalina/core/StandardContext.java =================================================================== --- java/org/apache/catalina/core/StandardContext.java (revision 1001832) +++ java/org/apache/catalina/core/StandardContext.java (revision 1001833) @@ -26,7 +26,9 @@ import java.net.URL; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.LinkedHashMap; @@ -47,14 +49,17 @@ import javax.naming.NamingException; import javax.naming.directory.DirContext; import javax.servlet.FilterConfig; +import javax.servlet.Servlet; import javax.servlet.ServletContainerInitializer; import javax.servlet.ServletContext; import javax.servlet.ServletContextAttributeListener; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.ServletException; +import javax.servlet.ServletRegistration; import javax.servlet.ServletRequestAttributeListener; import javax.servlet.ServletRequestListener; +import javax.servlet.ServletSecurityElement; import javax.servlet.descriptor.JspConfigDescriptor; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionListener; @@ -4009,8 +4014,24 @@ return null; } + /** + * hook to register that we need to scan for security annotations. + * @param registration + */ + public ServletRegistration.Dynamic dynamicServletAdded(Wrapper wrapper) { + return new ApplicationServletRegistration(wrapper, this); + } /** + * hook to track which registrations need annotation scanning + * @param servlet + */ + public void dynamicServletCreated(Servlet servlet) { + + } + + + /** * A helper class to manage the filter mappings in a Context. */ private static final class ContextFilterMaps { @@ -5075,7 +5096,64 @@ } + public Set addServletSecurity(ApplicationServletRegistration registration, ServletSecurityElement servletSecurityElement) { + Set conflicts = new HashSet(); + Collection urlPatterns = registration.getMappings(); + for (String urlPattern : urlPatterns) { + boolean foundConflict = false; + + SecurityConstraint[] securityConstraints = + findConstraints(); + for (SecurityConstraint securityConstraint : securityConstraints) { + + SecurityCollection[] collections = + securityConstraint.findCollections(); + for (SecurityCollection collection : collections) { + if (collection.findPattern(urlPattern)) { + // First pattern found will indicate if there is a + // conflict since for any given pattern all matching + // constraints will be from either the descriptor or + // not. It is not permitted to have a mixture + if (collection.isFromDescriptor()) { + // Skip this pattern + foundConflict = true; + conflicts.add(urlPattern); + } else { + // Need to overwrite constraint for this pattern + // so remove every pattern found + + //TODO spec 13.4.2 appears to say only the conflicting pattern is overwritten, not the entire security constraint. + removeConstraint(securityConstraint); + } + } + if (foundConflict) { + break; + } + } + if (foundConflict) { + break; + } + } + //TODO spec 13.4.2 appears to say that non-conflicting patterns are still used. + //TODO you can't calculate the eventual security constraint now, you have to wait until the context is started, + //since application code can add url patterns after calling setSecurity. + if (!foundConflict) { + SecurityConstraint[] newSecurityConstraints = + SecurityConstraint.createConstraints(servletSecurityElement, + urlPattern); + for (SecurityConstraint securityConstraint : + newSecurityConstraints) { + addConstraint(securityConstraint); + } + } + } + + return conflicts; + + } + + /** * Return a File object representing the base directory for the * entire servlet container (i.e. the Engine container if present). Index: java/org/apache/catalina/core/ApplicationContext.java =================================================================== --- java/org/apache/catalina/core/ApplicationContext.java (revision 1001832) +++ java/org/apache/catalina/core/ApplicationContext.java (revision 1001833) @@ -1067,17 +1067,18 @@ } else { wrapper.setServletClass(servlet.getClass().getName()); wrapper.setServlet(servlet); - } - - return new ApplicationServletRegistration(wrapper, context); - } + } + return context.dynamicServletAdded(wrapper); + } + public T createServlet(Class c) throws ServletException { try { @SuppressWarnings("unchecked") T servlet = (T) context.getInstanceManager().newInstance(c.getName()); + context.dynamicServletCreated(servlet); return servlet; } catch (IllegalAccessException e) { throw new ServletException(e); Index: java/org/apache/catalina/Context.java =================================================================== --- java/org/apache/catalina/Context.java (revision 1001832) +++ java/org/apache/catalina/Context.java (revision 1001833) @@ -24,8 +24,10 @@ import javax.servlet.ServletContainerInitializer; import javax.servlet.ServletContext; +import javax.servlet.ServletSecurityElement; import javax.servlet.descriptor.JspConfigDescriptor; +import org.apache.catalina.core.ApplicationServletRegistration; import org.apache.tomcat.InstanceManager; import org.apache.tomcat.JarScanner; import org.apache.tomcat.util.http.mapper.Mapper; @@ -1224,5 +1226,13 @@ boolean isServlet22(); InstanceManager getInstanceManager(); + + /** + * Notification that servlet security has been dynamically set in a ServletRegistration.Dynamic + * @param registration servlet security was modified for + * @param servletSecurityElement new security constraints for this servlet + * @return urls currently mapped to this registration that are already present in web.xml + */ + Set addServletSecurity(ApplicationServletRegistration registration, ServletSecurityElement servletSecurityElement); }