You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

XML文档(SAML AuthnRequest)签名成功但摘要校验失败求助

SAML AuthnRequest签名验证失败问题

我需要对SAML AuthnRequest类型的XML文档进行签名并Base64编码后发送至服务器,但签名始终无法通过验证。

签名生成代码

public byte[] sign(Document doc, String signatureMethodName, String digestMethodName, boolean useExclusiveCanonization, boolean effectiveSignDocument) throws XMLSignatureException, MarshalException, NoSuchAlgorithmException, SAXException, IOException, ParserConfigurationException, TransformerException {
        XMLSignatureFactory signatureFactory = XMLSignatureFactory.getInstance("DOM");
        KeyInfoFactory keyInfoFactory = signatureFactory.getKeyInfoFactory();
        
        Document deepCopiedDoc = effectiveSignDocument ? null : DocumentLoader.parse(DocumentLoader.stringify(doc, true));
        
        DOMSignContext context = new DOMSignContext(privateKey, effectiveSignDocument ? doc.getDocumentElement() : deepCopiedDoc.getDocumentElement());
        //context.setBaseURI("#" + doc.getDocumentElement().getAttribute("ID"));
        context.setDefaultNamespacePrefix("ds");
        
        Reference reference;
        SignedInfo signedInfo;
        try {
            DigestMethod digestMethod = signatureFactory.newDigestMethod(digestMethodName, null);
            SignatureMethod signatureMethod = signatureFactory.newSignatureMethod(signatureMethodName, null);
            String canonization = useExclusiveCanonization ? CanonicalizationMethod.EXCLUSIVE : CanonicalizationMethod.INCLUSIVE;

            List<Transform> transforms = Arrays.asList(
                    signatureFactory.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null),
                    signatureFactory.newTransform(canonization, (TransformParameterSpec) null)
            );

            reference = signatureFactory.newReference("", digestMethod, transforms, null, null);
            
            signedInfo = signatureFactory
                .newSignedInfo(
                    signatureFactory.newCanonicalizationMethod(canonization, (C14NMethodParameterSpec) null),
                    signatureMethod,
                    Collections.singletonList(reference)
                );
            
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
            return null;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            throw e;
        }
        
        List<X509Data> data = List.of(keyInfoFactory.newX509Data(List.of(certificate)));
        KeyInfo keyInfo = keyInfoFactory.newKeyInfo(data);
                
        XMLSignature signature = signatureFactory.newXMLSignature(signedInfo, keyInfo);
        signature.sign(context);
        
        String signatureValue;
        if(effectiveSignDocument) {
            //NodeList signatureElement = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
            //doc.getDocumentElement().insertBefore(signatureElement.item(0), doc.getDocumentElement().getFirstChild());

            signatureValue = doc.getElementsByTagName("ds:SignatureValue").item(0).getTextContent();
        } else {
            signatureValue = deepCopiedDoc.getElementsByTagName("ds:SignatureValue").item(0).getTextContent();
        }
        
        signatureValue = signatureValue
                .replace("\n", "")
                .replace(" ", "")
                .replace("\r", "");
        
        return Base64.getDecoder().decode(signatureValue);
    }

调用代码

authnRequestDom = fromJaxbToDom(authnRequest);
            //authnRequestDom.normalizeDocument();

            xmlSigner.sign(
                authnRequestDom,
                SignatureMethod.RSA_SHA256,
                DigestMethod.SHA256,
                true,
                true
            );
            
            String samlRequest = Base64.getEncoder().encodeToString(DocumentLoader.stringify(authnRequestDom, true, true).getBytes());

            return new LoginSAMLRequest(authnRequest.getDestination(), samlRequest, relayState);

已尝试的排查动作

  • 使用包含式规范化替代独占式规范化
  • 更改摘要和签名算法组合
  • 调整变换列表顺序/内容

以上尝试均未解决问题,签名仍无法通过验证。

编辑1:验证端确认

通过两款在线XML签名验证工具检测,均返回签名无效结果,确认问题出在签名生成环节,而非服务器验证环节。

编辑2:DocumentLoader.stringify方法代码

public static String stringify(Document doc, boolean minified, boolean headerIsPresent) throws TransformerException {
    StringWriter writer = new StringWriter();
    StreamResult result = new StreamResult(writer);
    Transformer transformer = TransformerFactory.newInstance().newTransformer();

    if (!headerIsPresent) {
        transformer.setOutputProperty(OMIT_XML_DECLARATION, "yes");
    }

    transformer.transform(new DOMSource(doc), result);
    return writer.toString();
}

寻求各位的解决方案建议。


内容的提问来源于stack exchange,提问作者mdeg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 07:14:54