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":"成功 ...
随机推荐
- ES6的新特性(10)——Class 的基本语法
Class 的基本语法 简介 JavaScript 语言中,生成实例对象的传统方法是通过构造函数.下面是一个例子. function Point(x, y) { this.x = x; this.y ...
- win2008 r2 开启TLS1.2
Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityPr ...
- PSP Daily软件Alpha版本——基于NABCD评论,及改进建议
1.根据(不限于)NABCD评论作品的选题: 此软件的用户人群较为明确,即:用户(软件工程课上学生)记录例行报告.写每周PSP表格和统计的需求.潜在用户还有未来该课堂的学生和需要用PSP方法记录任务完 ...
- 关于cnblog.com的用户体验
首先我自己目前是一个学生党,每天在博客园上就上发布一些自己做的东西以及老师布置的作业,还能在上面学习很多别人的一些好的列子,我就希望博客园能够很好地为我们这些学生服务,当我们用它时能够很好地达到我们的 ...
- java调试器
javac.exe是编译.java文件 java.exe是执行编译好的.class文件 javadoc.exe是生成Java说明文档 jdb.exe是Java调试器 javaprof.exe是剖析工具 ...
- Traffic Steering for Service Function Chaining
Introduction 目前通过vlan标签来把流量引向对应的sfc 以前的sfc静态(SFs相邻组成SFC),有了sdn之后具有动态性.(SFs不需要彼此相邻.将流量动态地导向所需的SFs.) 流 ...
- J2EE Oa项目上传服务器出现的乱码解决过程
(= =)搞了许久觉得有必要记下来.. 由于我本地的mysql都设置好了,但是服务器的又不能去改它 毕竟还有其他人要用- -: 所以只能是我建的时候去设置一下了, 首先先建数据库 ,表;; creat ...
- DELL服务器PXE前期处理
thaks:https://www.cnblogs.com/520ZXL/ PXE批量推系统,服务器要具备条件:raid处理好,设置为pxe启动,与PXE服务器网络要通 先进入磁盘阵列(ctrl+R) ...
- QTemporaryDir及QTemporaryFile建立临时目录及文件夹
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QTemporaryDir及QTemporaryFile建立临时目录及文件夹 本文地址 ...
- php中扩展pecl与pear
要为大家分享的内容是PECL 和 PEAR 他们之间的不同和相同之处. PEAR 是“PHP Extension and Application Repository”的缩写,即PHP扩展和应用仓库. ...