// ========================================================================
// Author : Gosta Jonasson
// Copyright (c) 2002 Gösta Jonasson gosta@kth.se. All rights reserved.
// Permission to use, copy, modify and distribute this software
// for non-commercial or commercial purposes and without fee is
// hereby granted provided that this copyright notice appears in
// all copies.
// ========================================================================

package org.mortbay.http.handler;

import java.io.IOException;
import java.util.Hashtable;
import org.mortbay.http.HttpException;
import org.mortbay.http.HttpRequest;
import org.mortbay.http.HttpResponse;

/** 
 *  Handler to authenticate access from certain IP-addresses. <br>
 *  <br>
 *  A server configuration-XML-file can look something like this: <br>
 *  &lt;Configure class="org.mortbay.jetty.Server"&gt; <br>
 *    ... <br>
 *    &lt;Call name="addContext"&gt; <br>
 *      ... <br>
 *      &lt;Call name="addHandler"&gt; <br>
 *        &lt;Arg&gt; <br>
 *          &lt;New class="IPAccessHandler"&gt; <br>
 *            &lt;Set name="Standard"&gt;deny&lt;/Set&gt; <br>
 *		      &lt;Set name="AllowIP"&gt;192.168.0.103&lt;/Set&gt; <br>
 *		      &lt;Set name="AllowIP"&gt;192.168.0.100&lt;/Set&gt; <br>
 *          &lt;/New&gt; <br>
 *        &lt;/Arg&gt; <br>
 *     &lt;/Call&gt; <br>
 *     ... <br>
 *  <br>
 *  This would deny access for everyone except the requests from the IPs
 *  192.168.0.100 and 192.168.0.103.
 *
 * @version v0.1 2002/03/20
 * @author Gösta Jonasson <a href="mailto:gosta@kth.se">gosta@kth.se</a>
 */
public class IPAccessHandler extends AbstractHttpHandler
{

    /** The standard way to deal with not configured IPs (true=allowed) */
    boolean standard = false;

    /** Hashtable where the configured IPs are kept */
    Hashtable ips;
 
    /**
     * Constructor for the class
     */
    public IPAccessHandler() {
	super();
	ips = new Hashtable();
    }

    /**
     * Checks if the given ipstring (x.x.x.x) is authorized or not
     *
     * @param ipstring	The ip-address as a String
     * @return True if the IP is allowed access, otherwise false.
     */
    public boolean checkIP(String ipstring) {
	Boolean ipconstrain = (Boolean)ips.get(ipstring);
	if (ipconstrain != null)	{
	    return ipconstrain.booleanValue();
	} else {
	    return standard;
	}
    }
	
    /**
     * Handles the incoming request
     *
     * @param pathInContext	
     * @param pathParams	
     * @param request	The incoming HTTP-request
     * @param response	The outgoing HTTP-response
     */
    public void handle(String pathInContext,
                       String pathParams,
                       HttpRequest request,
                       HttpResponse response)
        throws HttpException, IOException {

	try	{
			
	    String ip = request.getRemoteAddr();
	    boolean authorized = checkIP(ip);
		
	    if (!authorized) {
				// The IP is NOT allowed
		response.sendError(HttpResponse.__403_Forbidden);
		request.setHandled(true);
		return; 
	    } else {
				// The IP is allowed
		return;
	    }
	} catch (Exception ex) {
            System.out.println(ex);
            response.sendError(HttpResponse.__500_Internal_Server_Error);
            request.setHandled(true);
        }
    }

    /**
     * Allow the given ip-address access
     *
     * @param ipstring	The ip-address as a String on the format "x.x.x.x"
     */
    public void setAllowIP(String ipstring) {
	ips.put(ipstring,new Boolean(true));
    }

    /**
     * Deny the given ip-address access
     *
     * @param ipstring	The ip-address as a String on the format "x.x.x.x"
     */
    public void setDenyIP(String ipstring) {
	ips.put(ipstring,new Boolean(false));
    }

    /**
     * Set the standard action beeing taken when not registred
     * IPs wants access
     *
     * @param s The standard-string (either 'allow' or 'deny')
     */
    public void setStandard(String s) {
	s = s.toLowerCase();
	if (s.indexOf("allow") > -1) {
	    standard = true;
	} else {
	    standard = false;
	}
    }


    /** 
     *  Main method for testing & debugging.
     *
     */
    private static void main(String[] args) {
	IPAccessHandler ipah = new IPAccessHandler();
	ipah.setStandard("deny");
	ipah.setAllowIP("217.215.71.167");
	ipah.setDenyIP("217.215.71.149");
	System.out.println(ipah.checkIP("217.215.71.245")+" = false");
	System.out.println(ipah.checkIP("217.215.71.167")+" = true");
	System.out.println(ipah.checkIP("217.215.71.149")+" = false");
	System.out.println(ipah.checkIP("0.0.0.0")+" = false");

	IPAccessHandler ipah2 = new IPAccessHandler();
	ipah2.setStandard("allow");
	ipah2.setAllowIP("217.215.71.167");
	ipah2.setDenyIP("217.215.71.149");
	System.out.println(ipah2.checkIP("217.215.71.245")+" = true");
	System.out.println(ipah2.checkIP("217.215.71.167")+" = true");
	System.out.println(ipah2.checkIP("217.215.71.149")+" = false");
	System.out.println(ipah2.checkIP("0.0.0.0")+" = true");
    }
}
