/*
* Copyright (C) 2014 Civilian Framework.
*
* Licensed under the Civilian License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.civilian-framework.org/license.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* 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.civilian.processor;
import java.util.ArrayList;
import java.util.regex.Pattern;
import org.civilian.Processor;
import org.civilian.Request;
import org.civilian.Response;
import org.civilian.internal.Logs;
import org.civilian.util.Check;
/**
* IpFilter is a Processor which stops requests, if their remote ip address
* is not contained in a whitelist of allowed ips.
*/
public class IpFilter extends Processor
{
public static final String LOCALHOST = "localhost";
public IpFilter(String... allowedIps)
{
// build tests
ArrayList<IpTest> tests = new ArrayList<>();
for (int i=0; i<allowedIps.length; i++)
{
String allowedIp = Check.notNull(allowedIps[i], "ip");
if (allowedIp.equals("all"))
{
tests.clear();
break;
}
else if (allowedIp.equals(LOCALHOST))
{
tests.add(new LiteralTest("127.0.0.1"));
tests.add(new LiteralTest("0:0:0:0:0:0:0:1"));
}
else if (allowedIp.contains("*"))
tests.add(new WildcardTest(allowedIp));
else
tests.add(new LiteralTest(allowedIp));
}
if (tests.size() > 0)
tests.toArray(ipTests_ = new IpTest[tests.size()]);
// build info
StringBuilder sb = new StringBuilder("Allowed IPs: ");
if (ipTests_ != null)
{
for (int i = 0; i<ipTests_.length; i++)
{
if (i > 0)
sb.append(", ");
sb.append(ipTests_[i]);
}
}
else
sb.append("all");
info_ = sb.toString();
}
public int size()
{
return ipTests_.length;
}
public IpTest getIpTest(int i)
{
return ipTests_[i];
}
@Override public boolean process(Request request, ProcessorChain chain) throws Exception
{
// if no ip tests are defined, we allow all ips
if (ipTests_ != null)
{
String remoteIp = request.getRemoteInfo().getIp();
if (!isAllowedIp(remoteIp))
{
if (Logs.PROCESSOR.isDebugEnabled())
Logs.PROCESSOR.debug("forbidden ip " + remoteIp);
request.getResponse().sendError(Response.Status.FORBIDDEN);
return true; // we have processed the request, no further processing
}
}
return chain.next(request); // ip allowed: continue processing
}
public boolean isAllowedIp(String ip)
{
if (ipTests_ == null)
return true;
if (ip != null)
{
for (int i=0; i<ipTests_.length; i++)
{
if (ipTests_[i].isAllowed(ip))
return true;
}
}
return false;
}
/**
* Implements a test if a request with a certain IP should be allowed.
*/
public static abstract class IpTest
{
public abstract boolean isAllowed(String ip);
@Override public abstract String toString();
}
private static class LiteralTest extends IpTest
{
public LiteralTest(String ip)
{
ip_ = ip;
}
@Override public boolean isAllowed(String ip)
{
return ip_.equals(ip);
}
@Override public String toString()
{
return ip_;
}
private String ip_;
}
private static class WildcardTest extends IpTest
{
public WildcardTest(String pattern)
{
ipPattern_ = Pattern.compile(pattern.replace(".", "\\.").replace("*", "([0-9]{1,3})"));
display_ = pattern;
}
@Override public boolean isAllowed(String ip)
{
return ipPattern_.matcher(ip).matches();
}
@Override public String toString()
{
return display_;
}
private Pattern ipPattern_;
private String display_;
}
private IpTest[] ipTests_;
}