/**
   * Validates the SOAP Response from the service and verifies the signature if needed.
   *
   * @param soapMessage SOAPMessage that needs to be validated.
   * @param sharedData Any shared data that may be required between the request and the response.
   * @return SOAPMessage Validated SOAP Response.
   * @exception SOAPBindingException for any failure.
   */
  public SOAPMessage validateResponse(SOAPMessage soapMessage, Map sharedData)
      throws SOAPBindingException {

    try {
      Message msg = new Message(soapMessage);
      if (_config.isResponseSignEnabled() && !SecurityUtils.verifyMessage(msg)) {
        throw new SOAPBindingException(WSSUtils.bundle.getString("cannotVerifySignature"));
      }
      Utils.enforceProcessingRules(msg, null, true);
      return soapMessage;
    } catch (Exception ex) {
      WSSUtils.debug.error(
          "MessageProcessor.validateResponse: " + " Response validation failed.", ex);
      throw new SOAPBindingException(WSSUtils.bundle.getString("validateResponseFailed"));
    }
  }
  /**
   * This method is used to validate the SOAP Message Request by the processing rules of Liberty
   * SOAPBinding specifications.
   *
   * @param soapMessage SOAPMessage that needs to be validated.
   * @param subject Subject that may be used to populate the authenticated entity/user principal and
   *     any other credential information.
   * @param sharedData that may be used to store any data needed between the request and response.
   * @param httpRequest HttpServletRequest associated with this SOAP Message request.
   * @return Object Credential object after successful validation.
   * @exception SOAPBindingException for any error occured during validation.
   */
  public Object validateRequest(
      SOAPMessage soapMessage, Subject subject, Map sharedData, HttpServletRequest httpRequest)
      throws SOAPBindingException {

    WSSUtils.debug.message("SOAPProvider.validateRequest : Init");
    Message req = null;
    try {
      req = new Message(soapMessage);
      sharedData.put(SOAPBindingConstants.LIBERTY_REQUEST, req);

      if (req.getSecurityProfileType() != Message.ANONYMOUS && !SecurityUtils.verifyMessage(req)) {
        WSSUtils.debug.error(
            "MessageProcessor.validateRequest: Signature" + "Verification failed.");
        throw new SOAPBindingException(WSSUtils.bundle.getString("cannotVerifySignature"));
      }

      Utils.enforceProcessingRules(req, null, true);

      if (_config != null) {
        String authMech = req.getAuthenticationMechanism();
        if (authMech == null || !_config.getSecurityMechanisms().contains(authMech)) {

          throw new SOAPBindingException(WSSUtils.bundle.getString("unsupportedAuthMech"));
        }
      } else {
        throw new SOAPBindingException(WSSUtils.bundle.getString("nullConfiguration"));
      }

      return SOAPRequestHandler.getAuthenticator()
          .authenticate(subject, null, null, _config, req, true);

    } catch (SecurityException se) {

      WSSUtils.debug.error(
          "MessageProcessor.validateRequest: Request" + "Validation has failed.", se);
      throw new SOAPBindingException(se.getMessage());

    } catch (Exception sfe) {

      WSSUtils.debug.error("MessageProcessor.validateRequest: SOAPFault" + "Exception.", sfe);
      throw new SOAPBindingException(sfe.getMessage());
    }
  }
  /**
   * 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"));
    }
  }