/* =============================================================================== * * Part of the InfoGlue Content Management Platform (www.infoglue.org) * * =============================================================================== * * Copyright (C) * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2, as published by the * Free Software Foundation. See the file LICENSE.html for more information. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY, including 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. * * =============================================================================== */ package org.infoglue.cms.security; import java.security.Principal; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Properties; import javax.servlet.FilterChain; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import org.infoglue.cms.exception.SystemException; import org.infoglue.cms.util.CmsPropertyHandler; import org.infoglue.cms.util.IPMatcher; import org.infoglue.deliver.util.Timer; /** * This abstract class defines what a authentication module has to implement. * It also acts as a factory class for the authentication framework. * * @author Mattias Bogeblad */ public abstract class AuthenticationModule { private final static Logger logger = Logger.getLogger(AuthenticationModule.class.getName()); /** * This is the authentication framework factory method which looks at the system configuration and instantiates an implementation based on this. * A deviation from the normal pattern exists and it is related to how SSO-implementations (in this case CAS initially) is handled. As CAS requires the * complete delegation of the request process (login form etc) to the CAS-service it is harder to login other systems or search spiders etc and a strong requirement * from customers has been to allow for certain IP-ranges to be directed to the basic authentication module instead (Infoglue's own) which is simpler to automate. * So for this to work the metod contains matching on IP and an optional parameter which forces fallback. * * @param transactionObject Optional database object if the authentication should be carried out within a transaction. * @param successLoginUrl The url to return the user to when the login is successful. * @param request The user's HttpServletRequest. * @param forceBasicModule In some cases - like when running WebDAV and CAS is not an option (or is it). * @return The implementation of AuthenticationModule in question. * @throws SystemException */ public static AuthenticationModule getAuthenticationModule(Object transactionObject, String successLoginUrl, HttpServletRequest request, boolean forceBasicModule) throws SystemException { AuthenticationModule authenticationModule = null; try { String authenticatorClass = InfoGlueAuthenticationFilter.authenticatorClass; String authorizerClass = InfoGlueAuthenticationFilter.authorizerClass; String invalidLoginUrl = InfoGlueAuthenticationFilter.invalidLoginUrl; String loginUrl = InfoGlueAuthenticationFilter.loginUrl; String logoutUrl = InfoGlueAuthenticationFilter.logoutUrl; String serverName = InfoGlueAuthenticationFilter.serverName; Properties extraProperties = InfoGlueAuthenticationFilter.extraProperties; String casRenew = InfoGlueAuthenticationFilter.casRenew; String casServiceUrl = InfoGlueAuthenticationFilter.casServiceUrl; String casValidateUrl = InfoGlueAuthenticationFilter.casValidateUrl; String casProxyValidateUrl = InfoGlueAuthenticationFilter.casProxyValidateUrl; String casLogoutUrl = InfoGlueAuthenticationFilter.casLogoutUrl; if(authenticatorClass.contains("CAS") && (forceBasicModule || fallBackToBasicBasedOnIP(request))) { authenticationModule = (AuthenticationModule)Class.forName("org.infoglue.cms.security.InfoGlueBasicAuthenticationModule").newInstance(); authenticationModule.setAuthenticatorClass("org.infoglue.cms.security.InfoGlueBasicAuthenticationModule"); authenticationModule.setAuthorizerClass(authorizerClass); authenticationModule.setInvalidLoginUrl("Login!invalidLogin.action"); authenticationModule.setLoginUrl("Login.action"); authenticationModule.setLogoutUrl("Login!logout.action"); authenticationModule.setServerName(serverName); authenticationModule.setExtraProperties(extraProperties); authenticationModule.setCasRenew(casRenew); if(successLoginUrl != null && successLoginUrl.length() > 0) { int index = successLoginUrl.indexOf("&ticket="); if(index > -1) { successLoginUrl = successLoginUrl.substring(0, index); } int index2 = successLoginUrl.indexOf("?ticket="); if(index2 > -1) { successLoginUrl = successLoginUrl.substring(0, index2); } logger.info("successLoginUrl:" + successLoginUrl); authenticationModule.setCasServiceUrl(successLoginUrl); authenticationModule.setSuccessLoginUrl(successLoginUrl); } else authenticationModule.setCasServiceUrl(casServiceUrl); authenticationModule.setCasValidateUrl(casValidateUrl); authenticationModule.setCasProxyValidateUrl(casProxyValidateUrl); authenticationModule.setCasLogoutUrl(casLogoutUrl); authenticationModule.setTransactionObject(transactionObject); } else { authenticationModule = (AuthenticationModule)Class.forName(authenticatorClass).newInstance(); authenticationModule.setAuthenticatorClass(authenticatorClass); authenticationModule.setAuthorizerClass(authorizerClass); authenticationModule.setInvalidLoginUrl(invalidLoginUrl); authenticationModule.setLoginUrl(loginUrl); authenticationModule.setLogoutUrl(logoutUrl); authenticationModule.setServerName(serverName); authenticationModule.setExtraProperties(extraProperties); authenticationModule.setCasRenew(casRenew); if(successLoginUrl != null && successLoginUrl.length() > 0) { int index = successLoginUrl.indexOf("&ticket="); if(index > -1) { successLoginUrl = successLoginUrl.substring(0, index); } int index2 = successLoginUrl.indexOf("?ticket="); if(index2 > -1) { successLoginUrl = successLoginUrl.substring(0, index2); } logger.info("successLoginUrl:" + successLoginUrl); authenticationModule.setCasServiceUrl(successLoginUrl); authenticationModule.setSuccessLoginUrl(successLoginUrl); } else authenticationModule.setCasServiceUrl(casServiceUrl); authenticationModule.setCasValidateUrl(casValidateUrl); authenticationModule.setCasProxyValidateUrl(casProxyValidateUrl); authenticationModule.setCasLogoutUrl(casLogoutUrl); authenticationModule.setTransactionObject(transactionObject); } } catch(Exception e) { //return getAuthenticationModule(transactionObject, successLoginUrl, request, true); logger.error("An error occurred when we tried to get an authenticationModule:" + e, e); throw new SystemException("An error occurred when we tried to get an authenticationModule: " + e.getMessage(), e); } return authenticationModule; } /** * This method takes a request object and matches the clients IP (or X-Forwarded IP if allowed) against the system defined IP:s. */ private static boolean fallBackToBasicBasedOnIP(HttpServletRequest request) { Timer t = new Timer(); if(request == null) return false; String ipAddressesToFallbackToBasicAuth = CmsPropertyHandler.getIpAddressesToFallbackToBasicAuth(); logger.info("ipAddressesToFallbackToBasicAuth: " + ipAddressesToFallbackToBasicAuth); if(ipAddressesToFallbackToBasicAuth == null || ipAddressesToFallbackToBasicAuth.equals("") || ipAddressesToFallbackToBasicAuth.indexOf("ipAddressesToFallbackToBasicAuth") > -1) return false; String[] ipAddressesToFallbackToBasicAuthArray = ipAddressesToFallbackToBasicAuth.split(","); List<String> list = Arrays.asList(ipAddressesToFallbackToBasicAuthArray); boolean allowXForwardedIPCheck = CmsPropertyHandler.getAllowXForwardedIPCheck(); String ipRemote = request.getRemoteAddr(); String ipRequest = null; if (allowXForwardedIPCheck) { String ipRemoteCandidate = request.getHeader("X-Forwarded-For"); if(ipRemoteCandidate != null && !ipRemoteCandidate.equals("")) ipRemote = ipRemoteCandidate; } logger.info("ipAddressesToFallbackToBasicAuth: " + ipAddressesToFallbackToBasicAuth + "\nRequest: "+ipRequest+", Remote: "+ipRemote); boolean isInList = IPMatcher.isIpInList(list, ipRemote, ipRequest); if(logger.isInfoEnabled()) t.printElapsedTime("Auth took"); return isInList; } public abstract String authenticateUser(HttpServletRequest request, HttpServletResponse response, FilterChain fc) throws Exception; public abstract String authenticateUser(Map request) throws Exception; public abstract Principal loginUser(HttpServletRequest request, HttpServletResponse response, Map status) throws Exception; public abstract boolean logoutUser(HttpServletRequest request, HttpServletResponse response) throws Exception; public abstract String getLoginDialogUrl(HttpServletRequest request, HttpServletResponse response) throws Exception; public abstract String getAuthenticatorClass(); public abstract void setAuthenticatorClass(String authenticatorClass); public abstract String getAuthorizerClass(); public abstract void setAuthorizerClass(String authorizerClass); public abstract String getInvalidLoginUrl(); public abstract void setInvalidLoginUrl(String invalidLoginUrl); public abstract String getSSOUserName(HttpServletRequest request) throws Exception; public abstract String getLoginUrl(); public abstract void setLoginUrl(String loginUrl); public abstract String getSuccessLoginUrl(); public abstract void setSuccessLoginUrl(String successLoginUrl); public abstract String getLogoutUrl(); public abstract void setLogoutUrl(String logoutUrl); public abstract String getServerName(); public abstract void setServerName(String serverName); public abstract Properties getExtraProperties(); public abstract void setExtraProperties(Properties properties); public abstract String getCasRenew(); public abstract void setCasRenew(String casRenew); public abstract String getCasServiceUrl(); public abstract void setCasServiceUrl(String casServiceUrl); public abstract String getCasValidateUrl(); public abstract void setCasValidateUrl(String casValidateUrl); public abstract String getCasProxyValidateUrl(); public abstract void setCasProxyValidateUrl(String casProxyValidateUrl); public abstract String getCasLogoutUrl(); public abstract void setCasLogoutUrl(String casLogoutUrl); public abstract String getCasAuthorizedProxy(); public abstract void setCasAuthorizedProxy(String casAuthorizedProxy); public abstract Object getTransactionObject(); public abstract void setTransactionObject(Object transactionObject); public abstract boolean enforceJ2EEContainerPrincipal(); }