|
What this is
Other links
The source code/* * $Header: /cvsroot/mvnforum/myvietnam/src/net/myvietnam/mvncore/security/FloodControl.java,v 1.10 2005/01/18 12:16:44 minhnn Exp $ * $Author: minhnn $ * $Revision: 1.10 $ * $Date: 2005/01/18 12:16:44 $ * * ==================================================================== * * Copyright (C) 2002-2005 by MyVietnam.net * * This program 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 2 * of the License, or any later version. * * All copyright notices regarding MyVietnam and MyVietnam CoreLib * MUST remain intact in the scripts and source code. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Correspondence and Marketing Questions can be sent to: * info@MyVietnam.net * * @author: Minh Nguyen minhnn@MyVietnam.net * @author: Mai Nguyen mai.nh@MyVietnam.net */ package net.myvietnam.mvncore.security; import java.util.*; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import net.myvietnam.mvncore.exception.FloodException; import net.myvietnam.mvncore.util.DateUtil; /** * This class is used to control the number of actions per hour. This is usually * used to prevent the flood of any action. You should call FloodControl.setOption() * when your application is inited. * <p> * Note that the action id from 0 to 999 is belong to mvnCore, application used it * should not use the value in this range */ public class FloodControl { private static Log log = LogFactory.getLog(FloodControl.class); /** The value from 0 to 999 should belong to mvnCore */ public static int MAX_MVNCORE_ACTION_ID = 999; private static Map actionControlMap = new TreeMap(); static final long REMOVE_INTERVAL = DateUtil.MINUTE * 2;//2 minutes private FloodControl() { } /** * To set the mamximum number of actions per hour for an action. * If the caller does not call this method, the the action has no limit * @param action Integer the action that want to set the option * @param actionsPerHour int the maximum number of actions per hour */ public static void setOption(Integer action, int actionsPerHour) { getControlledAction(action).setActionsPerHour(actionsPerHour); } public static int getActionsPerHour(Integer action) { return getControlledAction(action).getActionsPerHour(); } /** * Check that an action of an IP has reach the maximum number of allowed times * @param action Integer the action to check * @param strIP String the IP to check * @return boolean true if it has reached the maximum */ public static boolean reachMaximum(Integer action, String strIP) { return getControlledAction(action).reachMaximum(strIP); } /** * This is a utility method to ensure that the action has not reached the mamximum. * It calls the method reachMaximum and throw an exception if it reached the maximum. * A program could use this method to use the default error message, otherwise * it has to use reachMaximum * @param action Integer the action to ensure * @param strIP String the IP to ensure * @throws FloodException if it reached the maximum * @see FloodControl#reachMaximum(Integer, String) */ public static void ensureNotReachMaximum(Integer action, String strIP) throws FloodException { if (reachMaximum(action, strIP)) { log.info("Attempt to exceed the maximum number of actions: ActionID = " + action + " and IP = " + strIP); //@todo : localize me throw new FloodException("You have reached the maximum number of actions for this page (actionID = " + action + "). Please try this page later. This is to prevent forum from being flooded."); } } /** * Increase the number of action. This method should be called the the program * has done this action. Forget to call this method will void the reachMaximum method. * @param action Integer the action to increase the number of times * @param strIP String the IP to increase the number of times */ public static void increaseCount(Integer action, String strIP) { getControlledAction(action).increaseCount(strIP); } /** * Reset the action history. This method is useful in such a case in the login * process that after login successfully, the value should be reset. Please note * that this is just an example and usually no need to use this method. * @param action Integer * @param strIP String */ public static void resetActionHistory(Integer action, String strIP) { getControlledAction(action).resetActionHistory(strIP); } /** * Return the instance of ControlledAction for the action. It will create * new instance if no previous instance for this action exist. * @param action Integer * @return ControlledAction */ private static synchronized ControlledAction getControlledAction(Integer action) { ControlledAction controlledAction = (ControlledAction)actionControlMap.get(action); if (controlledAction == null) { controlledAction = new ControlledAction(); actionControlMap.put(action, controlledAction); } return controlledAction; } } /** * For one action that handles a list of all IP */ class ControlledAction { private int actionsPerHour = 0; private Map ipMap = new TreeMap(); private long lastRemoveTime = 0; void setActionsPerHour(int actionsPerHour) { if (actionsPerHour >= 0) { this.actionsPerHour = actionsPerHour; } } int getActionsPerHour() { return actionsPerHour; } boolean reachMaximum(String strIP) { removeTimeoutControlledIP(); return getControlledIP(strIP).reachMaximum(); } void increaseCount(String strIP) { removeTimeoutControlledIP(); getControlledIP(strIP).increaseCount(); } void resetActionHistory(String strIP) { removeTimeoutControlledIP(); getControlledIP(strIP).resetActionHistory(); } private synchronized ControlledIP getControlledIP(String strIP) { ControlledIP controlledIP = (ControlledIP)ipMap.get(strIP); if (controlledIP == null) { controlledIP = new ControlledIP(actionsPerHour); ipMap.put(strIP, controlledIP); } else { // there is a ControlledIP, update the actionsPerHour controlledIP.setActionsPerHour(actionsPerHour); } return controlledIP; } private synchronized void removeTimeoutControlledIP() { long now = System.currentTimeMillis(); if ((now - lastRemoveTime) > FloodControl.REMOVE_INTERVAL) { lastRemoveTime = now; Collection ipList = ipMap.values(); for (Iterator iter = ipList.iterator(); iter.hasNext(); ) { ControlledIP currentControlledIP = (ControlledIP)iter.next(); if (now - currentControlledIP.getLastIncrementTime() > DateUtil.HOUR) { iter.remove(); } } } } } /** * For one action per one IP */ class ControlledIP { private int actionsPerHour = 0; private long lastRemoveTime = 0; private long lastIncrementTime = 0; private ArrayList actionHistoryList = new ArrayList(); ControlledIP(int actionsPerHour) { if (actionsPerHour >= 0) { this.actionsPerHour = actionsPerHour; } } void setActionsPerHour(int actionsPerHour) { if (actionsPerHour >= 0) { this.actionsPerHour = actionsPerHour; } } long getLastIncrementTime() { return lastIncrementTime; } void increaseCount() { long now = System.currentTimeMillis(); lastIncrementTime = now; actionHistoryList.add(new Long(now)); } void resetActionHistory() { lastRemoveTime = 0; lastIncrementTime = 0; actionHistoryList.clear(); } boolean reachMaximum() { if (actionsPerHour == 0) {//unlimited return false; } if (actionHistoryList.size() < actionsPerHour) { return false; } // now try to remove timeout actions removeTimeoutActions(); return (actionHistoryList.size() >= actionsPerHour); } private synchronized void removeTimeoutActions() { long now = System.currentTimeMillis(); if (now - lastRemoveTime > FloodControl.REMOVE_INTERVAL) { lastRemoveTime = now; for (Iterator iter = actionHistoryList.iterator(); iter.hasNext(); ) { Long currentAction = (Long)iter.next(); if ((now - currentAction.longValue()) > DateUtil.HOUR) { iter.remove(); } } //for } } } |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.