/**
   * when getting query params through this, only configured params will be appended as query params
   * The required params can be configured from application-authenticators.xml
   *
   * @param request
   * @return
   */
  public static String getQueryStringWithConfiguredParams(HttpServletRequest request) {

    boolean configAvailable =
        FileBasedConfigurationBuilder.getInstance().isAuthEndpointQueryParamsConfigAvailable();
    List<String> queryParams =
        FileBasedConfigurationBuilder.getInstance().getAuthEndpointQueryParams();
    String action = FileBasedConfigurationBuilder.getInstance().getAuthEndpointQueryParamsAction();

    StringBuilder queryStrBuilder = new StringBuilder("");
    Map<String, String[]> reqParamMap = request.getParameterMap();

    if (configAvailable) {
      if (action != null
          && action.equals(FrameworkConstants.AUTH_ENDPOINT_QUERY_PARAMS_ACTION_EXCLUDE)) {
        if (reqParamMap != null) {
          for (Map.Entry<String, String[]> entry : reqParamMap.entrySet()) {
            String paramName = entry.getKey();
            String paramValue = entry.getValue()[0];

            // skip issuer and type and sessionDataKey parameters
            if (SESSION_DATA_KEY.equals(paramName)
                || FrameworkConstants.RequestParams.ISSUER.equals(paramName)
                || FrameworkConstants.RequestParams.TYPE.equals(paramName)) {
              continue;
            }

            if (!queryParams.contains(paramName)) {
              if (queryStrBuilder.length() > 0) {
                queryStrBuilder.append('&');
              }

              try {
                queryStrBuilder
                    .append(URLEncoder.encode(paramName, UTF_8))
                    .append('=')
                    .append(URLEncoder.encode(paramValue, UTF_8));
              } catch (UnsupportedEncodingException e) {
                log.error(
                    "Error while URL Encoding query param to be sent to the AuthenticationEndpoint",
                    e);
              }
            }
          }
        }
      } else {
        for (String param : queryParams) {
          String paramValue = request.getParameter(param);

          if (paramValue != null) {
            if (queryStrBuilder.length() > 0) {
              queryStrBuilder.append('&');
            }
            try {
              queryStrBuilder
                  .append(URLEncoder.encode(param, UTF_8))
                  .append('=')
                  .append(URLEncoder.encode(paramValue, UTF_8));
            } catch (UnsupportedEncodingException e) {
              log.error(
                  "Error while URL Encoding query param to be sent to the AuthenticationEndpoint",
                  e);
            }
          }
        }
      }
    } else {
      if (reqParamMap != null) {
        for (Map.Entry<String, String[]> entry : reqParamMap.entrySet()) {
          String paramName = entry.getKey();
          String paramValue = entry.getValue()[0];

          // skip issuer and type and sessionDataKey parameters
          if (SESSION_DATA_KEY.equals(paramName)
              || FrameworkConstants.RequestParams.ISSUER.equals(paramName)
              || FrameworkConstants.RequestParams.TYPE.equals(paramName)) {
            continue;
          }

          if (queryStrBuilder.length() > 0) {
            queryStrBuilder.append('&');
          }

          try {
            queryStrBuilder
                .append(URLEncoder.encode(paramName, UTF_8))
                .append('=')
                .append(URLEncoder.encode(paramValue, UTF_8));
          } catch (UnsupportedEncodingException e) {
            log.error(
                "Error while URL Encoding query param to be sent to the AuthenticationEndpoint", e);
          }
        }
      }
    }

    return queryStrBuilder.toString();
  }
  /**
   * 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;
  }