1 //
2 // PolicyImportHelper.cs
3 //
4 // Author:
5 //       Martin Baulig <martin.baulig@xamarin.com>
6 //
7 // Copyright (c) 2012 Xamarin Inc. (http://www.xamarin.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining a copy
10 // of this software and associated documentation files (the "Software"), to deal
11 // in the Software without restriction, including without limitation the rights
12 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 // copies of the Software, and to permit persons to whom the Software is
14 // furnished to do so, subject to the following conditions:
15 //
16 // The above copyright notice and this permission notice shall be included in
17 // all copies or substantial portions of the Software.
18 //
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 // THE SOFTWARE.
26 using System;
27 using System.Xml;
28 using System.Collections.Generic;
29 using System.ServiceModel.Description;
30 
31 using QName = System.Xml.XmlQualifiedName;
32 
33 namespace System.ServiceModel.Channels {
34 
35 	internal static class PolicyImportHelper {
36 
37 		internal const string SecurityPolicyNS = "http://schemas.xmlsoap.org/ws/2005/07/securitypolicy";
38 		internal const string PolicyNS = "http://schemas.xmlsoap.org/ws/2004/09/policy";
39 		internal const string MimeSerializationNS = "http://schemas.xmlsoap.org/ws/2004/09/policy/optimizedmimeserialization";
40 		internal const string HttpAuthNS = "http://schemas.microsoft.com/ws/06/2004/policy/http";
41 
42 		internal const string FramingPolicyNS = "http://schemas.microsoft.com/ws/2006/05/framing/policy";
43 		internal const string NetBinaryEncodingNS = "http://schemas.microsoft.com/ws/06/2004/mspolicy/netbinary1";
44 
45 		internal const string WSSecurityNS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";
46 
GetTransportBindingPolicy(PolicyAssertionCollection collection)47 		internal static XmlElement GetTransportBindingPolicy (PolicyAssertionCollection collection)
48 		{
49 			return FindAndRemove (collection, "TransportBinding", SecurityPolicyNS);
50 		}
51 
GetStreamedMessageFramingPolicy(PolicyAssertionCollection collection)52 		internal static XmlElement GetStreamedMessageFramingPolicy (PolicyAssertionCollection collection)
53 		{
54 			return FindAndRemove (collection, "Streamed", FramingPolicyNS);
55 		}
56 
GetBinaryMessageEncodingPolicy(PolicyAssertionCollection collection)57 		internal static XmlElement GetBinaryMessageEncodingPolicy (PolicyAssertionCollection collection)
58 		{
59 			return FindAndRemove (collection, "BinaryEncoding", NetBinaryEncodingNS);
60 		}
61 
GetMtomMessageEncodingPolicy(PolicyAssertionCollection collection)62 		internal static XmlElement GetMtomMessageEncodingPolicy (PolicyAssertionCollection collection)
63 		{
64 			return FindAndRemove (collection, "OptimizedMimeSerialization", MimeSerializationNS);
65 		}
66 
FindAndRemove(PolicyAssertionCollection collection, string name, string ns)67 		static XmlElement FindAndRemove (PolicyAssertionCollection collection, string name, string ns)
68 		{
69 			var element = collection.Find (name, ns);
70 			if (element != null)
71 				collection.Remove (element);
72 			return element;
73 		}
74 
FindAssertionByNS( PolicyAssertionCollection collection, string ns)75 		internal static List<XmlElement> FindAssertionByNS (
76 			PolicyAssertionCollection collection, string ns)
77 		{
78 			var list = new List<XmlElement> ();
79 			foreach (var assertion in collection) {
80 				if (assertion.NamespaceURI.Equals (ns))
81 					list.Add (assertion);
82 			}
83 			return list;
84 		}
85 
GetPolicyElements(XmlElement root, out bool error)86 		internal static List<XmlElement> GetPolicyElements (XmlElement root, out bool error)
87 		{
88 			XmlElement policy = null;
89 			var list = new List<XmlElement> ();
90 
91 			foreach (var node in root.ChildNodes) {
92 				var e = node as XmlElement;
93 				if (e == null)
94 					continue;
95 				if (!PolicyNS.Equals (e.NamespaceURI) || !e.LocalName.Equals ("Policy")) {
96 					error = true;
97 					return list;
98 				}
99 				if (policy != null) {
100 					error = true;
101 					return list;
102 				}
103 				policy = e;
104 			}
105 
106 			if (policy == null) {
107 				error = true;
108 				return list;
109 			}
110 
111 			foreach (var node in policy.ChildNodes) {
112 				var e = node as XmlElement;
113 				if (e != null)
114 					list.Add (e);
115 			}
116 
117 			error = false;
118 			return list;
119 		}
120 
FindPolicyElement(MetadataImporter importer, XmlElement root, QName name, bool required, bool removeWhenFound, out XmlElement element)121 		internal static bool FindPolicyElement (MetadataImporter importer, XmlElement root,
122 		                                        QName name, bool required, bool removeWhenFound,
123 		                                        out XmlElement element)
124 		{
125 			if (!FindPolicyElement (root, name, removeWhenFound, out element)) {
126 				importer.AddWarning ("Invalid policy element: {0}", root.OuterXml);
127 				return false;
128 			}
129 			if (required && (element == null)) {
130 				importer.AddWarning ("Did not find policy element `{0}'.", name);
131 				return false;
132 			}
133 			return true;
134 		}
135 
FindPolicyElement(XmlElement root, QName name, bool removeWhenFound, out XmlElement element)136 		internal static bool FindPolicyElement (XmlElement root, QName name,
137 		                                        bool removeWhenFound, out XmlElement element)
138 		{
139 			XmlElement policy = null;
140 			foreach (var node in root.ChildNodes) {
141 				var e = node as XmlElement;
142 				if (e == null)
143 					continue;
144 				if (!PolicyNS.Equals (e.NamespaceURI) || !e.LocalName.Equals ("Policy")) {
145 					element = null;
146 					return false;
147 				}
148 				if (policy != null) {
149 					element = null;
150 					return false;
151 				}
152 				policy = e;
153 			}
154 
155 			if (policy == null) {
156 				element = null;
157 				return true;
158 			}
159 
160 			element = null;
161 			foreach (var node in policy.ChildNodes) {
162 				var e = node as XmlElement;
163 				if (e == null)
164 					continue;
165 				if (!name.Namespace.Equals (e.NamespaceURI) || !name.Name.Equals (e.LocalName))
166 					continue;
167 
168 				element = e;
169 				break;
170 			}
171 
172 			if (!removeWhenFound || (element == null))
173 				return true;
174 
175 			policy.RemoveChild (element);
176 
177 			bool foundAnother = false;
178 			foreach (var node in policy.ChildNodes) {
179 				var e = node as XmlElement;
180 				if (e != null) {
181 					foundAnother = true;
182 					break;
183 				}
184 			}
185 
186 			if (!foundAnother)
187 				root.RemoveChild (policy);
188 			return true;
189 		}
190 
GetElement(MetadataImporter importer, XmlElement root, string name, string ns)191 		internal static XmlElement GetElement (MetadataImporter importer,
192 		                                       XmlElement root, string name, string ns)
193 		{
194 			return GetElement (importer, root, name, ns, false);
195 		}
196 
GetElement(MetadataImporter importer, XmlElement root, string name, string ns, bool required)197 		internal static XmlElement GetElement (MetadataImporter importer,
198 		                                       XmlElement root, string name, string ns,
199 		                                       bool required)
200 		{
201 			return GetElement (importer, root, new QName (name, ns), required);
202 		}
203 
GetElement(MetadataImporter importer, XmlElement root, QName name, bool required)204 		internal static XmlElement GetElement (MetadataImporter importer,
205 		                                       XmlElement root, QName name, bool required)
206 		{
207 			var list = root.GetElementsByTagName (name.Name, name.Namespace);
208 			if (list.Count < 1) {
209 				if (required)
210 					importer.AddWarning ("Did not find required policy element `{0}'", name);
211 				return null;
212 			}
213 
214 			if (list.Count > 1) {
215 				importer.AddWarning ("Found duplicate policy element `{0}'", name);
216 				return null;
217 			}
218 
219 			var element = list [0] as XmlElement;
220 			if (required && (element == null))
221 				importer.AddWarning ("Did not find required policy element `{0}'", name);
222 			return element;
223 		}
224 
WrapPolicy(XmlElement element)225 		internal static XmlElement WrapPolicy (XmlElement element)
226 		{
227 			var policy = element.OwnerDocument.CreateElement ("wsp", "Policy", PolicyNS);
228 			policy.AppendChild (element);
229 			return policy;
230 		}
231 
232 		//
233 		// Add a single element, wrapping it inside <wsp:Policy>
234 		//
AddWrappedPolicyElement(XmlElement root, XmlElement element)235 		internal static void AddWrappedPolicyElement (XmlElement root, XmlElement element)
236 		{
237 			if (root.OwnerDocument != element.OwnerDocument)
238 				element = (XmlElement)root.OwnerDocument.ImportNode (element, true);
239 			if (!element.NamespaceURI.Equals (PolicyNS) || !element.LocalName.Equals ("Policy"))
240 				element = WrapPolicy (element);
241 			root.AppendChild (element);
242 		}
243 
244 		//
245 		// Add multiple elements, wrapping them inside a single <wsp:Policy>
246 		//
AddWrappedPolicyElements(XmlElement root, params XmlElement[] elements)247 		internal static void AddWrappedPolicyElements (XmlElement root, params XmlElement[] elements)
248 		{
249 			var policy = root.OwnerDocument.CreateElement ("wsp", "Policy", PolicyNS);
250 			root.AppendChild (policy);
251 
252 			foreach (var element in elements) {
253 				XmlElement imported;
254 				if (root.OwnerDocument != element.OwnerDocument)
255 					imported = (XmlElement)root.OwnerDocument.ImportNode (element, true);
256 				else
257 					imported = element;
258 				policy.AppendChild (element);
259 			}
260 		}
261 	}
262 }
263 
264