package com.eactive.eai.admin; 

import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.Filter;
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.apache.commons.lang3.StringUtils;

import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.util.Logger;

public class FrontFilter implements Filter
{ 
    public static final String PROP_GROUP    = "FrontFilter";
    public static final String PROP_KEY1     = "SERVER_LIST";
    public static final String PROP_KEY2     = "CLIENT_LIST";
    private FilterConfig config;
    
    public void destroy(){
        
    }

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) 
    throws IOException, ServletException{
        try {
            HttpServletRequest request = (HttpServletRequest)req;
            HttpServletResponse response = (HttpServletResponse)res;
            PropManager manager = PropManager.getInstance();
            String serverList = manager.getProperty(PROP_GROUP,PROP_KEY1);
            String clientList = manager.getProperty(PROP_GROUP,PROP_KEY2);
            if(serverList==null) {
                Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
                logger.warn("FrontFilter] Cannot configure the "+PROP_GROUP+"."+PROP_KEY1+" property.");
                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,"Cannot configure the "+PROP_GROUP+"."+PROP_KEY1+" property.");
                return;
            }
            
            if(clientList == null) clientList = "";
            
            String[] serverIpList = serverList.split(",");
            String[] clientIpList = clientList.split(",");
            
            Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
            
//            logger.warn("FrontFilter] Executed - " + request.getRequestURI());
            
            //xecure adapter이여서 filtering pass 하기 위해서
            String requestUri = StringUtils.removeStart(request.getRequestURI(), request.getContextPath());
        	if (request.getRequestURI().startsWith("/adapter/http/")
            	|| request.getRequestURI().startsWith("/EAIProxy.jsp")
            	|| request.getRequestURI().startsWith("/HTT/")
            	|| request.getRequestURI().startsWith("/Adapter")
            	|| StringUtils.startsWithIgnoreCase(requestUri, "/api/")
    			|| StringUtils.startsWith(requestUri, "/oauth/")
        		|| StringUtils.equals(requestUri, "/healthcheck.html")){
        		if(logger.isDebug()) {
                	logger.debug("FrontFilter] HTTP anonymous Access allowed page - " + request.getRequestURI());
                }
            }
            else {
            	// 2009.04.02
	            // Server 리스트와 Client 리스트를 분리하고 
            	// Pattern 등록 허용 (172.26.128.*)
            	String remoteAddr = request.getRemoteAddr();
            	//String remoteAddr = getClientIP(request);
	            if( isAllowedIP(serverIpList, remoteAddr) ) {
	            	if(logger.isDebug()) {
	                	logger.debug("FrontFilter] HTTP Access. server IP - " + remoteAddr);
	                }
	            }
	            else if( isAllowedIP(clientIpList, remoteAddr) ) {
	                if(logger.isDebug()) {
	                	logger.debug("FrontFilter] HTTP Access. client IP - " + remoteAddr);
	                }
	            }
	            else {
	            	if(logger.isWarn()) {
		                logger.warn("FrontFilter] Invalid Access. - " + remoteAddr);
	            	}
		            response.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid Access.");
	                return;   
	            }
            }
            
            chain.doFilter(req,res);     
        } catch(Exception e) {
            Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
            logger.error("FrontFilter] Error - " + e.getMessage(), e);
            throw new ServletException(e.getMessage());
                   
        }
    }
    
    private boolean isAllowedIP(String[] ipList, String remoteIp) {
    	
    	if(ipList == null || ipList.length == 0) {
    		return false;
    	}
    	
    	for( String allow : ipList ) {
    		if (allow.indexOf('*') == -1) {
            	if (allow.equals(remoteIp)) {
            		return true;
            	}
            } else {
				String allowRegexp = allow.replaceAll("\\*", "[0-9]+").trim();
				Matcher matcher = Pattern.compile(allowRegexp, Pattern.CASE_INSENSITIVE).matcher(remoteIp);
				if (matcher.matches()) {
					return true;
				}
            }
    	}
    	return false;
    }
    
    public void init(FilterConfig config) throws ServletException{
        this.config = config;
        if(this.config != null) {
        	this.config.getFilterName();
        }
    }
    private String getClientIP(HttpServletRequest request){
    	String remoteAddr = request.getHeader("HTTP_X_FORWARDED_FOR");
    	if (StringUtils.isBlank(remoteAddr) || !isIp(remoteAddr) ){
    		remoteAddr = request.getHeader("Proxy-Client-IP");
    	}
    	if (StringUtils.isBlank(remoteAddr) || !isIp(remoteAddr)){
    		remoteAddr = request.getHeader("WL-Proxy-Client-IP");
    	}
    	if (StringUtils.isBlank(remoteAddr) || !isIp(remoteAddr)){
    		remoteAddr = request.getRemoteAddr();
    	}
    	return remoteAddr;
    }

	private boolean isIp(String ip) {
		Matcher matcher = Pattern
				.compile("(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}")
				.matcher(ip.trim());
		if (matcher.matches()) {
			return true;
		}
		return false;
	}
} 
