/**
   * Creates a {@code KeyValueType} that wraps the specified public key. This method supports DSA
   * and RSA keys.
   *
   * @param key the {@code PublicKey} that will be represented as a {@code KeyValueType}.
   * @return the constructed {@code KeyValueType} or {@code null} if the specified key is neither a
   *     DSA nor a RSA key.
   */
  public static KeyValueType createKeyValue(PublicKey key) {
    if (key instanceof RSAPublicKey) {
      RSAPublicKey pubKey = (RSAPublicKey) key;
      byte[] modulus = pubKey.getModulus().toByteArray();
      byte[] exponent = pubKey.getPublicExponent().toByteArray();

      RSAKeyValueType rsaKeyValue = new RSAKeyValueType();
      rsaKeyValue.setModulus(Base64.encodeBytes(modulus).getBytes());
      rsaKeyValue.setExponent(Base64.encodeBytes(exponent).getBytes());
      return rsaKeyValue;
    } else if (key instanceof DSAPublicKey) {
      DSAPublicKey pubKey = (DSAPublicKey) key;
      byte[] P = pubKey.getParams().getP().toByteArray();
      byte[] Q = pubKey.getParams().getQ().toByteArray();
      byte[] G = pubKey.getParams().getG().toByteArray();
      byte[] Y = pubKey.getY().toByteArray();

      DSAKeyValueType dsaKeyValue = new DSAKeyValueType();
      dsaKeyValue.setP(Base64.encodeBytes(P).getBytes());
      dsaKeyValue.setQ(Base64.encodeBytes(Q).getBytes());
      dsaKeyValue.setG(Base64.encodeBytes(G).getBytes());
      dsaKeyValue.setY(Base64.encodeBytes(Y).getBytes());
      return dsaKeyValue;
    }
    throw logger.unsupportedType(key.toString());
  }
  public void verifyRedirectBindingSignature(PublicKey publicKey, String paramKey)
      throws VerificationException {
    String request = facade.getRequest().getQueryParamValue(paramKey);
    String algorithm =
        facade.getRequest().getQueryParamValue(GeneralConstants.SAML_SIG_ALG_REQUEST_KEY);
    String signature =
        facade.getRequest().getQueryParamValue(GeneralConstants.SAML_SIGNATURE_REQUEST_KEY);
    String decodedAlgorithm =
        facade.getRequest().getQueryParamValue(GeneralConstants.SAML_SIG_ALG_REQUEST_KEY);

    if (request == null) {
      throw new VerificationException("SAML Request was null");
    }
    if (algorithm == null) throw new VerificationException("SigAlg was null");
    if (signature == null) throw new VerificationException("Signature was null");

    // Shibboleth doesn't sign the document for redirect binding.
    // todo maybe a flag?

    String relayState = facade.getRequest().getQueryParamValue(GeneralConstants.RELAY_STATE);
    KeycloakUriBuilder builder = KeycloakUriBuilder.fromPath("/").queryParam(paramKey, request);
    if (relayState != null) {
      builder.queryParam(GeneralConstants.RELAY_STATE, relayState);
    }
    builder.queryParam(GeneralConstants.SAML_SIG_ALG_REQUEST_KEY, algorithm);
    String rawQuery = builder.build().getRawQuery();

    try {
      // byte[] decodedSignature = RedirectBindingUtil.urlBase64Decode(signature);
      byte[] decodedSignature = Base64.decode(signature);

      SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.getFromXmlMethod(decodedAlgorithm);
      Signature validator = signatureAlgorithm.createSignature(); // todo plugin signature alg
      validator.initVerify(publicKey);
      validator.update(rawQuery.getBytes("UTF-8"));
      if (!validator.verify(decodedSignature)) {
        throw new VerificationException("Invalid query param signature");
      }
    } catch (Exception e) {
      throw new VerificationException(e);
    }
  }