/**
   * Handles the request for http post binding
   *
   * @param request The HTTP request with SAML2 message
   * @param response The HTTP response
   * @param isLogout Whether the request is a logout request
   * @throws SSOAgentException
   */
  public String buildPostRequest(
      HttpServletRequest request, HttpServletResponse response, boolean isLogout)
      throws SSOAgentException {

    RequestAbstractType requestMessage = null;
    if (!isLogout) {
      requestMessage = buildAuthnRequest(request);
      if (ssoAgentConfig.getSAML2().isRequestSigned()) {
        requestMessage =
            SSOAgentUtils.setSignature(
                (AuthnRequest) requestMessage,
                XMLSignature.ALGO_ID_SIGNATURE_RSA,
                new X509CredentialImpl(ssoAgentConfig.getSAML2().getSSOAgentX509Credential()));
      }

    } else {
      LoggedInSessionBean sessionBean =
          (LoggedInSessionBean)
              request.getSession(false).getAttribute(SSOAgentConstants.SESSION_BEAN_NAME);
      if (sessionBean != null) {
        requestMessage =
            buildLogoutRequest(
                sessionBean.getSAML2SSO().getSubjectId(),
                sessionBean.getSAML2SSO().getSessionIndex());
        if (ssoAgentConfig.getSAML2().isRequestSigned()) {
          requestMessage =
              SSOAgentUtils.setSignature(
                  (LogoutRequest) requestMessage,
                  XMLSignature.ALGO_ID_SIGNATURE_RSA,
                  new X509CredentialImpl(ssoAgentConfig.getSAML2().getSSOAgentX509Credential()));
        }
      } else {
        throw new SSOAgentException("SLO Request can not be built. SSO Session is null");
      }
    }
    String encodedRequestMessage =
        encodeRequestMessage(requestMessage, SAMLConstants.SAML2_POST_BINDING_URI);

    Map<String, String[]> paramsMap = new HashMap<String, String[]>();
    paramsMap.put(
        SSOAgentConstants.SAML2SSO.HTTP_POST_PARAM_SAML2_AUTH_REQ,
        new String[] {encodedRequestMessage});
    if (ssoAgentConfig.getSAML2().getRelayState() != null) {
      paramsMap.put(
          RelayState.DEFAULT_ELEMENT_LOCAL_NAME,
          new String[] {ssoAgentConfig.getSAML2().getRelayState()});
    }

    // Add any additional parameters defined
    if (ssoAgentConfig.getQueryParams() != null && !ssoAgentConfig.getQueryParams().isEmpty()) {
      paramsMap.putAll(ssoAgentConfig.getQueryParams());
    }

    StringBuilder htmlParams = new StringBuilder();
    for (Map.Entry<String, String[]> entry : paramsMap.entrySet()) {
      if (entry.getKey() != null && entry.getValue() != null && entry.getValue().length > 0) {
        for (String param : entry.getValue()) {
          htmlParams
              .append("<input type='hidden' name='")
              .append(entry.getKey())
              .append("' value='")
              .append(param)
              .append("'>\n");
        }
      }
    }
    String htmlPayload = ssoAgentConfig.getSAML2().getPostBindingRequestHTMLPayload();
    if (htmlPayload == null || !htmlPayload.contains("<!--$saml_params-->")) {
      htmlPayload =
          "<html>\n"
              + "<body>\n"
              + "<p>You are now redirected back to "
              + ssoAgentConfig.getSAML2().getIdPURL()
              + " \n"
              + "If the redirection fails, please click the post button.</p>\n"
              + "<form method='post' action='"
              + ssoAgentConfig.getSAML2().getIdPURL()
              + "'>\n"
              + "<p>\n"
              + htmlParams.toString()
              + "<button type='submit'>POST</button>\n"
              + "</p>\n"
              + "</form>\n"
              + "<script type='text/javascript'>\n"
              + "document.forms[0].submit();\n"
              + "</script>\n"
              + "</body>\n"
              + "</html>";
    } else {
      htmlPayload = htmlPayload.replace("<!--$saml_params-->", htmlParams.toString());
    }
    return htmlPayload;
  }
  protected void processSSOResponse(HttpServletRequest request) throws SSOAgentException {

    LoggedInSessionBean sessionBean = new LoggedInSessionBean();
    sessionBean.setSAML2SSO(sessionBean.new SAML2SSO());

    String saml2ResponseString =
        new String(
            Base64.decode(
                request.getParameter(SSOAgentConstants.SAML2SSO.HTTP_POST_PARAM_SAML2_RESP)),
            Charset.forName("UTF-8"));
    Response saml2Response = (Response) SSOAgentUtils.unmarshall(saml2ResponseString);
    sessionBean.getSAML2SSO().setResponseString(saml2ResponseString);
    sessionBean.getSAML2SSO().setSAMLResponse(saml2Response);

    Assertion assertion = null;
    if (ssoAgentConfig.getSAML2().isAssertionEncrypted()) {
      List<EncryptedAssertion> encryptedAssertions = saml2Response.getEncryptedAssertions();
      EncryptedAssertion encryptedAssertion = null;
      if (!org.apache.commons.collections.CollectionUtils.isEmpty(encryptedAssertions)) {
        encryptedAssertion = encryptedAssertions.get(0);
        try {
          assertion = getDecryptedAssertion(encryptedAssertion);
        } catch (Exception e) {
          if (log.isDebugEnabled()) {
            log.debug("Assertion decryption failure : ", e);
          }
          throw new SSOAgentException("Unable to decrypt the SAML2 Assertion");
        }
      }
    } else {
      List<Assertion> assertions = saml2Response.getAssertions();
      if (assertions != null && !assertions.isEmpty()) {
        assertion = assertions.get(0);
      }
    }
    if (assertion == null) {
      if (isNoPassive(saml2Response)) {
        LOGGER.log(Level.FINE, "Cannot authenticate in passive mode");
        return;
      }
      throw new SSOAgentException("SAML2 Assertion not found in the Response");
    }

    String idPEntityIdValue = assertion.getIssuer().getValue();
    if (idPEntityIdValue == null || idPEntityIdValue.isEmpty()) {
      throw new SSOAgentException("SAML2 Response does not contain an Issuer value");
    } else if (!idPEntityIdValue.equals(ssoAgentConfig.getSAML2().getIdPEntityId())) {
      throw new SSOAgentException("SAML2 Response Issuer verification failed");
    }
    sessionBean.getSAML2SSO().setAssertion(assertion);
    // Cannot marshall SAML assertion here, before signature validation due to a weird issue in
    // OpenSAML

    // Get the subject name from the Response Object and forward it to login_action.jsp
    String subject = null;
    if (assertion.getSubject() != null && assertion.getSubject().getNameID() != null) {
      subject = assertion.getSubject().getNameID().getValue();
    }

    if (subject == null) {
      throw new SSOAgentException("SAML2 Response does not contain the name of the subject");
    }

    sessionBean.getSAML2SSO().setSubjectId(subject); // set the subject
    request.getSession().setAttribute(SSOAgentConstants.SESSION_BEAN_NAME, sessionBean);

    // validate audience restriction
    validateAudienceRestriction(assertion);

    // validate signature
    validateSignature(saml2Response, assertion);

    // Marshalling SAML2 assertion after signature validation due to a weird issue in OpenSAML
    sessionBean.getSAML2SSO().setAssertionString(marshall(assertion));

    ((LoggedInSessionBean) request.getSession().getAttribute(SSOAgentConstants.SESSION_BEAN_NAME))
        .getSAML2SSO()
        .setSubjectAttributes(getAssertionStatements(assertion));

    // For removing the session when the single sign out request made by the SP itself
    if (ssoAgentConfig.getSAML2().isSLOEnabled()) {
      String sessionId = assertion.getAuthnStatements().get(0).getSessionIndex();
      if (sessionId == null) {
        throw new SSOAgentException(
            "Single Logout is enabled but IdP Session ID not found in SAML2 Assertion");
      }
      ((LoggedInSessionBean) request.getSession().getAttribute(SSOAgentConstants.SESSION_BEAN_NAME))
          .getSAML2SSO()
          .setSessionIndex(sessionId);
      SSOAgentSessionManager.addAuthenticatedSession(request.getSession(false));
    }

    request.getSession().setAttribute(SSOAgentConstants.SESSION_BEAN_NAME, sessionBean);
  }
  /**
   * Returns the redirection URL with the appended SAML2 Request message
   *
   * @param request SAML 2 request
   * @return redirectionUrl
   */
  public String buildRedirectRequest(HttpServletRequest request, boolean isLogout)
      throws SSOAgentException {

    RequestAbstractType requestMessage = null;
    if (!isLogout) {
      requestMessage = buildAuthnRequest(request);
    } else {
      LoggedInSessionBean sessionBean =
          (LoggedInSessionBean)
              request.getSession(false).getAttribute(SSOAgentConstants.SESSION_BEAN_NAME);
      if (sessionBean != null) {
        requestMessage =
            buildLogoutRequest(
                sessionBean.getSAML2SSO().getSubjectId(),
                sessionBean.getSAML2SSO().getSessionIndex());
      } else {
        throw new SSOAgentException("SLO Request can not be built. SSO Session is NULL");
      }
    }
    String idpUrl = null;

    String encodedRequestMessage =
        encodeRequestMessage(requestMessage, SAMLConstants.SAML2_REDIRECT_BINDING_URI);
    StringBuilder httpQueryString =
        new StringBuilder(
            SSOAgentConstants.SAML2SSO.HTTP_POST_PARAM_SAML2_AUTH_REQ
                + "="
                + encodedRequestMessage);

    String relayState = ssoAgentConfig.getSAML2().getRelayState();
    if (relayState != null) {
      try {
        httpQueryString.append(
            "&"
                + RelayState.DEFAULT_ELEMENT_LOCAL_NAME
                + "="
                + URLEncoder.encode(relayState, "UTF-8").trim());
      } catch (UnsupportedEncodingException e) {
        throw new SSOAgentException(
            "Error occurred while URLEncoding " + RelayState.DEFAULT_ELEMENT_LOCAL_NAME, e);
      }
    }

    if (ssoAgentConfig.getQueryParams() != null && !ssoAgentConfig.getQueryParams().isEmpty()) {
      StringBuilder builder = new StringBuilder();
      for (Map.Entry<String, String[]> entry : ssoAgentConfig.getQueryParams().entrySet()) {
        if (entry.getKey() != null && entry.getValue() != null && entry.getValue().length > 0) {
          for (String param : entry.getValue()) {
            builder.append("&").append(entry.getKey()).append("=").append(param);
          }
        }
      }
      httpQueryString.append(builder);
    }

    if (ssoAgentConfig.getSAML2().isRequestSigned()) {
      SSOAgentUtils.addDeflateSignatureToHTTPQueryString(
          httpQueryString,
          new X509CredentialImpl(ssoAgentConfig.getSAML2().getSSOAgentX509Credential()));
    }

    if (ssoAgentConfig.getSAML2().getIdPURL().indexOf("?") > -1) {
      idpUrl = ssoAgentConfig.getSAML2().getIdPURL().concat("&").concat(httpQueryString.toString());
    } else {
      idpUrl = ssoAgentConfig.getSAML2().getIdPURL().concat("?").concat(httpQueryString.toString());
    }
    return idpUrl;
  }