Java tutorial
/** * 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.valve.rootAuth; import java.io.IOException; import java.net.URLDecoder; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.httpclient.HttpException; import org.apache.log4j.Logger; import org.apache.regexp.RE; import org.apache.regexp.RESyntaxException; import com.google.gsa.AuthorizationProcessImpl; import com.google.gsa.Credentials; import com.google.gsa.sessions.Sessions; import com.google.gsa.sessions.UserSession; import com.google.gsa.valve.configuration.ValveConfiguration; import com.google.gsa.valve.configuration.ValveRepositoryConfiguration; import com.google.gsa.valve.utils.URLUTF8Encoder; import com.google.gsa.sessions.nonValidSessionException; import java.io.UnsupportedEncodingException; import java.net.URL; import java.util.Vector; /** * This is the default class that drives the authorization process based on the * repositories declared in the config file, where the individual authorization * class is included there as well. * <p> * The name of the authentication classes that need to be processed are included * in a vector that is reused multiple times to check if URL patterns with any * of them. If there is any URL pattern defined in the config file that * matches with the url sent to the authorize() method, a new authorization * class of that kind is created. * <p> * At the end, it collects the error message coming from the specific * authorization class' authorize() method. If there is any problem during * the processing, it's returned as well. * * @see RootAuthenticationProcess * */ public class RootAuthorizationProcess implements AuthorizationProcessImpl { //logger private Logger logger = null; //Valve configuration private ValveConfiguration valveConf = null; private static Vector<ValveRepositoryConfiguration> repositoryConfigurations = null; //Krb and session vars private static boolean isKerberos = false; private static boolean isSessionEnabled = false; private static boolean isSAML = false; private static boolean sendCookies = true; private static int sessionVarsSet = -1; private static String authCookieName = null; private static String internalURL = null; private Sessions sessions = null; private static final String ENCODING = "UTF-8"; /** * Class constructor * */ public RootAuthorizationProcess() { // Invoke parent constructor super(); logger = Logger.getLogger(RootAuthorizationProcess.class); } /** * Sets user credentials * * @param creds */ public void setCredentials(Credentials creds) { //do nothing } /** * * This is the default root authorize method that manages the whole * authorization lifecycle when accessing the backend repositories. * <p> * Based on the information included in the config file, it uses that * information to manage the authorization process. If there is any URL * pattern defined in the config file that matches with the url sent to * the authorize() method, a new authorization class of that kind is created. * <p> * At the end, it collects the error message coming from the specific * authorization class' authorize() method. If there is any problem during * the processing, it's returned as well. * * @param request HTTP request * @param response HTTP response * @param authCookies vector that contains the authentication cookies * @param url the document url * @param id the default credential id * * @return the HTTP error code * * @throws HttpException * @throws IOException */ public int authorize(HttpServletRequest request, HttpServletResponse response, Cookie[] authCookies, String url, String id) throws HttpException, IOException, nonValidSessionException { logger.debug("Authorize"); // Initialize status code int statusCode = HttpServletResponse.SC_UNAUTHORIZED; boolean patternMatch = false; boolean rootIDExists = false; //UserSession UserSession userSession = null; //GSA cookie Cookie gsaAuthCookie = null; //Encoding support String newURL = null; //Try to avoid the double encoding problem try { newURL = URLDecoder.decode(url, ENCODING); } catch (IllegalArgumentException e) { logger.error("Illegal Argument when decoding/encoding URL"); newURL = url; } URLUTF8Encoder encoder = new URLUTF8Encoder(); url = encoder.encodeURL(new URL(newURL)); //read vars if (valveConf != null) { //Set config vars setValveConf(); } else { logger.error("Configuration error: Config file is not present"); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Configuration error - Kerberos is not set properly"); return HttpServletResponse.SC_INTERNAL_SERVER_ERROR; } //set auth Cookie Cookie[] cookies = request.getCookies(); //SAML if (cookies == null) { cookies = authCookies; } if (cookies != null) { logger.debug("authCookieName is: " + authCookieName); for (int i = 0; i < cookies.length; i++) { logger.debug("Cookie found: " + cookies[i].getName() + "; value=" + cookies[i].getValue()); if (cookies[i].getName().equals(authCookieName)) { gsaAuthCookie = cookies[i]; logger.debug("Auth Cookie found!"); break; } } } //manage Sessions if (isSessionEnabled) { logger.debug("Session is enabled. Getting session instance"); try { //Session Support. Get Sessions instance sessions = Sessions.getInstance(); //Get user session userSession = manageSessions(gsaAuthCookie); } catch (nonValidSessionException nVS) { //throw Exception throw nVS; } catch (Exception e) { logger.error("Error when geting session: " + e.getMessage(), e); } } //setting auth cookies if ((!isSessionEnabled) || ((isSessionEnabled) && (sendCookies) && (!isSAML))) { //send auth cookies as those coming straight from the browser authCookies = request.getCookies(); } else { //auth cookies are those that are in the session authCookies = userSession.getCookies(); } logger.debug("Authz authorizing [" + url + "]"); //protection if (repositoryConfigurations == null) { logger.error("Authorization Repository Vector has not been initialized"); return HttpServletResponse.SC_UNAUTHORIZED; } //Pattern of the host that has been confiogured that needs to be macthed to the URL that is being authorized. RE authZHost = null; //The host of the GSA, need to detect a request from this host and skip past it RE queryHostRE = null; try { queryHostRE = new RE("/search", RE.MATCH_CASEINDEPENDENT); } catch (RESyntaxException reSynTaxExp) { logger.error("Failed to created queryHost RE: " + reSynTaxExp.getMessage()); } ValveRepositoryConfiguration repository = null; logger.debug("Repository length: " + repositoryConfigurations.size()); for (int i = 0; i < repositoryConfigurations.size(); i++) { repository = repositoryConfigurations.elementAt(i); logger.debug("Repository ID: " + repository.getId()); //Pattern for this repository that needs to be macthed try { authZHost = new RE(repository.getPattern(), RE.MATCH_CASEINDEPENDENT); } catch (RESyntaxException reSynTaxExp) { logger.error("Failed to created authZHost RE: " + reSynTaxExp.getMessage()); logger.error("Pattern trying to use: " + repository.getPattern()); } if (queryHostRE.match(url)) { logger.debug("Query AuthZ"); statusCode = HttpServletResponse.SC_OK; patternMatch = true; } else { if (authZHost.match(url)) { //Need the correct authZProcess implementation for this repository ID AuthorizationProcessImpl authZProcess = getAuthorizationProcess(repository); if (authZProcess != null) { //URL matches a pattern if (repository.getId().equals("root")) { //If this is a match for the root id then it's the internal host used to test valve/test.html, so should just return valid logger.debug("Internal AuthZ"); statusCode = HttpServletResponse.SC_OK; patternMatch = true; rootIDExists = true; } else { logger.info("Authorizing with " + repository.getId()); patternMatch = true; //Add credentials try { addCredentials(authZProcess, userSession); } catch (Exception e) { logger.error("Error during Kerberos authZ treatment : " + e.getMessage(), e); } try { String repoID = repository.getId(); statusCode = authZProcess.authorize(request, response, authCookies, url, repoID); //If statusCode is UNAUTHORIZED, then the process has to stop here if (statusCode == HttpServletResponse.SC_UNAUTHORIZED) { break; } } catch (Exception e) { logger.error("Error during authorization: " + e.getMessage(), e); } } } else { logger.debug("The URL matches with the pattern defined for repository " + "[" + repository.getId() + "] but could not instantiate the class"); } } } } if (!patternMatch) { //check if "root" repository was created in the config file //if not: check if the URL is a Valve one. If so, return SC_OK if (!rootIDExists) { RE internalRE = new RE(new URL(internalURL).getHost(), RE.MATCH_CASEINDEPENDENT); boolean samePorts = (((new URL(internalURL)).getPort()) == ((new URL(url)).getPort())); if ((internalRE.match(url)) && (samePorts)) { logger.debug("This is an internal URL"); statusCode = HttpServletResponse.SC_OK; } else { logger.debug("No pattern has been defined at any repository for this URL"); //Set Status Code equal to "-1", so we do know there was no pattern found statusCode = -1; } } else { logger.debug("No pattern has been defined at any repository for this URL"); //Set Status Code equal to "-1", so we do know there was no pattern found statusCode = -1; } } //protection userSession = null; return statusCode; } /** * Gets the authorization process instance needed to process the request * * @param repository the repository configuration information * * @return the authorization class */ private AuthorizationProcessImpl getAuthorizationProcess(ValveRepositoryConfiguration repository) { AuthorizationProcessImpl authProcess = null; //protection if (repository != null) { try { String authZComponent = repository.getAuthZ(); logger.debug("Authorization module is: " + authZComponent); if (authZComponent != null) { authProcess = (AuthorizationProcessImpl) Class.forName(authZComponent).newInstance(); authProcess.setValveConfiguration(valveConf); } else { logger.debug("This repository[" + repository.getId() + "] does not cointain any Authorization class"); } } catch (LinkageError le) { logger.error(repository.getId() + " - Can't instantiate class [AuthorizationProcess-LinkageError]: " + le.getMessage(), le); authProcess = null; } catch (InstantiationException ie) { logger.error(repository.getId() + " - Can't instantiate class [AuthorizationProcess-InstantiationException]: " + ie.getMessage(), ie); authProcess = null; } catch (IllegalAccessException iae) { logger.error(repository.getId() + " - Can't instantiate class [AuthorizationProcess-IllegalAccessException]: " + iae.getMessage(), iae); authProcess = null; } catch (ClassNotFoundException cnfe) { logger.error(repository.getId() + " - Can't instantiate class [AuthorizationProcess-ClassNotFoundException]: " + cnfe.getMessage(), cnfe); authProcess = null; } catch (Exception e) { logger.error(repository.getId() + " - Can't instantiate class [AuthorizationProcess-Exception]: " + e.getMessage(), e); authProcess = null; } } return authProcess; } /** * Sets the Valve Configuration instance to read the parameters * from there * * @param valveConf the Valve configuration instance */ public void setValveConfiguration(ValveConfiguration valveConf) { //if (this.valveConf == null) { logger.debug("Setting Valve Configuration"); this.valveConf = valveConf; if (repositoryConfigurations == null) { setRepositoryConfigurations(); } //} } /** * Sets the vector that contains all the authorization class names * in order to process it more efficiently. * */ private void setRepositoryConfigurations() { //Instantiate each of the repositories defined in the configuration repositoryConfigurations = new Vector<ValveRepositoryConfiguration>(); String repositoryIds[] = valveConf.getRepositoryIds(); ValveRepositoryConfiguration repository = null; logger.debug("Reading repositories"); for (int i = 0; i < repositoryIds.length; i++) { try { repository = valveConf.getRepository(repositoryIds[i]); if (repository.getAuthZ() == null || repository.getAuthZ().equals("")) { logger.info("No authZ defined for " + repository.getId()); } else { logger.debug("Authorisation process for [" + repository.getId() + "] found"); repositoryConfigurations.add(repository); } } catch (Exception e) { logger.error("Error during Authorization Vector creation: " + e.getMessage(), e); } } logger.debug("Authorization vector has been created"); } /** * Sends the credentials store in the session to the backend application * * @param authZProcess authorization process instance * @param userSession user session */ public void addCredentials(AuthorizationProcessImpl authZProcess, UserSession userSession) { logger.debug("addCredentials method"); try { if (userSession != null) { logger.debug("userSession is not empty: " + userSession.getUserName()); Credentials credentials = userSession.getUserCredentials(); if (credentials != null) { logger.debug("Setting credentials for authorization"); //Adding credentials authZProcess.setCredentials(credentials); } else { logger.debug("There are no credentials available"); } } } catch (Exception ex) { logger.error("Error when adding credentials: " + ex.getMessage(), ex); } finally { } } /** * It manages session and checks the session (if it exists) is still valid. * * @param gsaAuthCookie authentication cookie * * @return the user session if it exists, null otherwise * * @throws nonValidSessionException */ public UserSession manageSessions(Cookie gsaAuthCookie) throws nonValidSessionException { UserSession userSession = null; logger.debug("ManageSessions method. Check if Session is enabled [" + isSessionEnabled + "]"); if (isSessionEnabled) { //check if the session is active logger.debug("The session is enabled"); String userID = null; try { userID = URLDecoder.decode(gsaAuthCookie.getValue(), ENCODING); } catch (UnsupportedEncodingException e) { logger.error("Error during decoding Auth Cookie: " + e.getMessage(), e); userID = gsaAuthCookie.getValue(); } logger.debug("the userID has been read: " + userID); boolean isSessionInvalid = sessions.isSessionInvalid(userID); logger.debug("Session invalidity checked: " + isSessionInvalid); if (isSessionInvalid) { //protect this code synchronized (sessions) { logger.debug("the session is invalid"); boolean doesSessionStillExist = sessions.doesSessionExist(userID); logger.debug("Session still exists: " + doesSessionStillExist); if (doesSessionStillExist) { logger.debug("the session does exists: let's delete it"); //delete Session sessions.deleteSession(userID); } logger.debug("Setting session invalidity"); throw new nonValidSessionException("The session is invalid. It does not longer exists"); } } //end session invalid //look for the existing session userSession = sessions.getUserSession(userID); if (userSession == null) { logger.error("User Session is not valid"); throw new nonValidSessionException("The session does not exists"); } else { if (isSessionEnabled) { //update the last access int sessionTimeout = new Integer(valveConf.getSessionConfig().getSessionTimeout()).intValue(); if (sessionTimeout >= 0) { long lastAccessTime = getCurrentTime(); if (lastAccessTime > 0) { logger.debug("New access time: " + lastAccessTime); userSession.setSessionLastAccessTime(lastAccessTime); sessions.addSession(userID, userSession); } } } } } return userSession; } /** * Gets the current time * * @return current time */ public long getCurrentTime() { long currentTime = System.currentTimeMillis(); return currentTime; } /** * Deletes all cookies that start with "gsa" * * @param request HTTP request * @param response HTTP response */ public void deleteCookies(HttpServletRequest request, HttpServletResponse response) { // Retrieve cookies Cookie[] allCookies = request.getCookies(); try { // Protection if (allCookies != null) { // Look for the authentication cookie for (int i = 0; i < allCookies.length; i++) { logger.debug("Cookie: " + allCookies[i].getName()); //look for all the cookies start with "gsa" and delete them if ((allCookies[i].getName()).startsWith("gsa")) { Cookie gsaCookie = new Cookie(allCookies[i].getName(), allCookies[i].getValue()); gsaCookie.setMaxAge(0); response.addCookie(gsaCookie); // Debug if (logger.isDebugEnabled()) logger.debug("GSA cookie: [" + gsaCookie.getName() + " has been deleted ]"); } } } } catch (Exception e) { logger.error("Error when deleting cookies: " + e.getMessage(), e); } } /** * Gets the redirect URL when it's needed to reauthenticate * * @param url request url * @param loginUrl login url * * @return the redirect url */ public String redirectUrl(String url, String loginUrl) { //redirect String redirectUrl = null; if (url != null) { redirectUrl = loginUrl + "?returnPath=" + url; } else { redirectUrl = loginUrl; } logger.debug("redirecting to " + redirectUrl); return redirectUrl; } /** * Updates in the session the last access time * * @param userSession user session */ public void updateLastAccessTime(UserSession userSession) { long currentTime = System.currentTimeMillis(); logger.debug("Last access time: " + userSession.getSessionLastAccessTime()); userSession.setSessionLastAccessTime(currentTime); } /** * Reads only once the configuration parameter needed * */ private void setValveConf() { logger.debug("Starting setValveConf method"); try { if (sessionVarsSet == -1) { //These vars have never been set for this instance isSessionEnabled = new Boolean(valveConf.getSessionConfig().isSessionEnabled()).booleanValue(); logger.debug("Setting isSessionEnabled: " + isSessionEnabled); isKerberos = new Boolean(valveConf.getKrbConfig().isKerberos()).booleanValue(); logger.debug("Setting isKerberos: " + isKerberos); if (isSessionEnabled) { sendCookies = new Boolean(valveConf.getSessionConfig().getSendCookies()).booleanValue(); } else { sendCookies = false; } logger.debug("Setting sendCookies: " + sendCookies); isSAML = new Boolean(valveConf.getSAMLConfig().isSAML()).booleanValue(); logger.debug("Setting isSAML: " + isSAML); authCookieName = valveConf.getAuthCookieName(); logger.debug("Setting authCookieName: " + authCookieName); internalURL = valveConf.getLoginUrl(); logger.debug("Setting internalURL: " + internalURL); //Set the the following var to a value distinct than "-1" sessionVarsSet = 0; } } catch (Exception e) { logger.error("Error reading config parameters. Check config file"); } } }