/**
 * @author tbellemb
 * @version 1.1
 * Creation date : 30.09.2004
 * Last modification date : 8.10.2004
 * Modifications :
 */

package org.esupportail.filter.trustedFilter;

import java.io.IOException;
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 javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;

public class TrustedFilter implements Filter{
	
	private String trustedPassword;	 
	
	// Const. for logging
	private static final int LOG_DEBUG = 0;
	private static final int LOG_INFO = 1;
	private static final int LOG_WARN = 2;
	private static final int LOG_ERROR = 3;
	
	private static final String SELECTED_FILTER_SESSION_VAR = "org.esupportail.filter.authenticationRouter.selectFilter";
	private static final String TRUSTED_PASSWORD = "org.esupportail.filter.trustedFilter.trustedPassword";
	private static final String AUTHENTICATION_TYPE = "basic";
	public final static String TRUSTED_FILTER_USER = "org.esupportail.filter.trustedFilter.user";
	
	
	public Logger logger;
	
	
	public void init(FilterConfig config) throws ServletException {
		trustedPassword = config.getInitParameter(TRUSTED_PASSWORD);
		logger = Logger.getLogger("org.esupportail.filter.trustedFilter.TrustedFilter");
	}// init
	
		
	/*
	 * Make the String lenght multiple of for FOR A BASE64 ENCODING or DECODING
	 */
	private static String makeMultipleOf4(String s){
		StringBuffer result = new StringBuffer(s);
		int stringLength = s.length();
		if(stringLength%4!=0){
			for(int i=0; i<(4-(stringLength%4)); i++){
				result.append("=");
			}// for
		}// if
		return result.toString();
	}// makeMultipleOf4
	
	
	/*
	 * log function
	 */
	public void log(int type, String message){
		if(type == LOG_DEBUG && logger.isDebugEnabled()){
			logger.debug(message);
		}// LOG_DEBUG
		else if(type == LOG_INFO){
			logger.info(message);
		}// LOG_INFO
		else if(type == LOG_WARN){
			logger.warn(message);
		}// LOG_WARN
		else if(type == LOG_ERROR){
			logger.warn(message);
		}// LOG_ERROR
	}// log
	
	
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
		
		
		log(LOG_INFO, "Entering TrustedFilter...");
		
		
		//////////////////////////////////////
		// make sure we've got an HTTP request
		//
		if (!(request instanceof HttpServletRequest)
				|| !(response instanceof HttpServletResponse))
			throw new ServletException(getClass().getName()+".doFilter() - TrustedFilter protects only HTTP resources");
		
		
		///////////////////////////////////////////////////////////////////////////////////////////////////////////
		// checking that the selectedFilter session variable is set to TRUSTED (by the AuthenticationRouter filter)
		//
		//
		HttpSession session = ((HttpServletRequest) request).getSession();
		if (session == null || session.getAttribute(SELECTED_FILTER_SESSION_VAR)==null || !session.getAttribute(SELECTED_FILTER_SESSION_VAR).equals("TRUSTED")){
			log(LOG_DEBUG, "No session or session attribut SELECTED_FILTER not set to TRUSTED");
			log(LOG_INFO, "Leaving TrustedFilter...");
			filterChain.doFilter(request, response);
			return;
		}// if
		else{
			log(LOG_DEBUG, "Session attribut SELECTED_FILTER set to TRUSTED");
		}// else
		
		
		///////////////////////
		// wrapping the request
		//
		request = new TrustedFilterRequestWrapper((HttpServletRequest)request);
		
		
		////////////////////////////////////////////////////
		// if the user is already authenticated - do nothing
		//
		if(session.getAttribute(TRUSTED_FILTER_USER)!=null){
			log(LOG_DEBUG, "Session in progress");
			log(LOG_INFO, "Leaving TrustedFilter...");
			filterChain.doFilter(request, response);
			return;
		}//if
		
		
		/////////////////////////////////////
		// getting the header "authorization"
		//
		String header = ((HttpServletRequest)request).getHeader("authorization");
		
		
		/////////////////////////////////////////////////////////////////////////////////////////
		// if there is no "authorization" header then send a 401 error and ask for authentication
		//
		if(header==null || header.equals("")){
			log(LOG_DEBUG, "No authorization header");
			log(LOG_INFO, "Leaving TrustedFilter...");
			((HttpServletResponse)response).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
			((HttpServletResponse)response).setHeader("WWW-Authenticate", "Basic");         	
			return;
		}// if
		
		
		////////////////////////////////////////////////////////////////////////////////
		// processing the header to get authentication informations (login and password)
		//
		// removing the authentication type (and spaces) from the header
		String encodedAuthorization = header.substring(AUTHENTICATION_TYPE.length()).trim();
		// decoding the authorization
		String decodedAuthorization = Base64CoDec.decode(makeMultipleOf4(encodedAuthorization));
		// getting the password
		String password = decodedAuthorization.substring(decodedAuthorization.indexOf(":")+1);
		// getting the user (to save in session variable)
		String user = decodedAuthorization.substring(0, decodedAuthorization.indexOf(":"));
		if(logger.isDebugEnabled()) {
			log(LOG_DEBUG, "user > "+user);
		}//if
		
		
		///////////////////////////////////////////////////////////////////////////////////////////////////////
		// if the password is not the trustedPassword send a 401 error and ask for authentication else continue
		//
		if(!password.equals(trustedPassword)){
			// password not trusted - we leave
			log(LOG_INFO, "Password not trusted");
			log(LOG_INFO, "Leaving TrustedFilter...");
			((HttpServletResponse)response).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
			((HttpServletResponse)response).setHeader("WWW-Authenticate", "Basic");         	
			return;
		}//if
		else{
			// password trusted - have fun !
			log(LOG_INFO, "Password trusted");
			// store the authenticated user in the session
			if (session != null){
				// probably unncessary
				session.setAttribute(TRUSTED_FILTER_USER, user);
			}// if
			log(LOG_INFO, "Leaving TrustedFilter...");
			filterChain.doFilter(request, response);
			return;
		}// else 
	}// doFilter
	
	public void destroy() {
	}// destroy
	
}// TrustedFilter
