*/
public void setEnabled(boolean enabled);
+ /**
+ * Set the flag that indicates
+ * {@link javax.servlet.annotation.ServletSecurity} annotations must be
+ * scanned when the Servlet is first used.
+ *
+ * @param b The new value of the flag
+ */
+ public void setServletSecurityAnnotationScanRequired(boolean b);
+
+ /**
+ * Scan for (if necessary) and process (if found) the
+ * {@link javax.servlet.annotation.ServletSecurity} annotations for the
+ * Servlet associated with this wrapper.
+ */
+ public void servletSecurityAnnotationScan() throws ServletException;
}
// The Servlet may specify security constraints through annotations.
// Ensure that they have been processed before constraints are checked
Wrapper wrapper = (Wrapper) request.getMappingData().wrapper;
- if (wrapper.getServlet() == null) {
- wrapper.load();
- }
+ wrapper.servletSecurityAnnotationScan();
Realm realm = this.context.getRealm();
// Is this request URI subject to a security constraint?
private boolean fireRequestListenersOnForwards = false;
+ /**
+ * Servlets created via {@link ApplicationContext#createServlet(Class)} for
+ * tracking purposes.
+ */
+ private Set<Servlet> createdServlets = new HashSet<Servlet>();
+
// ----------------------------------------------------- Context Properties
* @param wrapper The wrapper for the Servlet that was added
*/
public ServletRegistration.Dynamic dynamicServletAdded(Wrapper wrapper) {
+ Servlet s = wrapper.getServlet();
+ if (s != null && createdServlets.contains(s)) {
+ // Mark the wrapper to indicate annotations need to be scanned
+ wrapper.setServletSecurityAnnotationScanRequired(true);
+ }
return new ApplicationServletRegistration(wrapper, this);
}
* @param servlet
*/
public void dynamicServletCreated(Servlet servlet) {
- // NOOP - Hook for JACC implementations
+ createdServlets.add(servlet);
}
initializers.clear();
+ createdServlets.clear();
+
if(log.isDebugEnabled())
log.debug("resetContext " + getObjectName());
}
*/
protected boolean enabled = true;
+ protected volatile boolean servletSecurityAnnotationScanRequired = false;
+
/**
* Static class array used when the SecurityManager is turned on and
* <code>Servlet.init</code> is invoked.
instance = servlet;
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setServletSecurityAnnotationScanRequired(boolean b) {
+ this.servletSecurityAnnotationScanRequired = b;
+ }
+
// --------------------------------------------------------- Public Methods
}
}
- ServletSecurity secAnnotation =
- servlet.getClass().getAnnotation(ServletSecurity.class);
- Context ctxt = (Context) getParent();
- if (secAnnotation != null) {
- ctxt.addServletSecurity(
- new ApplicationServletRegistration(this, ctxt),
- new ServletSecurityElement(secAnnotation));
- }
-
+ processServletSecurityAnnotation(servlet);
// Special handling for ContainerServlet instances
if ((servlet instanceof ContainerServlet) &&
- (isContainerProvidedServlet(servletClass) ||
- ctxt.getPrivileged() )) {
+ (isContainerProvidedServlet(servletClass) ||
+ ((Context) getParent()).getPrivileged() )) {
((ContainerServlet) servlet).setWrapper(this);
}
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void servletSecurityAnnotationScan() throws ServletException {
+ if (instance == null) {
+ load();
+ } else {
+ if (servletSecurityAnnotationScanRequired) {
+ processServletSecurityAnnotation(instance);
+ }
+ }
+ }
+
+ private void processServletSecurityAnnotation(Servlet servlet) {
+ // Calling this twice isn't harmful so no syncs
+ servletSecurityAnnotationScanRequired = false;
+
+ ServletSecurity secAnnotation =
+ servlet.getClass().getAnnotation(ServletSecurity.class);
+ Context ctxt = (Context) getParent();
+ if (secAnnotation != null) {
+ ctxt.addServletSecurity(
+ new ApplicationServletRegistration(this, ctxt),
+ new ServletSecurityElement(secAnnotation));
+ }
+ }
+
private synchronized void initServlet(Servlet servlet)
throws ServletException {
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import javax.servlet.Servlet;
+import javax.servlet.ServletContainerInitializer;
+import javax.servlet.ServletContext;
import javax.servlet.ServletException;
+import javax.servlet.ServletRegistration;
import javax.servlet.annotation.HttpConstraint;
import javax.servlet.annotation.HttpMethodConstraint;
import javax.servlet.annotation.ServletSecurity;
assertEquals(200, rc);
}
+ public void testSecurityAnnotationsAddServlet1() throws Exception {
+ doTestSecurityAnnotationsAddServlet(false);
+ }
+
+ public void testSecurityAnnotationsAddServlet2() throws Exception {
+ doTestSecurityAnnotationsAddServlet(true);
+ }
+
+ private void doTestSecurityAnnotationsAddServlet(boolean useCreateServlet)
+ throws Exception {
+
+ // Setup Tomcat instance
+ Tomcat tomcat = getTomcatInstance();
+
+ // Must have a real docBase - just use temp
+ Context ctx =
+ tomcat.addContext("", System.getProperty("java.io.tmpdir"));
+
+ Servlet s = new DenyAllServlet();
+ ServletContainerInitializer sci = new SCI(s, useCreateServlet);
+ ctx.addServletContainerInitializer(sci, null);
+
+ tomcat.start();
+
+ ByteChunk bc = new ByteChunk();
+ int rc;
+ rc = getUrl("http://localhost:" + getPort() + "/", bc, null, null);
+
+ if (useCreateServlet) {
+ assertNull(bc.toString());
+ assertEquals(403, rc);
+ } else {
+ assertEquals("OK", bc.toString());
+ assertEquals(200, rc);
+ }
+ }
+
private void doTest(String servletClassName, boolean usePost,
boolean useRole, boolean expect200) throws Exception {
public static class RoleDenyServlet extends TestServlet {
private static final long serialVersionUID = 1L;
}
+
+ public static class SCI implements ServletContainerInitializer {
+
+ private Servlet servlet;
+ private boolean createServlet;
+
+ public SCI(Servlet servlet, boolean createServlet) {
+ this.servlet = servlet;
+ this.createServlet = createServlet;
+ }
+
+ @Override
+ public void onStartup(Set<Class<?>> c, ServletContext ctx)
+ throws ServletException {
+ Servlet s;
+
+ if (createServlet) {
+ s = ctx.createServlet(servlet.getClass());
+ } else {
+ s = servlet;
+ }
+ ServletRegistration.Dynamic r = ctx.addServlet("servlet", s);
+ r.addMapping("/");
+ }
+ }
}