com.google.gsa.Kerberos.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gsa.Kerberos.java

Source

/**
 * Copyright (C) 2008 Google - Enterprise EMEA SE
 *
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 * 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 com.google.gsa;

import com.google.gsa.sessions.SessionTimer;

import com.google.gsa.valve.modules.krb.KerberosAuthenticationProcess;

import com.google.gsa.sessions.Sessions;
import com.google.gsa.sessions.UserIDEncoder;
import com.google.gsa.sessions.UserSession;
import com.google.gsa.valve.configuration.ValveConfiguration;
import com.google.gsa.valve.configuration.ValveConfigurationException;
import com.google.gsa.valve.configuration.ValveConfigurationInstance;
import com.google.gsa.valve.saml.SAMLArtifactProcessor;
import com.google.gsa.valve.saml.authn.SAMLAuthN;
import com.google.gsa.valve.utils.ValveUtils;

import java.io.IOException;

import java.io.UnsupportedEncodingException;

import java.net.URLEncoder;

import java.security.Principal;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import java.util.Set;

import java.util.Vector;

import javax.naming.NamingException;

import javax.security.auth.Subject;

import javax.servlet.*;
import javax.servlet.http.*;

import org.apache.commons.httpclient.HttpException;
import org.apache.log4j.Logger;

/**
 * This is the main authentication servlet when a silent kerberos tickets are 
 * being used to get user credentials. It implements the whole authentication 
 * process when the user is authenticated using his/her kerberos ticket obtained 
 * silently during the browser connection. This ticket is collected up, 
 * included in the authentication credentials and starts the global 
 * authentication process for the user.
 * <p>
 * It invokes the root authentication process to garantee the user is 
 * authenticated in all the backend repositories. It supports both the SAML 
 * and the Forms Based interface.
 * <p>
 * If the overall process result is an unauthorized, a 401 error message is 
 * sent back to the user's browser.
 * <p>
 * It also handles crawling when Forms Based authentication has been set.
 * 
 */
public class Kerberos extends HttpServlet {

    //logger
    private static Logger logger = null;

    //Cookie vars
    private String authCookieDomain = null;
    private String authCookiePath = null;
    private String authCookieName = null;
    private int authMaxAge = 300;
    private String refererCookieName = null;

    //user session vars    
    SessionTimer sessionTimer;
    long maxSessionAge;
    long sessionTimeout;
    long sessionCleanup;
    boolean isSessionEnabled = false;

    //Non Krb AuthN var
    private String authenticationProcessClsName = null;

    //Kerberos Subject Map
    private static Map<String, Subject> krbSubjects = new HashMap<String, Subject>();

    private static String gsaValveConfigPath = null;
    private ValveConfiguration valveConf;

    //Krb vars
    boolean KrbUsrPwdCrawler = false;
    boolean KrbAdditionalAuthN = false;
    String KrbLoginUrl = null;
    String KrbUsrPwdCrawlerUrl = null;
    String loginUrl = null;
    boolean isKerberos = false;
    boolean isNegotiate = false;
    //Var that tells the default Credential ID for Kerberos
    private static final String KRB5_ID = "krb5";

    private static final String GSA_CRAWLER_USER = "gsa-crawler";
    private static final String GSA_CRAWLING_CONTENT = "(Enterprise";

    private static final String KRB_COOKIE_NAME = "gsa_krb5_auth";

    //encoding
    private static String encoder = "UTF-8";

    //SAML
    boolean isSAML = false;
    String refererSAML = null;
    String relayState = null;
    String samlRequest = null;

    static {

        // Instantiate logger
        logger = Logger.getLogger(Kerberos.class);

    }

