private RequestedAuthnContext buildRequestedAuthnContext(AuthnRequest inboundAuthnRequest)
      throws SAMLSSOException {

    /* AuthnContext */
    RequestedAuthnContextBuilder requestedAuthnContextBuilder = null;
    RequestedAuthnContext requestedAuthnContext = null;

    String includeAuthnContext =
        properties.get(IdentityApplicationConstants.Authenticator.SAML2SSO.INCLUDE_AUTHN_CONTEXT);

    if (StringUtils.isNotEmpty(includeAuthnContext)
        && "as_request".equalsIgnoreCase(includeAuthnContext)) {
      if (inboundAuthnRequest != null) {
        RequestedAuthnContext incomingRequestedAuthnContext =
            inboundAuthnRequest.getRequestedAuthnContext();
        if (incomingRequestedAuthnContext != null) {
          requestedAuthnContextBuilder = new RequestedAuthnContextBuilder();
          requestedAuthnContext = requestedAuthnContextBuilder.buildObject();
          requestedAuthnContext.setDOM(incomingRequestedAuthnContext.getDOM());
        }
      }
    } else if (StringUtils.isEmpty(includeAuthnContext)
        || "yes".equalsIgnoreCase(includeAuthnContext)) {
      requestedAuthnContextBuilder = new RequestedAuthnContextBuilder();
      requestedAuthnContext = requestedAuthnContextBuilder.buildObject();
      /* AuthnContextClass */
      AuthnContextClassRefBuilder authnContextClassRefBuilder = new AuthnContextClassRefBuilder();
      AuthnContextClassRef authnContextClassRef =
          authnContextClassRefBuilder.buildObject(
              SAMLConstants.SAML20_NS,
              AuthnContextClassRef.DEFAULT_ELEMENT_LOCAL_NAME,
              SAMLConstants.SAML20_PREFIX);

      String authnContextClassProp =
          properties.get(
              IdentityApplicationConstants.Authenticator.SAML2SSO.AUTHENTICATION_CONTEXT_CLASS);

      if (StringUtils.isNotEmpty(authnContextClassProp)) {
        authnContextClassRef.setAuthnContextClassRef(
            IdentityApplicationManagementUtil.getSAMLAuthnContextClasses()
                .get(authnContextClassProp));
      } else {
        authnContextClassRef.setAuthnContextClassRef(AuthnContext.PPT_AUTHN_CTX);
      }

      /* Authentication Context Comparison Level */
      String authnContextComparison =
          properties.get(
              IdentityApplicationConstants.Authenticator.SAML2SSO
                  .AUTHENTICATION_CONTEXT_COMPARISON_LEVEL);

      if (StringUtils.isNotEmpty(authnContextComparison)) {
        if (AuthnContextComparisonTypeEnumeration.EXACT
            .toString()
            .equalsIgnoreCase(authnContextComparison)) {
          requestedAuthnContext.setComparison(AuthnContextComparisonTypeEnumeration.EXACT);
        } else if (AuthnContextComparisonTypeEnumeration.MINIMUM
            .toString()
            .equalsIgnoreCase(authnContextComparison)) {
          requestedAuthnContext.setComparison(AuthnContextComparisonTypeEnumeration.MINIMUM);
        } else if (AuthnContextComparisonTypeEnumeration.MAXIMUM
            .toString()
            .equalsIgnoreCase(authnContextComparison)) {
          requestedAuthnContext.setComparison(AuthnContextComparisonTypeEnumeration.MAXIMUM);
        } else if (AuthnContextComparisonTypeEnumeration.BETTER
            .toString()
            .equalsIgnoreCase(authnContextComparison)) {
          requestedAuthnContext.setComparison(AuthnContextComparisonTypeEnumeration.BETTER);
        }
      } else {
        requestedAuthnContext.setComparison(AuthnContextComparisonTypeEnumeration.EXACT);
      }
      requestedAuthnContext.getAuthnContextClassRefs().add(authnContextClassRef);
    }
    return requestedAuthnContext;
  }
  /**
   * Returns the redirection URL with the appended SAML2 Request message
   *
   * @param request SAML 2 request
   * @return redirectionUrl
   */
  @Override
  public String buildRequest(
      HttpServletRequest request,
      boolean isLogout,
      boolean isPassive,
      String loginPage,
      AuthenticationContext context)
      throws SAMLSSOException {

    doBootstrap();
    String contextIdentifier = context.getContextIdentifier();
    RequestAbstractType requestMessage;

    if (request.getParameter(SSOConstants.HTTP_POST_PARAM_SAML2_AUTH_REQ) == null) {
      String queryParam = context.getQueryParams();
      if (queryParam != null) {
        String[] params = queryParam.split("&");
        for (String param : params) {
          String[] values = param.split("=");
          if (values.length == 2 && SSOConstants.HTTP_POST_PARAM_SAML2_AUTH_REQ.equals(values[0])) {
            request.setAttribute(SSOConstants.HTTP_POST_PARAM_SAML2_AUTH_REQ, values[1]);
            break;
          }
        }
      }
    }

    if (!isLogout) {
      requestMessage = buildAuthnRequest(request, isPassive, loginPage, context);
    } else {
      String username = (String) request.getSession().getAttribute(SSOConstants.LOGOUT_USERNAME);
      String sessionIndex =
          (String) request.getSession().getAttribute(SSOConstants.LOGOUT_SESSION_INDEX);
      String nameQualifier =
          (String) request.getSession().getAttribute(SSOConstants.NAME_QUALIFIER);
      String spNameQualifier =
          (String) request.getSession().getAttribute(SSOConstants.SP_NAME_QUALIFIER);

      requestMessage =
          buildLogoutRequest(username, sessionIndex, loginPage, nameQualifier, spNameQualifier);
    }
    String idpUrl = null;
    boolean isSignAuth2SAMLUsingSuperTenant = false;

    String encodedRequestMessage = encodeRequestMessage(requestMessage);
    StringBuilder httpQueryString = new StringBuilder("SAMLRequest=" + encodedRequestMessage);

    try {
      httpQueryString.append("&RelayState=" + URLEncoder.encode(contextIdentifier, "UTF-8").trim());
    } catch (UnsupportedEncodingException e) {
      throw new SAMLSSOException("Error occurred while url encoding RelayState", e);
    }

    if (SSOUtils.isAuthnRequestSigned(properties)) {
      String signatureAlgoProp =
          properties.get(IdentityApplicationConstants.Authenticator.SAML2SSO.SIGNATURE_ALGORITHM);
      if (StringUtils.isEmpty(signatureAlgoProp)) {
        signatureAlgoProp = IdentityApplicationConstants.XML.SignatureAlgorithm.RSA_SHA1;
      }
      String signatureAlgo =
          IdentityApplicationManagementUtil.getXMLSignatureAlgorithms().get(signatureAlgoProp);

      Map<String, String> parameterMap =
          FileBasedConfigurationBuilder.getInstance()
              .getAuthenticatorBean(SSOConstants.AUTHENTICATOR_NAME)
              .getParameterMap();
      if (parameterMap.size() > 0) {
        isSignAuth2SAMLUsingSuperTenant =
            Boolean.parseBoolean(parameterMap.get(SIGN_AUTH2_SAML_USING_SUPER_TENANT));
      }
      if (isSignAuth2SAMLUsingSuperTenant) {
        SSOUtils.addSignatureToHTTPQueryString(
            httpQueryString,
            signatureAlgo,
            new X509CredentialImpl(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME, null));
      } else {
        SSOUtils.addSignatureToHTTPQueryString(
            httpQueryString,
            signatureAlgo,
            new X509CredentialImpl(context.getTenantDomain(), null));
      }
    }
    if (loginPage.indexOf("?") > -1) {
      idpUrl = loginPage.concat("&").concat(httpQueryString.toString());
    } else {
      idpUrl = loginPage.concat("?").concat(httpQueryString.toString());
    }
    return idpUrl;
  }
  /**
   * @param request
   * @param isLogout
   * @param isPassive
   * @param loginPage
   * @return return encoded SAML Auth request
   * @throws SAMLSSOException
   */
  public String buildPostRequest(
      HttpServletRequest request,
      boolean isLogout,
      boolean isPassive,
      String loginPage,
      AuthenticationContext context)
      throws SAMLSSOException {

    doBootstrap();
    RequestAbstractType requestMessage;
    String signatureAlgoProp = null;
    String digestAlgoProp = null;
    String includeCertProp = null;
    String signatureAlgo = null;
    String digestAlgo = null;
    boolean includeCert = false;

    // get Signature Algorithm
    signatureAlgoProp =
        properties.get(IdentityApplicationConstants.Authenticator.SAML2SSO.SIGNATURE_ALGORITHM);
    if (StringUtils.isEmpty(signatureAlgoProp)) {
      signatureAlgoProp = IdentityApplicationConstants.XML.SignatureAlgorithm.RSA_SHA1;
    }
    signatureAlgo =
        IdentityApplicationManagementUtil.getXMLSignatureAlgorithms().get(signatureAlgoProp);

    // get Digest Algorithm
    digestAlgoProp =
        properties.get(IdentityApplicationConstants.Authenticator.SAML2SSO.DIGEST_ALGORITHM);
    if (StringUtils.isEmpty(digestAlgoProp)) {
      digestAlgoProp = IdentityApplicationConstants.XML.DigestAlgorithm.SHA1;
    }
    digestAlgo = IdentityApplicationManagementUtil.getXMLDigestAlgorithms().get(digestAlgoProp);

    includeCertProp =
        properties.get(IdentityApplicationConstants.Authenticator.SAML2SSO.INCLUDE_CERT);
    if (StringUtils.isEmpty(includeCertProp) || Boolean.parseBoolean(includeCertProp)) {
      includeCert = true;
    }

    if (!isLogout) {
      requestMessage = buildAuthnRequest(request, isPassive, loginPage, context);
      if (SSOUtils.isAuthnRequestSigned(properties)) {
        SSOUtils.setSignature(
            requestMessage,
            signatureAlgo,
            digestAlgo,
            includeCert,
            new X509CredentialImpl(context.getTenantDomain(), null));
      }
    } else {
      String username = (String) request.getSession().getAttribute(SSOConstants.LOGOUT_USERNAME);
      String sessionIndex =
          (String) request.getSession().getAttribute(SSOConstants.LOGOUT_SESSION_INDEX);
      String nameQualifier =
          (String) request.getSession().getAttribute(SSOConstants.NAME_QUALIFIER);
      String spNameQualifier =
          (String) request.getSession().getAttribute(SSOConstants.SP_NAME_QUALIFIER);

      requestMessage =
          buildLogoutRequest(username, sessionIndex, loginPage, nameQualifier, spNameQualifier);
      if (SSOUtils.isLogoutRequestSigned(properties)) {
        SSOUtils.setSignature(
            requestMessage,
            signatureAlgo,
            digestAlgo,
            includeCert,
            new X509CredentialImpl(context.getTenantDomain(), null));
      }
    }

    return SSOUtils.encode(SSOUtils.marshall(requestMessage));
  }
  /**
   * @param logoutRequest
   * @param sessionId
   * @param queryString
   * @return
   * @throws IdentityException
   */
  public SAMLSSOReqValidationResponseDTO process(
      LogoutRequest logoutRequest, String sessionId, String queryString) throws IdentityException {

    try {
      SAMLSSOReqValidationResponseDTO reqValidationResponseDTO =
          new SAMLSSOReqValidationResponseDTO();
      reqValidationResponseDTO.setLogOutReq(true);

      String subject = null;
      String issuer = null;
      String defaultSigningAlgoUri = IdentityApplicationManagementUtil.getSigningAlgoURIByConfig();
      String defaultDigestAlgoUri = IdentityApplicationManagementUtil.getDigestAlgoURIByConfig();

      // Get the sessions from the SessionPersistenceManager and prepare
      // the logout responses
      SSOSessionPersistenceManager ssoSessionPersistenceManager =
          SSOSessionPersistenceManager.getPersistenceManager();
      if (StringUtils.isBlank(sessionId)) {
        String message = "Session was already Expired";
        log.error(message);
        return buildErrorResponse(
            logoutRequest.getID(),
            SAMLSSOConstants.StatusCodes.REQUESTOR_ERROR,
            message,
            logoutRequest.getDestination(),
            defaultSigningAlgoUri,
            defaultDigestAlgoUri);
      }
      String sessionIndex = ssoSessionPersistenceManager.getSessionIndexFromTokenId(sessionId);

      if (StringUtils.isBlank(sessionId)) {
        String message = "Session index value not found in the request";
        log.error(message);
        reqValidationResponseDTO =
            buildErrorResponse(
                logoutRequest.getID(),
                SAMLSSOConstants.StatusCodes.REQUESTOR_ERROR,
                message,
                null,
                defaultSigningAlgoUri,
                defaultDigestAlgoUri);
        reqValidationResponseDTO.setLogoutFromAuthFramework(true);
        return reqValidationResponseDTO;
      }
      // Only if the logout request is received.
      if (logoutRequest != null) {
        if (logoutRequest.getIssuer() == null) {
          String message = "Issuer should be mentioned in the Logout Request";
          log.error(message);
          return buildErrorResponse(
              logoutRequest.getID(),
              SAMLSSOConstants.StatusCodes.REQUESTOR_ERROR,
              message,
              logoutRequest.getDestination(),
              defaultSigningAlgoUri,
              defaultDigestAlgoUri);
        }

        // TODO : Check for BaseID and EncryptedID as well.
        if (logoutRequest.getNameID() != null) {
          NameID nameID = logoutRequest.getNameID();
          subject = nameID.getValue();
        } else {
          String message = "Subject Name should be specified in the Logout Request";
          log.error(message);
          return buildErrorResponse(
              logoutRequest.getID(),
              SAMLSSOConstants.StatusCodes.REQUESTOR_ERROR,
              message,
              logoutRequest.getDestination(),
              defaultSigningAlgoUri,
              defaultDigestAlgoUri);
        }

        if (logoutRequest.getSessionIndexes() == null) {
          String message = "At least one Session Index should be present in the Logout Request";
          log.error(message);
          return buildErrorResponse(
              logoutRequest.getID(),
              SAMLSSOConstants.StatusCodes.REQUESTOR_ERROR,
              message,
              logoutRequest.getDestination(),
              defaultSigningAlgoUri,
              defaultDigestAlgoUri);
        }

        SessionInfoData sessionInfoData = ssoSessionPersistenceManager.getSessionInfo(sessionIndex);

        if (sessionInfoData == null) {
          String message = "No Established Sessions corresponding to Session Indexes provided.";
          log.error(message);
          reqValidationResponseDTO =
              buildErrorResponse(
                  logoutRequest.getID(),
                  SAMLSSOConstants.StatusCodes.REQUESTOR_ERROR,
                  message,
                  null,
                  defaultSigningAlgoUri,
                  defaultDigestAlgoUri);
          reqValidationResponseDTO.setLogoutFromAuthFramework(true);
          return reqValidationResponseDTO;
        }

        issuer = logoutRequest.getIssuer().getValue();

        if (issuer.contains("@")) {
          String tenantDomain = issuer.substring(issuer.lastIndexOf('@') + 1);
          issuer = issuer.substring(0, issuer.lastIndexOf('@'));
          if (StringUtils.isNotEmpty(tenantDomain) && StringUtils.isNotEmpty(issuer)) {
            SAMLSSOUtil.setTenantDomainInThreadLocal(tenantDomain);
            if (log.isDebugEnabled()) {
              log.debug(
                  "Tenant Domain :"
                      + " "
                      + tenantDomain
                      + " "
                      + "&"
                      + " "
                      + "Issuer name :"
                      + issuer
                      + " "
                      + "has being spilt");
            }
          } else {
            SAMLSSOServiceProviderDO serviceProvider =
                sessionInfoData.getServiceProviderList().get(issuer);
            if (serviceProvider != null) {
              SAMLSSOUtil.setTenantDomainInThreadLocal(
                  sessionInfoData.getServiceProviderList().get(issuer).getTenantDomain());
            } else {
              throw new IdentityException(
                  "Service provider :" + issuer + " does not exist in session " + "info data.");
            }
          }
        } else {
          SAMLSSOServiceProviderDO serviceProvider =
              sessionInfoData.getServiceProviderList().get(issuer);
          if (serviceProvider != null) {
            SAMLSSOUtil.setTenantDomainInThreadLocal(
                sessionInfoData.getServiceProviderList().get(issuer).getTenantDomain());
          } else {
            throw new IdentityException(
                "Service provider :" + issuer + " does not exist in session info " + "data.");
          }
        }
        subject = sessionInfoData.getSubject(issuer);

        Map<String, SAMLSSOServiceProviderDO> sessionsList =
            sessionInfoData.getServiceProviderList();
        SAMLSSOServiceProviderDO logoutReqIssuer = sessionsList.get(issuer);

        if (logoutReqIssuer.isDoSingleLogout()) {
          // validate session index
          SessionIndex requestSessionIndex =
              logoutRequest.getSessionIndexes().size() > 0
                  ? logoutRequest.getSessionIndexes().get(0)
                  : null;

          if (requestSessionIndex == null
              || !sessionIndex.equals(requestSessionIndex.getSessionIndex())) {
            String message =
                "Session Index validation for Logout Request failed. "
                    + "Received: ["
                    + (requestSessionIndex == null ? "null" : requestSessionIndex.getSessionIndex())
                    + "]."
                    + " Expected: ["
                    + sessionIndex
                    + "]";
            log.error(message);
            return buildErrorResponse(
                logoutRequest.getID(),
                SAMLSSOConstants.StatusCodes.REQUESTOR_ERROR,
                message,
                logoutRequest.getDestination(),
                logoutReqIssuer.getSigningAlgorithmUri(),
                logoutReqIssuer.getDigestAlgorithmUri());
          }
        }

        if (logoutReqIssuer.isDoValidateSignatureInRequests()) {

          // Validate 'Destination'
          List<String> idpUrlSet =
              SAMLSSOUtil.getDestinationFromTenantDomain(
                  SAMLSSOUtil.getTenantDomainFromThreadLocal());

          if (logoutRequest.getDestination() == null
              || !idpUrlSet.contains(logoutRequest.getDestination())) {
            String message =
                "Destination validation for Logout Request failed. "
                    + "Received: ["
                    + logoutRequest.getDestination()
                    + "]."
                    + " Expected: ["
                    + StringUtils.join(idpUrlSet, ',')
                    + "]";
            log.error(message);
            return buildErrorResponse(
                logoutRequest.getID(),
                SAMLSSOConstants.StatusCodes.REQUESTOR_ERROR,
                message,
                logoutRequest.getDestination(),
                logoutReqIssuer.getSigningAlgorithmUri(),
                logoutReqIssuer.getDigestAlgorithmUri());
          }

          // Validate Signature
          boolean isSignatureValid =
              SAMLSSOUtil.validateLogoutRequestSignature(
                  logoutRequest, logoutReqIssuer.getCertAlias(), subject, queryString);
          if (!isSignatureValid) {
            String message = "Signature validation for Logout Request failed";
            log.error(message);
            return buildErrorResponse(
                logoutRequest.getID(),
                SAMLSSOConstants.StatusCodes.REQUESTOR_ERROR,
                message,
                logoutRequest.getDestination(),
                logoutReqIssuer.getSigningAlgorithmUri(),
                logoutReqIssuer.getDigestAlgorithmUri());
          }
        }

        SingleLogoutMessageBuilder logoutMsgBuilder = new SingleLogoutMessageBuilder();
        Map<String, String> rpSessionsList = sessionInfoData.getRPSessionsList();
        List<SingleLogoutRequestDTO> singleLogoutReqDTOs = new ArrayList<SingleLogoutRequestDTO>();

        for (Map.Entry<String, SAMLSSOServiceProviderDO> entry : sessionsList.entrySet()) {
          String key = entry.getKey();
          SAMLSSOServiceProviderDO value = entry.getValue();

          if (!key.equals(issuer)) {
            SingleLogoutRequestDTO logoutReqDTO = new SingleLogoutRequestDTO();
            if (StringUtils.isNotBlank(value.getSloRequestURL())) {
              logoutReqDTO.setAssertionConsumerURL(value.getSloRequestURL());
            } else if (StringUtils.isNotBlank(value.getSloResponseURL())) {
              logoutReqDTO.setAssertionConsumerURL(value.getSloResponseURL());
            } else {
              logoutReqDTO.setAssertionConsumerURL(value.getAssertionConsumerUrl());
            }

            LogoutRequest logoutReq =
                logoutMsgBuilder.buildLogoutRequest(
                    sessionInfoData.getSubject(key),
                    sessionIndex,
                    SAMLSSOConstants.SingleLogoutCodes.LOGOUT_USER,
                    logoutReqDTO.getAssertionConsumerURL(),
                    value.getNameIDFormat(),
                    value.getTenantDomain(),
                    value.getSigningAlgorithmUri(),
                    value.getDigestAlgorithmUri());
            String logoutReqString = SAMLSSOUtil.encode(SAMLSSOUtil.marshall(logoutReq));
            logoutReqDTO.setLogoutResponse(logoutReqString);
            logoutReqDTO.setRpSessionId(rpSessionsList.get(key));
            singleLogoutReqDTOs.add(logoutReqDTO);
          } else {
            reqValidationResponseDTO.setIssuer(value.getIssuer());
            reqValidationResponseDTO.setDoSignResponse(value.isDoSignResponse());
            reqValidationResponseDTO.setSigningAlgorithmUri(value.getSigningAlgorithmUri());
            reqValidationResponseDTO.setDigestAlgorithmUri(value.getDigestAlgorithmUri());
            if (StringUtils.isNotBlank(value.getSloResponseURL())) {
              reqValidationResponseDTO.setAssertionConsumerURL(value.getSloResponseURL());
            } else {
              reqValidationResponseDTO.setAssertionConsumerURL(value.getAssertionConsumerUrl());
            }
          }
        }

        reqValidationResponseDTO.setLogoutRespDTO(
            singleLogoutReqDTOs.toArray(new SingleLogoutRequestDTO[singleLogoutReqDTOs.size()]));

        LogoutResponse logoutResponse =
            logoutMsgBuilder.buildLogoutResponse(
                logoutRequest.getID(),
                SAMLSSOConstants.StatusCodes.SUCCESS_CODE,
                null,
                reqValidationResponseDTO.getAssertionConsumerURL(),
                reqValidationResponseDTO.isDoSignResponse(),
                SAMLSSOUtil.getTenantDomainFromThreadLocal(),
                reqValidationResponseDTO.getSigningAlgorithmUri(),
                reqValidationResponseDTO.getDigestAlgorithmUri());

        reqValidationResponseDTO.setLogoutResponse(
            SAMLSSOUtil.encode(SAMLSSOUtil.marshall(logoutResponse)));
        reqValidationResponseDTO.setValid(true);
      }

      return reqValidationResponseDTO;
    } catch (UserStoreException | IdentityException e) {
      throw new IdentityException("Error Processing the Logout Request", e);
    }
  }