1 //
2 // System.ServiceModel.EndpointAddress.cs
3 //
4 // Author: Duncan Mak (duncan@novell.com)
5 //	   Atsushi Enomoto (atsushi@ximian.com)
6 //
7 // Copyright (C) 2005-2006 Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 
29 using System;
30 using System.IO;
31 using System.Reflection;
32 using System.Resources;
33 using System.Runtime.Serialization;
34 using System.Security.Cryptography.X509Certificates;
35 using System.Xml;
36 using System.Xml.Schema;
37 using System.Xml.Serialization;
38 using System.ServiceModel.Channels;
39 using System.ServiceModel.Description;
40 #if !MOBILE
41 using System.Security.Cryptography.Xml;
42 #endif
43 
44 namespace System.ServiceModel
45 {
46 	public class EndpointAddress
47 	{
48 		static readonly Uri w3c_anonymous = new Uri (Constants.WsaAnonymousUri);
49 		static readonly Uri anonymous_role = new Uri ("http://schemas.microsoft.com/2005/12/ServiceModel/Addressing/Anonymous");
50 		static readonly Uri none_role = new Uri ("http://schemas.microsoft.com/2005/12/ServiceModel/Addressing/None");
51 
52 		public static Uri AnonymousUri {
53 			get { return anonymous_role; }
54 		}
55 
56 		public static Uri NoneUri {
57 			get { return none_role; }
58 		}
59 
60 		Uri address;
61 		AddressHeaderCollection headers;
62 		EndpointIdentity identity;
63 		XmlDictionaryReader metadata_reader;
64 		XmlDictionaryReader extension_reader;
65 
66 		static XmlSchema schema;
67 
EndpointAddress(string uri)68 		public EndpointAddress (string uri)
69 			: this (new Uri (uri), new AddressHeader [0])
70 		{
71 		}
72 
EndpointAddress(Uri uri, params AddressHeader [] addressHeaders)73 		public EndpointAddress (Uri uri, params AddressHeader [] addressHeaders)
74 			: this (uri, null, new AddressHeaderCollection (addressHeaders), null, null) {}
75 
EndpointAddress(Uri uri, EndpointIdentity identity, params AddressHeader [] addressHeaders)76 		public EndpointAddress (Uri uri, EndpointIdentity identity, params AddressHeader [] addressHeaders)
77 			: this (uri, identity, new AddressHeaderCollection (addressHeaders), null, null) {}
78 
EndpointAddress(Uri uri, EndpointIdentity identity, AddressHeaderCollection headers)79 		public EndpointAddress (Uri uri, EndpointIdentity identity, AddressHeaderCollection headers)
80 			: this (uri, identity, headers, null, null) {}
81 
EndpointAddress( Uri uri, EndpointIdentity identity, AddressHeaderCollection headers, XmlDictionaryReader metadataReader, XmlDictionaryReader extensionReader)82 		public EndpointAddress (
83 			Uri uri, EndpointIdentity identity,
84 			AddressHeaderCollection headers,
85 			XmlDictionaryReader metadataReader,
86 			XmlDictionaryReader extensionReader)
87 		{
88 			if (uri == null)
89 				throw new ArgumentNullException ("uri");
90 			if (!uri.IsAbsoluteUri)
91 				throw new ArgumentException ("The argument uri must be absolute");
92 			this.address = uri;
93 			this.identity = identity;
94 			this.headers = headers;
95 			metadata_reader = metadataReader;
96 			extension_reader = extensionReader;
97 		}
98 
99 		public bool IsAnonymous {
100 			get { return address.Equals (anonymous_role); }
101 		}
102 
103 		public bool IsNone {
104 			get { return address.Equals (none_role); }
105 		}
106 
107 		public AddressHeaderCollection Headers {
108 			get { return headers; }
109 		}
110 
111 		public EndpointIdentity Identity {
112 			get { return identity; }
113 		}
114 
115 		public Uri Uri {
116 			get { return address; }
117 		}
118 
119 #if !MOBILE
120 		internal static XmlSchema Schema {
121 			get {
122 				if (schema == null) {
123 					Assembly a = Assembly.GetCallingAssembly ();
124 					Stream s = a.GetManifestResourceStream ("WS-Addressing.schema");
125 					schema = XmlSchema.Read (s, null);
126 				}
127 
128 				return schema;
129 			}
130 		}
131 #endif
132 
133 		[MonoTODO]
ApplyTo(Message message)134 		public void ApplyTo (Message message)
135 		{
136 			throw new NotImplementedException ();
137 		}
138 
Equals(object obj)139 		public override bool Equals (object obj)
140 		{
141 			EndpointAddress other = obj as EndpointAddress;
142 			if (other == null ||
143 			    other.Uri == null || !other.Uri.Equals (this.Uri) ||
144 			    other.Headers.Count != this.Headers.Count)
145 				return false;
146 
147 			foreach (AddressHeader h in this.Headers) {
148 				bool match = false;
149 				foreach (AddressHeader o in other.Headers)
150 					if (h.Equals (o)) {
151 						match = true;
152 						break;
153 					}
154 				if (!match)
155 					return false;
156 			}
157 
158 			return true;
159 		}
160 
GetHashCode()161 		public override int GetHashCode ()
162 		{
163 			return address.GetHashCode ();
164 		}
165 
GetReaderAtExtensions()166 		public XmlDictionaryReader GetReaderAtExtensions ()
167 		{
168 			return extension_reader;
169 		}
170 
GetReaderAtMetadata()171 		public XmlDictionaryReader GetReaderAtMetadata ()
172 		{
173 			return metadata_reader;
174 		}
175 
operator ==(EndpointAddress address1, EndpointAddress address2)176 		public static bool operator == (EndpointAddress address1, EndpointAddress address2)
177 		{
178 			if ((object) address1 == null)
179 				return (object) address2 == null;
180 			if ((object) address2 == null)
181 				return false;
182 			return address1.Equals (address2);
183 		}
184 
operator !=(EndpointAddress address1, EndpointAddress address2)185 		public static bool operator != (EndpointAddress address1, EndpointAddress address2)
186 		{
187 			return ! (address1 == address2);
188 		}
189 
190 //#if !MOBILE
ReadFrom( XmlDictionaryReader reader)191 		public static EndpointAddress ReadFrom (
192 			XmlDictionaryReader reader)
193 		{
194 			if (reader == null)
195 				throw new ArgumentNullException ("reader");
196 
197 			return ReadFromInternal (null, reader, null, null, null, null);
198 		}
199 
ReadFrom( AddressingVersion addressingVersion, XmlDictionaryReader reader)200 		public static EndpointAddress ReadFrom (
201 			AddressingVersion addressingVersion,
202 			XmlDictionaryReader reader)
203 		{
204 			return ReadFrom (addressingVersion, (XmlReader) reader);
205 		}
206 
ReadFrom( AddressingVersion addressingVersion, XmlReader reader)207 		public static EndpointAddress ReadFrom (
208 			AddressingVersion addressingVersion,
209 			XmlReader reader)
210 		{
211 			if (addressingVersion == null)
212 				throw new ArgumentNullException ("addressingVersion");
213 			if (reader == null)
214 				throw new ArgumentNullException ("reader");
215 
216 			return ReadFromInternal (addressingVersion, reader, null, null, null, null);
217 		}
218 
ReadFrom( XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString ns)219 		public static EndpointAddress ReadFrom (
220 			XmlDictionaryReader reader,
221 			XmlDictionaryString localName,
222 			XmlDictionaryString ns)
223 		{
224 			return ReadFrom (AddressingVersion.WSAddressing10,
225 					 reader, localName, ns);
226 		}
227 
ReadFrom( AddressingVersion addressingVersion, XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString ns)228 		public static EndpointAddress ReadFrom (
229 			AddressingVersion addressingVersion,
230 			XmlDictionaryReader reader,
231 			XmlDictionaryString localName,
232 			XmlDictionaryString ns)
233 		{
234 			// Empty localName and ns will be rejected by ReadStartElement() by feeding empty strings.
235 			return ReadFromInternal (addressingVersion, reader, null, null, localName ?? XmlDictionaryString.Empty, ns ?? XmlDictionaryString.Empty);
236 		}
237 
ReadFrom( AddressingVersion addressingVersion, XmlReader reader, string localName, string ns)238 		public static EndpointAddress ReadFrom (
239 			AddressingVersion addressingVersion,
240 			XmlReader reader, string localName, string ns)
241 		{
242 			// Empty localName and ns will be rejected by ReadStartElement() by feeding empty strings.
243 			return ReadFromInternal (addressingVersion, reader, localName ?? String.Empty, ns ?? String.Empty, null, null);
244 		}
245 
ReadFromInternal( AddressingVersion addressingVersion, XmlReader reader, string localName, string ns, XmlDictionaryString dictLocalName, XmlDictionaryString dictNS)246 		private static EndpointAddress ReadFromInternal (
247 			AddressingVersion addressingVersion,
248 			XmlReader reader, string localName, string ns,
249 			XmlDictionaryString dictLocalName,
250 			XmlDictionaryString dictNS)
251 		{
252 			reader.MoveToContent ();
253 			if (reader.NodeType != XmlNodeType.Element ||
254 			    reader.IsEmptyElement)
255 				throw new ArgumentException ("Cannot detect appropriate WS-Addressing Address element.");
256 
257 			if (localName != null)
258 				reader.ReadStartElement (localName, ns);
259 			else if (dictLocalName != null)
260 				((XmlDictionaryReader) reader).ReadStartElement (dictLocalName, dictNS);
261 			else
262 				reader.ReadStartElement ();
263 			reader.MoveToContent ();
264 
265 			if (addressingVersion == null) {
266 				if (reader.NamespaceURI == AddressingVersion.WSAddressing10.Namespace)
267 					addressingVersion = AddressingVersion.WSAddressing10;
268 				else
269 				if (reader.NamespaceURI == AddressingVersion.WSAddressingAugust2004.Namespace)
270 					addressingVersion = AddressingVersion.WSAddressingAugust2004;
271 				else
272 					throw new ArgumentException ("Cannot detect appropriate WS-Addressing version.");
273 			}
274 
275 			EndpointAddress ea = ReadContents (addressingVersion, reader);
276 
277 			reader.MoveToContent ();
278 			reader.ReadEndElement ();
279 			return ea;
280 		}
281 
ReadContents( AddressingVersion addressingVersion, XmlReader reader)282 		private static EndpointAddress ReadContents (
283 			AddressingVersion addressingVersion, XmlReader reader)
284 		{
285 			Uri uri = null;
286 			EndpointIdentity identity = null;
287 			reader.MoveToContent ();
288 			if (reader.LocalName == "Address" &&
289 			    reader.NamespaceURI == addressingVersion.Namespace &&
290 			    reader.NodeType == XmlNodeType.Element &&
291 			    !reader.IsEmptyElement)
292 				uri = new Uri (reader.ReadElementContentAsString ());
293 			else
294 				throw new XmlException (String.Format (
295 					"Expecting 'Address' from namespace '{0}', but found '{1}' from namespace '{2}'",
296 					addressingVersion.Namespace, reader.LocalName, reader.NamespaceURI));
297 
298 			reader.MoveToContent ();
299 #if !MOBILE
300 			MetadataSet metadata = null;
301 			if (reader.LocalName == "Metadata" &&
302 			    reader.NamespaceURI == addressingVersion.Namespace &&
303 			    !reader.IsEmptyElement) {
304 				reader.Read ();
305 				metadata = (MetadataSet) new XmlSerializer (typeof (MetadataSet)).Deserialize (reader);
306 				reader.MoveToContent ();
307 				reader.ReadEndElement ();
308 			}
309 			reader.MoveToContent ();
310 			if (reader.LocalName == "Identity" &&
311 			    reader.NamespaceURI == Constants.WsaIdentityUri) {
312 				// FIXME: implement
313 				reader.Skip ();
314 			}
315 #endif
316 
317 			if (addressingVersion == AddressingVersion.WSAddressing10 && uri == w3c_anonymous)
318 				uri = anonymous_role;
319 
320 #if MOBILE
321 			return new EndpointAddress (uri, identity);
322 #else
323 			if (metadata == null)
324 				return new EndpointAddress (uri, identity);
325 			return new EndpointAddress (uri, identity,
326 				AddressHeader.CreateAddressHeader (metadata));
327 #endif
328 		}
329 
ToString()330 		public override string ToString ()
331 		{
332 			return address.ToString ();
333 		}
334 
WriteContentsTo( AddressingVersion addressingVersion, XmlDictionaryWriter writer)335 		public void WriteContentsTo (
336 			AddressingVersion addressingVersion,
337 			XmlDictionaryWriter writer)
338 		{
339 			if (writer == null)
340 				throw new ArgumentNullException ("writer");
341 #if MOBILE
342 			if (addressingVersion == AddressingVersion.None) {
343 				writer.WriteString (Uri.AbsoluteUri);
344 			} else {
345 				writer.WriteStartElement ("Address", addressingVersion.Namespace);
346 				writer.WriteString (Uri.AbsoluteUri);
347 				writer.WriteEndElement ();
348 			}
349 #else
350 			if (addressingVersion == AddressingVersion.None)
351 				writer.WriteString (Uri.AbsoluteUri);
352 			else {
353 				writer.WriteStartElement ("Address", addressingVersion.Namespace);
354 				writer.WriteString (Uri.AbsoluteUri);
355 				writer.WriteEndElement ();
356 
357 				if (Identity == null)
358 					return;
359 
360 				if (Headers != null)
361 					foreach (AddressHeader ah in Headers)
362 						ah.WriteAddressHeader (writer);
363 
364 				writer.WriteStartElement ("Identity", Constants.WsaIdentityUri);
365 
366 				X509CertificateEndpointIdentity x509 =
367 					Identity as X509CertificateEndpointIdentity;
368 				if (x509 != null) {
369 					KeyInfo ki = new KeyInfo ();
370 					KeyInfoX509Data x = new KeyInfoX509Data ();
371 					foreach (X509Certificate2 cert in x509.Certificates)
372 						x.AddCertificate (cert);
373 					ki.AddClause (x);
374 					ki.GetXml ().WriteTo (writer);
375 				} else {
376 					DataContractSerializer ds = new DataContractSerializer (Identity.IdentityClaim.GetType ());
377 					ds.WriteObject (writer, Identity.IdentityClaim);
378 				}
379 				writer.WriteEndElement ();
380 			}
381 #endif
382 		}
383 
WriteContentsTo( AddressingVersion addressingVersion, XmlWriter writer)384 		public void WriteContentsTo (
385 			AddressingVersion addressingVersion,
386 			XmlWriter writer)
387 		{
388 			WriteContentsTo (addressingVersion,
389 				XmlDictionaryWriter.CreateDictionaryWriter (writer));
390 		}
391 
WriteTo( AddressingVersion addressingVersion, XmlDictionaryWriter writer)392 		public void WriteTo (
393 			AddressingVersion addressingVersion,
394 			XmlDictionaryWriter writer)
395 		{
396 			WriteTo (addressingVersion, writer, "EndpointReference", addressingVersion.Namespace);
397 		}
398 
WriteTo( AddressingVersion addressingVersion, XmlWriter writer)399 		public void WriteTo (
400 			AddressingVersion addressingVersion, XmlWriter writer)
401 		{
402 			WriteTo (addressingVersion,
403 				XmlDictionaryWriter.CreateDictionaryWriter (writer));
404 		}
405 
WriteTo( AddressingVersion addressingVersion, XmlDictionaryWriter writer, XmlDictionaryString localName, XmlDictionaryString ns)406 		public void WriteTo (
407 			AddressingVersion addressingVersion,
408 			XmlDictionaryWriter writer,
409 			XmlDictionaryString localName,
410 			XmlDictionaryString ns)
411 		{
412 			writer.WriteStartElement (localName, ns);
413 			WriteContentsTo (addressingVersion, writer);
414 			writer.WriteEndElement ();
415 		}
416 
WriteTo( AddressingVersion addressingVersion, XmlWriter writer, string localName, string ns)417 		public void WriteTo (
418 			AddressingVersion addressingVersion,
419 			XmlWriter writer, string localName, string ns)
420 		{
421 			writer.WriteStartElement (localName, ns);
422 			WriteContentsTo (addressingVersion, writer);
423 			writer.WriteEndElement ();
424 		}
425 	}
426 }
427