Rewrite url in Spring Boot AWS container

155 views Asked by At

I have a spring boot app that is likely to be Software as a Medical Device, and has a section that is protected with oauth2, and a demo section. I'd like to have these at separate hostnames, e.g. protected.example.com and demo.example.com. I can do this perfectly well with a simple Apache2 proxypass directive:

ServerName demo.example.com
ProxyPassReverse / http://localhost:9000/demo/
ProxyPass / http://localhost:9000/demo/

The problem is that I need to deploy this on Amazon Web Services, which won't let me redirect to a path, only to a server. I've implemented tuckey-urlrewrite-filter, but it gets invoked AFTER SecurityContextPersistenceFilter, and putting it before that filter fails:

17:40:00 ERROR o.a.c.c.C.[Tomcat].[localhost].[/].[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception java.lang.NullPointerException: null
    at org.tuckey.web.filters.urlrewrite.UrlRewriteFilter.doFilter(UrlRewriteFilter.java:373)

I'm not sure I want to bypass Spring Security for any url in https://demo.example.com. I understand that I could break out demo into a separate container/context/whatever, but this seems computationally redundant and risks having parallel codebases. My goal is for someone who is invited to view demo.example.com to not know that protected.example.com exists. Is there a "simple" approach to this:

  1. A simple way to allow demo.example.com to AllowAll()
  2. A way to put /demo on a separate port
  3. A way to allow urlrewrite-filter to go to the top of the filter chain.
  4. An undocumented feature in AWS

Unleash your creativity!

1

There are 1 answers

0
Jeff E Mandel On

Here is what I've learned. The problem was putting the Tuckey (or ANY filter) before SecurityContextPersistenceFilter. The request doesn't have PathInfo populated until after the HeaderWriterFilter. It does have the URI. Moving the filter later in the chain solves this problem, but it should precede authentication filters.

What I didn't mention in my original post was that /demo and the protected area share the static resources, so prepending /demo on URIs for demo.example.com must be avoided for these. The solution is:

public class rewriteDemoFilter extends GenericFilterBean {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String hostname = request.getServerName();
        String path = request.getRequestURI();
        String base;
        if (path.length() == 1) {
            base = "";
        } else {
            String[] components = path.split("/");
            base = components[1];
        }
        if (hostname.equalsIgnoreCase("demo.example.com")) {
            switch (base) {
                case "js":
                case "sounds":
                case "webjars":
                case "css":
                case "images":
                    break;
                default:
                    path = "/demo" + path;
            }
            request.getRequestDispatcher(path).forward(servletRequest, servletResponse);
        } else {
            filterChain.doFilter(servletRequest, servletResponse);
        }
     }
}

This filter should be added in the Security configuration:

.addFilterAfter(new rewriteDemoFilter(), HeaderWriterFilter.class)

The advantage of this solution is that URL mangling is all done in the Spring app, so my development environment (Apache forwarding to the Spring app launched from the command line) and my AWS environment (a Docker image running in an ECS task) don't require distinct mechanisms to rewrite the path. The downside is that my security is bypassed, but since the filter only processes requests destined for the unprotected realms of the site and the strict firewall removes dangerous patterns from the URI, I'm moderately optimistic that only small trucks can drive through the hole.