    /**
     * Init method
     * 
     * @param config servlet config
     * 
     * @throws ServletException
     */
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
    }

    /**
     * Servlet's doGet: processes a doGet request. Calls doPost.
     * 
     * @param request HTTP request
     * @param response HTTP response
     * 
     * @throws ServletException 
     * @throws IOException
     */
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        doPost(request, response);

    }

    /**
     * Servlet's doPost: processes a POST request. Controls the overall 
     * kerberos silent authentication process. It supports both the Security 
     * Framework's SAML and Forms Based interface.
     * <p>
     * You can find more information on the Security Framework's Kerberos guide 
     * about the scenarios implemented here
     * 
     * @param request HTTP request
     * @param response HTTP response
     * 
     * @throws ServletException
     * @throws IOException
     */
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        logger.debug("Kerberos servlet");

        if (gsaValveConfigPath == null) {
            if (request.getAttribute("gsaValveConfigPath") == null) {
                //Read parameter from config file: SAML
                gsaValveConfigPath = readValveConfigPath();
            } else {
                gsaValveConfigPath = request.getAttribute("gsaValveConfigPath").toString();
            }
        }

        logger.debug("Valve Config Path is: " + gsaValveConfigPath);

        // Initialize status code
        int statusCode = HttpServletResponse.SC_UNAUTHORIZED;

        //Authentication Processes 
        AuthenticationProcessImpl authenticationProcessCls = null;
        KerberosAuthenticationProcess krbAuthN = new KerberosAuthenticationProcess();

        //Initialize cookies vars
        Cookie gsaRefererCookie = null;
        Cookie gsaAuthCookie = null;

        //Session Cookie arrays
        Vector<Cookie> krbCookies = new Vector<Cookie>();
        Vector<Cookie> nonKrbCookies = new Vector<Cookie>();

        //user agent
        String userAgent = null;

        //user credentials
        Credentials creds = null;

        //User Session and Session ID vars definition
        UserSession userSession = null;
        String sessionID = null;
        String encodedSessionID = null;

        //Create the credentials store
        try {
            this.valveConf = ValveConfigurationInstance.getValveConfig(gsaValveConfigPath);
        } catch (ValveConfigurationException e) {
            logger.error("Valve Config instantiation error: " + e);
        }

        logger.debug("Creating the credentials store");
        creds = new Credentials();
        String username = null;

        //Setting Valve parameters
        logger.debug("Setting Valve params");
        setValveParams(request);

        //Protection
        if ((!isKerberos) || (!isNegotiate)) {
            logger.error(
                    "Configuration error: if you want to use Kerberos silent AuthN, isKerberos and isNegotiate config vars have to be set to true");
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                    "Configuration error - Kerberos is not set properly");
            return;
        }

        Cookie cookies[] = null;

        // Retrieve cookies
        cookies = request.getCookies();

        // Protection: look for auth and referer cookies
        if (cookies != null) {

            // Look for the referer cookie
            for (int i = 0; i < cookies.length; i++) {

                // Look for the referer cookie
                if ((cookies[i].getName()).equals(refererCookieName)) {

                    // Cache cookie
                    gsaRefererCookie = cookies[i];

                    logger.debug("Referer cookie already exists: " + gsaRefererCookie.getValue());

                } else {
                    // Look for the auth cookie
                    if ((cookies[i].getName()).equals(authCookieName)) {

                        // Cache cookie
                        gsaAuthCookie = cookies[i];

                        logger.debug("Auth cookie already exists: " + gsaAuthCookie.getValue());

                    }
                }

                if ((gsaRefererCookie != null) && (gsaAuthCookie != null)) {
                    // Exit
                    break;
                }

            }

        }

        // Protection
        if (!isSAML) {
            if (gsaRefererCookie == null) {

                // Raise error
                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                        "The GSA authentication servlet couldn't read the referer cookie");

                // Log error
                logger.error(
                        "The GSA authentication servlet couldn't read the referer cookie, pls. check the cookie domain value");

                // Return
                return;

            }
        } else {
            //SAML

            //Get SAML Params
            relayState = request.getParameter("RelayState");
            samlRequest = request.getParameter("SAMLRequest");
            //String relayStateCookie = valveConf.getSAMLConfig().getRelayStateCookie();
            boolean noParams = false;
            boolean cookieExist = true;

            //Protection
            if ((relayState == null) || (relayState.equals(""))) {
                noParams = true;
            } else {
                if ((samlRequest == null) || (samlRequest.equals(""))) {
                    noParams = true;
                }
            }

            createRefererCookie(gsaRefererCookie);

            //if ((noParams)&&(!cookieExist)) {
            if (noParams) {
                response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid request");
                return;
            }
        }

        logger.debug("Let's validate if gsaAuthCookie is present");

        if (gsaAuthCookie != null) {

            if (!isSAML) {
                //redirect
                String redirect = gsaRefererCookie.getValue();

                logger.debug("redirect is " + redirect);
                //redirect only if the URL is different than the login one                    
                if (!redirect.equals(loginUrl)) {

                    //user properly authenticated
                    logger.debug("The user was properly authenticated. Lets redirect to..." + redirect);

                    // Redirect
                    response.sendRedirect(redirect);

                } else {
                    logger.debug("It's the login URL. No redirect");
                }
            } else {
                logger.debug("As this is SAML. Let's obviate the previous authentication cookie");
                gsaAuthCookie = null;
            }
        }

        userSession = new UserSession();

        Sessions sessions = Sessions.getInstance();
        sessions.setMaxSessionAgeMinutes(maxSessionAge);
        sessions.setSessionTimeoutMinutes(sessionTimeout);

        if (gsaAuthCookie == null) {

            logger.debug("gsaAuthCookie does not exist");

            isNegotiate = true;

            // Read User-Agent header
            userAgent = request.getHeader("User-Agent");

            logger.debug("userAgent is... " + userAgent);

            //check if user is gsa-crawler
            if (userAgent.startsWith(GSA_CRAWLER_USER)) {

                logger.debug("User is " + GSA_CRAWLER_USER);

                //check if user is gsa-crawler and have to authenticate it thru a form                                  
                if (KrbUsrPwdCrawler) {

                    logger.debug("gsa-crawler has to access thru username and password");

                    //check if crawler already provided credentials

                    if (request.getParameter("UserIDKrb") == null) {

                        //the login page have to be filled in by the admin user before reaching here. Return error
                        logger.error("The login page [" + KrbUsrPwdCrawlerUrl
                                + "] has to be invoked and its credentials fields filled in before reaching here");
                        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                                "It means the GSA Valve Kerberos configuration is not done properly or you just forgot to fill in the Kerberos credentials in the login page");
                        return;

                    } else {

                        //user already submits credentials
                        logger.debug("Crawler has already sent credentials");
                        //set isNegotiate equal false (it authenticates the user thru username and pwd credentials)                                                                                    
                        isNegotiate = false;

                        //set Crawler credentials
                        setCrawlerCredentials(request, creds, KrbAdditionalAuthN);

                        //authenticate user
                        statusCode = krbAuthentication(request, response, krbAuthN, krbCookies,
                                gsaRefererCookie.getValue(), creds, isNegotiate);

                        // Protection: check status code
                        if (statusCode != HttpServletResponse.SC_OK) {

                            // Raise error
                            response.sendError(statusCode, "Authentication process failed!");

                            // Debug
                            if (logger.isDebugEnabled())
                                logger.debug("Krb Authentication process failed with code: " + statusCode);

                            if (statusCode == HttpServletResponse.SC_UNAUTHORIZED) {
                                logger.debug(
                                        "Note: this 401 could not be an error as sending 401 could be part of the Negotiation process");
                            }

                            // Return
                            return;

                        }

                        //check if the additional authN method is available. If so, start authN with these creds as well
                        //N: modification for always lanching the root authN process. Comment out the following line
                        //if (KrbAdditionalAuthN) {

                        statusCode = nonKrbAuthentication(request, response, authenticationProcessCls,
                                nonKrbCookies, gsaRefererCookie.getValue(), creds);

                        //check if the status code is indeterminate
                        if (statusCode == -1) {
                            //the process could not determinate the authorization
                            //as there is no pattern that matches with any repository
                            statusCode = HttpServletResponse.SC_UNAUTHORIZED;
                        }

                        // Protection: check status code
                        if (statusCode != HttpServletResponse.SC_OK) {

                            // Raise error
                            response.sendError(statusCode, "Authentication process failed!");

                            // Debug
                            if (logger.isDebugEnabled())
                                logger.debug("Non Krb Authentication process failed with code: " + statusCode);

                            // Return
                            return;

                        }

                        //}

                    }
                } else { // end KrbUsrPwdCrawler is set. 
                    //If KrbUsrPwdCrawler is not set to true, then do nothing (assume content is feeded)
                    //just send back the error as a configuration one (we shouldn't configure Froms-based crawling)
                    response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                            "Configuration error. Review your configuration as you can not define this rule if it's not set properly (see doc on how to set it up using Kerberos config attributes)");
                    return;
                }

            } else { //User is not Crawler

                logger.debug("User is NOT crawler");

                //check if we have double AuthN or not
                if (!KrbAdditionalAuthN) {

                    logger.debug("Krb silent authN only");

                    //set isNegotiate equal true (it authenticates the user thru kerberos ticket)                                                                                    
                    isNegotiate = true;

                    String refererCookieValue = null;
                    if (gsaRefererCookie != null) {
                        refererCookieValue = new String(gsaRefererCookie.getValue());
                    }

                    //authenticate user
                    statusCode = krbAuthentication(request, response, krbAuthN, krbCookies, refererCookieValue,
                            creds, isNegotiate);

                    // Protection: check status code
                    if (statusCode != HttpServletResponse.SC_OK) {

                        // Raise error
                        response.sendError(statusCode, "Authentication process failed!");

                        // Debug
                        if (logger.isDebugEnabled())
                            logger.debug("Krb Authentication process failed with code: " + statusCode);

                        if (statusCode == HttpServletResponse.SC_UNAUTHORIZED) {
                            logger.debug(
                                    "Note: this 401 could not be an error as sending 401 could be part of the Negotiation process");
                        }

                        // Return
                        return;

                    } else {

                        boolean doesKrbSubjectExist = lookForKrbCreds(creds);

                        if (!doesKrbSubjectExist) {
                            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                                    "Credentials not valid. Try to close your browser and try it again");

                            // Log error
                            logger.error("Kerberos Subject is not present when authenticating");

                            // Return
                            return;
                        }

                        //N: call rootAuthN once we have the Kerberos creds
                        //N: Begin update
                        if (!KrbAdditionalAuthN) {
                            statusCode = nonKrbAuthentication(request, response, authenticationProcessCls,
                                    nonKrbCookies, refererCookieValue, creds);

                            //check if the status code is indeterminate
                            if (statusCode == -1) {
                                //the process could not determinate the authorization
                                //as there is no pattern that matches with any repository
                                statusCode = HttpServletResponse.SC_UNAUTHORIZED;
                            }

                            // Protection: check status code
                            if (statusCode != HttpServletResponse.SC_OK) {

                                // Raise error
                                response.sendError(statusCode, "Authentication process failed!");

                                // Debug
                                if (logger.isDebugEnabled())
                                    logger.debug("Non Krb Authentication process failed with code: " + statusCode);

                                // Return
                                return;
                            }

                        }
                        //N:End update

                    }

                } else { //Double AuthN required. So that apart from the Krb silent authN, we authN the user as well thru username and pwd

                    logger.debug("Krb and Forms based AuthN mechanisms");

                    //check if Krb credentials are already set
                    Cookie gsaKrbCookie = getCookie(request, KRB_COOKIE_NAME);

                    //if (gsaKrbCookie != null) { //Kerberos cookie set
                    if (!isKrbProcess(gsaKrbCookie)) { //Kerberos cookie set    

                        logger.debug("Krb cookie is set. Krb AuthN already in place");

                        Subject krbSubj = getKrbSubject(gsaKrbCookie.getValue());

                        //Protection
                        if (krbSubj == null) { // couldn't localize the subject. 

                            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                                    "Credentials not valid. Try to close your browser and try it again");

                            // Log error
                            logger.error("Kerberos Subject is not present when authenticating");

                            // Return
                            return;
                        } else {

                            logger.debug("The Krb subject exists. This is the Forms based AuthN part");

                            //check if parameters are present
                            if (request.getParameter("UserIDKrb") == null) {

                                logger.debug("Login page has not been already invoked");

                                String redirectUrl = contructKrbLoginURL();

                                logger.debug("Redirecting to...." + redirectUrl);

                                //redirect to the login page
                                response.sendRedirect(response.encodeRedirectURL(redirectUrl));

                                // Return
                                return;

                            } else {

                                //user already submits credentials
                                logger.debug("User has already sent credentials");

                                createCredsDoubleAuthN(request, creds, krbSubj);

                                logger.debug("User Credentials created. Let's authenticate the user without Krb");

                                statusCode = nonKrbAuthentication(request, response, authenticationProcessCls,
                                        nonKrbCookies, gsaRefererCookie.getValue(), creds);

                                //check if the status code is indeterminate
                                if (statusCode == -1) {
                                    //the process could not determinate the authorization
                                    //as there is no pattern that matches with any repository
                                    statusCode = HttpServletResponse.SC_UNAUTHORIZED;
                                }

                                // Protection: check status code
                                if (statusCode != HttpServletResponse.SC_OK) {

                                    // Raise error
                                    response.sendError(statusCode, "Authentication process failed!");

                                    // Debug
                                    if (logger.isDebugEnabled())
                                        logger.debug(
                                                "Non Krb Authentication process failed with code: " + statusCode);

                                    // Return
                                    return;

                                }
                                boolean resultDelete = deleteKrbSubject(gsaKrbCookie.getValue());
                                if (!resultDelete) {
                                    logger.error("Not KrbSubj found when deleting it");
                                }

                            }
                        }

                    } else { //Krb cookie does not exist
                        logger.debug(
                                "Krb cookie does not exist. Let's silently authenticate the user thru Krb firstly");
                        logger.debug("Krb silent authN only");

                        //set isNegotiate equal true (it authenticates the user thru kerberos ticket)                                                                                    
                        isNegotiate = true;

                        //authenticate user
                        statusCode = krbAuthentication(request, response, krbAuthN, krbCookies,
                                gsaRefererCookie.getValue(), creds, isNegotiate);

                        // Protection: check status code
                        if (statusCode != HttpServletResponse.SC_OK) {

                            // Raise error
                            response.sendError(statusCode, "Authentication process failed!");

                            // Debug
                            if (logger.isDebugEnabled())
                                logger.debug("Krb Authentication process failed with code: " + statusCode);

                            if (statusCode == HttpServletResponse.SC_UNAUTHORIZED) {
                                logger.debug(
                                        "Note: this 401 could not be an error as sending 401 could be part of the Negotiation process");
                            }

                            // Return
                            return;

                        } else {
                            Cookie krbCookie = krbCookies.elementAt(0);
                            String krbAuthCookieValue = krbCookie.getValue();

                            logger.debug("Krb cookie value: " + krbAuthCookieValue);
                            if (krbAuthCookieValue == null) {
                                logger.error("Krb cookie not present");
                                // Raise error
                                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                                        "Kerberos cookie not present");
                                // Return
                                return;
                            } else {
                                addKrbCookie(response, krbCookie);
                                addKrbSubject(krbAuthCookieValue, krbAuthN.getUserSubject());
                                logger.debug(
                                        "The User Krb identity is already present. Let's authenticate the user thru username/password");
                                //redirect to Login page
                                String redirectUrl = contructKrbLoginURL();
                                response.sendRedirect(response.encodeRedirectURL(redirectUrl));
                                logger.debug("Redirect to.... " + redirectUrl);
                                return;
                            }

                        }

                    }

                }
            }

            logger.debug("Krb and/or Forms based AuthN OK. Let's create the session");

            //set username and cookies
            username = creds.getCredential(KRB5_ID).getUsername();

            //creation time var
            long creationTime = System.currentTimeMillis();

            //Setting session values
            sessionID = UserIDEncoder.getID(username, creationTime);
            encodedSessionID = URLEncoder.encode(sessionID, encoder);

            logger.debug("Krb Username is... " + username);

            // setSession                                               
            boolean sessionOk = settingSession(userSession, gsaAuthCookie, creds, username, krbAuthN, creationTime,
                    encodedSessionID, krbCookies, nonKrbCookies);

            logger.debug("Session is .... " + sessionOk);

            if (!sessionOk) {
                //SAML
                statusCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
                response.setStatus(statusCode);

                // Log error
                logger.error("Kerberos Subject has not been created properly");

                // Return
                return;
            } else {
                //Store Session in the Session Map
                sessions.addSession(sessionID, userSession);

                sessions.setMaxSessionAgeMinutes(maxSessionAge);

                if (isSessionEnabled) {
                    sessions.setSessionTimeoutMinutes(sessionTimeout);
                } else {
                    sessions.setSessionTimeoutMinutes(-1);
                }

                logger.debug("User Session created");

                // Add internal authentication cookie
                response.addCookie(gsaAuthCookie);

                logger.debug("Auth cookie added");

                // Debug
                if (logger.isDebugEnabled())
                    logger.debug("Authentication process successful");

                if (!isSAML) {
                    // Debug
                    if (logger.isDebugEnabled())
                        logger.debug("Redirecting user to: " + gsaRefererCookie.getValue());

                    // Redirect
                    response.sendRedirect(gsaRefererCookie.getValue());
                } else {
                    try {
                        redirectingSAML(response, cookies, sessionID);
                    } catch (ValveConfigurationException e) {
                        logger.error("Configuration error: " + e.getMessage(), e);
                        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                    }
                }

            }

        } //end of AuthN cases

    }

    /**
     * Sets the crawler credentials recovered during the crawling process
     * 
     * @param request HTTP request
     * @param KrbAdditionalAuthN if there is an additional authentication process
     */
    private void setCrawlerCredentials(HttpServletRequest request, Credentials creds, boolean KrbAdditionalAuthN) {
        // Read HTTP request parameters
        String username = request.getParameter("UserIDKrb");
        String password = request.getParameter("PasswordKrb");
        Credential krb5Cred = new Credential(KRB5_ID);
        Credential rootCred = new Credential("root");
        krb5Cred.setUsername(username);
        krb5Cred.setPassword(password);
        creds = new Credentials();
        if (KrbAdditionalAuthN) {
            username = request.getParameter("UserID");
            password = request.getParameter("Password");
            rootCred = new Credential("root");
            rootCred.setUsername(username);
            rootCred.setPassword(password);
            creds.add(rootCred);
            creds.add(krb5Cred);
        } else {
            creds.add(krb5Cred);
        }
    }

    /**
     * It invokes the kerberos authentication class to validate the 
     * authentication process
     * 
     * @param request HTTP request
     * @param response HTTP response 
     * @param krbAuthCookies authentication cookies
     * @param url document url
     * @param creds credentials
     * @param isNegotiate if it's a negotiate process
     * 
     * @return HTTP error code
     */
    private int krbAuthentication(HttpServletRequest request, HttpServletResponse response,
            KerberosAuthenticationProcess krbAuthN, Vector<Cookie> krbAuthCookies, String url, Credentials creds,
            boolean isNegotiate) {

        int statusCode = HttpServletResponse.SC_UNAUTHORIZED;
        logger.debug("krbAuthentication: Krb authentication process");
        try {
            krbAuthN.setIsNegotiate(isNegotiate);
            krbAuthN.setValveConfiguration(valveConf);
            statusCode = krbAuthN.authenticate(request, response, krbAuthCookies, url, creds, KRB5_ID);
        } catch (HttpException e) {
            logger.error("Http error during Kerberos authentication " + e);
            statusCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
        } catch (IOException e) {
            logger.error("I/O error during Kerberos authentication " + e);
            statusCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
        }
        logger.debug("Krb Auth - Status code is... " + statusCode);
        return statusCode;
    }

    /**
     * It invokes the additional non-Kerberos authentication process
     * 
     * @param request HTTP request
     * @param response HTTP response
     * @param nonKrbAuthCookies authentication cookies
     * @param url document url
     * @param creds credentials
     * 
     * @return HTTP error code
     */
    private int nonKrbAuthentication(HttpServletRequest request, HttpServletResponse response,
            AuthenticationProcessImpl authenticationProcessCls, Vector<Cookie> nonKrbAuthCookies, String url,
            Credentials creds) {

        int statusCode = HttpServletResponse.SC_UNAUTHORIZED;

        // Instantiate the authentication process class
        try {

            // Instantiate the authorization process class
            authenticationProcessCls = (AuthenticationProcessImpl) Class.forName(authenticationProcessClsName)
                    .newInstance();

        } catch (InstantiationException e) {

            // Log error
            logger.error(
                    "InstantiationException - Authentication servlet parameter [authenticationProcessImpl] has not been set correctly");

            statusCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
            // Return
            return statusCode;

        } catch (IllegalAccessException e) {

            // Log error
            logger.error(
                    "IllegalAccessException - Authentication servlet parameter [authenticationProcessImpl] has not been set correctly");

            statusCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
            // Return
            return statusCode;

        } catch (ClassNotFoundException e) {

            // Log error
            logger.error(
                    "ClassNotFoundException - Authentication servlet parameter [authenticationProcessImpl] has not been set correctly");
            logger.error("Cannot find class: " + authenticationProcessClsName);

            statusCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
            // Return
            return statusCode;

        }

        try {
            logger.debug("Lets authenticate the user");
            // Execute the authentication process in here 
            authenticationProcessCls.setValveConfiguration(valveConf);
            statusCode = authenticationProcessCls.authenticate(request, response, nonKrbAuthCookies, url, creds,
                    "root");

            logger.debug("Non Krb Auth - Status code is... " + statusCode);

        } catch (Exception e) {

            // Debug
            logger.error("Authentication process raised exception: " + e.getMessage(), e);

        }

        return statusCode;

    }

    /**
     * Setting the authentication cookie and the user session
     * 
     * @param username username
     * @param creationTime creation time
     * @param encodedSessionID encoded session id
     * 
     * @return if the setting process was successful
     */
    private boolean settingSession(UserSession userSession, Cookie gsaAuthCookie, Credentials creds,
            String username, KerberosAuthenticationProcess krbAuthN, long creationTime, String encodedSessionID,
            Vector<Cookie> krbCookies, Vector<Cookie> nonKrbCookies) {

        boolean result = false;

        logger.debug("Creating auth cookie with value: " + encodedSessionID);

        // Instantiate authentication cookie with default value
        gsaAuthCookie = new Cookie(authCookieName, encodedSessionID);

        // Set cookie domain
        gsaAuthCookie.setDomain(authCookieDomain);

        // Set cookie path
        gsaAuthCookie.setPath(authCookiePath);

        // Set expiration time
        gsaAuthCookie.setMaxAge(authMaxAge);

        logger.debug("Creating Session");

        userSession.setUserName(username);
        userSession.setSessionCreationTime(creationTime);
        userSession.setSessionLastAccessTime(creationTime);
        userSession.setUserCredentials(creds);

        //Cookies
        settingSessionCookies(krbCookies, nonKrbCookies, gsaAuthCookie, userSession);

        if (krbAuthN.getUserSubject() != null) {
            logger.debug("Kerberos Subject exists");

            userSession.setKerberosCredentials(krbAuthN.getUserSubject());

            result = true;

        } else {
            // Log error
            logger.error("Kerberos Subject has not been created properly");

            // Return
            return result;

        }

        return result;
    }

    /**
     * Sets the kerberos and non-kerberos authentication cookies
     * 
     */
    private void settingSessionCookies(Vector<Cookie> krbCookies, Vector<Cookie> nonKrbCookies,
            Cookie gsaAuthCookie, UserSession userSession) {
        int numKrb = 0;
        int numNonKrb = 0;
        int authCookie = 1;

        Cookie[] totalCookies;

        //check number of cookies
        if (!krbCookies.isEmpty()) {
            numKrb = krbCookies.size();
            logger.debug("numKrb: " + numKrb);
        }
        if (!nonKrbCookies.isEmpty()) {
            numNonKrb = nonKrbCookies.size();
            logger.debug("numNonKrb: " + numNonKrb);
        }

        //setting Cookies
        int numCookies = numKrb + numNonKrb + authCookie;

        logger.debug("numCookies: " + numCookies);

        totalCookies = new Cookie[numCookies];

        //setting authCookie
        logger.debug("Inserting authCoookie at totalCookie");
        totalCookies[0] = gsaAuthCookie;
        int index = 1;
        //getting Krb cookies
        if (numKrb > 0) {
            int krbIndex = 0;
            for (int i = index; i < (numKrb + 1); i++) {
                logger.debug("Inserting totalCookie [i=" + (i) + "]");
                logger.debug("with cookie: " + krbCookies.elementAt(krbIndex));
                totalCookies[i] = krbCookies.elementAt(krbIndex);
                krbIndex++;
                index++;
            }
        }
        //getting nonKrb cookies
        if (numNonKrb > 0) {
            int nonKrbIndex = 0;
            for (int j = index; j < numCookies; j++) {
                logger.debug("Inserting totalCookie [j=" + (j) + "]: ");
                logger.debug("with cookie: " + nonKrbCookies.elementAt(nonKrbIndex));
                totalCookies[j] = nonKrbCookies.elementAt(nonKrbIndex);
                nonKrbIndex++;
            }
        }

        userSession.setCookies(totalCookies);
    }

    /**
     * Gets a cookie from the request
     * 
     * @param request HTTP request
     * @param cookieName cookie name
     * 
     * @return cookie (if it exists)
     */
    private Cookie getCookie(HttpServletRequest request, String cookieName) {

        Cookie cookie = null;
        Cookie[] cookies = null;

        // Retrieve cookies from the request
        cookies = request.getCookies();

        // Protection: look for auth and referer cookies
        if (cookies != null) {

            // Look for the referer cookie
            for (int i = 0; i < cookies.length; i++) {

                // Look for the referer cookie
                if ((cookies[i].getName()).equals(cookieName)) {

                    // Cache cookie
                    cookie = cookies[i];

                    logger.debug("Cookie already exists: " + cookie.getValue());

                    // Exit
                    break;
                }

            }

        }

        return cookie;

    }

    /**
     * Add a new cookie to the response
     * 
     * @param response HTTP response
     * @param krbCookie cookie
     */
    private void addKrbCookie(HttpServletResponse response, Cookie krbCookie) {
        boolean sendCookies = true;
        if (valveConf.getSessionConfig().isSessionEnabled().equals("true")) {
            if (valveConf.getSessionConfig().getSendCookies().equals("false")) {
                sendCookies = false;
            }
        }
        if (!sendCookies) {
            //add Krb cookie into the response
            response.addCookie(krbCookie);
        }
    }

    /**
     * Adds a new Kerberos subject into the vector
     * 
     * @param key subject key
     * @param sub subject
     */
    private void addKrbSubject(String key, Subject sub) {
        krbSubjects.put(key, sub);
    }

    /**
     * Gets a kerberos subject from the vector
     * 
     * @param key subject key
     * 
     * @return subject
     */
    private Subject getKrbSubject(String key) {
        Subject sub = null;
        if (krbSubjects != null) {
            sub = krbSubjects.get(key);
        }
        return sub;
    }

    /**
     * Deletes a Kerberos subject
     * 
     * @param key subject key
     * 
     * @return if the subject was deleted
     */
    private boolean deleteKrbSubject(String key) {
        Subject sub = null;
        boolean result = false;
        if (krbSubjects != null) {
            sub = krbSubjects.remove(key);
            if (sub != null) {
                result = true;
            }
        }
        return result;
    }

    /**
     * Looks for Kerberos credentials in the credentials
     * 
     * @return
     */
    private boolean lookForKrbCreds(Credentials creds) {
        //check if Krb subject is Ok
        boolean krbCredFound = false;
        if (creds.getCredential(KRB5_ID) != null) {
            Subject krbSubject = creds.getCredential(KRB5_ID).getSubject();
            if (krbSubject != null) {
                krbCredFound = true;
                //set new Krb cred
                creds.getCredential(KRB5_ID).setKrbSubject(krbSubject);
            }
        }
        return krbCredFound;
    }

    /**
     * Creates credentials for managing double authentication
     * 
     * @param request HTTP request
     * @param krbSubject user subject
     */
    private void createCredsDoubleAuthN(HttpServletRequest request, Credentials creds, Subject krbSubject) {
        //set creds
        String username = request.getParameter("UserIDKrb");
        String password = request.getParameter("PasswordKrb");

        //Add krb creds
        Credential krb5Cred = new Credential(KRB5_ID);
        krb5Cred.setKrbSubject(krbSubject);
        krb5Cred.setUsername(getPrincipalFromSubject(krbSubject));
        creds.add(krb5Cred);

        //Add root creds
        Credential rootCred = new Credential("root");
        rootCred.setUsername(username);
        rootCred.setPassword(password);
        //add them to creds
        creds.add(rootCred);

    }

    /**
     * Gets the principal from the subject
     * 
     * @param subject user subject
     * 
     * @return principal
     */
    public String getPrincipalFromSubject(Subject subject) {

        String principal = null;

        logger.debug("Getting principal from Subject");
        try {
            Set principals = subject.getPrincipals();
            if (!principals.isEmpty()) {
                logger.debug("Subject contains at least one Principal");
                Iterator it = principals.iterator();
                if (it.hasNext()) {
                    Principal ppal = (Principal) it.next();
                    principal = ppal.getName().substring(0, ppal.getName().indexOf("@"));
                    logger.debug("Getting the first principal: " + principal);
                }
            }
        } catch (Exception e) {
            logger.error("Error retrieving the client's Principal from the Subject: " + e.getMessage(), e);
        }

        return principal;
    }

    /**
     * Sets Valve configuration parameters
     * 
     * @param request HTTP request
     */
    public void setValveParams(HttpServletRequest request) {

        // Read HTTP request attributes
        try {
            authCookieName = valveConf.getAuthCookieName();
            logger.debug("authCookieName: " + authCookieName);
            refererCookieName = valveConf.getRefererCookieName();
            logger.debug("refererCookieName: " + refererCookieName);

            authCookieDomain = valveConf.getAuthCookieDomain();
            authCookiePath = valveConf.getAuthCookiePath();
            try {
                authMaxAge = Integer.parseInt(valveConf.getAuthMaxAge());
            } catch (NumberFormatException nfe) {
            }
            authenticationProcessClsName = valveConf.getAuthenticationProcessImpl();
            KrbLoginUrl = valveConf.getKrbConfig().getKrbLoginUrl();
            KrbUsrPwdCrawlerUrl = valveConf.getKrbConfig().getKrbUsrPwdCrawlerUrl();
            loginUrl = valveConf.getLoginUrl();

            //Set Kerberos and Session vars
            maxSessionAge = (new Long(valveConf.getSessionConfig().getMaxSessionAge())).longValue();
            sessionTimeout = (new Long(valveConf.getSessionConfig().getSessionTimeout())).longValue();
            sessionCleanup = (new Long(valveConf.getSessionConfig().getSessionCleanup())).longValue();

            //Is it SAML
            if (valveConf.getSAMLConfig().isSAML().equals("true")) {
                isSAML = true;
            }

            //Is it Kerberos?
            if (valveConf.getKrbConfig().isKerberos().equals("true")) {
                isKerberos = true;
                //Is it Negotiate?
                if (valveConf.getKrbConfig().isNegotiate().equals("true")) {
                    isNegotiate = true;
                } else {
                    isNegotiate = false;
                }
            } else {
                isKerberos = false;
            }

            //Set Session Vars
            if (valveConf.getSessionConfig().isSessionEnabled().equals("true")) {
                isSessionEnabled = true;
            } else {
                isSessionEnabled = false;
            }

            if (valveConf.getKrbConfig().isKrbUsrPwdCrawler().equals("true")) {
                KrbUsrPwdCrawler = true;
            } else {
                KrbUsrPwdCrawler = false;
            }

            if (valveConf.getKrbConfig().isKrbAdditionalAuthN().equals("true")) {
                KrbAdditionalAuthN = true;
            } else {
                KrbAdditionalAuthN = false;
            }

            //Session support: cleanup process
            if ((isSessionEnabled) || (isKerberos)) {
                logger.debug("Getting sessionTimer instance");
                sessionTimer = SessionTimer.getInstance(isSessionEnabled, isKerberos, sessionCleanup);
                sessionTimer.setTimer();
            }

        } catch (Exception e) {
            logger.error("Exception reading Configuration parameters: " + e.getMessage(), e);
        }
    }

    /**
     * Reads the valve configuration path
     * 
     * @return
     */
    public String readValveConfigPath() {

        String valveConfigPath = null;

        try {
            //Get Config
            javax.naming.Context ctx = new javax.naming.InitialContext();
            javax.naming.Context env = (javax.naming.Context) ctx.lookup("java:comp/env");

            //Get gsaValveConfigPath
            valveConfigPath = (String) env.lookup("gsaValveConfigPath");
        } catch (NamingException e) {
            logger.debug("Error when reading the Valve Config Path " + e);
        }

        return valveConfigPath;
    }

    /**
     * Creates the referer cookie
     * 
     */
    private void createRefererCookie(Cookie gsaRefererCookie) {
        // Instantiate authentication cookie with default value
        gsaRefererCookie = new Cookie(refererCookieName, valveConf.getTestFormsCrawlUrl());

        // Set cookie domain
        gsaRefererCookie.setDomain(authCookieDomain);

        // Set cookie path
        gsaRefererCookie.setPath(authCookiePath);

        // Set expiration time
        gsaRefererCookie.setMaxAge(authMaxAge);
    }

    /**
     * Redirects the user back to the client's URL that checks the SAML 
     * authentication process
     * 
     * @param response HTTP response
     * @param cookies authentication cookies
     * @param sessionID session identifier
     * 
     * @throws IOException
     */
    private void redirectingSAML(HttpServletResponse response, Cookie[] cookies, String sessionID)
            throws IOException, ValveConfigurationException {
        //create the artifact
        long maxArtifactAge = new Long(valveConf.getSAMLConfig().getMaxArtifactAge()).longValue();
        //Instead of using the username, we'll use the session id
        String artifact = SAMLArtifactProcessor.getInstance(maxArtifactAge).storeArtifact(sessionID);

        //Create the referer var                    
        refererSAML = ValveUtils.getGSAHost("", valveConf, cookies, valveConf.getRefererCookieName());

        //redirect to the GSA's Artifact consumer
        SAMLAuthN samlAuthN = new SAMLAuthN();
        String redirectURL = null;
        try {
            redirectURL = samlAuthN.redirectLocation(refererSAML, relayState, artifact);
        } catch (UnsupportedEncodingException e) {
            logger.error("Error when creating the SAML redirecting URL: " + e);
        }
        logger.debug("SAML:Redirecting to " + redirectURL);
        response.sendRedirect(redirectURL);
    }

    /**
     * Constructs the SAML URL for Kerberos authentication
     * 
     * @return SAML URL for Kerberos authentication
     */
    private String contructKrbLoginURL() {

        String loginURL = null;

        try {
            boolean isSAML = new Boolean(valveConf.getSAMLConfig().isSAML()).booleanValue();

            if (!isSAML) {
                loginURL = KrbLoginUrl;
            } else {
                loginURL = KrbLoginUrl + "?SAMLRequest=" + URLEncoder.encode(samlRequest, encoder) + "&RelayState="
                        + URLEncoder.encode(relayState, encoder);
            }

        } catch (Exception ex) {
            logger.error("Error during Kerberos Login URL construction: " + ex);
        }

        return loginURL;

    }

    /**
     * Checks if it's a Kerberos process when there is double authentication 
     * process.
     * 
     * @param krbCookie kerberos authentication cookie
     * 
     * @return boolean - if it's Kerberos processing point
     */
    private boolean isKrbProcess(Cookie krbCookie) {

        boolean isKrbProcess = false;

        try {
            if ((krbCookie != null) && (!isSAML)) {
                isKrbProcess = false;
            } else {
                if (!isSAML) {
                    //Krb cookie exists for Forms based authentication
                    isKrbProcess = true;
                } else {
                    //is SAML
                    if (krbCookie == null) {
                        //Krb cookie does not exist. First authentication process
                        //Lets process Krb authn
                        isKrbProcess = true;
                    } else {
                        //check if this is part of first authentication process
                        //or it's part of a reauthenication one (so that the krb cookie already exists)
                        Subject krbSubj = getKrbSubject(krbCookie.getValue());

                        if (krbSubj == null) {
                            //the Krb process has not been launched yet
                            isKrbProcess = true;
                        } else {
                            //the Krb process was already launched
                            isKrbProcess = false;
                        }

                    }
                }
            }

        } catch (Exception ex) {
            logger.error("Error during checking if it's Kerberos process: " + ex);
            isKrbProcess = false;
        }

        return isKrbProcess;

    }

}