/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.flow.controller;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.geoserver.filters.GeoServerFilter;
import org.geoserver.platform.GeoServerExtensions;
import org.geoserver.platform.GeoServerResourceLoader;
import org.geoserver.platform.resource.Resource;
import org.geoserver.security.PropertyFileWatcher;
import org.geotools.util.logging.Logging;
/**
* A class that allows the configuration of an ip black list, rejecting requests from ip addresses configured in the controlflow.properties file
*
* @author Juan Marin, OpenGeo
*
*/
public class IpBlacklistFilter implements GeoServerFilter {
static final Logger LOGGER = Logging.getLogger(IpBlacklistFilter.class);
static final String PROPERTYFILENAME="controlflow.properties";
static final String BLPROPERTY="ip.blacklist";
static final String WLPROPERTY="ip.whitelist";
private Set<String> blackListedAddresses;
private Set<String> whiteListedAddresses;
private final PropertyFileWatcher configFile;
/**
* Constructor used for testing purposes
*
* @param props configuraiton properties
*/
public IpBlacklistFilter(Properties props) {
this.blackListedAddresses = loadConfiguration(props, BLPROPERTY);
this.whiteListedAddresses = loadConfiguration(props, WLPROPERTY);
configFile = null;
}
/**
* Default constructor
*/
public IpBlacklistFilter() {
try {
GeoServerResourceLoader loader = GeoServerExtensions.bean(GeoServerResourceLoader.class);
Resource resource = loader.get(PROPERTYFILENAME);
configFile = new PropertyFileWatcher(resource);
blackListedAddresses = reloadConfiguration(BLPROPERTY);
whiteListedAddresses = reloadConfiguration(WLPROPERTY);
} catch (Exception e) {
LOGGER.log(Level.FINER, e.getMessage(), e);
throw new RuntimeException(e);
}
}
/**
* Filters ip black list
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
if (isBlackListed(httpRequest)) {
if (response instanceof HttpServletResponse) {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN,
"This IP has been blocked. Please contact the server administrator");
return;
}
}
chain.doFilter(request, response);
}
private boolean isBlackListed(HttpServletRequest httpRequest) throws IOException {
if(configFile != null && configFile.isStale()){
synchronized(configFile){
if(configFile.isStale()){
this.blackListedAddresses = reloadConfiguration(BLPROPERTY);
this.whiteListedAddresses = reloadConfiguration(WLPROPERTY);
}
}
}
if(blackListedAddresses.isEmpty()){
return false;
}
String incomingIp = IpFlowController.getRemoteAddr(httpRequest);
boolean blocked=false;
//Check IP on blackList roles (to block)
for(String blackListRole: blackListedAddresses){
if(incomingIp.matches(blackListRole)){
blocked=true;
break;
}
}
//Check IP (if blocked) on whiteList roles (to unlock)
if(blocked && !whiteListedAddresses.isEmpty()){
for(String whiteListRole: whiteListedAddresses){
if(incomingIp.matches(whiteListRole)){
blocked=false;
break;
}
}
}
return blocked;
}
private Set<String> reloadConfiguration(String property) throws IOException {
Properties props = configFile.getProperties();
if(props == null){
//file doesn't exist
return Collections.emptySet();
}
return loadConfiguration(props,property);
}
private Set<String> loadConfiguration(Properties props, String property) {
String rawList = props.getProperty(property);
if(null == rawList){
return Collections.emptySet();
}
Set<String> ipAddresses = new HashSet<String>();
for(String ip : rawList.split(",")){
ipAddresses.add(ip.trim().replaceAll("\\*","(.{0,1}[0-9]+.{0,1}){0,4}"));
}
return ipAddresses;
}
@Override
public void init(FilterConfig config) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}