Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardWrapper.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardWrapper.java?rev=1823322&r1=1823321&r2=1823322&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardWrapper.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardWrapper.java Tue Feb 6 12:49:49 2018 @@ -5,17 +5,15 @@ * 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.catalina.core; import java.io.PrintStream; @@ -44,11 +42,9 @@ import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; -import javax.servlet.ServletSecurityElement; import javax.servlet.SingleThreadModel; import javax.servlet.UnavailableException; import javax.servlet.annotation.MultipartConfig; -import javax.servlet.annotation.ServletSecurity; import org.apache.catalina.Container; import org.apache.catalina.ContainerServlet; @@ -114,12 +110,12 @@ public class StandardWrapper extends Con * servlet is considered permanent. */ protected long available = 0L; - + /** - * The broadcaster that sends j2ee notifications. + * The broadcaster that sends j2ee notifications. */ protected NotificationBroadcasterSupport broadcaster = null; - + /** * The count of allocations that are currently active (even if they * are for the same instance, as will be true on a non-STM servlet). @@ -231,12 +227,12 @@ public class StandardWrapper extends Con */ protected Stack<Servlet> instancePool = null; - + /** * Wait time for servlet unload in ms. */ protected long unloadDelay = 2000; - + /** * True if this StandardWrapper is for the JspServlet @@ -259,12 +255,12 @@ public class StandardWrapper extends Con protected StandardWrapperValve swValve; protected long loadTime=0; protected int classLoadTime=0; - + /** * Multipart config */ protected MultipartConfigElement multipartConfigElement = null; - + /** * Async support */ @@ -275,26 +271,24 @@ public class StandardWrapper extends Con */ protected boolean enabled = true; - protected volatile boolean servletSecurityAnnotationScanRequired = false; - private boolean overridable = false; - + /** - * Static class array used when the SecurityManager is turned on and + * Static class array used when the SecurityManager is turned on and * <code>Servlet.init</code> is invoked. */ protected static Class<?>[] classType = new Class[]{ServletConfig.class}; - - + + /** - * Static class array used when the SecurityManager is turned on and + * Static class array used when the SecurityManager is turned on and * <code>Servlet.service</code> is invoked. - */ + */ @Deprecated protected static Class<?>[] classTypeUsedInService = new Class[]{ ServletRequest.class, ServletResponse.class}; - + private final ReentrantReadWriteLock parametersLock = new ReentrantReadWriteLock(); @@ -625,7 +619,7 @@ public class StandardWrapper extends Con public String[] getServletMethods() throws ServletException { instance = loadServlet(); - + Class<? extends Servlet> servletClazz = instance.getClass(); if (!javax.servlet.http.HttpServlet.class.isAssignableFrom( servletClazz)) { @@ -665,8 +659,8 @@ public class StandardWrapper extends Con public Servlet getServlet() { return instance; } - - + + /** * Set the associated servlet instance. */ @@ -675,13 +669,13 @@ public class StandardWrapper extends Con instance = servlet; } - + /** * {@inheritDoc} */ @Override public void setServletSecurityAnnotationScanRequired(boolean b) { - this.servletSecurityAnnotationScanRequired = b; + // NO-OP } // --------------------------------------------------------- Public Methods @@ -695,19 +689,19 @@ public class StandardWrapper extends Con @Override public void backgroundProcess() { super.backgroundProcess(); - + if (!getState().isAvailable()) return; - + if (getServlet() != null && (getServlet() instanceof PeriodicEventListener)) { ((PeriodicEventListener) getServlet()).periodicEvent(); } } - - + + /** * Extract the root cause from a servlet exception. - * + * * @param e The servlet exception */ public static Throwable getRootCause(ServletException e) { @@ -836,7 +830,7 @@ public class StandardWrapper extends Con } boolean newInstance = false; - + // If not SingleThreadedModel, return the same instance every time if (!singleThreadModel) { // Load and initialize our instance if necessary @@ -1070,7 +1064,7 @@ public class StandardWrapper extends Con @Override public synchronized void load() throws ServletException { instance = loadServlet(); - + if (!instanceInitialized) { initServlet(instance); } @@ -1078,12 +1072,12 @@ public class StandardWrapper extends Con if (isJspServlet) { StringBuilder oname = new StringBuilder(MBeanUtils.getDomain(getParent())); - + oname.append(":type=JspMonitor,name="); oname.append(getName()); - + oname.append(getWebModuleKeyProperties()); - + try { jspMonitorON = new ObjectName(oname.toString()); Registry.getRegistry(null, null) @@ -1161,8 +1155,6 @@ public class StandardWrapper extends Con } } - processServletSecurityAnnotation(servlet.getClass()); - // Special handling for ContainerServlet instances if ((servlet instanceof ContainerServlet) && (isContainerProvidedServlet(servletClass) || @@ -1205,44 +1197,13 @@ public class StandardWrapper extends Con */ @Override public void servletSecurityAnnotationScan() throws ServletException { - if (getServlet() == null) { - Class<?> clazz = null; - try { - clazz = getParent().getLoader().getClassLoader().loadClass( - getServletClass()); - processServletSecurityAnnotation(clazz); - } catch (ClassNotFoundException e) { - // Safe to ignore. No class means no annotations to process - } - } else { - if (servletSecurityAnnotationScanRequired) { - processServletSecurityAnnotation(getServlet().getClass()); - } - } + // NO-OP } - private void processServletSecurityAnnotation(Class<?> clazz) { - // Calling this twice isn't harmful so no syncs - servletSecurityAnnotationScanRequired = false; - - Context ctxt = (Context) getParent(); - - if (ctxt.getIgnoreAnnotations()) { - return; - } - - ServletSecurity secAnnotation = - clazz.getAnnotation(ServletSecurity.class); - if (secAnnotation != null) { - ctxt.addServletSecurity( - new ApplicationServletRegistration(this, ctxt), - new ServletSecurityElement(secAnnotation)); - } - } private synchronized void initServlet(Servlet servlet) throws ServletException { - + if (instanceInitialized && !singleThreadModel) return; // Call the initialization method of this servlet @@ -1454,12 +1415,12 @@ public class StandardWrapper extends Con if (swallowOutput) { SystemLogHandler.startCapture(); } - + // Call the servlet destroy() method try { instanceSupport.fireInstanceEvent (InstanceEvent.BEFORE_DESTROY_EVENT, instance); - + if( Globals.IS_SECURITY_ENABLED) { try { SecurityUtil.doAsPrivilege("destroy", @@ -1470,7 +1431,7 @@ public class StandardWrapper extends Con } else { instance.destroy(); } - + instanceSupport.fireInstanceEvent (InstanceEvent.AFTER_DESTROY_EVENT, instance); @@ -1701,7 +1662,7 @@ public class StandardWrapper extends Con public boolean isAsyncSupported() { return asyncSupported; } - + @Override public void setAsyncSupported(boolean asyncSupported) { this.asyncSupported = asyncSupported; @@ -1711,7 +1672,7 @@ public class StandardWrapper extends Con public boolean isEnabled() { return enabled; } - + @Override public void setEnabled(boolean enabled) { this.enabled = enabled; @@ -1787,24 +1748,24 @@ public class StandardWrapper extends Con */ @Override protected synchronized void startInternal() throws LifecycleException { - - // Send j2ee.state.starting notification + + // Send j2ee.state.starting notification if (this.getObjectName() != null) { - Notification notification = new Notification("j2ee.state.starting", - this.getObjectName(), + Notification notification = new Notification("j2ee.state.starting", + this.getObjectName(), sequenceNumber++); broadcaster.sendNotification(notification); } - + // Start up this component super.startInternal(); setAvailable(0L); - // Send j2ee.state.running notification + // Send j2ee.state.running notification if (this.getObjectName() != null) { - Notification notification = - new Notification("j2ee.state.running", this.getObjectName(), + Notification notification = + new Notification("j2ee.state.running", this.getObjectName(), sequenceNumber++); broadcaster.sendNotification(notification); } @@ -1823,15 +1784,15 @@ public class StandardWrapper extends Con protected synchronized void stopInternal() throws LifecycleException { setAvailable(Long.MAX_VALUE); - - // Send j2ee.state.stopping notification + + // Send j2ee.state.stopping notification if (this.getObjectName() != null) { - Notification notification = - new Notification("j2ee.state.stopping", this.getObjectName(), + Notification notification = + new Notification("j2ee.state.stopping", this.getObjectName(), sequenceNumber++); broadcaster.sendNotification(notification); } - + // Shut down our servlet instance (if it has been initialized) try { unload(); @@ -1843,43 +1804,43 @@ public class StandardWrapper extends Con // Shut down this component super.stopInternal(); - // Send j2ee.state.stopped notification + // Send j2ee.state.stopped notification if (this.getObjectName() != null) { - Notification notification = - new Notification("j2ee.state.stopped", this.getObjectName(), + Notification notification = + new Notification("j2ee.state.stopped", this.getObjectName(), sequenceNumber++); broadcaster.sendNotification(notification); } - - // Send j2ee.object.deleted notification - Notification notification = - new Notification("j2ee.object.deleted", this.getObjectName(), + + // Send j2ee.object.deleted notification + Notification notification = + new Notification("j2ee.object.deleted", this.getObjectName(), sequenceNumber++); broadcaster.sendNotification(notification); } - + @Override protected String getObjectNameKeyProperties() { StringBuilder keyProperties = new StringBuilder("j2eeType=Servlet,name="); - + String name = getName(); if (Util.objectNameValueNeedsQuote(name)) { name = ObjectName.quote(name); } keyProperties.append(name); - + keyProperties.append(getWebModuleKeyProperties()); return keyProperties.toString(); } - + private String getWebModuleKeyProperties() { - + StringBuilder keyProperties = new StringBuilder(",WebModule=//"); String hostName = getParent().getParent().getName(); if (hostName == null) { @@ -1887,7 +1848,7 @@ public class StandardWrapper extends Con } else { keyProperties.append(hostName); } - + String contextName = ((Context) getParent()).getName(); if (!contextName.startsWith("/")) { keyProperties.append('/'); @@ -1898,7 +1859,7 @@ public class StandardWrapper extends Con if (parent instanceof StandardContext) { ctx = (StandardContext) getParent(); } - + keyProperties.append(",J2EEApplication="); if (ctx == null) { keyProperties.append("none"); @@ -1911,10 +1872,10 @@ public class StandardWrapper extends Con } else { keyProperties.append(ctx.getJ2EEServer()); } - + return keyProperties.toString(); } - + /** * JSR 77. Always return false. @@ -1922,19 +1883,19 @@ public class StandardWrapper extends Con public boolean isStateManageable() { return false; } - - /* Remove a JMX notificationListener + + /* Remove a JMX notificationListener * @see javax.management.NotificationEmitter#removeNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object) */ @Override - public void removeNotificationListener(NotificationListener listener, + public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object object) throws ListenerNotFoundException { broadcaster.removeNotificationListener(listener,filter,object); } - + protected MBeanNotificationInfo[] notificationInfo; - + /* Get JMX Broadcaster Info * @TODO use StringManager for international support! * @TODO This two events we not send j2ee.state.failed and j2ee.attribute.changed! @@ -1949,7 +1910,7 @@ public class StandardWrapper extends Con "j2ee.object.created"}, Notification.class.getName(), "servlet is created" - ), + ), new MBeanNotificationInfo(new String[] { "j2ee.state.starting"}, Notification.class.getName(), @@ -1980,37 +1941,37 @@ public class StandardWrapper extends Con return notificationInfo; } - - + + /* Add a JMX-NotificationListener * @see javax.management.NotificationBroadcaster#addNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object) */ @Override - public void addNotificationListener(NotificationListener listener, + public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object object) throws IllegalArgumentException { broadcaster.addNotificationListener(listener,filter,object); } - - + + /** - * Remove a JMX-NotificationListener + * Remove a JMX-NotificationListener * @see javax.management.NotificationBroadcaster#removeNotificationListener(javax.management.NotificationListener) */ @Override - public void removeNotificationListener(NotificationListener listener) + public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException { broadcaster.removeNotificationListener(listener); } - - + + // ------------------------------------------------------------- Attributes - - + + @Deprecated public boolean isEventProvider() { return false; } - + @Deprecated public boolean isStatisticsProvider() { return false;
Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/ContextConfig.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/ContextConfig.java?rev=1823322&r1=1823321&r2=1823322&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/ContextConfig.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/ContextConfig.java Tue Feb 6 12:49:49 2018 @@ -433,15 +433,14 @@ public class ContextConfig implements Li LoginConfig loginConfig = context.getLoginConfig(); SecurityConstraint constraints[] = context.findConstraints(); - if (context.getIgnoreAnnotations() && - (constraints == null || constraints.length ==0) && + if ((constraints == null || constraints.length ==0) && !context.getPreemptiveAuthentication()) { + // No need for an authenticator return; } else { if (loginConfig == null) { - // Not metadata-complete or security constraints present, need - // an authenticator to support @ServletSecurity annotations - // and/or constraints + // Security constraints present. Need an authenticator to + // support them. loginConfig = DUMMY_LOGIN_CONFIG; context.setLoginConfig(loginConfig); } Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/Tomcat.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/Tomcat.java?rev=1823322&r1=1823321&r2=1823322&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/Tomcat.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/Tomcat.java Tue Feb 6 12:49:49 2018 @@ -955,6 +955,9 @@ public class Tomcat { if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) { context.setConfigured(true); + // Process annotations + WebAnnotationSet.loadApplicationAnnotations(context); + // LoginConfig is required to process @ServletSecurity // annotations if (context.getLoginConfig() == null) { Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/WebAnnotationSet.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/WebAnnotationSet.java?rev=1823322&r1=1823321&r2=1823322&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/WebAnnotationSet.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/WebAnnotationSet.java Tue Feb 6 12:49:49 2018 @@ -23,10 +23,13 @@ import javax.annotation.Resource; import javax.annotation.Resources; import javax.annotation.security.DeclareRoles; import javax.annotation.security.RunAs; +import javax.servlet.ServletSecurityElement; +import javax.servlet.annotation.ServletSecurity; import org.apache.catalina.Container; import org.apache.catalina.Context; import org.apache.catalina.Wrapper; +import org.apache.catalina.core.ApplicationServletRegistration; import org.apache.catalina.deploy.ContextEnvironment; import org.apache.catalina.deploy.ContextResource; import org.apache.catalina.deploy.ContextResourceEnvRef; @@ -136,9 +139,17 @@ public class WebAnnotationSet { * Ref JSR 250, equivalent to the run-as element in * the deployment descriptor */ - RunAs annotation = clazz.getAnnotation(RunAs.class); - if (annotation != null) { - wrapper.setRunAs(annotation.value()); + RunAs runAs = clazz.getAnnotation(RunAs.class); + if (runAs != null) { + wrapper.setRunAs(runAs.value()); + } + + // Process ServletSecurity annotation + ServletSecurity servletSecurity = clazz.getAnnotation(ServletSecurity.class); + if (servletSecurity != null) { + context.addServletSecurity( + new ApplicationServletRegistration(wrapper, context), + new ServletSecurityElement(servletSecurity)); } } } Modified: tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml?rev=1823322&r1=1823321&r2=1823322&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml (original) +++ tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Tue Feb 6 12:49:49 2018 @@ -90,6 +90,11 @@ When using Tomcat embedded, only perform Authenticator configuration once during web application start. (markt) </fix> + <fix> + Process all <code>ServletSecurity</code> annotations at web application + start rather than at servlet load time to ensure constraints are applied + consistently. (markt) + </fix> </changelog> </subsection> <subsection name="Other"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org