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
相关产品推荐
相关产品推荐

