Java tutorial
/* * JOSSO: Java Open Single Sign-On * * Copyright 2004-2009, Atricore, Inc. * * 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.josso.gl2.agent; import java.io.IOException; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.Locale; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.Cookie; //import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.catalina.Globals; import org.apache.catalina.HttpRequest; import org.apache.catalina.HttpResponse; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleListener; import org.apache.catalina.Logger; import org.apache.catalina.Manager; import org.apache.catalina.Realm; import org.apache.catalina.Request; import org.apache.catalina.Response; import org.apache.catalina.Session; import org.apache.catalina.SessionEvent; import org.apache.catalina.SessionListener; import org.apache.catalina.Valve; //import org.apache.catalina.ValveContext; import org.apache.catalina.authenticator.SavedRequest; import org.apache.catalina.deploy.SecurityConstraint; import org.apache.catalina.util.LifecycleSupport; import org.apache.catalina.valves.ValveBase; import org.josso.agent.Constants; import org.josso.agent.LocalSession; import org.josso.agent.Lookup; import org.josso.agent.SSOAgentRequest; import org.josso.agent.SSOPartnerAppConfig; import org.josso.agent.SingleSignOnEntry; //import org.apache.coyote.Request; import org.apache.coyote.tomcat5.CoyoteRequest; import org.apache.coyote.tomcat5.CoyoteRequestFacade; import com.sun.web.security.WebPrincipal; import java.security.Principal; import javax.servlet.ServletRequest; import javax.servlet.ServletRequestWrapper; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import javax.security.auth.Subject; import javax.servlet.http.HttpServletRequest; import org.josso.agent.http.HttpSSOAgentRequest; //import org.apache.catalina.Container; import com.sun.web.security.WebProgrammaticLogin; import org.apache.catalina.Container; import techDecision.Base64; /** * Boucle de traitement JOSSO pour servlet Catalina qui n'est pas un agent mais en relation avec lui * @author spopoff@rocketmail.com <a href="mailto:gbrigand@josso.org">Gianluca Brigandi</a> * @version 0.2 */ public class SSOAgentValve extends ValveBase implements Lifecycle, SessionListener { /** * The debugging detail level for this component. */ protected int debug = 1; /** * Descriptive information about this Valve implementation. */ protected static String info = "org.apache.catalina.authenticator.SingleSignOn"; /** * The lifecycle event support for this component. */ protected LifecycleSupport lifecycle = new LifecycleSupport(this); /** * Component started flag. */ protected boolean started = false; private FacesSSOAgent _agent; /** * Catalina Session to Local Session Map. */ Map _sessionMap = Collections.synchronizedMap(new HashMap()); private static final String AUTH_TYPE_INFO_KEY = "javax.servlet.http.authType"; // Used for the auth-type string. public static final String WEBAUTH_PROGRAMMATIC = "PROGRAMMATIC"; static final String AUTHORIZATION_HEADER = "authorization"; private static final String BASIC = "Basic"; private static final Log logg = LogFactory.getLog(SSOAgentValve.class); private String jossoSessionId = null; private String theOriginal = null; private Cookie cookie = null; private LocalSession localSession = null; private Session session = null; private String assertionId = null; private int iBoucle = 0; private final String COOKIE_LOGIN = "JOSSO_SESSION_LOGIN"; // ------------------------------------------------------------- Properties /** * Return the debugging detail level. */ @Override public int getDebug() { return (this.debug); } /** * Set the debugging detail level. * * @param debug The new debugging detail level */ @Override public void setDebug(int debug) { this.debug = debug; } // ------------------------------------------------------ SessionListener Methods public void sessionEvent(SessionEvent event) { // obtain the local session for the catalina session, and notify the listeners for it. localSession = (LocalSession) _sessionMap.get(event.getSession()); if (event.getType().equals(Session.SESSION_DESTROYED_EVENT)) localSession.expire(); } // ------------------------------------------------------ Lifecycle Methods /** * Add a lifecycle event listener to this component. * * @param listener The listener to add */ @Override public void addLifecycleListener(LifecycleListener listener) { lifecycle.addLifecycleListener(listener); } /** * Get the lifecycle listeners associated with this lifecycle. If this * Lifecycle has no listeners registered, a zero-length array is returned. */ @Override public LifecycleListener[] findLifecycleListeners() { return lifecycle.findLifecycleListeners(); } /** * Remove a lifecycle event listener from this component. * * @param listener The listener to remove */ public void removeLifecycleListener(LifecycleListener listener) { lifecycle.removeLifecycleListener(listener); } /** * Prepare for the beginning of active use of the public methods of this * component. This method should be called after <code>configure()</code>, * and before any of the public methods of the component are utilized. * * @throws LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override public void start() throws LifecycleException { // Validate and update our current component state if (started) throw new LifecycleException("SSOAgentValve already started"); lifecycle.fireLifecycleEvent(START_EVENT, null); started = true; try { Lookup lookup = Lookup.getInstance(); //lookup.add("josso-agent2-config.xml"); //_agent = (FacesSSOAgent) lookup.lookupSSOAgent("josso-agent2-config.xml"); lookup.init("josso-agent2-config.xml", container.getName()); _agent = (FacesSSOAgent) lookup.lookupSSOAgent(); _agent.setDebug(debug); _agent.setCatalinaContainer(container); } catch (Exception e) { log("Erreur starting ", e); //e.printStackTrace(System.err); throw new LifecycleException("Error starting SSOAgentValve : " + e.getMessage()); } _agent.start(); debug = 1; if (debug >= 1) log("SSOAgentValve Started"); } /** * Gracefully terminate the active use of the public methods of this * component. This method should be the last one called on a given * instance of this component. * * @throws LifecycleException if this component detects a fatal error * that needs to be reported */ @Override public void stop() throws LifecycleException { // Validate and update our current component state if (!started) throw new LifecycleException("SSOAgentValve not started"); lifecycle.fireLifecycleEvent(STOP_EVENT, null); started = false; if (_agent != null) _agent.stop(); if (debug >= 1) log("SSOAgentValve Stopped"); } // ---------------------------------------------------------- Valve Methods /** * Return descriptive information about this Valve implementation. */ @Override public String getInfo() { return (info); } /** * Perform single-sign-on support processing for this request. * * @param request The servlet request we are processing * @param response The servlet response we are creating * @throws IOException if an input/output error occurs * @throws ServletException if a servlet error occurs */ public int invoke(Request request, Response response) throws IOException, ServletException { // If this is not an HTTP request and response, just pass them on int ret = 0; if (!(request instanceof HttpRequest) || !(response instanceof HttpResponse)) { //context.invokeNext(request, response); ret = Valve.INVOKE_NEXT; return ret; } HttpServletRequest hreq = (HttpServletRequest) request.getRequest(); HttpServletResponse hres = (HttpServletResponse) response.getResponse(); if (debug >= 1) log("***Processing : " + hreq.getContextPath() + " [" + hreq.getRequestURL() + "] path=" + hreq.getPathInfo()); try { container = (Container) request.getContext(); } catch (Exception e) { log("Erreur sur cast container", e); } try { // ------------------------------------------------------------------ // Check with the agent if this context should be processed. // ------------------------------------------------------------------ String contextPath = hreq.getContextPath(); String vhost = hreq.getServerName(); _agent.setCatalinaContainer(container); // In catalina, the empty context is considered the root context if ("".equals(contextPath)) contextPath = "/"; // T1 si l'appli n'est pas partenaire alors pas de SSO on continue if (!_agent.isPartnerApp(vhost, contextPath)) { if (debug >= 1) log("T1 Context is not a josso partner app : " + hreq.getContextPath()); hres.sendError(hres.SC_UNAUTHORIZED, "vrifier config agent ajouter le contexte"); ret = Valve.END_PIPELINE; return ret; } else { log("T1 Context IS a josso partner app =" + hreq.getContextPath()); } // T2 ------------------------------------------------------------------ // Check some basic HTTP handling // ------------------------------------------------------------------ // P3P Header for IE 6+ compatibility when embedding JOSSO in a IFRAME SSOPartnerAppConfig cfg = _agent.getPartnerAppConfig(vhost, contextPath); if (cfg.isSendP3PHeader() && !hres.isCommitted()) { hres.setHeader("P3P", cfg.getP3PHeaderValue()); } // ------------------------------------------------------------------ // Check if this URI is subject to SSO protection // ------------------------------------------------------------------ //T9 if (isResourceIgnored(cfg, request)) { log("T9 ressource non ssois (accs libre)"); ret = Valve.INVOKE_NEXT; return ret; } // Get our session ... session = getSession(((HttpRequest) request), true); testCookieSession(hreq); //T3 on revient aprs authentification russie et pour finalisation if (_agent.isSSOIDloged(jossoSessionId)) { iBoucle++; log("T3 SSOAgentValve Info retour authentifi pour " + jossoSessionId + " faire retour vers " + theOriginal); //********************************************************************************************** localSession = new CatalinaLocalSession(session); //T4 on revrifie ma prsence d'une entre SSOID SSOAgentRequest r = new CatalinaSSOAgentRequest(SSOAgentRequest.ACTION_ESTABLISH_SECURITY_CONTEXT, jossoSessionId, localSession); SingleSignOnEntry entry = _agent.processRequest(r); if (debug == 1) log("T3 Executed agent acction ACTION_ESTABLISH_SECURITY_CONTEXT"); // ------------------------------------------------------------------ // Has a valid user already been authenticated? // ------------------------------------------------------------------ //T3-1 if (entry != null) { if (debug == 1) log("T3-1 Principal '" + entry.principal + "' has already been authenticated"); // TODO : Not supported // (request).setAuthType(entry.authType); // (request).setUserPrincipal(entry.principal); //T3-2 } else { log("T3-2 No Valid SSO Session, attempt an optional login?"); // This is a standard anonymous request! if (cookie != null) { // cookie is not valid cookie = _agent.newJossoCookie(hreq.getContextPath(), "-"); hres.addCookie(cookie); } //T3-2-1 if (cookie != null || (getSavedRequestURL(session) == null && _agent.isAutomaticLoginRequired(hreq))) { if (debug == 1) log("T3-2-1 SSO Session is not valid, attempting automatic login"); // Save current request, so we can co back to it later ... log("T3-2-1 ***On sauve la requte 2 ***"); saveRequest((HttpRequest) request, session); String loginUrl = _agent.buildLoginOptionalUrl(hreq); if (debug == 1) log("T3-2-1 Redirecting to login url '" + loginUrl + "'"); //set non cache headers _agent.prepareNonCacheResponse(hres); hres.sendRedirect(hres.encodeRedirectURL(loginUrl)); ret = Valve.INVOKE_NEXT; return ret; } else { if (debug == 1) log("T3-2-1 SSO cookie is not present, but login optional process is not required"); } } try { log("Avant sur webProgrammaticLogin -------------" + iBoucle); if (!WebProgrammaticLogin.login(jossoSessionId, assertionId, "jossoRealm", hreq, hres)) { log("Erreur sur webProgrammaticLogin"); } else { log("Russite sur webProgrammaticLogin"); } log("Aprs sur webProgrammaticLogin-------------" + iBoucle); } catch (Exception err) { log("SSOAgentValve Erreur2 finalisation contexte securit", err); throw err; } // propagate the login and logout URLs to // partner applications. hreq.setAttribute("org.josso.agent.gateway-login-url", _agent.getGatewayLoginUrl()); hreq.setAttribute("org.josso.agent.gateway-logout-url", _agent.getGatewayLogoutUrl()); hreq.setAttribute("org.josso.agent.ssoSessionid", jossoSessionId); //hres.sendRedirect(theOriginal); System.out.println("**********************Termin**********************"); ret = Valve.INVOKE_NEXT; return ret; } else { log("T3 SSOAgentValve Info retour pas authentifi pour " + jossoSessionId); iBoucle = 0; } String username = processAuthorizationToken(hreq); //TA2 //equivalent la page de login si pas autoris on passe par l'authent if (username == null && getSavedRequestURL(session) == null && !hreq.getRequestURI().endsWith(_agent.getJOSSOLoginUri()) && !hreq.getRequestURI().endsWith(_agent.getJOSSOUserLoginUri())) { log("TA2 Il faut une authentification pralable (premire URL)! session=" + session.getId()); //return sendAuthenticateChallenge(msgInfo); //return sendAuthenticateChallenge2(msgInfo); saveRequest((HttpRequest) request, session); theOriginal = getSavedRequestURL(session); hres.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); //response.setHeader("Location", jeVeux); hres.sendRedirect(hreq.getContextPath() + "/josso_login/"); ret = Valve.END_PIPELINE; return ret; } //T4 // ------------------------------------------------------------------ // Check if the partner application required the login form // ------------------------------------------------------------------ if (debug >= 1) log("T4 Checking if its a josso_login_request for '" + hreq.getRequestURI() + "'"); // /josso_login/ ou /josso_user_login/ c'est pas la page de login qui fait cela ? if (hreq.getRequestURI().endsWith(_agent.getJOSSOLoginUri()) || hreq.getRequestURI().endsWith(_agent.getJOSSOUserLoginUri())) { if (debug >= 1) log("T4 josso_login_request received for uri '" + hreq.getRequestURI() + "'"); //save referer url in case the user clicked on Login from some public resource (page) //so agent can redirect the user back to that page after successful login if (hreq.getRequestURI().endsWith(_agent.getJOSSOUserLoginUri())) { saveLoginBackToURL(hreq, session, true); } else { saveLoginBackToURL(hreq, session, false); } String loginUrl = _agent.buildLoginUrl(hreq); if (debug >= 1) log("T4 Redirecting to login url '" + loginUrl + "'"); //set non cache headers _agent.prepareNonCacheResponse(hres); hres.sendRedirect(hres.encodeRedirectURL(loginUrl)); //question on termine ou on continue ret = Valve.END_PIPELINE; return ret; } //T5 // ------------------------------------------------------------------ // Check if the partner application required a logout // ------------------------------------------------------------------ if (debug >= 1) log("T5 Checking if its a josso_logout request for '" + hreq.getRequestURI() + "'"); if (hreq.getRequestURI().endsWith(_agent.getJOSSOLogoutUri())) { if (debug >= 1) log("T5 josso_logout request received for uri '" + hreq.getRequestURI() + "'"); String logoutUrl = _agent.buildLogoutUrl(hreq, cfg); if (debug >= 1) log("T5 Redirecting to logout url '" + logoutUrl + "'"); // Clear previous COOKIE ... Cookie ssoCookie = _agent.newJossoCookie(hreq.getContextPath(), "-"); hres.addCookie(ssoCookie); //set non cache headers _agent.prepareNonCacheResponse(hres); hres.sendRedirect(hres.encodeRedirectURL(logoutUrl)); ret = Valve.END_PIPELINE; return ret; } //T6 // ------------------------------------------------------------------ // Check for the single sign on cookie // ------------------------------------------------------------------ testCookieSession(hreq); if (debug >= 1) log("T6 Session is: " + session); //localSession = new CatalinaLocalSession(session); //T7 // ------------------------------------------------------------------ // Check if the partner application submitted custom login form // ------------------------------------------------------------------ // /josso_authentication/ if (debug >= 1) { log("T7 Checking if its a josso_authentication for '" + hreq.getRequestURI() + "'"); } if (hreq.getRequestURI().endsWith(_agent.getJOSSOAuthenticationUri())) { if (debug >= 1) log("T7 josso_authentication received for uri '" + hreq.getRequestURI() + "'"); HttpSSOAgentRequest customAuthRequest = new HttpSSOAgentRequest( SSOAgentRequest.ACTION_CUSTOM_AUTHENTICATION, jossoSessionId, localSession); customAuthRequest.setRequest(hreq); customAuthRequest.setResponse(hres); customAuthRequest.setContext(request.getContext()); _agent.processRequest(customAuthRequest); ret = Valve.INVOKE_NEXT; return ret; } //T8 // si pas de cookie de session SSO if (cookie == null || cookie.getValue().equals("-")) { // ------------------------------------------------------------------ // Trigger LOGIN OPTIONAL if required // ------------------------------------------------------------------ if (debug >= 1) log("T8 SSO cookie is not present, verifying optional login process "); //T8-1 /josso_security_check // We have no cookie, remember me is enabled and a security check without assertion was received ... // This means that the user could not be identified ... go back to the original resource if (hreq.getRequestURI().endsWith(_agent.getJOSSOSecurityCheckUri()) && hreq.getParameter("josso_assertion_id") == null) { if (debug >= 1) log("T8-1 " + _agent.getJOSSOSecurityCheckUri() + " received without assertion. Login Optional Process failed"); String requestURI = this.getSavedRequestURL(session); _agent.prepareNonCacheResponse(hres); hres.sendRedirect(hres.encodeRedirectURL(requestURI)); ret = Valve.INVOKE_NEXT; return ret; } //T8-2 // This is a standard anonymous request! if (!hreq.getRequestURI().endsWith(_agent.getJOSSOSecurityCheckUri())) { // If saved request is NOT null, we're in the middle of another process ... if (!isResourceIgnored(cfg, request) && _agent.isAutomaticLoginRequired(hreq)) { if (debug >= 1) log("T8-2 SSO cookie is not present, attempting automatic login"); // Save current request, so we can co back to it later ... saveRequest((HttpRequest) request, session); String loginUrl = _agent.buildLoginOptionalUrl(hreq); if (debug >= 1) log("T8-2 Redirecting to login url '" + loginUrl + "'"); //set non cache headers _agent.prepareNonCacheResponse(hres); hres.sendRedirect(hres.encodeRedirectURL(loginUrl)); ret = Valve.END_PIPELINE; return ret; } else { if (debug >= 1) log("T8-2 SSO cookie is not present, but login optional process is not required"); } } //T8-3 if (debug >= 1) log("T8-3 SSO cookie is not present, checking for outbound relaying"); if (!(hreq.getRequestURI().endsWith(_agent.getJOSSOSecurityCheckUri()) && hreq.getParameter("josso_assertion_id") != null)) { log("T8-3 SSO cookie not present and relaying was not requested, skipping"); //context.invokeNext(request, response); ret = Valve.INVOKE_NEXT; return ret; } } // This URI should be protected by SSO, go on ... if (debug >= 1) log("Session is: " + session); // ------------------------------------------------------------------ // Invoke the SSO Agent // ------------------------------------------------------------------ if (debug >= 1) log("Executing agent..."); _agent.setCatalinaContainer((Container) request.getContext()); //T10 /josso_security_check // ------------------------------------------------------------------ // Check if a user has been authenticated and should be checked by the agent. // ------------------------------------------------------------------ if (debug >= 1) log("T10 Checking if its a josso_security_check for '" + hreq.getRequestURI() + "'"); if (hreq.getRequestURI().endsWith(_agent.getJOSSOSecurityCheckUri()) && hreq.getParameter("josso_assertion_id") != null) { if (debug >= 1) log("T10 josso_security_check received for uri '" + hreq.getRequestURI() + "' assertion id '" + hreq.getParameter("josso_assertion_id")); assertionId = hreq.getParameter(Constants.JOSSO_ASSERTION_ID_PARAMETER); HttpSSOAgentRequest relayRequest; relayRequest = new HttpSSOAgentRequest(SSOAgentRequest.ACTION_RELAY, null, localSession, assertionId); if (debug >= 1) log("T10 Outbound relaying requested for assertion id=" + assertionId + " sessionID=" + relayRequest.getSessionId()); relayRequest.setRequest(hreq); relayRequest.setResponse(hres); relayRequest.setContext(request.getContext()); SingleSignOnEntry entry = _agent.processRequest(relayRequest); //T10-1 if (entry == null) { // This is wrong! We should have an entry here! if (debug >= 1) log("T10-1 Outbound relaying failed for assertion id [" + assertionId + "], no Principal found."); // Throw an exception, we will handle it below ! throw new RuntimeException( "Outbound relaying failed. No Principal found. Verify your SSO Agent Configuration!"); } //T10-2 if (debug >= 1) log("T10-2 Outbound relaying succesfull for assertion id [" + assertionId + "]"); if (debug >= 1) log("T10-2 Assertion id [" + assertionId + "] mapped to SSO session id [" + entry.ssoId + "]"); // The cookie is valid to for the partner application only ... in the future each partner app may // store a different auth. token (SSO SESSION) value securityCheck(hreq, hres, entry, cfg, "T10"); /*try { cookie = _agent.newJossoCookie(hreq.getContextPath(), entry.ssoId); hres.addCookie(cookie); } catch (Exception e) { log("Pas de bras pas de chocolat !", e); } jossoSessionId = entry.ssoId; //T10-3 //Redirect user to the saved splash resource (in case of auth request) or to request URI otherwise String requestURI = getSavedSplashResource(session.getSession()); if(requestURI == null) { requestURI = getSavedRequestURL(session); if (requestURI == null) { if (cfg.getDefaultResource() != null) { requestURI = cfg.getDefaultResource(); } else { // If no saved request is found, redirect to the partner app root : requestURI = hreq.getRequestURI().substring( 0, (hreq.getRequestURI().length() - _agent.getJOSSOSecurityCheckUri().length())); } // If we're behind a reverse proxy, we have to alter the URL ... this was not necessary on tomcat 5.0 ?! String singlePointOfAccess = _agent.getSinglePointOfAccess(); if (singlePointOfAccess != null) { requestURI = singlePointOfAccess + requestURI; } else { String reverseProxyHost = hreq.getHeader(org.josso.gateway.Constants.JOSSO_REVERSE_PROXY_HEADER); if (reverseProxyHost != null) { requestURI = reverseProxyHost + requestURI; } } if (debug >= 1) log("T10-3 No saved request found, using : '" + requestURI + "'"); } } clearSavedRequestURLs(session); _agent.clearAutomaticLoginReferer(hreq); _agent.prepareNonCacheResponse(hres); //T10-4 // Check if we have a post login resource : String postAuthURI = cfg.getPostAuthenticationResource(); if (postAuthURI != null) { String postAuthURL = _agent.buildPostAuthUrl(hres, requestURI, postAuthURI); if (debug >= 1) log("T10-4 Redirecting to post-auth-resource '" + postAuthURL + "'"); hres.sendRedirect(postAuthURL); } else { if (debug >= 1) log("T10-4 Redirecting to original '" + requestURI + "'"); hres.sendRedirect(hres.encodeRedirectURL(requestURI)); //on garde des fois que ... theOriginal = hres.encodeRedirectURL(requestURI); } _agent.addEntrySSOIDsuccessed(entry.ssoId); log("T10 Fin josso_check jossoSessionId="+jossoSessionId);*/ //c'est pas fini et pas en erreur pourtant ... ret = Valve.END_PIPELINE; return ret; } //T11 // si on arrive la c'est une erreur! log("T11 Fin de la boucle validate donc tout va bien"); ret = Valve.INVOKE_NEXT; return ret; } catch (Throwable t) { // This is a 'hack' : Because this valve exectues before the ErrorReportingValve, we need to preapare // some stuff and invoke the next valve in the chain always ... // Store this error, it will be checked by the ErrorReportingValve hreq.setAttribute(Globals.EXCEPTION_ATTR, t); // Mark this response as error! response.setError(); // Let the next valves work on this //context.invokeNext(request, response); ret = Valve.END_PIPELINE; } finally { if (debug >= 1) log("Processed : " + hreq.getContextPath() + " [" + hreq.getRequestURL() + "] ret=" + ret); //return ret; } log("retourne ret=" + ret); return ret; } // --------------------------------------------------------- Public Methods /** * Return a String rendering of this object. */ @Override public String toString() { StringBuffer sb = new StringBuffer("SSOAgentValve["); // Sometimes the container is not present when this method is invoked ... sb.append(container != null ? container.getName() : ""); sb.append("]"); return (sb.toString()); } // -------------------------------------------------------- Package Methods // ------------------------------------------------------ Protected Methods /** * Return the internal Session that is associated with this HttpRequest, * or <code>null</code> if there is no such Session. * * @param request The HttpRequest we are processing */ protected Session getSession(HttpRequest request) { return (getSession(request, false)); } /** * Return the internal Session that is associated with this HttpRequest, * possibly creating a new one if necessary, or <code>null</code> if * there is no such session and we did not create one. * * @param request The HttpRequest we are processing * @param create Should we create a session if needed? */ protected Session getSession(HttpRequest request, boolean create) { HttpServletRequest hreq = (HttpServletRequest) request.getRequest(); HttpSession hses = hreq.getSession(create); if (debug >= 1) log("getSession() : hses " + hses); if (hses == null) return (null); // Get catalina Context from request ... Manager manager = request.getContext().getManager(); if (debug >= 1) log("getSession() : manager is " + manager); if (manager == null) return (null); else { try { return (manager.findSession(hses.getId())); } catch (IOException e) { return (null); } } } /** * Log a message on the Logger associated with our Container (if any). * * @param message Message to be logged */ protected void log(String message) { Logger logger = container.getLogger(); if (logger != null) logger.log(this.toString() + ": " + message); else logg.info(this.toString() + ": " + message); //je sais c'est pas bien mais des fois il faut !!! System.out.println(this.toString() + ": " + message); } /** * Log a message on the Logger associated with our Container (if any). * * @param message Message to be logged * @param throwable Associated exception */ protected void log(String message, Throwable throwable) { Logger logger = container.getLogger(); if (logger != null) logger.log(this.toString() + ": " + message, throwable); else { logg.error(this.toString() + ": " + message); throwable.printStackTrace(System.out); } } /** * Return the request URI (with the corresponding query string, if any) * from the saved request so that we can redirect to it. * * @param session Our current session */ private String getSavedRequestURL(Session session) { SavedRequest saved = (SavedRequest) session .getNote(org.apache.catalina.authenticator.Constants.FORM_REQUEST_NOTE); if (saved == null) return (null); StringBuffer sb = new StringBuffer(saved.getRequestURI()); if (saved.getQueryString() != null) { sb.append('?'); sb.append(saved.getQueryString()); } return (sb.toString()); } /** * Return the splash resource from session so that we can redirect the user to it * if (s)he was logged in using custom form * @param session Our current session */ private String getSavedSplashResource(HttpSession session) { return (String) session.getAttribute(Constants.JOSSO_SPLASH_RESOURCE_PARAMETER); } /** * Save the original request information into our session. * * @param request The request to be saved * @param session The session to contain the saved information * @throws IOException */ private void saveRequest(HttpRequest request, Session session) { // Create and populate a SavedRequest object for this request HttpServletRequest hreq = (HttpServletRequest) request.getRequest(); SavedRequest saved = new SavedRequest(); Cookie cookies[] = hreq.getCookies(); if (cookies != null) { for (int i = 0; i < cookies.length; i++) saved.addCookie(cookies[i]); } Enumeration names = hreq.getHeaderNames(); while (names.hasMoreElements()) { String name = (String) names.nextElement(); Enumeration values = hreq.getHeaders(name); while (values.hasMoreElements()) { String value = (String) values.nextElement(); saved.addHeader(name, value); } } Enumeration locales = hreq.getLocales(); while (locales.hasMoreElements()) { Locale locale = (Locale) locales.nextElement(); saved.addLocale(locale); } Map parameters = hreq.getParameterMap(); Iterator paramNames = parameters.keySet().iterator(); while (paramNames.hasNext()) { String paramName = (String) paramNames.next(); String paramValues[] = (String[]) parameters.get(paramName); saved.addParameter(paramName, paramValues); } saved.setMethod(hreq.getMethod()); saved.setQueryString(hreq.getQueryString()); saved.setRequestURI(hreq.getRequestURI()); // Stash the SavedRequest in our session for later use session.setNote(org.apache.catalina.authenticator.Constants.FORM_REQUEST_NOTE, saved); } /** * Save referer URI into our session for later use. * * This method is used so agent can know from which * public resource (page) user requested login. * * @param request http request * @param session current session * @param overrideSavedResource true if saved resource should be overridden, false otherwise */ protected void saveLoginBackToURL(HttpServletRequest request, Session session, boolean overrideSavedResource) { String referer = request.getHeader("referer"); //saved request will exist only if user requested some protected resource SavedRequest saved = (SavedRequest) session .getNote(org.apache.catalina.authenticator.Constants.FORM_REQUEST_NOTE); if ((saved == null || overrideSavedResource) && referer != null && !referer.equals("")) { saved = new SavedRequest(); int p = referer.indexOf("?"); String uri = p >= 0 ? referer.substring(0, p) : referer; String queryStr = p >= 0 ? referer.substring(p) : null; saved.setRequestURI(uri); saved.setQueryString(queryStr); session.setNote(org.apache.catalina.authenticator.Constants.FORM_REQUEST_NOTE, saved); } } /** * Remove saved request URLs from session * to avoid mixing up resources from previous operations * (logins, logouts) with the current one. * * @param session Our current session */ protected void clearSavedRequestURLs(Session session) { session.removeNote(org.apache.catalina.authenticator.Constants.FORM_REQUEST_NOTE); session.getSession().removeAttribute(Constants.JOSSO_SPLASH_RESOURCE_PARAMETER); } protected boolean isResourceIgnored(SSOPartnerAppConfig cfg, Request request) { // There are some web-resources to ignore. String[] ignoredWebResources = cfg.getIgnoredWebRources(); if (debug >= 1) log("Found [" + (ignoredWebResources != null ? ignoredWebResources.length + "" : "no") + "] ignored web resources "); if (ignoredWebResources != null && ignoredWebResources.length > 0) { Realm realm = request.getContext().getRealm(); SecurityConstraint[] constraints = realm.findSecurityConstraints((HttpRequest) request, request.getContext()); if ((constraints != null)) { for (int i = 0; i < ignoredWebResources.length; i++) { // For each ignored web resource, find a correspondig web resource collection. String ignoredWebResource = ignoredWebResources[i]; for (int j = 0; j < constraints.length; j++) { // Find a matching web resource collection for each ignored web resources SecurityConstraint constraint = constraints[j]; if (constraint.findCollection(ignoredWebResource) != null) { // We should ignore this URI, it's not subject to SSO protection. if (debug >= 1) log("Not subject to SSO protection : web-resource-name:" + ignoredWebResource); return true; } } } } else { log("Pas trouv les contraintes de scurit sur les ressources"); } } return false; } private void setAuthenticationResult(String name, Subject s, HttpServletRequest request) { log("**SSOAgentValve** finalise le flux http nom=" + name); _sessionMap.put(AUTH_TYPE_INFO_KEY, "JOSSO"); CoyoteRequest httpReq = null; Session session = null; try { httpReq = getUnwrappedCoyoteRequest(request); session = getSession(httpReq); } catch (Exception e) { log("**SSOAgentValve** erreur sur la requte coyote ou la session ", e); return; } if (httpReq == null) { log("**SSOAgentValve** requte coyote vide"); return; } else { for (Principal p : s.getPrincipals()) { if (p.getName().equals(name)) { httpReq.setUserPrincipal(p); httpReq.setAuthType("JOSSO"); log("**SSOAgentValve** requte coyote avec principal p=" + p.getName()); break; } } } if (session == null) { log("**SSOAgentValve** session active vide"); return; } else { for (Principal p : s.getPrincipals()) { if (p.getName().equals(name)) { session.setPrincipal(p); session.setAuthType("JOSSO"); log("**SSOAgentValve** session avec principal p=" + p.getName()); break; } } } } private Boolean attachePrincipal(HttpServletRequest request, WebPrincipal principal) { // Need real request object not facade CoyoteRequest req = getUnwrappedCoyoteRequest(request); if (req == null) { return Boolean.valueOf(false); } req.setUserPrincipal(principal); req.setAuthType(WEBAUTH_PROGRAMMATIC); // Try to retrieve a Session object (not the facade); if it exists // store the principal there as well. This will allow web container // authorization to work in subsequent requests in this session. Session realSession = getSession(req); if (realSession != null) { realSession.setPrincipal((WebPrincipal) principal); realSession.setAuthType(WEBAUTH_PROGRAMMATIC); log("Programmatic login set principal in session principal=" + principal.toString()); } else { System.err.println("Programmatic login: No session available."); return false; } return Boolean.valueOf(true); } /** * Return the unwrapped <code>CoyoteRequest</code> object. */ private CoyoteRequest getUnwrappedCoyoteRequest(HttpServletRequest request) { CoyoteRequest req = null; ServletRequest servletRequest = request; try { ServletRequest prevRequest = null; while (servletRequest != prevRequest && servletRequest instanceof ServletRequestWrapper) { prevRequest = servletRequest; servletRequest = ((ServletRequestWrapper) servletRequest).getRequest(); } if (servletRequest instanceof CoyoteRequestFacade) { req = ((CoyoteRequestFacade) servletRequest).getUnwrappedCoyoteRequest(); } } catch (Exception ex) { System.err.println("Programmatic login faiied to get request" + ex.toString()); } return req; } private void testCookieSession(HttpServletRequest req) { // ------------------------------------------------------------------ // Check for the single sign on cookie // ------------------------------------------------------------------ if (debug == 1) log("Checking for SSO cookie"); cookie = null; Cookie cookies[] = req.getCookies(); if (cookies == null) cookies = new Cookie[0]; for (int i = 0; i < cookies.length; i++) { if (org.josso.gateway.Constants.JOSSO_SINGLE_SIGN_ON_COOKIE.equals(cookies[i].getName())) { cookie = cookies[i]; break; } } jossoSessionId = (cookie == null) ? null : cookie.getValue(); localSession = new CatalinaLocalSession(session); } private Boolean testCookie2Session(HttpServletRequest req, String sessionID) { // ------------------------------------------------------------------ // Check for the single sign on cookie // ------------------------------------------------------------------ Boolean ret = false; Cookie cookies[] = req.getCookies(); if (cookies == null) cookies = new Cookie[0]; for (int i = 0; i < cookies.length; i++) { if (COOKIE_LOGIN.equals(cookies[i].getName()) && sessionID.equals(cookies[i].getValue())) { ret = true; break; } } return ret; } private String processAuthorizationToken(HttpServletRequest request) { String token = request.getHeader(AUTHORIZATION_HEADER); log("Analyse du message en vue d'authentification sur token=" + token); if (token != null && token.startsWith(BASIC + " ")) { token = token.substring(6).trim(); log("Dcodage du token=" + token); // Decode and parse the authorization token String decoded = new String(Base64.decode(token)); int colon = decoded.indexOf(':'); if (colon <= 0 || colon == decoded.length() - 1) { log("Erreur analyse decoded token=" + decoded); return (null); } String username = decoded.substring(0, colon); return username; } log("Rien dans le header chec de l'authentification..."); return null; } @Override public void postInvoke(Request request, Response response) { System.out.println("Ne sert rien dans cette logique mais fait plaisir"); } private void securityCheck(HttpServletRequest hreq, HttpServletResponse hres, SingleSignOnEntry entry, SSOPartnerAppConfig cfg, String phase) { String ssoId = entry.ssoId; try { cookie = _agent.newJossoCookie(hreq.getContextPath(), ssoId); hres.addCookie(cookie); } catch (Exception e) { log(phase + " Pas de bras pas de chocolat !", e); } jossoSessionId = ssoId; //T10-3 //Redirect user to the saved splash resource (in case of auth request) or to request URI otherwise String requestURI = getSavedSplashResource(session.getSession()); if (requestURI == null) { requestURI = getSavedRequestURL(session); if (requestURI == null) { if (cfg.getDefaultResource() != null) { requestURI = cfg.getDefaultResource(); } else { // If no saved request is found, redirect to the partner app root : requestURI = hreq.getRequestURI().substring(0, (hreq.getRequestURI().length() - _agent.getJOSSOSecurityCheckUri().length())); } // If we're behind a reverse proxy, we have to alter the URL ... this was not necessary on tomcat 5.0 ?! String singlePointOfAccess = _agent.getSinglePointOfAccess(); if (singlePointOfAccess != null) { requestURI = singlePointOfAccess + requestURI; } else { String reverseProxyHost = hreq .getHeader(org.josso.gateway.Constants.JOSSO_REVERSE_PROXY_HEADER); if (reverseProxyHost != null) { requestURI = reverseProxyHost + requestURI; } } if (debug >= 1) log(phase + "-3 No saved request found, using : '" + requestURI + "'"); } } clearSavedRequestURLs(session); _agent.clearAutomaticLoginReferer(hreq); _agent.prepareNonCacheResponse(hres); //T10-4 // Check if we have a post login resource : String postAuthURI = cfg.getPostAuthenticationResource(); try { if (postAuthURI != null) { String postAuthURL = _agent.buildPostAuthUrl(hres, requestURI, postAuthURI); if (debug >= 1) { log(phase + "-4 Redirecting to post-auth-resource '" + postAuthURL + "'"); } hres.sendRedirect(postAuthURL); } else { if (debug >= 1) { log(phase + "-4 Redirecting to original '" + requestURI + "'"); } hres.sendRedirect(hres.encodeRedirectURL(requestURI)); //on garde des fois que ... theOriginal = hres.encodeRedirectURL(requestURI); } } catch (IOException iOException) { log(phase + " Erreur redirection", iOException); } _agent.addEntrySSOIDsuccessed(ssoId, entry.getPrincipal().getName()); log(phase + " Fin josso_check jossoSessionId=" + jossoSessionId); //c'est pas fini et pas en erreur pourtant ... } /** * This creates a new JOSSO Cookie for the given path and value. * * @param path the path associated with the cookie, normaly the partner application context. * @param value the SSO Session ID * @param type le type du cookie * @return */ private Cookie newJossoCookie2(String path, String value, String type) { // Some browsers don't like cookies without paths. This is useful for partner applications configured in the root context if (path == null || "".equals(path)) path = "/"; Cookie ssoCookie = new Cookie(type, value); ssoCookie.setMaxAge(-1); ssoCookie.setPath(path); // TODO : Check domain / secure ? //ssoCookie.setDomain(cfg.getSessionTokenScope()); //ssoCookie.setSecure(true); return ssoCookie; } }