Commit 8af0a8d1 authored by Matija Obreza's avatar Matija Obreza
Browse files

LocaleURLFilter must execute before springSecurityFilter

parent d1afddb8
/*
* Copyright 2017 Global Crop Diversity Trust
* Copyright 2018 Global Crop Diversity Trust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -21,9 +21,7 @@ import java.util.Enumeration;
import java.util.Locale;
import java.util.regex.Matcher;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
......@@ -33,66 +31,91 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.filter.GenericFilterBean;
/**
* Handles the very important locale selection by URL
*/
public class LocaleURLFilter implements Filter {
public class LocaleURLFilter extends GenericFilterBean {
private static final Logger LOG = LoggerFactory.getLogger(LocaleURLFilter.class);
private static final LocaleURLMatcher localeUrlMatcher = new LocaleURLMatcher();
public static final String REQUEST_LOCALE_ATTR = LocaleURLFilter.class.getName() + ".LOCALE";
private static final String REQUEST_INTERNAL_URL = LocaleURLFilter.class.getName() + ".INTERNALURL";
private static final String REQUEST_LOCALE_LANGUAGE = LocaleURLFilter.class.getName() + ".LANGUAGE";
private String[] allowedLocales = null;
private Locale defaultLocale;
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
final String excludePaths = filterConfig.getInitParameter("exclude-paths");
public LocaleURLFilter() {
addRequiredProperty("excludePaths");
addRequiredProperty("allowedLocales");
addRequiredProperty("defaultLocale");
}
public void setExcludePaths(String excludePaths) {
if (StringUtils.isNotBlank(excludePaths)) {
final String[] ex = excludePaths.split("\\s+");
final String[] ex = excludePaths.split("\\s*,\\s*");
for (final String e : ex) {
LOG.info("Excluding path: {}", e);
}
localeUrlMatcher.setExcludedPaths(ex);
}
final String defaultLocale = filterConfig.getInitParameter("default-locale");
if (defaultLocale != null) {
this.defaultLocale = Locale.forLanguageTag(defaultLocale);
} else {
this.defaultLocale = Locale.getDefault();
}
LOG.info("Using default locale: {}", this.defaultLocale);
final String allowedLocales = filterConfig.getInitParameter("allowed-locales");
}
public void setAllowedLocales(String allowedLocales) {
if (StringUtils.isNotBlank(allowedLocales)) {
final String[] ex = allowedLocales.split("\\s+");
final String[] ex = allowedLocales.split("\\s*,\\s*");
for (final String l : ex) {
LOG.info("Allowed locale: {}", l);
}
this.allowedLocales = ex;
}
}
public void setDefaultLocale(String defaultLocale) {
LOG.info("Default locale: {}", defaultLocale);
if (defaultLocale != null) {
this.defaultLocale = Locale.forLanguageTag(defaultLocale);
} else {
this.defaultLocale = Locale.getDefault();
}
LOG.info("Using default locale: {}", this.defaultLocale);
}
@Override
public void destroy() {
LOG.info("Destroying LocaleURLFilter");
}
@Override
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
final HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
final String url = httpRequest.getRequestURI().substring(httpRequest.getContextPath().length());
if (localeUrlMatcher.isExcludedPath(url)) {
LOG.debug("Excluded " + url);
filterChain.doFilter(servletRequest, servletResponse);
return;
}
LOG.trace("Incoming URL: {}", url);
LOG.debug("Incoming URL: {}", url);
{
final Enumeration<String> attrNames = httpRequest.getAttributeNames();
while (attrNames.hasMoreElements()) {
final String attrName = attrNames.nextElement();
LOG.trace("Request attr {} = {}", attrName, httpRequest.getAttribute(attrName));
}
}
String existingUrlLanguage = (String) httpRequest.getAttribute(REQUEST_LOCALE_LANGUAGE);
if (existingUrlLanguage != null) {
final LocaleWrappedServletResponse localeResponse = new LocaleWrappedServletResponse(httpResponse, localeUrlMatcher, existingUrlLanguage, defaultLocale.toLanguageTag());
LOG.debug("Found REQUEST_LOCALE_LANGUAGE {} in request", existingUrlLanguage);
filterChain.doFilter(servletRequest, localeResponse);
return;
}
final Matcher matcher = localeUrlMatcher.matcher(url);
if (matcher.matches()) {
......@@ -128,29 +151,28 @@ public class LocaleURLFilter implements Filter {
}
httpRequest.setAttribute(REQUEST_LOCALE_ATTR, urlLocale);
httpRequest.setAttribute(REQUEST_LOCALE_LANGUAGE, urlLanguage);
httpRequest.setAttribute(REQUEST_INTERNAL_URL, getInternalUrl(remainingUrl, httpRequest.getQueryString()));
if (LOG.isTraceEnabled()) {
LOG.trace("URL matches! lang={} remaining={}", urlLanguage, remainingUrl);
LOG.trace("Country: {} Lang: {} locale={}", urlLocale.getCountry(), urlLocale.getLanguage(), urlLocale);
LOG.debug("URL matches! lang={} remaining={}", urlLanguage, remainingUrl);
LOG.debug("Country: {} Lang: {} locale={}", urlLocale.getCountry(), urlLocale.getLanguage(), urlLocale);
final Enumeration<String> attrNames = httpRequest.getAttributeNames();
while (attrNames.hasMoreElements()) {
final String attrName = attrNames.nextElement();
LOG.trace("Request attr {} = {}", attrName, httpRequest.getAttribute(attrName));
LOG.debug("Request attr {} = {}", attrName, httpRequest.getAttribute(attrName));
}
LOG.trace("Proxying request to remaining URL {}", remainingUrl);
LOG.debug("Proxying request to remaining URL {}", remainingUrl);
}
final LocaleWrappedServletResponse localeResponse = new LocaleWrappedServletResponse(httpResponse, localeUrlMatcher, urlLanguage, defaultLocale.toLanguageTag());
final LocaleWrappedServletRequest localeRequest = new LocaleWrappedServletRequest(httpRequest, url, remainingUrl);
// request.getRequestDispatcher(remainingUrl == null ? "/" :
// remainingUrl).forward(servletRequest, localeResponse);
filterChain.doFilter(localeRequest, localeResponse);
} else {
LOG.trace("No match on url {}", url);
LOG.debug("No match on url {}", url);
httpRequest.setAttribute(REQUEST_INTERNAL_URL, getInternalUrl(url, httpRequest.getQueryString()));
final LocaleWrappedServletResponse localeResponse = new LocaleWrappedServletResponse(httpResponse, localeUrlMatcher, null, defaultLocale.toLanguageTag());
filterChain.doFilter(servletRequest, localeResponse);
......
/**
* Copyright 2014 Global Crop Diversity Trust
/*
* Copyright 2018 Global Crop Diversity Trust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -12,7 +12,7 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
*/
package org.genesys2.server.servlet.filter;
......
/**
* Copyright 2014 Global Crop Diversity Trust
/*
* Copyright 2018 Global Crop Diversity Trust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -12,7 +12,7 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
*/
package org.genesys2.server.servlet.filter;
......@@ -39,8 +39,7 @@ public class LocaleWrappedServletRequest extends HttpServletRequestWrapper {
public String getServletPath() {
String servletPath = super.getServletPath();
if (this.originalUrl.equals(servletPath)) {
if (LOG.isDebugEnabled())
LOG.debug("servletPath: {} remaining: {}", servletPath, remainingUrl);
LOG.trace("servletPath={} remaining={}", servletPath, remainingUrl);
return remainingUrl;
}
return servletPath;
......@@ -50,11 +49,9 @@ public class LocaleWrappedServletRequest extends HttpServletRequestWrapper {
public String getRequestURI() {
String requestURI = super.getRequestURI();
if (this.originalUrl.equals(requestURI)) {
if (LOG.isDebugEnabled())
LOG.debug("requestURI: {} remaining={}", requestURI, remainingUrl);
LOG.trace("requestURI={} remaining={}", requestURI, remainingUrl);
return remainingUrl;
}
return requestURI;
}
}
/**
* Copyright 2014 Global Crop Diversity Trust
/*
* Copyright 2018 Global Crop Diversity Trust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -12,10 +12,12 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
*/
package org.genesys2.server.servlet.filter;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
......@@ -34,12 +36,14 @@ public class LocaleWrappedServletResponse extends HttpServletResponseWrapper {
super(response);
this.localeUrlMatcher = localeUrlMatcher;
this.prefix = updatePrefix(urlLanguage);
LOG.debug("Response prefix={} lang={}", prefix, urlLanguage);
this.defaultLanguagePrefix = "/" + defaultLanguage + "/";
}
private boolean isExcluded(String url) {
// Exclude querystring-only urls, URLs starting with // and anything excluded by the matcher
boolean excluded = url.startsWith("?") || url.startsWith("//") || localeUrlMatcher.isExcluded(url);
// Exclude querystring-only urls, URLs starting with //, http:// or https:// and anything excluded by
// the matcher
boolean excluded = url.startsWith("?") || url.startsWith("//") || url.startsWith("http://") || url.startsWith("https://") || localeUrlMatcher.isExcluded(url);
LOG.trace("isExcluded? {} --> {}", url, excluded);
return excluded;
}
......@@ -48,12 +52,13 @@ public class LocaleWrappedServletResponse extends HttpServletResponseWrapper {
public String encodeURL(String url) {
if (isExcluded(url)) {
if (url.startsWith(defaultLanguagePrefix)) {
LOG.debug("URL starts with defaultLanguagePrefix={} trimming down", defaultLanguagePrefix);
return super.encodeURL(url.substring(defaultLanguagePrefix.length() - 1));
}
return super.encodeURL(url);
} else {
String encodedURL = prefix + super.encodeURL(url);
LOG.trace("encodeURL {} to {}", url, encodedURL);
LOG.debug("encodeURL {} to {}", url, encodedURL);
return encodedURL;
}
}
......@@ -65,7 +70,7 @@ public class LocaleWrappedServletResponse extends HttpServletResponseWrapper {
return super.encodeUrl(url);
} else {
String encodedURL = prefix + super.encodeUrl(url);
LOG.trace("encodeUrl {} to {}", url, encodedURL);
LOG.debug("encodeUrl {} to {}", url, encodedURL);
return encodedURL;
}
}
......@@ -76,7 +81,7 @@ public class LocaleWrappedServletResponse extends HttpServletResponseWrapper {
return super.encodeRedirectURL(url);
} else {
String encodedURL = prefix + super.encodeRedirectURL(url);
LOG.trace("encodeRedirectURL {} to {}", url, encodedURL);
LOG.debug("encodeRedirectURL {} to {}", url, encodedURL);
return encodedURL;
}
}
......@@ -88,11 +93,38 @@ public class LocaleWrappedServletResponse extends HttpServletResponseWrapper {
return super.encodeRedirectUrl(url);
} else {
String encodedURL = prefix + super.encodeRedirectUrl(url);
LOG.trace("encodeRedirectUrl {} to {}", url, encodedURL);
LOG.debug("encodeRedirectUrl {} to {}", url, encodedURL);
return encodedURL;
}
}
@Override
public void sendRedirect(String location) throws IOException {
if (isExcluded(location)) {
super.sendRedirect(location);
} else {
String prefixedUrl = prefix + location;
LOG.debug("sendRedirect {} to {}", location, prefixedUrl);
super.sendRedirect(prefixedUrl);
}
}
@Override
public void setHeader(String name, String value) {
LOG.debug("setHeader {}: {}", name, value);
if ("Location".equalsIgnoreCase(name)) {
if (isExcluded(value)) {
super.setHeader(name, value);
} else {
String prefixedUrl = prefix + value;
LOG.debug("Rewrote redirect header {}: {} -> {}", name, value, prefixedUrl);
super.setHeader(name, prefixedUrl);
}
} else {
super.setHeader(name, value);
}
}
private String updatePrefix(String language) {
if (StringUtils.isBlank(language)) {
return "";
......
......@@ -17,9 +17,14 @@ package org.genesys2.spring.config;
import java.util.EnumSet;
import javax.servlet.*;
import com.hazelcast.web.SessionListener;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterRegistration;
import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import javax.servlet.SessionTrackingMode;
import org.genesys2.server.servlet.filter.LocaleURLFilter;
import org.sitemesh.builder.SiteMeshFilterBuilder;
......@@ -33,6 +38,8 @@ import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatche
import org.tuckey.web.filters.urlrewrite.UrlRewriteFilter;
import org.tuckey.web.filters.urlrewrite.gzip.GzipFilter;
import com.hazelcast.web.SessionListener;
/**
* Boots up Spring MVC and registers additional servlet filters
*/
......@@ -64,12 +71,12 @@ public class WebInitializer extends AbstractAnnotationConfigDispatcherServletIni
return new Filter[] { characterEncodingFilter };
}
@Override
protected DispatcherServlet createDispatcherServlet(final WebApplicationContext servletAppContext) {
final DispatcherServlet dispatcherServlet = (DispatcherServlet) super.createDispatcherServlet(servletAppContext);
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
return dispatcherServlet;
}
@Override
protected DispatcherServlet createDispatcherServlet(final WebApplicationContext servletAppContext) {
final DispatcherServlet dispatcherServlet = (DispatcherServlet) super.createDispatcherServlet(servletAppContext);
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
return dispatcherServlet;
}
@Override
public void onStartup(final ServletContext servletContext) throws ServletException {
......@@ -100,19 +107,18 @@ public class WebInitializer extends AbstractAnnotationConfigDispatcherServletIni
hazelcastWebFilter.setInitParameter("targetFilterLifecycle", "true");
hazelcastWebFilter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.REQUEST), false, "/*");
// Locale URL filter configuration
final FilterRegistration.Dynamic localeURLFilter = servletContext.addFilter("localeURLFilter", LocaleURLFilter.class);
localeURLFilter.setInitParameter("defaultLocale", "en");
localeURLFilter.setInitParameter("allowedLocales", "en,es,de,fr,fa,ar,ru,zh,pt");
localeURLFilter.setInitParameter("excludePaths", "/html,/login-attempt");
localeURLFilter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST, DispatcherType.INCLUDE, DispatcherType.FORWARD), false, "/*");
// Then the spring security
final DelegatingFilterProxy filter = new DelegatingFilterProxy("springSecurityFilterChain");
filter.setContextAttribute("org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcher");
servletContext.addFilter("springSecurityFilterChain", filter).addMappingForUrlPatterns(null, false, "/*");
// Locale URL filter configuration
// TODO Upgrade to @WebFilter
final FilterRegistration.Dynamic localeURLFilter = servletContext.addFilter("localeURLFilter", LocaleURLFilter.class);
localeURLFilter.setInitParameter("exclude-paths", "/html /login-attempt");
localeURLFilter.setInitParameter("default-locale", "en");
localeURLFilter.setInitParameter("allowed-locales", "en es de fr fa ar ru zh pt");
localeURLFilter.addMappingForUrlPatterns(null, false, "/*");
// http://stackoverflow.com/a/22409634
final ConfigurableSiteMeshFilter sitemeshWithErrors = new ConfigurableSiteMeshFilter() {
@Override
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment