public static SAMLConfiguration getInstance(boolean noInit) {
    if (logger.isDebugEnabled()) {
      logger.debug("getInstance(String, boolean) - start"); // $NON-NLS-1$
    }

    if (instance == null) {
      instance = new SAMLConfiguration();
    }

    instance.setNoInit(noInit);

    if (logger.isDebugEnabled()) {
      logger.debug("getInstance(String, boolean) - end"); // $NON-NLS-1$
    }
    return instance;
  }
  /**
   * @param SAMLToken - SAML Assertion XML
   * @param contextAttributeName - SAML Attribute name containing Context data
   * @param verfiySignature
   * @return a base64 encoded string containing the context
   * @throws SAMLValidationException - if validation fails
   */
  public static List<AttributeStatement> validate(byte[] SAMLToken, SAMLConfiguration samlConfig)
      throws SAMLValidationException {
    if (logger.isDebugEnabled()) {
      logger.debug("validate(byte[], SAMLConfiguration) - start"); // $NON-NLS-1$
    }

    Decrypter samlDecrypter = samlConfig.getSamlDecrypter();
    SignatureTrustEngine sigTrustEngine = samlConfig.getTrustEngine();
    String myURI = samlConfig.getMyURI();
    MessageReplayRule replayRule = samlConfig.getReplayRule();

    BasicParserPool ppMgr = new BasicParserPool();
    ppMgr.setNamespaceAware(true);

    VerifySignatureType verfiySignature = samlConfig.getVerifySignature();

    List<AttributeStatement> attrStatements = null;
    if (SAMLToken != null) {
      try {

        InputStream in = new ByteArrayInputStream(SAMLToken);
        Document SAMLDoc;
        try {
          SAMLDoc = ppMgr.parse(in);
        } catch (XMLParserException e) {
          logger.error(
              "validate(byte[], String, Decrypter, SignatureTrustEngine, String, MessageReplayRule, ParserPool, VerifySignatureType)",
              e); //$NON-NLS-1$

          throw createSAMLValidationException("Error parsing SAML XML", true, e);
        }
        Element responseElement = SAMLDoc.getDocumentElement();

        SAMLType samlType = SAMLType.Response;
        if (responseElement == null) {
          throw createSAMLValidationException(
              "Missing SAML Encrypted Assertion or Assertion or Assertion Response", true);
        }
        if (!"Response".equals(responseElement.getLocalName())
            || !SAMLConstants.SAML20P_NS.equals(responseElement.getNamespaceURI())) {
          if (!"Assertion".equals(responseElement.getLocalName())
              || !SAMLConstants.SAML20_NS.equals(responseElement.getNamespaceURI())) {
            if (!"EncryptedAssertion".equals(responseElement.getLocalName())
                || !SAMLConstants.SAML20_NS.equals(responseElement.getNamespaceURI())) {
              throw createSAMLValidationException(
                  "Missing or invalid SAML Encrypted Assertion or Assertion or Assertion Response",
                  true);
            } else {
              samlType = SAMLType.EncryptedAssertion;
            }
          } else {
            samlType = SAMLType.Assertion;
          }
        } else {
          samlType = SAMLType.Response;
        }

        if (samlType == SAMLType.Response) {
          // Unmarshall SAML Assertion Response into an OpenSAML Java object.
          UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory();
          Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(responseElement);
          Response samlResponse;
          try {
            samlResponse = (Response) unmarshaller.unmarshall(responseElement);
          } catch (UnmarshallingException e) {
            logger.error(
                "validate(byte[], String, Decrypter, SignatureTrustEngine, String, MessageReplayRule, ParserPool, VerifySignatureType)",
                e); //$NON-NLS-1$

            throw createSAMLValidationException(
                "Error in unmarshalling SAML XML Document", true, e);
          }

          // Check the replay attack for Response
          if (replayRule != null) {
            BasicSAMLMessageContext messageContext = new BasicSAMLMessageContext();
            // messageContext.setInboundMessage(samlResponse);
            if (samlResponse.getIssuer() != null)
              messageContext.setInboundMessageIssuer(samlResponse.getIssuer().getValue());
            messageContext.setInboundSAMLMessageId(samlResponse.getID());

            try {
              replayRule.evaluate(messageContext);
            } catch (SecurityPolicyException e) {
              logger.error(
                  "validate(byte[], String, Decrypter, SignatureTrustEngine, String, MessageReplayRule, ParserPool, VerifySignatureType)",
                  e); //$NON-NLS-1$

              throw createSAMLValidationException("Possible Replay Attack for Response", false, e);
            }
          }

          // Validate the status code
          if (!StatusCode.SUCCESS_URI.equals(samlResponse.getStatus().getStatusCode().getValue())) {
            throw createSAMLValidationException("Invalid Status Code.", true);
          }

          boolean responseSignatureVerified =
              validateResponseSignature(samlResponse, sigTrustEngine, verfiySignature);

          // Get first encrypted Assertion, if not present get first unencrypted assertion
          int assertCount = samlResponse.getEncryptedAssertions().size();
          if (assertCount == 0) {
            assertCount = samlResponse.getAssertions().size();
            if (assertCount == 0) {
              throw createSAMLValidationException(
                  "No Assertion or EncryptedAssertion found in received response", true);
            } else {
              for (Assertion samlAssertion : samlResponse.getAssertions()) {
                attrStatements =
                    validateAssertion(
                        samlAssertion,
                        sigTrustEngine,
                        myURI,
                        replayRule,
                        verfiySignature,
                        responseSignatureVerified);
                break; // Use the first only
              }
            }
          } else {
            for (EncryptedAssertion samlEncryptedAssertion :
                samlResponse.getEncryptedAssertions()) {

              // Decryption

              Assertion samlAssertion = null;
              try {
                samlAssertion = samlDecrypter.decrypt(samlEncryptedAssertion);
              } catch (DecryptionException e) {
                logger.error(
                    "validate(byte[], String, Decrypter, SignatureTrustEngine, String, MessageReplayRule, ParserPool, VerifySignatureType)",
                    e); //$NON-NLS-1$

                throw createSAMLValidationException(
                    "Error Decrypting Received Encrypted Assertion", true, e);
              }
              attrStatements =
                  validateAssertion(
                      samlAssertion,
                      sigTrustEngine,
                      myURI,
                      replayRule,
                      verfiySignature,
                      responseSignatureVerified);

              break; // Use the first only
            }
          }
        } else if (samlType == SAMLType.EncryptedAssertion) {
          // Unmarshall SAML Encrypted Assertion into an OpenSAML Java object.
          UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory();
          Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(responseElement);
          EncryptedAssertion encryptedAssertion = null;
          try {
            encryptedAssertion = (EncryptedAssertion) unmarshaller.unmarshall(responseElement);
          } catch (UnmarshallingException e) {
            logger.error(
                "validate(byte[], String, Decrypter, SignatureTrustEngine, String, MessageReplayRule, ParserPool, VerifySignatureType)",
                e); //$NON-NLS-1$

            throw createSAMLValidationException(
                "Error in unmarshalling SAML XML Document", true, e);
          }

          boolean responseSignatureVerified = false;

          // Decryption

          Assertion samlAssertion = null;
          try {
            samlAssertion = samlDecrypter.decrypt(encryptedAssertion);
          } catch (DecryptionException e) {
            logger.error(
                "validate(byte[], String, Decrypter, SignatureTrustEngine, String, MessageReplayRule, ParserPool, VerifySignatureType)",
                e); //$NON-NLS-1$

            throw createSAMLValidationException(
                "Error Decrypting Received Encrypted Assertion", true, e);
          }

          attrStatements =
              validateAssertion(
                  samlAssertion,
                  sigTrustEngine,
                  myURI,
                  replayRule,
                  verfiySignature,
                  responseSignatureVerified);
        } else if (samlType == SAMLType.Assertion) {
          // Unmarshall SAML Assertion  into an OpenSAML Java object.
          UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory();
          Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(responseElement);
          Assertion samlAssertion = null;
          try {
            samlAssertion = (Assertion) unmarshaller.unmarshall(responseElement);
          } catch (UnmarshallingException e) {
            logger.error(
                "validate(byte[], String, Decrypter, SignatureTrustEngine, String, MessageReplayRule, ParserPool, VerifySignatureType)",
                e); //$NON-NLS-1$

            throw createSAMLValidationException(
                "Error in unmarshalling SAML XML Document", true, e);
          }

          boolean responseSignatureVerified = false;

          attrStatements =
              validateAssertion(
                  samlAssertion,
                  sigTrustEngine,
                  myURI,
                  replayRule,
                  verfiySignature,
                  responseSignatureVerified);
        }
      } catch (SAMLValidationException e) {
        throw e;
      }
    }

    if (logger.isDebugEnabled()) {
      logger.debug(
          "validate(byte[], String, Decrypter, SignatureTrustEngine, String, MessageReplayRule, ParserPool, VerifySignatureType) - end"); //$NON-NLS-1$
    }
    return attrStatements;
  }