/**
   * Signs Federation termination request before sending it to the remote provider.
   *
   * @param msg <code>SOAPMessage</code> 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 <code>SOAPMessage</code>
   * @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);
  }
  /**
   * Handles termination return message.
   *
   * @param request <code>HttpServletRequest</code> object that contains the request the client has
   *     made of the servlet.
   * @param response <code>HttpServletResponse</code> object that contains the response the servlet
   *     sends to the client.
   * @exception ServletException if an input or output error is detected when the servlet handles
   *     the request
   * @exception IOException if the request could not be handled
   */
  private void doGetPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    FSUtils.debug.message("FSTerminationReturnServlet doGetPost...");
    String providerAlias = FSServiceUtils.getMetaAlias(request);
    if (providerAlias == null || providerAlias.length() < 1) {
      if (FSUtils.debug.messageEnabled()) {
        FSUtils.debug.message(
            "Unable to retrieve alias, Hosted" + " Provider. Cannot process request");
      }
      response.sendError(
          response.SC_INTERNAL_SERVER_ERROR, FSUtils.bundle.getString("aliasNotFound"));
      return;
    }
    StringBuffer terminationDone = new StringBuffer();
    BaseConfigType hostedConfig = null;
    try {
      String hostedRole = metaManager.getProviderRoleByMetaAlias(providerAlias);
      String hostedEntityId = metaManager.getEntityIDByMetaAlias(providerAlias);
      String realm = IDFFMetaUtils.getRealmByMetaAlias(providerAlias);
      if (hostedRole != null && hostedRole.equalsIgnoreCase(IFSConstants.IDP)) {
        hostedConfig = metaManager.getIDPDescriptorConfig(realm, hostedEntityId);
      } else if (hostedRole != null && hostedRole.equalsIgnoreCase(IFSConstants.SP)) {
        hostedConfig = metaManager.getSPDescriptorConfig(realm, hostedEntityId);
      }
      if (hostedRole == null || hostedConfig == null) {
        throw new IDFFMetaException((String) null);
      }
    } catch (IDFFMetaException e) {
      FSUtils.debug.error("Failed to get Hosted Provider");
      response.sendError(
          response.SC_INTERNAL_SERVER_ERROR,
          FSUtils.bundle.getString(IFSConstants.FAILED_HOSTED_DESCRIPTOR));
      return;
    }
    terminationDone.append(
        FSServiceUtils.getTerminationDonePageURL(request, hostedConfig, providerAlias));

    if (FSUtils.debug.messageEnabled()) {
      FSUtils.debug.message("Final Done page URL at local end: " + terminationDone.toString());
    }
    response.sendRedirect(terminationDone.toString());
    return;
  }
 /**
  * Constructs a <code>FSNameIdentifierHelper</code> object.
  *
  * @param hostedConfig hosted provider's extended meta
  */
 public FSNameIdentifierHelper(BaseConfigType hostedConfig) {
   if (FSUtils.debug.messageEnabled()) {
     FSUtils.debug.message("FSNameIdentifierGeneratorHelper constructor" + " called");
   }
   try {
     String className =
         IDFFMetaUtils.getFirstAttributeValueFromConfig(
             hostedConfig, IFSConstants.NAMEID_IMPL_CLASS);
     generator = (INameIdentifier) (Class.forName(className).newInstance());
   } catch (ClassNotFoundException exp) {
     FSUtils.debug.error(
         "FSNameIdentifierGeneratorHelper constructor."
             + "Not able to create instance of Generator Impl",
         exp);
   } catch (Exception exp) {
     FSUtils.debug.error(
         "FSNameIdentifierGeneratorHelper constructor."
             + "Not able to create instance of Generator Impl",
         exp);
   }
 }
  /**
   * 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;
  }