/
XmlDsigXPathTransform.cs
198 lines (175 loc) · 7.08 KB
/
XmlDsigXPathTransform.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.IO;
using System.Xml;
using System.Xml.XPath;
namespace System.Security.Cryptography.Xml
{
// A class representing DSIG XPath Transforms
public class XmlDsigXPathTransform : Transform
{
private readonly Type[] _inputTypes = { typeof(Stream), typeof(XmlNodeList), typeof(XmlDocument) };
private readonly Type[] _outputTypes = { typeof(XmlNodeList) };
private string _xpathexpr;
private XmlDocument _document;
private XmlNamespaceManager _nsm;
public XmlDsigXPathTransform()
{
Algorithm = SignedXml.XmlDsigXPathTransformUrl;
}
public override Type[] InputTypes
{
get { return _inputTypes; }
}
public override Type[] OutputTypes
{
get { return _outputTypes; }
}
public override void LoadInnerXml(XmlNodeList nodeList)
{
// XPath transform is specified by text child of first XPath child
if (nodeList == null)
throw new CryptographicException(SR.Cryptography_Xml_UnknownTransform);
foreach (XmlNode node in nodeList)
{
string prefix = null;
string namespaceURI = null;
XmlElement elem = node as XmlElement;
if (elem != null)
{
if (elem.LocalName == "XPath")
{
_xpathexpr = elem.InnerXml.Trim(null);
XmlNodeReader nr = new XmlNodeReader(elem);
XmlNameTable nt = nr.NameTable;
_nsm = new XmlNamespaceManager(nt);
if (!Utils.VerifyAttributes(elem, (string)null))
{
throw new CryptographicException(SR.Cryptography_Xml_UnknownTransform);
}
// Look for a namespace in the attributes
foreach (XmlAttribute attrib in elem.Attributes)
{
if (attrib.Prefix == "xmlns")
{
prefix = attrib.LocalName;
namespaceURI = attrib.Value;
if (prefix == null)
{
prefix = elem.Prefix;
namespaceURI = elem.NamespaceURI;
}
_nsm.AddNamespace(prefix, namespaceURI);
}
}
break;
}
else
{
throw new CryptographicException(SR.Cryptography_Xml_UnknownTransform);
}
}
}
if (_xpathexpr == null)
throw new CryptographicException(SR.Cryptography_Xml_UnknownTransform);
}
protected override XmlNodeList GetInnerXml()
{
XmlDocument document = new XmlDocument();
XmlElement element = document.CreateElement(null, "XPath", SignedXml.XmlDsigNamespaceUrl);
if (_nsm != null)
{
// Add each of the namespaces as attributes of the element
foreach (string prefix in _nsm)
{
switch (prefix)
{
// Ignore the xml namespaces
case "xml":
case "xmlns":
break;
// Other namespaces
default:
// Ignore the default namespace
if (prefix != null && prefix.Length > 0)
element.SetAttribute("xmlns:" + prefix, _nsm.LookupNamespace(prefix));
break;
}
}
}
// Add the XPath as the inner xml of the element
element.InnerXml = _xpathexpr;
document.AppendChild(element);
return document.ChildNodes;
}
public override void LoadInput(object obj)
{
if (obj is Stream)
{
LoadStreamInput((Stream)obj);
}
else if (obj is XmlNodeList)
{
LoadXmlNodeListInput((XmlNodeList)obj);
}
else if (obj is XmlDocument)
{
LoadXmlDocumentInput((XmlDocument)obj);
}
}
private void LoadStreamInput(Stream stream)
{
XmlResolver resolver = (ResolverSet ? _xmlResolver : XmlResolverHelper.GetThrowingResolver());
XmlReader valReader = Utils.PreProcessStreamInput(stream, resolver, BaseURI);
_document = new XmlDocument();
_document.PreserveWhitespace = true;
_document.Load(valReader);
}
private void LoadXmlNodeListInput(XmlNodeList nodeList)
{
// Use C14N to get a document
XmlResolver resolver = (ResolverSet ? _xmlResolver : XmlResolverHelper.GetThrowingResolver());
CanonicalXml c14n = new CanonicalXml((XmlNodeList)nodeList, resolver, true);
using (MemoryStream ms = new MemoryStream(c14n.GetBytes()))
{
LoadStreamInput(ms);
}
}
private void LoadXmlDocumentInput(XmlDocument doc)
{
_document = doc;
}
public override object GetOutput()
{
CanonicalXmlNodeList resultNodeList = new CanonicalXmlNodeList();
if (!string.IsNullOrEmpty(_xpathexpr))
{
XPathNavigator navigator = _document.CreateNavigator();
XPathNodeIterator it = navigator.Select("//. | //@*");
XPathExpression xpathExpr = navigator.Compile("boolean(" + _xpathexpr + ")");
xpathExpr.SetContext(_nsm);
while (it.MoveNext())
{
XmlNode node = ((IHasXmlNode)it.Current).GetNode();
bool include = (bool)it.Current.Evaluate(xpathExpr);
if (include)
resultNodeList.Add(node);
}
// keep namespaces
it = navigator.Select("//namespace::*");
while (it.MoveNext())
{
XmlNode node = ((IHasXmlNode)it.Current).GetNode();
resultNodeList.Add(node);
}
}
return resultNodeList;
}
public override object GetOutput(Type type)
{
if (type != typeof(XmlNodeList) && !type.IsSubclassOf(typeof(XmlNodeList)))
throw new ArgumentException(SR.Cryptography_Xml_TransformIncorrectInputType, nameof(type));
return (XmlNodeList)GetOutput();
}
}
}