/**
   * Initiates the federation termination operation.
   *
   * @param request HTTP request
   * @param response HTTP response
   * @param ssoToken corresponding to the user's session
   * @return <code>true</code> if the termination initiation operation is successful; <code>false
   *     </code> 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;
  }
  /**
   * 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 <code>true</code> if termination request is sent to remote provider successfully;
   *     <code>false</code> 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;
  }