/**
   * Signs the message.
   *
   * @param soapMessage SOAPMessage that needs to be signed.
   * @param profile Security profile that needs to be used for signing.
   * @param assertion Security Assertion
   * @return SOAPMessage signed SOAPMessage.
   */
  private SOAPMessage signMessage(
      SOAPMessage soapMessage, String profile, SecurityAssertion assertion)
      throws SOAPBindingException {
    try {
      SOAPHeader soapHeader = soapMessage.getSOAPPart().getEnvelope().getHeader();
      if (soapHeader == null) {
        soapMessage.getSOAPPart().getEnvelope().addHeader();
      }
      SOAPBody soapBody = soapMessage.getSOAPPart().getEnvelope().getBody();
      if (soapBody == null) {
        throw new SOAPBindingException(WSSUtils.bundle.getString("nullSOAPBody"));
      }

      String bodyId = SAMLUtils.generateID();
      soapBody.setAttributeNS(WSSEConstants.NS_WSU_WSF11, WSSEConstants.WSU_ID, bodyId);
      List ids = new ArrayList();
      ids.add(bodyId);
      if (correlationId != null) {
        ids.add(correlationId);
      }

      Certificate cert = null;
      Element sigElem = null;
      ByteArrayInputStream bin = null;
      ByteArrayOutputStream bop = new ByteArrayOutputStream();
      Document doc = null;
      if (profile == null
          || profile.equals(Message.NULL_X509)
          || profile.equals(Message.TLS_X509)
          || profile.equals(Message.CLIENT_TLS_X509)
          || profile.equals(Message.NULL_X509_WSF11)
          || profile.equals(Message.TLS_X509_WSF11)
          || profile.equals(Message.CLIENT_TLS_X509_WSF11)) {

        BinarySecurityToken binaryToken = addBinaryToken(soapMessage);
        cert = SecurityUtils.getCertificate(binaryToken);
        soapMessage.writeTo(bop);
        bin = new ByteArrayInputStream(bop.toByteArray());
        doc = XMLUtils.toDOMDocument(bin, WSSUtils.debug);
        sigElem =
            SecurityUtils.getSignatureManager()
                .signWithWSSX509TokenProfile(
                    doc, cert, "", ids, SOAPBindingConstants.WSF_11_VERSION);

      } else if (profile.equals(Message.NULL_SAML)
          || profile.equals(Message.TLS_SAML)
          || profile.equals(Message.CLIENT_TLS_SAML)
          || profile.equals(Message.NULL_SAML_WSF11)
          || profile.equals(Message.TLS_SAML_WSF11)
          || profile.equals(Message.CLIENT_TLS_SAML_WSF11)) {

        cert = SecurityUtils.getCertificate(assertion);
        soapMessage.writeTo(bop);
        new ByteArrayInputStream(bop.toByteArray());
        bin = new ByteArrayInputStream(bop.toByteArray());
        doc = XMLUtils.toDOMDocument(bin, WSSUtils.debug);
        sigElem =
            SecurityUtils.getSignatureManager()
                .signWithWSSSAMLTokenProfile(
                    doc,
                    cert,
                    assertion.getAssertionID(),
                    "",
                    ids,
                    SOAPBindingConstants.WSF_11_VERSION);
      }

      if (sigElem == null) {
        WSSUtils.debug.error("MessageProcessor.signMessage: " + "SigElement is null");
        throw new SOAPBindingException(WSSUtils.bundle.getString("cannotSignMessage"));
      }

      Element securityHeader = getSecurityHeader(soapMessage);
      securityHeader.appendChild(securityHeader.getOwnerDocument().importNode(sigElem, true));

      return Utils.DocumentToSOAPMessage(sigElem.getOwnerDocument());

    } catch (Exception ex) {
      WSSUtils.debug.error("MessageProcessor.signMessage: " + "Signing failed.", ex);
      throw new SOAPBindingException(WSSUtils.bundle.getString("cannotSignMessage"));
    }
  }
  /**
   * Secures the request by getting the credential from the discovery service.
   *
   * @param offering Resource Offering of the discovery service.
   * @param credentials List of credentials that are required to access the discovery service.
   * @param serviceType Service Type that the discovery service should need to look for.
   * @param soapMessage SOAPMessage that needs to be secured.
   * @param sharedData Any shared data that may be used between the request and the response.
   * @return SOAPMessage Secured SOAP Message.
   * @exception SOAPBindingException for any failure.
   */
  public SOAPMessage secureRequest(
      ResourceOffering offering,
      List credentials,
      String serviceType,
      SOAPMessage soapMessage,
      Map sharedData)
      throws SOAPBindingException {

    WSSUtils.debug.message("MessageProcessor.secureRequest:Init");
    try {
      SOAPHeader header = addCorrelationHeader(soapMessage, null);
      QueryResponse discoResponse = getWebserviceOffering(offering, credentials, serviceType);

      if (WSSUtils.debug.messageEnabled()) {
        WSSUtils.debug.message(
            "MessageProcessor.secureRequest: " + "Discovery Response: " + discoResponse.toString());
      }

      List offerings = discoResponse.getResourceOffering();
      if (offerings == null || offerings.size() == 0) {
        WSSUtils.debug.error("MessageProcessor.secureRequest:: service " + "offerings are null.");
        throw new SOAPBindingException(WSSUtils.bundle.getString("noServiceOfferings"));
      }

      ResourceOffering serviceOffering =
          (ResourceOffering) discoResponse.getResourceOffering().get(0);

      List creds = discoResponse.getCredentials();

      String securityProfile = processResourceOffering(serviceOffering);

      // If the security profile is of SAML or Bearer insert a
      // security token for this profile.
      SecurityAssertion securityAssertion = null;
      if (securityProfile.equals(Message.NULL_SAML)
          || securityProfile.equals(Message.TLS_SAML)
          || securityProfile.equals(Message.CLIENT_TLS_SAML)
          || securityProfile.equals(Message.NULL_BEARER)
          || securityProfile.equals(Message.TLS_BEARER)
          || securityProfile.equals(Message.CLIENT_TLS_BEARER)
          || securityProfile.equals(Message.NULL_SAML_WSF11)
          || securityProfile.equals(Message.TLS_SAML_WSF11)
          || securityProfile.equals(Message.CLIENT_TLS_SAML_WSF11)
          || securityProfile.equals(Message.NULL_BEARER_WSF11)
          || securityProfile.equals(Message.TLS_BEARER_WSF11)
          || securityProfile.equals(Message.CLIENT_TLS_BEARER_WSF11)) {

        if (creds != null && creds.size() != 0) {
          securityAssertion = (SecurityAssertion) creds.get(0);
          securityAssertion.addToParent(header);
        }
      }

      if (securityProfile.equals(Message.NULL_SAML)
          || securityProfile.equals(Message.TLS_SAML)
          || securityProfile.equals(Message.CLIENT_TLS_SAML)
          || securityProfile.equals(Message.NULL_X509)
          || securityProfile.equals(Message.TLS_X509)
          || securityProfile.equals(Message.CLIENT_TLS_X509)
          || securityProfile.equals(Message.NULL_SAML_WSF11)
          || securityProfile.equals(Message.TLS_SAML_WSF11)
          || securityProfile.equals(Message.CLIENT_TLS_SAML_WSF11)
          || securityProfile.equals(Message.NULL_X509_WSF11)
          || securityProfile.equals(Message.TLS_X509_WSF11)
          || securityProfile.equals(Message.CLIENT_TLS_X509_WSF11)) {

        soapMessage = signMessage(soapMessage, securityProfile, securityAssertion);
      }

      if (WSSUtils.debug.messageEnabled()) {
        WSSUtils.debug.message(
            "MessageProcessor.secureRequest: "
                + com.sun.identity.shared.xml.XMLUtils.print(
                    soapMessage.getSOAPPart().getEnvelope()));
      }

      return soapMessage;

    } catch (Exception ex) {
      WSSUtils.debug.error(
          "MessageProcessor.secureRequest: Failure in " + "Securing the request.", ex);
      throw new SOAPBindingException(WSSUtils.bundle.getString("secureRequestFailed"));
    }
  }