XML签名Cannot resolve element with ID XXXX 解决方案
最近同银行做接口联调,需要对XML文件做加签和解签操作,本地的开发环境是Mac 10.10,JDK的版本是1.6.0.65。小小的一段加签代码,一直报错,却久久也找不到解决方法,网上的资料非常少,错误记录如下:
javax.xml.crypto.URIReferenceException: com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID FIQReq
Exception in thread "main" java.lang.RuntimeException: javax.xml.crypto.dsig.XMLSignatureException: javax.xml.crypto.URIReferenceException: com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID FIQReq
at util.xml.XMLSigner.sign(XMLSigner.java:111)
at test.TestSign.main(TestSign.java:34)
Caused by: javax.xml.crypto.dsig.XMLSignatureException: javax.xml.crypto.URIReferenceException: com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID FIQReq
at org.jcp.xml.dsig.internal.dom.DOMReference.dereference(DOMReference.java:412)
at org.jcp.xml.dsig.internal.dom.DOMReference.digest(DOMReference.java:338)
at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.digestReference(DOMXMLSignature.java:471)
at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.sign(DOMXMLSignature.java:367)
at util.xml.XMLSigner.sign(XMLSigner.java:108)
... 1 more
Caused by: javax.xml.crypto.URIReferenceException: com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID FIQReq
at org.jcp.xml.dsig.internal.dom.DOMURIDereferencer.dereference(DOMURIDereferencer.java:124)
at org.jcp.xml.dsig.internal.dom.DOMReference.dereference(DOMReference.java:404)
... 5 more
Caused by: com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID FIQReq
at com.sun.org.apache.xml.internal.security.utils.resolver.implementations.ResolverFragment.engineResolve(ResolverFragment.java:90)
at com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolver.resolve(ResourceResolver.java:283)
at org.jcp.xml.dsig.internal.dom.DOMURIDereferencer.dereference(DOMURIDereferencer.java:117)
... 6 more
唯一一个说的比较对的上的就是这篇Bug记录了:http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8017171
产生该问题的原因就是无法根据XML文档节点的ID属性定位到对应的节点,所以在加签的时候会提示不能解析该ID,那么怎样才能让他可以根据我节点的ID,解析并定位到对应的节点呢,让我们先看下我项目中的代码:
首先是要进行加签的XML文件:
<?xml version="1.0" encoding="UTF-8"?>
<SoEv>
<Message id="54b8db6c24574e23423********">
<FIQReq id="FIQReq">
<version>1.0.1</version>
<instId>9550811********</instId>
<certId>0001</certId>
<channelDate>20150608</channelDate>
<beginPos>0</beginPos>
<pageNum>10</pageNum>
</FIQReq>
</Message>
</SoEv>
加签的代码:
public void sign(Document doc, PrivateKey privateKey, String referenceId, Node signNode) {
if(!isInit){
throw new RuntimeException("XMLSigner is not init !");
}
try{
//创建 <Reference> 元素,引用指定ID的节点,<Signature> 元素不会被计算在内
Reference refToRootDoc = signFactory.newReference("#"+referenceId,
sha1DigMethod, Collections.singletonList(envelopedTransform), null, null);
//创建 <SignedInfo> 元素
SignedInfo signedInfo = signFactory.newSignedInfo(c14nWithCommentMethod,
rsa_sha1SigMethod, Collections.singletonList(refToRootDoc));
//创建签名实例
XMLSignature signature = signFactory.newXMLSignature(signedInfo, null);
//创建签名上下文,在指定节点生成
DOMSignContext dsc = new DOMSignContext(privateKey, signNode);
//设置签名域命名空间前缀
if (defaultNamespacePrefix != null) {
dsc.setDefaultNamespacePrefix(defaultNamespacePrefix); }
//签名
signature.sign(dsc);
}catch(Exception e){
System.out.println(e.getMessage());
throw new RuntimeException(e);
}
}
方法外传入需要做加签处理的XML文档树,私钥,需要加签节点的ID,这里就是上面XML中的FIQReq节点的ID内容(FIQReq),还有一个节点就是加签所生成的SignedInfo的父元素,也就是要把SignedInfo节点写在那个节点下面。
这样执行这段代码就会报如上所示的错误代码。
在上面介绍的http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8017171中,有这样三条解决建议:
There are 3 potential workarounds that you can apply: 1. Use a validating schema which will register the elements with ID references. 2. Register the ID elements with the DOMValidateContext.setIdAttributeNS method before validating the signature 3. Implement a custom URIDereferencer which can find these references and override the builtin URIDereferencer with the DOMValidateContext.setURIDereferencer method.
但是看起来还不是特别直观不能一下子解决该问题。但是给出了解决问题的方向,而我解决该问题的着眼点就在于第二条:
2. Register the ID elements with the DOMValidateContext.setIdAttributeNS method before validating the signature
上面介绍的加签代码虽然没有DOMValidateContext对象的参与,但是有DOMSignContext,他也有setIdAttributeNS方法,所以我们就是要在这个方法上做文章:
在上面的加签代码上加入如下两条代码即可解决该问题:
Element element = (Element)doc.getElementsByTagName(referenceId).item(0);
dsc.setIdAttributeNS(element, null, "id");
加入这两行代码后的整体代码变为:
/**
* XML签名
* <p>签名使用内嵌方式,生成在指定节点</p>
* @param doc XML文档
* @param privateKey 私钥
* @param referenceId 需签名的元素标识
* @param signNode 生成签名的节点
*/
public void sign(Document doc, PrivateKey privateKey, String referenceId, Node signNode) {
if(!isInit){
throw new RuntimeException("XMLSigner is not init !");
}
try{
//创建 <Reference> 元素,引用指定ID的节点,<Signature> 元素不会被计算在内
Reference refToRootDoc = signFactory.newReference("#"+referenceId,
sha1DigMethod, Collections.singletonList(envelopedTransform), null, null);
//创建 <SignedInfo> 元素
SignedInfo signedInfo = signFactory.newSignedInfo(c14nWithCommentMethod,
rsa_sha1SigMethod, Collections.singletonList(refToRootDoc));
//创建签名实例
XMLSignature signature = signFactory.newXMLSignature(signedInfo, null);
//创建签名上下文,在指定节点生成
DOMSignContext dsc = new DOMSignContext(privateKey, signNode);
//设置签名域命名空间前缀
if (defaultNamespacePrefix != null) {
dsc.setDefaultNamespacePrefix(defaultNamespacePrefix);
Element element = (Element)doc.getElementsByTagName(referenceId).item(0);
dsc.setIdAttributeNS(element, null, "id");
}
//签名
signature.sign(dsc);
}catch(Exception e){
System.out.println(e.getMessage());
throw new RuntimeException(e);
}
}
再次运行程序后,问题解决。
具体的加签操作指导,详见如下文档:
http://www.apihome.cn/api/java/XMLSignatureFactory.html(中文)
http://docs.oracle.com/javase/6/docs/technotes/guides/security/xmldsig/XMLDigitalSignature.html(英文,但是介绍的更详细,直接拷贝出来即可)
XML签名Cannot resolve element with ID XXXX 解决方案的更多相关文章
- [Fatal Error] :3:13: Open quote is expected for attribute "{1}" associated with an element type "id".
用DOM解析XML时出现了如下错误: [Fatal Error] :3:13: Open quote is expected for attribute "{1}" associa ...
- 【Java密码学】XML签名
http://www.oracle.com/technetwork/articles/javase/dig-signature-api-140772.html XML签名的结构和类型 基本上XML签名 ...
- XML签名
英文:https://www.javacodegeeks.com/2013/10/xml-security-with-digital-signature-in-java.html 中文:http:// ...
- mybatis mapper xml文件配置resultmap时,id行和result行有什么区别?
mybatis mapper xml文件配置resultmap时,id行和result行有什么区别? <resultMap id = "CashInvoiceMap" typ ...
- org.apache.shiro.session.UnknownSessionException: There is no session with id [xxxx]的解决方案
org.apache.shiro.session.UnknownSessionException: There is no session with id [xxxx]的解决方案 背景描述 Sprin ...
- Error parsing XML: junk after document element这样的错误 - CSDN博客
很多开发者可能在编写XML布局文件时提示Error parsing XML: junk after document element这样的错误,这里Android123提示大家一般合法的XML文件只有 ...
- 【RF库XML测试】Get Element
Name:Get ElementSource:XML <test library>Arguments:[ source | xpath=. ]Returns an element in t ...
- xml DTD中的ELEMENT和ATTLIST
是W3C的一个文档类型定义规则文件,是用来让浏览器根据你定义的DTD(文档类型定义)来解释页面代码的. doctype声明指出阅读程序应该用什么规则集来解释文档中的标记.在Web文档的情况下,“阅读程 ...
- javax.servlet.ServletException: Could not resolve view with name‘ XXXX’in servlet with name 'spring'的解决方案-----SKY
出现的异常如下: javax.servlet.ServletException: Could not resolve view with name '{"msg":"成功 ...
随机推荐
- hbase 修复 hbck
hbase 修复使用hbck 新版本的 hbck 可以修复各种错误,修复选项是: (1)-fix,向下兼容用,被-fixAssignments替代 (2)-fixAssignments,用于修复reg ...
- “Hello World!”团队第六周的第二次会议
今天是我们团队“Hello World!”团队第六周召开的第二次会议.博客内容: 一.会议时间 二.会议地点 三.会议成员 四.会议内容 五.todo list 六.会议照片 七.燃尽图 八.代码 一 ...
- 福大软工1816:Beta(7/7)
Beta 冲刺 (7/7) 队名:第三视角 组长博客链接 本次作业链接 团队部分 团队燃尽图 工作情况汇报 张扬(组长) 过去两天完成了哪些任务 文字/口头描述 组织会议 wxpy中多个功能的开发 整 ...
- iOS界面设计之基础控件的学习 --- UITextField
学习iOS界面设计也有段时间了,每次写到一些基础控件(如:UILable . UITextField)的时候就深觉应该总结一个函数来实现这些基础控件的属性设置,所以下面就是我对UITextField的 ...
- FreeMarker(XML模板)导出word
在项目中使用它完成的功能是按照固定的模板将数据导出到Word.比如台账.在完成后将处理过程按照台账的要求导出,有时程序中需要实现生成标准Word文档,要求能够打印,并且保持页面样式不变. 这个功能就是 ...
- matlab 图像Mat类型矩阵中的值(uint8)类型转换,防止溢出
a=[50,60,70; 80,90,50; 100,55,40] 假设a是一个灰度图的mat形式(当然实际的size肯定比这大,我只是举例子),如果需要对这个矩阵的像素进行加减处理,很可能会产生溢出 ...
- Delphi编程防止界面卡死的方法经验分享
Delphi编程防止界面卡死的方法经验分享! 1.循环里面防止界面卡死的方法可以使用Application.ProcessMessages: 例如下列方法: var n: Integ ...
- Delphi中的DBGrid控件
在Delphi中,DBGrid控件是一个开发数据库软件不能不使用的控件,其功能非常强大,可以配合SQL语句实现几乎所有数据报表的显示,操作也非常简单,属性.过程.事件等都非常直观,但是使用中,有时侯还 ...
- 【刷题】BZOJ 5248 [2018多省省队联测]一双木棋
Description 菲菲和牛牛在一块n行m列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手.棋局开始时,棋盘上没有任何棋子, 两人轮流在格子上落子,直到填满棋盘时结束.落子的规则是:一个格子可以落子 ...
- Bootstrap 环境安装
下载 Bootstrap 可以从 http://getbootstrap.com/ 上下载 Bootstrap 的最新版本.当点击这个链接时,将看到如下所示的网页: 您会看到两个按钮: Downloa ...