io.lavagna.web.security.SecurityFilter.java Source code

Java tutorial

Introduction

Here is the source code for io.lavagna.web.security.SecurityFilter.java

Source

/**
 * This file is part of lavagna.
 *
 * lavagna is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * lavagna is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with lavagna.  If not, see <http://www.gnu.org/licenses/>.
 */
package io.lavagna.web.security;

import static org.springframework.web.context.support.WebApplicationContextUtils.getRequiredWebApplicationContext;
import io.lavagna.web.security.SecurityConfiguration.UrlMatcher;

import java.io.IOException;
import java.util.List;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.tuple.ImmutablePair;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.context.WebApplicationContext;

/**
 * <pre>
 * FIXME: obviously I'm not happy with this one...
 *
 * - I was not able to do a dynamic configuration with spring security.
 * - I needed some additional control
 *
 * If there is some kind of alternatives that give me the same features/functionality as the current version...
 * </pre>
 */
public class SecurityFilter extends AbstractBaseFilter {

    private final PathMatcher pathMatcher = new AntPathMatcher();
    private final SortedMap<String, ImmutablePair<SecurityConfiguration, List<UrlMatcher>>> pathsToCheck = new TreeMap<>();

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        WebApplicationContext ctx = getRequiredWebApplicationContext(filterConfig.getServletContext());
        for (Entry<String, SecurityConfiguration> kv : ctx.getBeansOfType(SecurityConfiguration.class).entrySet()) {
            pathsToCheck.put(kv.getKey(), ImmutablePair.of(kv.getValue(), kv.getValue().buildMatcherList()));
        }
    }

    @Override
    protected void doFilterInternal(HttpServletRequest req, HttpServletResponse resp, FilterChain chain)
            throws IOException, ServletException {

        addHeaders(req, resp);

        for (ImmutablePair<SecurityConfiguration, List<UrlMatcher>> path : pathsToCheck.values()) {
            if (path.left.matchRequest(req)) {
                handleWith(req, resp, chain, path.right);
                return;
            }
        }

        chain.doFilter(req, resp);
    }

    private void handleWith(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain,
            List<UrlMatcher> matchers) throws IOException, ServletException {

        String reqUriWithoutContextPath = reqUriWithoutContextPath(request);

        for (UrlMatcher urlMatcher : matchers) {
            if (urlMatcher.match(reqUriWithoutContextPath, pathMatcher)) {
                if (urlMatcher.doAction(request, response)) {
                    // the action has been handled by the url matcher, no
                    // further processing is required
                    return;
                } else {
                    break;
                }
            }
        }

        filterChain.doFilter(request, response);
    }

    private static String reqUriWithoutContextPath(HttpServletRequest request) {
        return request.getRequestURI().substring(request.getServletContext().getContextPath().length());
    }

    private static boolean canApplyNoCachingHeaders(HttpServletRequest req) {
        String u = req.getRequestURI();
        return !("/".equals(u) || u.matches(".*\\.(css|gif|js|png|html|eot|svg|ttf|woff)$"));
    }

    /**
     */
    // TODO check if the no caching directives could be removed/or at least
    // changed... (?)
    private static void addHeaders(HttpServletRequest req, HttpServletResponse res) {
        if (canApplyNoCachingHeaders(req)) {
            res.addHeader("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate");
            res.addHeader("Expires", "0");
            res.addHeader("Pragma", "no-cache");
        }

        res.addHeader("X-Frame-Options", "SAMEORIGIN");
        res.addHeader("X-XSS-Protection", "1; mode=block");
        res.addHeader("x-content-type-options", "nosniff");
    }

}