/** * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 2006 Sun Microsystems Inc. All Rights Reserved * * The contents of this file are subject to the terms * of the Common Development and Distribution License * (the License). You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * https://opensso.dev.java.net/public/CDDLv1.0.html or * opensso/legal/CDDLv1.0.txt * See the License for the specific language governing * permission and limitations under the License. * * When distributing Covered Code, include this CDDL * Header Notice in each file and include the License file * at opensso/legal/CDDLv1.0.txt. * If applicable, add the following below the CDDL Header, * with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * * $Id: FSFedTerminationHandler.java,v 1.7 2009/11/03 00:49:26 madan_ranganath Exp $ * * Portions Copyrighted 2015-2016 ForgeRock AS. */ package com.sun.identity.federation.services.termination; import com.sun.identity.common.SystemConfigurationUtil; import com.sun.identity.federation.accountmgmt.FSAccountManager; import com.sun.identity.federation.accountmgmt.FSAccountMgmtException; import com.sun.identity.federation.accountmgmt.FSAccountFedInfo; import com.sun.identity.federation.accountmgmt.FSAccountFedInfoKey; import com.sun.identity.federation.common.IFSConstants; import com.sun.identity.federation.common.FSUtils; import com.sun.identity.federation.common.LogUtil; import com.sun.identity.federation.jaxb.entityconfig.BaseConfigType; import com.sun.identity.federation.message.FSFederationTerminationNotification; import com.sun.identity.federation.message.common.FSMsgException; import com.sun.identity.federation.meta.IDFFMetaUtils; import com.sun.identity.federation.plugins.FederationSPAdapter; import com.sun.identity.federation.services.util.FSSignatureUtil; import com.sun.identity.federation.services.util.FSServiceUtils; import com.sun.identity.federation.services.logout.FSLogoutUtil; import com.sun.identity.federation.services.FSSOAPService; import com.sun.identity.liberty.ws.meta.jaxb.ProviderDescriptorType; import com.sun.identity.plugin.session.SessionException; import com.sun.identity.plugin.session.SessionManager; import com.sun.identity.saml.assertion.NameIdentifier; import com.sun.identity.saml.common.SAMLConstants; import com.sun.identity.saml.common.SAMLException; import com.sun.identity.saml.common.SAMLResponderException; import com.sun.identity.saml.xmlsig.XMLSignatureManager; import com.sun.identity.shared.encode.URLEncDec; import com.sun.identity.shared.encode.CookieUtils; import javax.xml.soap.SOAPMessage; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.Cookie; import java.io.IOException; import java.util.List; import java.util.Iterator; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.logging.Level; import org.w3c.dom.Document; /** * Work engine that handles termination request/response. */ public class FSFedTerminationHandler { protected HttpServletResponse response; protected HttpServletRequest request; protected String locale = null; protected Object ssoToken = null; protected String userID = null; protected FSAccountFedInfo acctInfo = null; protected ProviderDescriptorType remoteDescriptor = null; protected ProviderDescriptorType hostedDescriptor = null; protected BaseConfigType hostedConfig = null; protected String relayState = ""; protected FSAccountManager managerInst = null; protected static String termination_done_url = null; protected static String error_page_url = null; protected static final String FEDERATE_COOKIE_NAME = SystemConfigurationUtil.getProperty(IFSConstants.FEDERATE_COOKIE_NAME); protected static final String RELAY_STATE = IFSConstants.TERMINATION_RELAY_STATE; protected String realm = ""; protected String hostedEntityId = ""; protected String remoteEntityId = ""; protected String metaAlias = ""; protected String hostedProviderRole = null; /** * Constructor. Initializes FSAccountManager, FSAllianceManager instance. */ public FSFedTerminationHandler() { FSUtils.debug.message("FSFedTerminationHandler Constructor..."); } /** * Invoked to set some commonly used URLs based on hosted provider. */ protected void setTerminationURL() { termination_done_url = FSServiceUtils.getTerminationDonePageURL( request, hostedConfig, metaAlias); error_page_url = FSServiceUtils.getErrorPageURL( request, hostedConfig, metaAlias); } /** * Sets state to the Federation Termination handler that is handling the * current federation termination. The hosted provider identifies the * provider who is handling the termnation request or initiating it locally. * @param hostedDescriptor the Hosted provider Descriptor */ public void setHostedDescriptor(ProviderDescriptorType hostedDescriptor) { FSUtils.debug.message( "Entered FSSPFedTerminationHandler::setHostedDescriptor"); this.hostedDescriptor = hostedDescriptor; } /** * Sets hosted provider's extended meta. * @param hostedConfig hosted provider's extended config */ public void setHostedDescriptorConfig(BaseConfigType hostedConfig) { this.hostedConfig = hostedConfig; } /** * Sets hosted provider's entity ID. * @param hostedId hosted provider's entity id */ public void setHostedEntityId(String hostedId) { hostedEntityId = hostedId; } /** * Sets hosted provider's role. * @param hostedProviderRole hosted provider's role */ public void setHostedProviderRole(String hostedProviderRole) { this.hostedProviderRole = hostedProviderRole; } /** * Sets hosted provider's meta alias. * @param metaAlias hosted provider's meta alias */ public void setMetaAlias(String metaAlias) { this.metaAlias = metaAlias; try { managerInst = FSAccountManager.getInstance(metaAlias); } catch (Exception e){ FSUtils.debug.error("FSFedTerminationHandler " + FSUtils.bundle.getString( IFSConstants.FEDERATION_FAILED_ACCOUNT_INSTANCE)); managerInst = null; } } /** * Sets realm. * @param realm The realm under which the entity resides. */ public void setRealm(String realm) { this.realm = realm; } /** * Sets remote provider's entity ID. * @param remoteId remote provider's entity id */ public void setRemoteEntityId(String remoteId) { remoteEntityId = remoteId; } /** * Sets state to the Federation Termination handler that is handling the * current federation termination. The remote provider identifies the * provider who sent a request or with whom termination is to be initiated. * @param remoteDescriptor the Remote provider Descriptor */ public void setRemoteDescriptor(ProviderDescriptorType remoteDescriptor) { FSUtils.debug.message( "Entered FSFedTerminationHandler::setRemoteDescriptor"); this.remoteDescriptor = remoteDescriptor; } /** * Sets the UserID. * @param userID the user who is initiating the termination process */ public void setUserID(String userID) { this.userID = userID; } /** * Sets the federation account information for the user with a specific * remote provider. * @param acctInfo the account fed info object */ public void setAccountInfo(FSAccountFedInfo acctInfo) { this.acctInfo = acctInfo; } /** * Finds the user based on the termination request received from a remote * provider. * @param reqTermination the termination request * @return true if the user is found; false * otherwise. */ public boolean setUserID(FSFederationTerminationNotification reqTermination) { try { // UserDN needs to be figured from termination request String sourceProviderId = ""; if (managerInst != null) { sourceProviderId = reqTermination.getProviderId(); if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message("sourceProviderId : " + sourceProviderId); } String opaqueHandle = (reqTermination.getNameIdentifier()).getName().trim(); if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message("processTerminationRequest Handle : " + opaqueHandle); } String associatedDomain = (reqTermination.getNameIdentifier().getNameQualifier()).trim(); if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message("Name Qualifier : " + associatedDomain); } if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message("Realm : " + realm); } String searchDomain = hostedEntityId; if ((associatedDomain != null) && (associatedDomain.length() != 0) && (!sourceProviderId.equals(associatedDomain))) { searchDomain = associatedDomain; } FSAccountFedInfoKey acctkey = new FSAccountFedInfoKey( searchDomain, opaqueHandle); Map env = new HashMap(); env.put(IFSConstants.FS_USER_PROVIDER_ENV_TERMINATION_KEY, reqTermination); this.userID = managerInst.getUserID(acctkey, realm, env); if (this.userID == null) { acctkey = new FSAccountFedInfoKey( remoteEntityId, opaqueHandle); this.userID = managerInst.getUserID(acctkey, realm, env); if (this.userID == null) { FSUtils.debug.message("UserID is null"); return false; } } if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message("user id is "+ userID); } return true; } } catch(FSAccountMgmtException e) { FSUtils.debug.error("In FSAccountMgmtException :: ", e); } this.userID = null; return false; } /** * Initiates the federation termination operation. * @param request HTTP request * @param response HTTP response * @param ssoToken corresponding to the user's session * @return true if the termination initiation operation is * successful; false otherwise. */ public boolean handleFederationTermination( HttpServletRequest request, HttpServletResponse response, Object ssoToken) { FSUtils.debug.message( "Entered FSFedTerminationHandler::handleFederationTermination"); this.request = request; this.locale = FSServiceUtils.getLocale(request); this.response = response; this.ssoToken = ssoToken; setTerminationURL(); if (managerInst == null) { FSUtils.debug.error("FSSPFedTerminationHandler " + "Account Manager instance is null"); if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message( "FSSPFedTerminationHandler::handleFederationTermination" + "failed to get Account Manager instance"); } FSServiceUtils.returnLocallyAfterOperation( response, termination_done_url, false, IFSConstants.TERMINATION_SUCCESS, IFSConstants.TERMINATION_FAILURE); return false; } try { this.userID = SessionManager.getProvider().getPrincipalName(ssoToken); } catch(SessionException e) { FSUtils.debug.error( "FSFedTerminationHandler::handleFederationTermination:", e); // cannot proceed without user LogUtil.error(Level.INFO,LogUtil.USER_NOT_FOUND,null,ssoToken); return false; } boolean bStatus = updateAccountInformation(null); FSUtils.debug.message("After updateAccountInformation"); if (!bStatus) { if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message( "FSSPFedTerminationHandler::handleFederationTermination " + "Federation Termination failed locally. Cannot update " + "account"); } String[] data = { userID }; LogUtil.error(Level.INFO,LogUtil.TERMINATION_FAILED,data, ssoToken); FSServiceUtils.returnLocallyAfterOperation( response, termination_done_url, false, IFSConstants.TERMINATION_SUCCESS, IFSConstants.TERMINATION_FAILURE); return false; } FSUtils.debug.message("Status of local update true"); String[] data = { userID }; LogUtil.access(Level.INFO,LogUtil.TERMINATION_SUCCESS,data, ssoToken); resetFederateCookie(); boolean bRemoteStatus = doFederationTermination( request, response, acctInfo); return bRemoteStatus; } /** * Updates the user account information. After sucessful operation, * the federation status corresponding to the user with the remote provider * is set to inactive. * @param ni NameIdentifier object corresponding to a user * @return boolean containing the status of the update operation */ protected boolean updateAccountInformation(NameIdentifier ni) { try { FSUtils.debug.message( "FSFedTerminationHandler::updateAccountInformation: start"); String searchDomain = remoteEntityId; // get name identifier to remove it from federation info key String nameId = null; String nameQualifier = null; if(ni != null) { nameQualifier = ni.getNameQualifier(); if(nameQualifier != null && (nameQualifier.length() != 0) && !nameQualifier.equals(remoteEntityId)) { searchDomain = nameQualifier; } nameId = ni.getName(); } if (nameId == null && acctInfo != null) { FSUtils.debug.message("FSAccountManager: getnameId in accInfo"); NameIdentifier temp = acctInfo.getLocalNameIdentifier(); if (temp != null) { nameId = temp.getName(); nameQualifier = temp.getNameQualifier(); } else { temp = acctInfo.getRemoteNameIdentifier(); if (temp != null) { nameId = temp.getName(); nameQualifier = temp.getNameQualifier(); } } } FSAccountFedInfoKey fedInfoKey = new FSAccountFedInfoKey(nameQualifier, nameId); managerInst.removeAccountFedInfo(userID, fedInfoKey, searchDomain); if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message("FSFedTerminationHandler:: " + "updateAccountInformation deactivate successfully completed"); } } catch (FSAccountMgmtException e) { FSUtils.debug.error( "FSFedTerminationHandler::updateAccountInformation " + FSUtils.bundle.getString( IFSConstants.TERMINATION_LOCAL_FAILED)); String[] data = { userID }; LogUtil.error(Level.INFO,LogUtil.TERMINATION_FAILED,data, ssoToken); return false; } // Clean SessionMap off the partner to be done here. if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message( "Cleaning Session manager for user : " + userID); FSUtils.debug.message( "Cleaning Session manager for remote provider: " + remoteEntityId); FSUtils.debug.message( "Cleaning Session manager for hosted provider: " + hostedEntityId); } FSLogoutUtil.cleanSessionMapPartnerList( userID, remoteEntityId, metaAlias, null); return true; } /** * Processes the termination request received from a * remote provider. Invoded when Http redirect profile is used. * @param request HTTP request * @param response HTTP response * @param reqTermination the federation termination request received from * remote provider */ public void processTerminationRequest( HttpServletRequest request, HttpServletResponse response, FSFederationTerminationNotification reqTermination) { FSUtils.debug.message( "Entered FSFedTerminationHandler::processTerminationRequest..."); this.request = request; this.locale = FSServiceUtils.getLocale(request); this.response = response; this.relayState = reqTermination.getRelayState(); setTerminationURL(); if (managerInst == null) { FSUtils.debug.error("FSSPFedTerminationHandler " + FSUtils.bundle.getString( IFSConstants.FEDERATION_FAILED_ACCOUNT_INSTANCE)); if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message( "FSSPFedTerminationHandler::handleFederationTermination" + "failed to get Account Manager instance"); } returnToSource(); return; } boolean bStatus = updateAccountInformation( reqTermination.getNameIdentifier()); if (!bStatus) { FSUtils.debug.message("Termination request processing failed"); String[] data = { FSUtils.bundle.getString( IFSConstants.TERMINATION_REQUEST_PROCESSING_FAILED) }; LogUtil.error(Level.INFO,LogUtil.TERMINATION_FAILED,data, ssoToken); returnToSource(); return; } FSUtils.debug.message("User sucessfully defederated"); String[] data = { FSUtils.bundle.getString( IFSConstants.TERMINATION_SUCCEEDED) }; LogUtil.access(Level.INFO,LogUtil.TERMINATION_SUCCESS,data, ssoToken); // Call SP Adaper for remote IDP initiated HTTP profile if (hostedProviderRole != null && hostedProviderRole.equalsIgnoreCase(IFSConstants.SP)) { FederationSPAdapter spAdapter = FSServiceUtils.getSPAdapter(hostedEntityId, hostedConfig); if (spAdapter != null) { FSUtils.debug.message("FSFedTerminationHandler.HTTP"); try { spAdapter.postTerminationNotificationSuccess( hostedEntityId, request, response, userID, reqTermination, IFSConstants.TERMINATION_IDP_HTTP_PROFILE); } catch (Exception e) { // ignore adapter exception FSUtils.debug.error("postTermNotification.IDP/HTTP", e); } } } returnToSource(); return; } /** * Processes the termination request received from a * remote provider. Invoded when SOAP profile is used. * @param reqTermination the federation termination request received from * remote provider * @return true when the process is successful; * false otherwise. */ public boolean processSOAPTerminationRequest( HttpServletRequest request, HttpServletResponse response, FSFederationTerminationNotification reqTermination) { FSUtils.debug.message( "Entered FSFedTerminationHandler::processSOAPTerminationRequest"); if (managerInst == null) { FSUtils.debug.error("FSSPFedTerminationHandler " + "Account Manager instance is null"); if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message( "FSSPFedTerminationHandler::handleFederationTermination" + "failed to get Account Manager instance"); } return false; } if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message( "Begin processTerminationRequest SOAP profile..."); } boolean bStatus = false; if (reqTermination != null) { boolean bUserStatus = setUserID(reqTermination); if (bUserStatus) { bStatus = updateAccountInformation( reqTermination.getNameIdentifier()); if (!bStatus) { FSUtils.debug.error("FSFedTerminationHandler " + FSUtils.bundle.getString( IFSConstants.TERMINATION_REQUEST_PROCESSING_FAILED)); return false; } else { FSUtils.debug.message("User sucessfully defederated"); // Call SP Adapter for remote IDP initiated SOAP case if (hostedProviderRole != null && hostedProviderRole.equalsIgnoreCase(IFSConstants.SP)) { FederationSPAdapter spAdapter = FSServiceUtils.getSPAdapter( hostedEntityId, hostedConfig); if (spAdapter != null) { FSUtils.debug.message( "FSFedTerminationHandler.SOAP"); try { spAdapter.postTerminationNotificationSuccess( hostedEntityId, request, response, userID, reqTermination, IFSConstants.TERMINATION_IDP_SOAP_PROFILE); } catch (Exception e) { // ignore adapter exception FSUtils.debug.error("postTerm.IDP/SOAP", e); } } } return true; } } else { FSUtils.debug.message( "Failed to get UserDN. Invalid termination request"); return false; } } else{ FSUtils.debug.error( "FSFedTerminationHandler::processTerminationRequest " + "Federation termination request is improper"); return false; } } /** * Resets ederate cookie when termination is done with one remote provider. * If no active federations exists then the cookie is set to "no"; otherwise * it is set to "yes". */ public void resetFederateCookie() { try { if (userID == null || userID.length() < 1) { return; } else { Cookie fedCookie; String cookieValue; if (managerInst.hasAnyActiveFederation(userID)) { if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message( "User : " + userID + " Federation Exists : " + IFSConstants.YES); } cookieValue = IFSConstants.YES; } else { if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message( "User : " + userID + " Federation Exists : " + IFSConstants.NO); } cookieValue = IFSConstants.NO; } FSUtils.debug.message("Setting Path to /"); if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message("Setting Age to " + IFSConstants.PERSISTENT_COOKIE_AGE + " Age"); } Set domains = SystemConfigurationUtil.getCookieDomainsForRequest(request); if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message("Provider cookie domain list is " + domains); } for (String domain : domains) { CookieUtils.addCookieToResponse(response, CookieUtils.newCookie(FEDERATE_COOKIE_NAME, cookieValue, IFSConstants.PERSISTENT_COOKIE_AGE, "/", domain)); } } } catch (FSAccountMgmtException e) { FSUtils.debug.error("Unable to read user federation information",e); return; } } /** * Determines the return location and redirects based on * federation termination Return URL of the provider that sent the * termination request. */ private void returnToSource() { FSUtils.debug.message( "Entered FSFedTerminationHandler::returnToSource"); try { StringBuffer finalReturnURL = new StringBuffer(); String retURL = remoteDescriptor.getFederationTerminationServiceReturnURL(); if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message("Redirecting to : " + retURL); } resetFederateCookie(); FSUtils.debug.message("Checking retURL for null value"); if (retURL == null || retURL.length() < 1) { FSUtils.debug.error("Return URL is null"); FSServiceUtils.showErrorPage( response, error_page_url, IFSConstants.TERMINATION_INVALID_REDIRECT_URL, IFSConstants.METADATA_ERROR); return; } else { finalReturnURL.append(retURL); if (!(relayState == null || relayState.length() < 1)) { char delimiter; if (retURL.indexOf(IFSConstants.QUESTION_MARK) < 0) { delimiter = IFSConstants.QUESTION_MARK; } else { delimiter = IFSConstants.AMPERSAND; } finalReturnURL.append(delimiter). append(RELAY_STATE). append(IFSConstants.EQUAL_TO). append(URLEncDec.encode(relayState)); } if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message("Now sendRedirecting to : " + finalReturnURL.toString()); } response.sendRedirect(finalReturnURL.toString()); return; } } catch (IOException e) { FSUtils.debug.error("Unable to get LRURL. No location to redirect." + " processing completed", e); } // create new bundle entry for redirect failure FSUtils.debug.message("After exception calling response.sendError"); FSServiceUtils.showErrorPage( response, error_page_url, IFSConstants.TERMINATION_INVALID_REDIRECT_URL, IFSConstants.METADATA_ERROR); return; } /** * Signs Federation termination request before sending it to the remote * provider. * @param msg SOAPMessage which includes termination request * to be sent to remote provider * @param idAttrName name of the id attribute to be signed * @param id the value of the id attributer to be signed * @return signed termination request in SOAPMessage * @exception SAMLException if an error occurred during signing */ protected SOAPMessage signTerminationRequest( SOAPMessage msg, String idAttrName, String id) throws SAMLException { FSUtils.debug.message( "FSSPFedTerminationHandler.signTerminationRequest: Called"); String certAlias = IDFFMetaUtils.getFirstAttributeValueFromConfig( hostedConfig, IFSConstants.SIGNING_CERT_ALIAS); if (certAlias == null || certAlias.length() == 0) { if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message( "FSSPFedTerminationHandler.signTerminationRequest: couldn't" + "obtain this site's cert alias."); } throw new SAMLResponderException( FSUtils.bundle.getString(IFSConstants.NO_CERT_ALIAS)); } if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message( "FSSPFedTerminationHandler.signTerminationRequest: Provider's " + "certAlias is found: " + certAlias); } XMLSignatureManager manager = XMLSignatureManager.getInstance(); Document doc = (Document)FSServiceUtils.createSOAPDOM(msg); String xpath = "//*[local-name()=\'ProviderID\']"; manager.signXML(doc, certAlias, SystemConfigurationUtil.getProperty( SAMLConstants.XMLSIG_ALGORITHM), idAttrName, id, false, xpath); return FSServiceUtils.convertDOMToSOAP(doc); } /** * Generates Federation termination request based onthe * FSAccountFedInfo object that represents the account * federation for a user between 2 providers. * @param acctInfo represents the current user account information * @return termination request message */ private FSFederationTerminationNotification createFederationTerminationRequest(FSAccountFedInfo acctInfo) { FSUtils.debug.message( "FSFedTerminationHandler::createFederationTerminationRequest:"); FSFederationTerminationNotification reqName = new FSFederationTerminationNotification(); if (reqName != null) { NameIdentifier nameIdentifier = acctInfo.getRemoteNameIdentifier(); if (nameIdentifier == null) { nameIdentifier = acctInfo.getLocalNameIdentifier(); } if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message("SP Provider Id : " + hostedEntityId); } reqName.setProviderId(hostedEntityId); reqName.setNameIdentifier(nameIdentifier); // TODO: Any more member settings + signature return reqName; } else { FSUtils.debug.message("failed to create termination request"); FSUtils.debug.error( "FSFedTerminationHandler::createFederationTerminationRequest " + FSUtils.bundle.getString( IFSConstants.TERMINATION_REQUEST_CREATION)); return null; } } /** * Initiates federation termination at remote end. * The termination requested is constructed and based on the profile the * request is sent over SOAP or as HTTP redirect. Profile is always based on * the SPs profile * @param acctInfo represents the user account federation information * @return true if termination request is sent to remote * provider successfully; false otherwise. */ private boolean doFederationTermination( HttpServletRequest request, HttpServletResponse response, FSAccountFedInfo acctInfo) { FSUtils.debug.message( "Entered FSFedTerminationHandler::doFederationTermination"); try { if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message( "FSFedTerminationHandler::doFederationTermination create" + " request start"); } FSFederationTerminationNotification reqFedTermination = createFederationTerminationRequest(acctInfo); reqFedTermination.setMinorVersion(FSServiceUtils.getMinorVersion( remoteDescriptor.getProtocolSupportEnumeration())); if (reqFedTermination == null) { if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message( "FSIDPFedTerminationHandler::Termination request could " + "not be formed"); } // Always show success page since local termination succeeded FSServiceUtils.returnLocallyAfterOperation( response, termination_done_url, true, IFSConstants.TERMINATION_SUCCESS, IFSConstants.TERMINATION_FAILURE); return false; } if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message( "FSIDPFedTerminationHandler::Termination request formed" + "successfully"); } // Find out which profile to use boolean isSOAPProfile = true; if (acctInfo.isRoleIDP()) { List hostProfiles = hostedDescriptor. getFederationTerminationNotificationProtocolProfile(); if (hostProfiles == null || hostProfiles.isEmpty()) { FSUtils.debug.error("FSFedTerminationHandler::" + "doFederationTermination no termination profile" + " cannot process request"); FSServiceUtils.returnLocallyAfterOperation( response, termination_done_url, true, IFSConstants.TERMINATION_SUCCESS, IFSConstants.TERMINATION_FAILURE); return false; } String profile = (String) hostProfiles.iterator().next(); if (profile.equalsIgnoreCase( IFSConstants.TERMINATION_SP_SOAP_PROFILE) || profile.equalsIgnoreCase( IFSConstants.TERMINATION_IDP_SOAP_PROFILE)) { isSOAPProfile = true; } else if (profile.equalsIgnoreCase( IFSConstants.TERMINATION_SP_HTTP_PROFILE) || profile.equalsIgnoreCase( IFSConstants.TERMINATION_IDP_HTTP_PROFILE)) { isSOAPProfile = false; } else { FSUtils.debug.error("FSFedTerminationHandler::" + "doFederationTermination Invalid termination profile" + " cannot process request"); FSServiceUtils.returnLocallyAfterOperation( response, termination_done_url, true, IFSConstants.TERMINATION_SUCCESS, IFSConstants.TERMINATION_FAILURE); return false; } } else { List remoteProfiles = remoteDescriptor. getFederationTerminationNotificationProtocolProfile(); if (remoteProfiles == null || remoteProfiles.isEmpty()) { FSUtils.debug.error("FSFedTerminationHandler::" + "doFederationTermination no termination profile" + " cannot process request"); FSServiceUtils.returnLocallyAfterOperation( response, termination_done_url, true, IFSConstants.TERMINATION_SUCCESS, IFSConstants.TERMINATION_FAILURE); return false; } String profile = (String)remoteProfiles.iterator().next(); if (profile.equalsIgnoreCase( IFSConstants.TERMINATION_SP_SOAP_PROFILE) || profile.equalsIgnoreCase( IFSConstants.TERMINATION_IDP_SOAP_PROFILE)) { isSOAPProfile = true; } else if (profile.equalsIgnoreCase( IFSConstants.TERMINATION_SP_HTTP_PROFILE) || profile.equalsIgnoreCase( IFSConstants.TERMINATION_IDP_HTTP_PROFILE)) { isSOAPProfile = false; } else { FSUtils.debug.error("FSFedTerminationHandler::" + "doFederationTermination Invalid termination profile" + " cannot process request"); FSServiceUtils.returnLocallyAfterOperation( response, termination_done_url, true, IFSConstants.TERMINATION_SUCCESS, IFSConstants.TERMINATION_FAILURE); return false; } } if (isSOAPProfile) { FSSOAPService instSOAP = FSSOAPService.getInstance(); if (instSOAP != null) { FSUtils.debug.message( "Signing suceeded. To call bindTerminationRequest"); //String id = reqFedTermination.getRequestID(); reqFedTermination.setID(IFSConstants.TERMINATIONID); SOAPMessage msgTermination = instSOAP.bind( reqFedTermination.toXMLString(true, true)); if (msgTermination != null) { try { if (FSServiceUtils.isSigningOn()) { int minorVersion = reqFedTermination.getMinorVersion(); if (minorVersion == IFSConstants.FF_11_PROTOCOL_MINOR_VERSION) { msgTermination = signTerminationRequest( msgTermination, IFSConstants.ID, reqFedTermination.getID()); } else if(minorVersion == IFSConstants.FF_12_PROTOCOL_MINOR_VERSION) { msgTermination = signTerminationRequest( msgTermination, IFSConstants.REQUEST_ID, reqFedTermination.getRequestID()); } else { FSUtils.debug.message( "invalid minor version."); } } boolean sendStatus = instSOAP.sendTerminationMessage( msgTermination, remoteDescriptor.getSoapEndpoint()); // Call SP Adapter for SP initiated SOAP profile if (hostedProviderRole != null && hostedProviderRole.equalsIgnoreCase( IFSConstants.SP)) { FederationSPAdapter spAdapter = FSServiceUtils.getSPAdapter( hostedEntityId, hostedConfig); if (spAdapter != null) { try { spAdapter. postTerminationNotificationSuccess( hostedEntityId, request, response, userID, reqFedTermination, IFSConstants. TERMINATION_SP_SOAP_PROFILE); } catch (Exception e) { // ignore adapter exception FSUtils.debug.error("postTerm.SP/SOAP", e); } } } // Always show success page since local termination // succeeded and that is what is important FSServiceUtils.returnLocallyAfterOperation( response, termination_done_url, true, IFSConstants.TERMINATION_SUCCESS, IFSConstants.TERMINATION_FAILURE); return sendStatus; } catch (Exception e) { FSUtils.debug.error( "FSFedTerminationHandler::" + "doFederationTermination " + FSUtils.bundle.getString( IFSConstants.TERMINATION_FAILED_SEND_REMOTE)); // Always show success page since local // termination succeeded FSServiceUtils.returnLocallyAfterOperation( response, termination_done_url, true, IFSConstants.TERMINATION_SUCCESS, IFSConstants.TERMINATION_FAILURE); return false; } } else { if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message( "FSSPFedTerminationHandler::doFederation" + "Termination failed. Error in forming Message"); } FSUtils.debug.error( "FSSPFedTerminationHandler.doFederationTermination " + FSUtils.bundle.getString( IFSConstants.TERMINATION_FAILED_SEND_REMOTE)); // Always show success page since local termination // succeeded FSServiceUtils.returnLocallyAfterOperation( response, termination_done_url, true, IFSConstants.TERMINATION_SUCCESS, IFSConstants.TERMINATION_FAILURE); return false; } } if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message( "FSFedTerminationHandler::doFederationTermination " + "failed. Cannot get Service Manager instance"); } FSUtils.debug.error( "FSSPFedTerminationHandler::doFederationTermination " + FSUtils.bundle.getString( IFSConstants.TERMINATION_FAILED_SEND_REMOTE)); // Always show success page since local termination succeeded FSServiceUtils.returnLocallyAfterOperation( response, termination_done_url, true, IFSConstants.TERMINATION_SUCCESS, IFSConstants.TERMINATION_FAILURE); return false; } else { if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message( "FSFedTerminationHandler::doFederationTermination " + "In Redirect profile"); } String urlEncodedRequest = reqFedTermination.toURLEncodedQueryString(); // Sign the request querystring if (FSServiceUtils.isSigningOn()) { String certAlias = IDFFMetaUtils.getFirstAttributeValueFromConfig( hostedConfig, IFSConstants.SIGNING_CERT_ALIAS); if (certAlias == null || certAlias.length() == 0) { if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message( "FSBrowserArtifactConsumerHandler:: " + "signSAMLRequest:" + "couldn't obtain this site's cert alias."); } throw new SAMLResponderException( FSUtils.bundle.getString( IFSConstants.NO_CERT_ALIAS)); } urlEncodedRequest = FSSignatureUtil.signAndReturnQueryString( urlEncodedRequest, certAlias); } StringBuffer redirectURL = new StringBuffer(); if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message("Request to be sent : " + urlEncodedRequest); } String retURL = remoteDescriptor.getFederationTerminationServiceURL(); redirectURL.append(retURL); if (retURL.indexOf(IFSConstants.QUESTION_MARK) == -1) { redirectURL.append(IFSConstants.QUESTION_MARK); } else { redirectURL.append(IFSConstants.AMPERSAND); } redirectURL.append(urlEncodedRequest); if (FSUtils.debug.messageEnabled()) { FSUtils.debug.message( "FSFedTerminationHandler::Redirect URL is " + redirectURL.toString()); } // Call SP Adaper for SP initiated HTTP profile // ideally this should be called from the // FSTerminationReturnServlet, but info not available there if (hostedProviderRole != null && hostedProviderRole.equalsIgnoreCase(IFSConstants.SP)) { FederationSPAdapter spAdapter = FSServiceUtils.getSPAdapter( hostedEntityId, hostedConfig); if (spAdapter != null) { try { spAdapter.postTerminationNotificationSuccess( hostedEntityId, request, response, userID, reqFedTermination, IFSConstants.TERMINATION_SP_HTTP_PROFILE); } catch (Exception e) { // ignore adapter exception FSUtils.debug.error("postTerm.SP/HTTP", e); } } } response.sendRedirect(redirectURL.toString()); return true; } } catch (IOException e) { FSUtils.debug.error("FSFedTerminationHandler" + FSUtils.bundle.getString( IFSConstants.FEDERATION_REDIRECT_FAILED)); } catch (FSMsgException e) { FSUtils.debug.error( "FSFedTerminationHandler::doFederationTermination " + FSUtils.bundle.getString( IFSConstants.TERMINATION_FAILED_SEND_REMOTE)); } catch (SAMLResponderException e) { FSUtils.debug.error( "FSFedTerminationHandler::doFederationTermination " + FSUtils.bundle.getString( IFSConstants.TERMINATION_FAILED_SEND_REMOTE)); } // Always show success page since local termination succeeded FSServiceUtils.returnLocallyAfterOperation( response, termination_done_url, true, IFSConstants.TERMINATION_SUCCESS, IFSConstants.TERMINATION_FAILURE); return false; } }