I am upgrading a web application (Servlet 3.0 / Tomcat 7) that requires basic authentication on most of its pages. This application has a small set of monitoring servlets, none of which should be protected. In my web.xml
, I currently have the following security-constraint
blocks (private info replaced by letters of the alphabet):
<security-constraint>
<display-name>Security Constraint</display-name>
<web-resource-collection>
<web-resource-name>Protected Area</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>CN=A,OU=B,OU=C,OU=D,DC=E,DC=F</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Unprotected Pages</web-resource-name>
<url-pattern>/health/*</url-pattern>
</web-resource-collection>
</security-constraint>
Within the "health" path there are three endpoints:
/health/monitor/status
/health/monitor/version
/health/monitor/version/xml
When I visit either of the version
endpoints, I am not prompted for credentials (as expected). However when I visit the status
page, the browser presents me with a basic authentication box. When I hit "Cancel", I'm allowed to load the page normally. Likewise if I've already logged in, I will not be prompted again by the status screen until my login expires.
I realize that this could be solved by not having the secure content deployed to /*
, but moving it would be a lot of work changing hard-coded paths and testing (it's a very old application)... and I have 5 or 6 more to do. I'm open to doing this if necessary, but I wanted to find out if this is possible without changing any secure content paths. I do have complete freedom over the paths of the monitoring servlets.
This seems related to Tomcat 7 - Multiple security-constraints not working but rather than total failure just one of my endpoints is failing, which I find very strange. I've spent some time searching and it looks like what I'm doing should work... but it doesn't.
I'm using web-app
version 3.0, deploying to Tomcat 7 (have tried versions 7.0.42 and 7.0.47). I have already tried changing the order of the security-constraint
blocks.
Thoughts?
Here is my full web.xml
for reference (note the monitoring servlets are managed via Java annotations, so are not present):
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
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">
<display-name>TPS</display-name>
<servlet>
<servlet-name>CFMLServlet</servlet-name>
<servlet-class>railo.loader.servlet.CFMLServlet</servlet-class>
<init-param>
<param-name>configuration</param-name>
<param-value>/WEB-INF/railo/</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>AMFServlet</servlet-name>
<servlet-class>railo.loader.servlet.AMFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>AttachmentServlet</servlet-name>
<servlet-class>com.package.toolshed.AttachmentServlet</servlet-class>
<init-param>
<param-name>configFilePath</param-name>
<param-value>com/package/toolshed/configuration/tps-config.xml</param-value>
</init-param>
<init-param>
<param-name>configPathParam</param-name>
<param-value>attachment.servlet.pathPrefix</param-value>
</init-param>
<load-on-startup>6</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CFMLServlet</servlet-name>
<url-pattern>*.cfm</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>CFMLServlet</servlet-name>
<url-pattern>*.cfml</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>CFMLServlet</servlet-name>
<url-pattern>*.cfc</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AMFServlet</servlet-name>
<url-pattern>/flashservices/gateway/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AttachmentServlet</servlet-name>
<url-pattern>/attachments/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.cfm</welcome-file>
<welcome-file>index.cfml</welcome-file>
</welcome-file-list>
<security-constraint>
<display-name>Security Constraint</display-name>
<web-resource-collection>
<web-resource-name>Protected Area</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>CN=A,OU=B,OU=C,OU=D,DC=E,DC=F</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Unprotected Pages</web-resource-name>
<url-pattern>/health/*</url-pattern>
</web-resource-collection>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>TPS</realm-name>
</login-config>
<security-role>
<role-name>CN=A,OU=B,OU=C,OU=D,DC=E,DC=F</role-name>
</security-role>
</web-app>
Figured this out.
It turns out that the status servlet was loading a CSS document, and that load was triggering the auth. What confuses me is that both status and version load JSPs, and these JSPs do not need to be considered in the security-constraint (one of the steps I took initially was to add
*.jsp
to my security constraint). The JSPs exist at the same path as the CSS.New, working web.xml