protected Extensions getSAMLExtensions(HttpServletRequest request) {

    try {
      String samlRequest = request.getParameter(SSOConstants.HTTP_POST_PARAM_SAML2_AUTH_REQ);
      if (samlRequest == null) {
        samlRequest = (String) request.getAttribute(SSOConstants.HTTP_POST_PARAM_SAML2_AUTH_REQ);
      }

      if (samlRequest != null) {
        XMLObject xmlObject;
        if (SSOConstants.HTTP_POST.equals(request.getMethod())) {
          xmlObject = unmarshall(SSOUtils.decodeForPost(samlRequest));
        } else {
          xmlObject = unmarshall(SSOUtils.decode(samlRequest));
        }
        if (xmlObject instanceof AuthnRequest) {
          AuthnRequest authnRequest = (AuthnRequest) xmlObject;
          Extensions oldExtensions = authnRequest.getExtensions();
          if (oldExtensions != null) {
            ExtensionsBuilder extBuilder = new ExtensionsBuilder();
            Extensions extensions =
                extBuilder.buildObject(
                    SAMLConstants.SAML20P_NS, Extensions.LOCAL_NAME, SAMLConstants.SAML20P_PREFIX);
            extensions.setDOM(oldExtensions.getDOM());
            return extensions;
          }
        }
      }
    } catch (Exception e) { // TODO IDENTITY-2421
      // ignore
      log.debug("Error while loading SAML Extensions", e);
    }

    return null;
  }
  /**
   * Validate the signature of a SAML2 Response and Assertion
   *
   * @param response SAML2 Response
   * @return true, if signature is valid.
   */
  private void validateSignature(Response response, Assertion assertion) throws SAMLSSOException {

    if (SSOUtils.isAuthnResponseSigned(properties)) {

      if (identityProvider.getCertificate() == null
          || identityProvider.getCertificate().isEmpty()) {
        throw new SAMLSSOException(
            "SAMLResponse signing is enabled, but IdP doesn't have a certificate");
      }

      if (response.getSignature() == null) {
        throw new SAMLSSOException(
            "SAMLResponse signing is enabled, but signature element "
                + "not found in SAML Response element.");
      } else {
        try {
          X509Credential credential =
              new X509CredentialImpl(tenantDomain, identityProvider.getCertificate());
          SignatureValidator validator = new SignatureValidator(credential);
          validator.validate(response.getSignature());
        } catch (ValidationException e) {
          throw new SAMLSSOException("Signature validation failed for SAML Response", e);
        }
      }
    }
    if (SSOUtils.isAssertionSigningEnabled(properties)) {

      if (identityProvider.getCertificate() == null
          || identityProvider.getCertificate().isEmpty()) {
        throw new SAMLSSOException(
            "SAMLAssertion signing is enabled, but IdP doesn't have a certificate");
      }

      if (assertion.getSignature() == null) {
        throw new SAMLSSOException(
            "SAMLAssertion signing is enabled, but signature element "
                + "not found in SAML Assertion element.");
      } else {
        try {
          X509Credential credential =
              new X509CredentialImpl(tenantDomain, identityProvider.getCertificate());
          SignatureValidator validator = new SignatureValidator(credential);
          validator.validate(assertion.getSignature());
        } catch (ValidationException e) {
          throw new SAMLSSOException("Signature validation failed for SAML Assertion", e);
        }
      }
    }
  }
  protected AuthnRequest getAuthnRequest(AuthenticationContext context) throws SAMLSSOException {

    AuthnRequest authnRequest = null;
    AuthenticationRequest authenticationRequest = context.getAuthenticationRequest();
    String[] samlRequestParams =
        authenticationRequest.getRequestQueryParam(SSOConstants.HTTP_POST_PARAM_SAML2_AUTH_REQ);
    String samlRequest = null;
    if (samlRequestParams != null && samlRequestParams.length > 0) {
      samlRequest = samlRequestParams[0];
      XMLObject xmlObject;
      if (authenticationRequest.isPost()) {
        xmlObject = unmarshall(SSOUtils.decodeForPost(samlRequest));
      } else {
        xmlObject = unmarshall(SSOUtils.decode(samlRequest));
      }
      if (xmlObject instanceof AuthnRequest) {
        authnRequest = (AuthnRequest) xmlObject;
      }
    }
    return authnRequest;
  }
  private LogoutRequest buildLogoutRequest(
      String user,
      String sessionIndexStr,
      String idpUrl,
      String nameQualifier,
      String spNameQualifier)
      throws SAMLSSOException {

    LogoutRequest logoutReq = new LogoutRequestBuilder().buildObject();

    logoutReq.setID(SSOUtils.createID());
    logoutReq.setDestination(idpUrl);

    DateTime issueInstant = new DateTime();
    logoutReq.setIssueInstant(issueInstant);
    logoutReq.setNotOnOrAfter(new DateTime(issueInstant.getMillis() + 5 * 60 * 1000));

    IssuerBuilder issuerBuilder = new IssuerBuilder();
    Issuer issuer = issuerBuilder.buildObject();

    String spEntityId =
        properties.get(IdentityApplicationConstants.Authenticator.SAML2SSO.SP_ENTITY_ID);

    if (spEntityId != null && !spEntityId.isEmpty()) {
      issuer.setValue(spEntityId);
    } else {
      issuer.setValue("carbonServer");
    }

    logoutReq.setIssuer(issuer);

    NameID nameId = new NameIDBuilder().buildObject();
    nameId.setFormat(NameIDType.UNSPECIFIED);
    nameId.setValue(user);
    nameId.setNameQualifier(nameQualifier);
    nameId.setSPNameQualifier(spNameQualifier);
    logoutReq.setNameID(nameId);

    SessionIndex sessionIndex = new SessionIndexBuilder().buildObject();

    if (sessionIndexStr != null) {
      sessionIndex.setSessionIndex(sessionIndexStr);
    } else {
      sessionIndex.setSessionIndex(UUID.randomUUID().toString());
    }

    logoutReq.getSessionIndexes().add(sessionIndex);
    logoutReq.setReason("Single Logout");

    return logoutReq;
  }
  private AuthnRequest buildAuthnRequest(
      HttpServletRequest request, boolean isPassive, String idpUrl, AuthenticationContext context)
      throws SAMLSSOException {

    IssuerBuilder issuerBuilder = new IssuerBuilder();
    Issuer issuer =
        issuerBuilder.buildObject("urn:oasis:names:tc:SAML:2.0:assertion", "Issuer", "samlp");

    String spEntityId =
        properties.get(IdentityApplicationConstants.Authenticator.SAML2SSO.SP_ENTITY_ID);

    if (spEntityId != null && !spEntityId.isEmpty()) {
      issuer.setValue(spEntityId);
    } else {
      issuer.setValue("carbonServer");
    }

    DateTime issueInstant = new DateTime();

    /* Creation of AuthRequestObject */
    AuthnRequestBuilder authRequestBuilder = new AuthnRequestBuilder();
    AuthnRequest authRequest =
        authRequestBuilder.buildObject(
            "urn:oasis:names:tc:SAML:2.0:protocol", "AuthnRequest", "samlp");
    authRequest.setForceAuthn(isForceAuthenticate(context));
    authRequest.setIsPassive(isPassive);
    authRequest.setIssueInstant(issueInstant);

    String includeProtocolBindingProp =
        properties.get(
            IdentityApplicationConstants.Authenticator.SAML2SSO.INCLUDE_PROTOCOL_BINDING);
    if (StringUtils.isEmpty(includeProtocolBindingProp)
        || Boolean.parseBoolean(includeProtocolBindingProp)) {
      authRequest.setProtocolBinding(SAMLConstants.SAML2_POST_BINDING_URI);
    }

    String acsUrl = IdentityUtil.getServerURL(FrameworkConstants.COMMONAUTH);

    authRequest.setAssertionConsumerServiceURL(acsUrl);
    authRequest.setIssuer(issuer);
    authRequest.setID(SSOUtils.createID());
    authRequest.setVersion(SAMLVersion.VERSION_20);
    authRequest.setDestination(idpUrl);

    String attributeConsumingServiceIndexProp =
        properties.get(
            IdentityApplicationConstants.Authenticator.SAML2SSO.ATTRIBUTE_CONSUMING_SERVICE_INDEX);
    if (StringUtils.isNotEmpty(attributeConsumingServiceIndexProp)) {
      try {
        authRequest.setAttributeConsumingServiceIndex(
            Integer.valueOf(attributeConsumingServiceIndexProp));
      } catch (NumberFormatException e) {
        log.error(
            "Error while populating SAMLRequest with AttributeConsumingServiceIndex: "
                + attributeConsumingServiceIndexProp,
            e);
      }
    }

    String includeNameIDPolicyProp =
        properties.get(IdentityApplicationConstants.Authenticator.SAML2SSO.INCLUDE_NAME_ID_POLICY);
    if (StringUtils.isEmpty(includeNameIDPolicyProp)
        || Boolean.parseBoolean(includeNameIDPolicyProp)) {
      NameIDPolicyBuilder nameIdPolicyBuilder = new NameIDPolicyBuilder();
      NameIDPolicy nameIdPolicy = nameIdPolicyBuilder.buildObject();
      nameIdPolicy.setFormat(NameIDType.UNSPECIFIED);
      // nameIdPolicy.setSPNameQualifier("Issuer");
      nameIdPolicy.setAllowCreate(true);
      authRequest.setNameIDPolicy(nameIdPolicy);
    }

    // Get the inbound SAMLRequest
    AuthnRequest inboundAuthnRequest = getAuthnRequest(context);

    RequestedAuthnContext requestedAuthnContext = buildRequestedAuthnContext(inboundAuthnRequest);
    if (requestedAuthnContext != null) {
      authRequest.setRequestedAuthnContext(requestedAuthnContext);
    }

    Extensions extensions = getSAMLExtensions(request);
    if (extensions != null) {
      authRequest.setExtensions(extensions);
    }

    return authRequest;
  }
  private void processSSOResponse(HttpServletRequest request) throws SAMLSSOException {

    Response samlResponse =
        (Response)
            unmarshall(
                new String(
                    Base64.decode(request.getParameter(SSOConstants.HTTP_POST_PARAM_SAML2_RESP))));

    Assertion assertion = null;

    if (SSOUtils.isAssertionEncryptionEnabled(properties)) {
      List<EncryptedAssertion> encryptedAssertions = samlResponse.getEncryptedAssertions();
      EncryptedAssertion encryptedAssertion = null;
      if (CollectionUtils.isNotEmpty(encryptedAssertions)) {
        encryptedAssertion = encryptedAssertions.get(0);
        try {
          assertion = getDecryptedAssertion(encryptedAssertion);
        } catch (Exception e) {
          throw new SAMLSSOException("Unable to decrypt the SAML Assertion", e);
        }
      }
    } else {
      List<Assertion> assertions = samlResponse.getAssertions();
      if (CollectionUtils.isNotEmpty(assertions)) {
        assertion = assertions.get(0);
      }
    }

    if (assertion == null) {
      if (samlResponse.getStatus() != null
          && samlResponse.getStatus().getStatusCode() != null
          && samlResponse
              .getStatus()
              .getStatusCode()
              .getValue()
              .equals(SSOConstants.StatusCodes.IDENTITY_PROVIDER_ERROR)
          && samlResponse.getStatus().getStatusCode().getStatusCode() != null
          && samlResponse
              .getStatus()
              .getStatusCode()
              .getStatusCode()
              .getValue()
              .equals(SSOConstants.StatusCodes.NO_PASSIVE)) {
        return;
      }
      throw new SAMLSSOException("SAML Assertion not found in the Response");
    }

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

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

    request.getSession().setAttribute("username", subject); // get the subject
    nameQualifier = assertion.getSubject().getNameID().getNameQualifier();
    spNameQualifier = assertion.getSubject().getNameID().getSPNameQualifier();

    // validate audience restriction
    validateAudienceRestriction(assertion);

    // validate signature this SP only looking for assertion signature
    validateSignature(samlResponse, assertion);

    request.getSession(false).setAttribute("samlssoAttributes", getAssertionStatements(assertion));

    // For removing the session when the single sign out request made by the SP itself
    if (SSOUtils.isLogoutEnabled(properties)) {
      String sessionId = assertion.getAuthnStatements().get(0).getSessionIndex();
      if (sessionId == null) {
        throw new SAMLSSOException(
            "Single Logout is enabled but IdP Session ID not found in SAML Assertion");
      }
      request.getSession().setAttribute(SSOConstants.IDP_SESSION, sessionId);
      request.getSession().setAttribute(SSOConstants.LOGOUT_USERNAME, nameQualifier);
      request.getSession().setAttribute(SSOConstants.SP_NAME_QUALIFIER, spNameQualifier);
    }
  }
  /**
   * @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));
  }
  /**
   * 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;
  }