/*
* JBoss, a division of Red Hat
* Copyright 2006, Red Hat Middleware, LLC, and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.portal.identity.sso.opensso;
import org.apache.catalina.valves.ValveBase;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.Context;
import org.apache.catalina.Session;
import org.apache.catalina.authenticator.Constants;
import org.jboss.portal.identity.helper.IdentityTools;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.security.jacc.PolicyContext;
import java.io.IOException;
import java.security.Principal;
import java.util.Set;
import java.util.Iterator;
import java.util.HashSet;
import com.iplanet.sso.SSOTokenManager;
import com.iplanet.sso.SSOToken;
/**
* @author <a href="mailto:boleslaw dot dawidowicz at redhat anotherdot com">Boleslaw Dawidowicz</a>
* @version $Revision: 0.1 $
*/
public class OpenSSOAuthenticationValve extends ValveBase
{
/** . */
private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(OpenSSOAuthenticationValve.class);
public static final String WEB_REQUEST_KEY = "javax.servlet.http.HttpServletRequest";
private Set urlPatterns;
private String loginURL;
private String logoutURL;
private boolean appendLoginGoto = true;
private boolean appendLogoutGoto = true;
private String loginParameters;
private String logoutParameters;
private String authType = "FORM";
public void invoke(Request request, Response response) throws IOException, ServletException
{
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpSession session = httpRequest.getSession();
request.setAttribute("ssoEnabled", "true");
SSOToken token = getToken();
String requestURI = request.getRequestURI();
// When token is not present and secured portal url is requested
if (isSecuredURI(requestURI) && token == null)
{
// Perform OpenSSO login by going to the OpenSSO authentication server
redirectToOpenSSOLogin(request, response);
return;
}
// When token present and valid
if (token != null && isTokenValid(token))
{
try
{
// Perform the portal JAAS authentication
String user = token.getProperty("UserId");
request.setAttribute("ssoSuccess", new Boolean(true));
Principal principal = ((Context) this.container).getRealm().authenticate(user, (String) null);
if (principal != null)
{
this.register(request, response, principal, getAuthType(), user,
(String) null);
}
}
catch (Exception e)
{
log.error("Failed to perform JAAS login: ", e);
}
}
// Continue processing the request
this.getNext().invoke(request, response);
// Signout request
if ((token != null && (!isTokenValid(token) || request.getAttribute("org.jboss.portal.logout") != null)))
{
destroyToken(token);
redirectToOpenSSOLogout(request,response);
}
else if (token == null && request.getUserPrincipal() != null)
{
// Illegal state - no SSO token present but still authenticated
request.getSession().invalidate();
}
}
private void redirectToOpenSSOLogin(HttpServletRequest request, HttpServletResponse response) throws IOException
{
StringBuffer redirect = new StringBuffer();
redirect.append(getLoginURL());
if (isAppendLoginGoto())
{
redirect.append("?goto=")
.append(request.getRequestURL());
}
if (getLoginParameters() != null && getLoginParameters().length() > 0)
{
if (isAppendLoginGoto())
{
redirect.append("&");
}
else
{
redirect.append("?");
}
redirect.append(getLoginParameters());
}
if (log.isDebugEnabled()) log.debug("Redirect to OpenSSO login URL: " + redirect.toString());
response.sendRedirect(redirect.toString());
}
private void redirectToOpenSSOLogout(HttpServletRequest request, HttpServletResponse response) throws IOException
{
StringBuffer redirect = new StringBuffer();
redirect.append(getLogoutURL());
if (isAppendLogoutGoto())
{
StringBuffer url = new StringBuffer();
if (request.isSecure())
{
url.append("https://");
}
else
{
url.append("http://");
}
url.append(request.getServerName())
.append(":")
.append(request.getServerPort())
.append(request.getContextPath());
redirect.append("?goto=")
.append(url);
}
if (getLogoutParameters() != null && getLogoutParameters().length() > 0)
{
if (isAppendLogoutGoto())
{
redirect.append("&");
}
else
{
redirect.append("?");
}
redirect.append(getLogoutParameters());
}
if (log.isDebugEnabled()) log.debug("Redirect to OpenSSO logout URL: " + redirect.toString());
response.sendRedirect(redirect.toString());
}
private SSOToken getToken()
{
try {
HttpServletRequest request = (HttpServletRequest) PolicyContext.getContext(WEB_REQUEST_KEY);
SSOTokenManager manager = SSOTokenManager.getInstance();
SSOToken token = manager.createSSOToken(request);
return token;
} catch (Exception e) {
log.debug("Failed to obtain SSO Token: " + e);
}
return null;
}
private boolean isTokenValid(SSOToken token)
{
if (token == null)
{
throw new IllegalArgumentException("Token cannot be null");
}
try {
SSOTokenManager manager = SSOTokenManager.getInstance();
return manager.isValidToken(token);
}
catch (Exception e)
{
log.debug("Failed to validate SSO Token: " + e);
}
return false;
}
private void destroyToken(SSOToken token)
{
if (token == null)
{
throw new IllegalArgumentException("Token cannot be null");
}
try {
SSOTokenManager manager = SSOTokenManager.getInstance();
manager.destroyToken(token);
}
catch (Exception e)
{
log.debug("Failed to destroy SSO Token: " + e);
}
}
private boolean isSecuredURI(String uri)
{
Set patterns = getSecuredUrlPatterns();
if (log.isDebugEnabled())
{
log.debug("Checking if requested uri '" + uri + "' matches secured url patterns: " + patterns);
}
for (Iterator iterator = patterns.iterator(); iterator.hasNext();)
{
String pattern = (String)iterator.next();
if (uri.indexOf(pattern) != -1)
{
return true;
}
}
return false;
}
public Set getSecuredUrlPatterns()
{
if (urlPatterns == null)
{
urlPatterns = IdentityTools.findSecuredURLs((Context)this.container);
//Remove wildcards
Set urls = new HashSet();
for (Iterator iterator = urlPatterns.iterator(); iterator.hasNext();)
{
String pattern = (String)iterator.next();
urls.add(pattern.replaceAll("\\*",""));
}
urlPatterns = urls;
}
return urlPatterns;
}
/**
* Register an authenticated Principal and authentication type in our
* request, in the current session (if there is one), and with our
* SingleSignOn valve, if there is one. Set the appropriate cookie to be
* returned.
*
* @param request
* The servlet request we are processing
* @param response
* The servlet response we are generating
* @param principal
* The authenticated Principal to be registered
* @param authType
* The authentication type to be registered
* @param username
* Username used to authenticate (if any)
* @param password
* Password used to authenticate (if any)
*/
private void register(Request request, Response response,
Principal principal, String authType, String username, String password)
{
// Cache the authentication information in our request
request.setAuthType(authType);
request.setUserPrincipal(principal);
Session session = request.getSessionInternal(false);
// Cache the authentication information in our session, if any
if (session != null)
{
session.setAuthType(authType);
session.setPrincipal(principal);
if (username != null)
{
session.setNote(Constants.SESS_USERNAME_NOTE, username);
}
else
{
session.removeNote(Constants.SESS_USERNAME_NOTE);
}
if (password != null)
{
session.setNote(Constants.SESS_PASSWORD_NOTE, password);
}
else
{
session.removeNote(Constants.SESS_PASSWORD_NOTE);
}
}
}
public String getLoginURL()
{
return loginURL;
}
public void setLoginURL(String loginURL)
{
this.loginURL = loginURL;
}
public String getLogoutURL()
{
return logoutURL;
}
public void setLogoutURL(String logoutURL)
{
this.logoutURL = logoutURL;
}
public boolean isAppendLoginGoto()
{
return appendLoginGoto;
}
public void setAppendLoginGoto(boolean appendLoginGoto)
{
this.appendLoginGoto = appendLoginGoto;
}
public boolean isAppendLogoutGoto()
{
return appendLogoutGoto;
}
public void setAppendLogoutGoto(boolean appendLogoutGoto)
{
this.appendLogoutGoto = appendLogoutGoto;
}
public String getLoginParameters()
{
return loginParameters;
}
public void setLoginParameters(String loginParameters)
{
this.loginParameters = loginParameters;
}
public String getLogoutParameters()
{
return logoutParameters;
}
public void setLogoutParameters(String logoutParameters)
{
this.logoutParameters = logoutParameters;
}
public String getAuthType()
{
return authType;
}
public void setAuthType(String authType)
{
this.authType = authType;
}
}