2

I'm working on an java-based web application, implementing SSO using Spring Security SAML on a Tomcat server. This application would play the service provider role (SP). The default Spring URL to retrieve this SP's metadata is:

https://www.server.com:8080/context/saml/metadata

This works just fine, returning the metadata XML file as expected. However, I run into a problem when I add a DefaultServlet servlet-mappings to the web.xml. Even just something as basic as:

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.gif</url-pattern>
</servlet-mapping>

If one or more default servlet mapping exists in the web.xml, the above URL returns a 404. Anyone know What could cause this and have a possible solution?

Update: I've put the exact servlet mapping from above in the Spring Security SAML sample application and it also prevents the metadata URL from working. If I comment it out or remove it, it works as expected. Below is that web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" 
xmlns="http://java.sun.com/xml/ns/j2ee" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

<display-name>Spring Security SAML</display-name>
<description>Sample application demonstrating Spring security SAML integration.</description>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        /WEB-INF/securityContext.xml
    </param-value>
</context-param>

<servlet>
    <servlet-name>saml</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>saml</servlet-name>
    <url-pattern>/saml/web/*</url-pattern>
</servlet-mapping>

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<!-- This servlet mapping prevents the /saml/metadata URL from working. -->
 <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.gif</url-pattern>
</servlet-mapping>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
</welcome-file-list>

<error-page>
    <exception-type>java.lang.Exception</exception-type>
    <location>/error.jsp</location>
</error-page>


</web-app>
AndyB
  • 1,896
  • 2
  • 22
  • 32

1 Answers1

2

I've tried to reproduce your problem with Spring SAML 1.0.0.RELEASE by following these steps:

  • downloaded Spring SAML sources
  • replaced sample/src/main/webapp/WEB-INF/web.xml with your web.xml
  • started the sample application using gradlew build tomcatRun

But I'm unable to reproduce your issue, everything continues working as it should. The problem is probably specific to some Tomcat version, please try to reproduce it with my steps and eventually try changing your Tomcat version.

Updated:

I was able to get it reproduced when deploying directly to Tomcat as you mention. The default servlet seems to skip execution of filters defined at /*. The following configuration should work for you:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
         xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

    <display-name>Spring Security SAML</display-name>
    <description>Sample application demonstrating Spring security SAML integration.</description>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/securityContext.xml
        </param-value>
    </context-param>

    <servlet>
        <servlet-name>saml</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>saml</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>jsp</servlet-name>
        <url-pattern>/WEB-INF/*</url-pattern>
    </servlet-mapping>

    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/images/*</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/css/*</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.gif</url-pattern>
    </servlet-mapping>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

    <error-page>
        <exception-type>java.lang.Exception</exception-type>
        <location>/error.jsp</location>
    </error-page>


</web-app>

Make sure to change file org.springframework.security.saml.web.MetadataController and replace @RequestMapping("/metadata") with @RequestMapping("/saml/web/metadata")

Vladimír Schäfer
  • 15,375
  • 2
  • 51
  • 71
  • I followed your steps and it worked for me too. However if I build the WAR file using Maven via Eclipse (clean compile install) and deploy that to Tomcat 7.0.47 via the Tomcat manager, the metadata download URL does not work. Any idea why it would work for one but not the other? I'm not familiar with Gradle. Does it use the same Tomcat instance I have installed or does it use its own embedded version? If the latter, which version of Tomcat would it be using? – AndyB Aug 10 '14 at 01:54
  • It's running Tomcat 7, but the configuration might be different from standalone Tomcat. Please see the updated answer. – Vladimír Schäfer Aug 10 '14 at 07:12
  • Your web.xml does get the sample app to work but I'm not seeing what the solution is. The changes you made would impact the saml servlet and its URL mapping. My understanding is that the metadata download URL is handled by the MetadataDisplayFilter which doesn't require the saml servlet since the Spring Security SAML Extension doc doesn't mention needing it. If I remove the saml servlet declaration and mapping in the sample app, I'd expect that to have no impact on the metadata download but that's not the case. Would you explain how your change in the web.xml impacts the metadata download? Thx – AndyB Aug 11 '14 at 18:40
  • 1
    In order for the /saml/metadata to work, Tomcat must execute the springSecurityFilterChain. For some internal Tomcat's reason inclusion of the default's servlet-mapping makes Tomcat skip the filter. By changing mapping of the "saml" dispatcher servlet from /saml/web/* to /* I'm forcing Tomcat to handle calls to /saml/metadata using the "saml" servlet and correctly execute the springSecurityFilterChain which then serves the metadata content. – Vladimír Schäfer Aug 11 '14 at 19:48
  • Ah yes! Took that nugget of knowledge and applied it to my own app. I've got it working. Thank you for help and patience! – AndyB Aug 11 '14 at 21:06