/**
   * Method engineCanResolve
   *
   * @param element
   * @param BaseURI
   * @param storage
   * @return
   */
  public boolean engineCanResolve(Element element, String BaseURI, StorageResolver storage) {

    cat.debug("Can I resolve " + element.getTagName());

    if (element == null) {
      return false;
    }

    boolean isKeyValue = XMLUtils.elementIsInSignatureSpace(element, Constants._TAG_KEYVALUE);
    boolean isRSAKeyValue = XMLUtils.elementIsInSignatureSpace(element, Constants._TAG_RSAKEYVALUE);

    if (isKeyValue) {
      try {
        Element nscontext =
            XMLUtils.createDSctx(element.getOwnerDocument(), "ds", Constants.SignatureSpecNS);

        this._rsaKeyElement =
            (Element)
                XPathAPI.selectSingleNode(element, "./ds:" + Constants._TAG_RSAKEYVALUE, nscontext);

        if (this._rsaKeyElement != null) {
          return true;
        }
      } catch (TransformerException ex) {
      }
    } else if (isRSAKeyValue) {

      // this trick is needed to allow the RetrievalMethodResolver to eat a
      // ds:RSAKeyValue directly (without KeyValue)
      this._rsaKeyElement = element;

      return true;
    }

    return false;
  }
  /**
   * Verifies signatures in entity descriptor represented by the <code>Document</code>.
   *
   * @param doc The document.
   * @throws SAML2MetaException if unable to verify the entity descriptor.
   */
  public static void verifySignature(Document doc) throws SAML2MetaException {
    NodeList sigElements = null;
    try {
      Element nscontext =
          org.apache.xml.security.utils.XMLUtils.createDSctx(doc, "ds", Constants.SignatureSpecNS);
      sigElements = XPathAPI.selectNodeList(doc, "//ds:Signature", nscontext);
    } catch (Exception ex) {
      if (debug.messageEnabled()) {
        debug.message("SAML2MetaSecurityUtils.verifySignature:", ex);
        throw new SAML2MetaException(ex.getMessage());
      }
    }
    int numSigs = sigElements.getLength();
    if (debug.messageEnabled()) {
      debug.message("SAML2MetaSecurityUtils.verifySignature:" + " # of signatures = " + numSigs);
    }

    if (numSigs == 0) {
      return;
    }

    // If there are signatures then explicitly identify the ID Attribute, See comments section of
    // http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8017265
    doc.getDocumentElement().setIdAttribute(SAML2Constants.ID, true);

    initializeKeyStore();

    for (int i = 0; i < numSigs; i++) {
      Element sigElement = (Element) sigElements.item(i);
      String sigParentName = sigElement.getParentNode().getLocalName();
      Object[] objs = {sigParentName};
      if (debug.messageEnabled()) {
        debug.message(
            "SAML2MetaSecurityUtils.verifySignature: "
                + "verifying signature under "
                + sigParentName);
      }

      try {
        XMLSignature signature = new XMLSignature(sigElement, "");
        signature.addResourceResolver(new com.sun.identity.saml.xmlsig.OfflineResolver());
        KeyInfo ki = signature.getKeyInfo();

        X509Certificate x509cert = null;
        if (ki != null && ki.containsX509Data()) {
          if (keyStore != null) {
            StorageResolver sr = new StorageResolver(new KeyStoreResolver(keyStore));
            ki.addStorageResolver(sr);
          }
          x509cert = ki.getX509Certificate();
        }

        if (x509cert == null) {
          if (debug.messageEnabled()) {
            debug.message(
                "SAML2MetaSecurityUtils.verifySignature:" + " try to find cert in KeyDescriptor");
          }
          String xpath =
              "following-sibling::*[local-name()=\""
                  + TAG_KEY_DESCRIPTOR
                  + "\" and namespace-uri()=\""
                  + NS_META
                  + "\"]";
          Node node = XPathAPI.selectSingleNode(sigElement, xpath);

          if (node != null) {
            Element kd = (Element) node;
            String use = kd.getAttributeNS(null, ATTR_USE);
            if ((use.length() == 0) || use.equals("signing")) {
              NodeList nl = kd.getChildNodes();
              for (int j = 0; j < nl.getLength(); j++) {
                Node child = nl.item(j);
                if (child.getNodeType() == Node.ELEMENT_NODE) {
                  String localName = child.getLocalName();
                  String ns = child.getNamespaceURI();
                  if (TAG_KEY_INFO.equals(localName) && NS_XMLSIG.equals(ns)) {

                    ki = new KeyInfo((Element) child, "");
                    if (ki.containsX509Data()) {
                      if (keyStore != null) {
                        KeyStoreResolver ksr = new KeyStoreResolver(keyStore);
                        StorageResolver sr = new StorageResolver(ksr);
                        ki.addStorageResolver(sr);
                      }

                      x509cert = ki.getX509Certificate();
                    }
                  }
                  break;
                }
              }
            }
          }
        }

        if (x509cert == null) {
          throw new SAML2MetaException("verify_no_cert", objs);
        }

        if (checkCert
            && ((keyProvider == null) || (keyProvider.getCertificateAlias(x509cert) == null))) {
          throw new SAML2MetaException("untrusted_cert", objs);
        }

        PublicKey pk = x509cert.getPublicKey();

        if (!signature.checkSignatureValue(pk)) {
          throw new SAML2MetaException("verify_fail", objs);
        }
      } catch (SAML2MetaException sme) {
        throw sme;
      } catch (Exception ex) {
        debug.error("SAML2MetaSecurityUtils.verifySignature: ", ex);
        throw new SAML2MetaException(
            Locale.getString(SAML2MetaUtils.resourceBundle, "verify_fail", objs)
                + "\n"
                + ex.getMessage());
      }
    }
  }