HttpTransportBindingElement.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. //
  2. // HttpTransportBindingElement.cs
  3. //
  4. // Author:
  5. // Atsushi Enomoto <[email protected]>
  6. //
  7. // Copyright (C) 2005-2010 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. using System;
  29. using System.Collections.Generic;
  30. using System.ComponentModel;
  31. using System.Net;
  32. using System.Net.Security;
  33. using System.Security.Authentication.ExtendedProtection;
  34. using System.ServiceModel.Channels;
  35. #if !MOBILE
  36. using System.ServiceModel.Channels.Http;
  37. #endif
  38. using System.ServiceModel.Description;
  39. #if !MOBILE
  40. using WS = System.Web.Services.Description;
  41. #endif
  42. using System.Xml;
  43. namespace System.ServiceModel.Channels
  44. {
  45. public class HttpTransportBindingElement : TransportBindingElement,
  46. IPolicyExportExtension, IWsdlExportExtension
  47. {
  48. bool allow_cookies, bypass_proxy_on_local,
  49. unsafe_ntlm_auth;
  50. bool use_default_proxy = true, keep_alive_enabled = true;
  51. int max_buffer_size = 0x10000;
  52. HostNameComparisonMode host_cmp_mode;
  53. Uri proxy_address;
  54. string realm = String.Empty;
  55. TransferMode transfer_mode;
  56. IDefaultCommunicationTimeouts timeouts;
  57. AuthenticationSchemes auth_scheme =
  58. AuthenticationSchemes.Anonymous;
  59. AuthenticationSchemes proxy_auth_scheme =
  60. AuthenticationSchemes.Anonymous;
  61. // If you add fields, do not forget them in copy constructor.
  62. HttpCookieContainerManager cookie_manager;
  63. public HttpTransportBindingElement ()
  64. {
  65. }
  66. protected HttpTransportBindingElement (
  67. HttpTransportBindingElement other)
  68. : base (other)
  69. {
  70. allow_cookies = other.allow_cookies;
  71. bypass_proxy_on_local = other.bypass_proxy_on_local;
  72. unsafe_ntlm_auth = other.unsafe_ntlm_auth;
  73. use_default_proxy = other.use_default_proxy;
  74. keep_alive_enabled = other.keep_alive_enabled;
  75. max_buffer_size = other.max_buffer_size;
  76. host_cmp_mode = other.host_cmp_mode;
  77. proxy_address = other.proxy_address;
  78. realm = other.realm;
  79. transfer_mode = other.transfer_mode;
  80. // FIXME: it does not look safe
  81. timeouts = other.timeouts;
  82. auth_scheme = other.auth_scheme;
  83. proxy_auth_scheme = other.proxy_auth_scheme;
  84. DecompressionEnabled = other.DecompressionEnabled;
  85. LegacyExtendedProtectionPolicy = other.LegacyExtendedProtectionPolicy;
  86. ExtendedProtectionPolicy = other.ExtendedProtectionPolicy;
  87. cookie_manager = other.cookie_manager;
  88. }
  89. [DefaultValue (AuthenticationSchemes.Anonymous)]
  90. public AuthenticationSchemes AuthenticationScheme {
  91. get { return auth_scheme; }
  92. set { auth_scheme = value; }
  93. }
  94. [DefaultValue (AuthenticationSchemes.Anonymous)]
  95. public AuthenticationSchemes ProxyAuthenticationScheme {
  96. get { return proxy_auth_scheme; }
  97. set { proxy_auth_scheme = value; }
  98. }
  99. [DefaultValue (false)]
  100. public bool AllowCookies {
  101. get { return allow_cookies; }
  102. set { allow_cookies = value; }
  103. }
  104. [DefaultValue (false)]
  105. public bool BypassProxyOnLocal {
  106. get { return bypass_proxy_on_local; }
  107. set { bypass_proxy_on_local = value; }
  108. }
  109. [DefaultValue (false)]
  110. [MonoTODO]
  111. public bool DecompressionEnabled { get; set; }
  112. [DefaultValue (HostNameComparisonMode.StrongWildcard)]
  113. public HostNameComparisonMode HostNameComparisonMode {
  114. get { return host_cmp_mode; }
  115. set { host_cmp_mode = value; }
  116. }
  117. [DefaultValue (true)]
  118. public bool KeepAliveEnabled {
  119. get { return keep_alive_enabled; }
  120. set { keep_alive_enabled = value; }
  121. }
  122. [DefaultValue (0x10000)]
  123. public int MaxBufferSize {
  124. get { return max_buffer_size; }
  125. set { max_buffer_size = value; }
  126. }
  127. [DefaultValue (null)]
  128. [TypeConverter (typeof (UriTypeConverter))]
  129. public Uri ProxyAddress {
  130. get { return proxy_address; }
  131. set { proxy_address = value; }
  132. }
  133. [DefaultValue ("")]
  134. public string Realm {
  135. get { return realm; }
  136. set { realm = value; }
  137. }
  138. public override string Scheme {
  139. get { return Uri.UriSchemeHttp; }
  140. }
  141. [DefaultValue (TransferMode.Buffered)]
  142. public TransferMode TransferMode {
  143. get { return transfer_mode; }
  144. set { transfer_mode = value; }
  145. }
  146. [DefaultValue (false)]
  147. public bool UnsafeConnectionNtlmAuthentication {
  148. get { return unsafe_ntlm_auth; }
  149. set { unsafe_ntlm_auth = value; }
  150. }
  151. [DefaultValue (true)]
  152. public bool UseDefaultWebProxy {
  153. get { return use_default_proxy; }
  154. set { use_default_proxy = value; }
  155. }
  156. [Obsolete ("Use ExtendedProtectionPolicy")]
  157. [MonoTODO]
  158. public object LegacyExtendedProtectionPolicy { get; set; }
  159. [MonoTODO]
  160. public ExtendedProtectionPolicy ExtendedProtectionPolicy { get; set; }
  161. public override bool CanBuildChannelFactory<TChannel> (
  162. BindingContext context)
  163. {
  164. return typeof (TChannel) == typeof (IRequestChannel);
  165. }
  166. #if !MOBILE && !XAMMAC_4_5
  167. public override bool CanBuildChannelListener<TChannel> (
  168. BindingContext context)
  169. {
  170. return typeof (TChannel) == typeof (IReplyChannel);
  171. }
  172. #endif
  173. public override IChannelFactory<TChannel> BuildChannelFactory<TChannel> (
  174. BindingContext context)
  175. {
  176. // remaining contexts are ignored ... e.g. such binding
  177. // element that always causes an error is ignored.
  178. return new HttpChannelFactory<TChannel> (this, context);
  179. }
  180. #if !MOBILE && !XAMMAC_4_5
  181. internal static object ListenerBuildLock = new object ();
  182. public override IChannelListener<TChannel> BuildChannelListener<TChannel> (
  183. BindingContext context)
  184. {
  185. // remaining contexts are ignored ... e.g. such binding
  186. // element that always causes an error is ignored.
  187. return new HttpChannelListener<TChannel> (this, context);
  188. }
  189. #endif
  190. public override BindingElement Clone ()
  191. {
  192. return new HttpTransportBindingElement (this);
  193. }
  194. public override T GetProperty<T> (BindingContext context)
  195. {
  196. // http://blogs.msdn.com/drnick/archive/2007/04/10/interfaces-for-getproperty-part-1.aspx
  197. if (typeof (T) == typeof (ISecurityCapabilities))
  198. return (T) (object) new HttpBindingProperties (this);
  199. if (typeof (T) == typeof (IBindingDeliveryCapabilities))
  200. return (T) (object) new HttpBindingProperties (this);
  201. if (typeof (T) == typeof (TransferMode))
  202. return (T) (object) TransferMode;
  203. if (typeof(T) == typeof(IHttpCookieContainerManager)) {
  204. if (!AllowCookies)
  205. return null;
  206. if (cookie_manager == null)
  207. cookie_manager = new HttpCookieContainerManager ();
  208. return (T) (object) cookie_manager;
  209. }
  210. return base.GetProperty<T> (context);
  211. }
  212. public WebSocketTransportSettings WebSocketSettings {
  213. get { throw new NotImplementedException (); }
  214. set { throw new NotImplementedException (); }
  215. }
  216. #if !MOBILE && !XAMMAC_4_5
  217. void IPolicyExportExtension.ExportPolicy (
  218. MetadataExporter exporter,
  219. PolicyConversionContext context)
  220. {
  221. if (exporter == null)
  222. throw new ArgumentNullException ("exporter");
  223. if (context == null)
  224. throw new ArgumentNullException ("context");
  225. PolicyAssertionCollection assertions = context.GetBindingAssertions ();
  226. XmlDocument doc = new XmlDocument ();
  227. ExportAddressingPolicy (context);
  228. switch (auth_scheme) {
  229. case AuthenticationSchemes.Basic:
  230. case AuthenticationSchemes.Digest:
  231. case AuthenticationSchemes.Negotiate:
  232. case AuthenticationSchemes.Ntlm:
  233. assertions.Add (doc.CreateElement ("http",
  234. auth_scheme.ToString () + "Authentication",
  235. "http://schemas.microsoft.com/ws/06/2004/policy/http"));
  236. break;
  237. }
  238. var transportProvider = this as ITransportTokenAssertionProvider;
  239. if (transportProvider != null) {
  240. var token = transportProvider.GetTransportTokenAssertion ();
  241. assertions.Add (CreateTransportBinding (token));
  242. }
  243. }
  244. XmlElement CreateTransportBinding (XmlElement transportToken)
  245. {
  246. var doc = new XmlDocument ();
  247. var transportBinding = doc.CreateElement (
  248. "sp", "TransportBinding", PolicyImportHelper.SecurityPolicyNS);
  249. var token = doc.CreateElement (
  250. "sp", "TransportToken", PolicyImportHelper.SecurityPolicyNS);
  251. PolicyImportHelper.AddWrappedPolicyElement (token, transportToken);
  252. var algorithmSuite = doc.CreateElement (
  253. "sp", "AlgorithmSuite", PolicyImportHelper.SecurityPolicyNS);
  254. var basic256 = doc.CreateElement (
  255. "sp", "Basic256", PolicyImportHelper.SecurityPolicyNS);
  256. PolicyImportHelper.AddWrappedPolicyElement (algorithmSuite, basic256);
  257. var layout = doc.CreateElement (
  258. "sp", "Layout", PolicyImportHelper.SecurityPolicyNS);
  259. var strict = doc.CreateElement (
  260. "sp", "Strict", PolicyImportHelper.SecurityPolicyNS);
  261. PolicyImportHelper.AddWrappedPolicyElement (layout, strict);
  262. PolicyImportHelper.AddWrappedPolicyElements (
  263. transportBinding, token, algorithmSuite, layout);
  264. return transportBinding;
  265. }
  266. [MonoTODO]
  267. void IWsdlExportExtension.ExportContract (WsdlExporter exporter,
  268. WsdlContractConversionContext context)
  269. {
  270. throw new NotImplementedException ();
  271. }
  272. [MonoTODO]
  273. void IWsdlExportExtension.ExportEndpoint (WsdlExporter exporter,
  274. WsdlEndpointConversionContext context)
  275. {
  276. var soap_binding = new WS.SoapBinding ();
  277. soap_binding.Transport = WS.SoapBinding.HttpTransport;
  278. soap_binding.Style = WS.SoapBindingStyle.Document;
  279. context.WsdlBinding.Extensions.Add (soap_binding);
  280. var soap_address = new WS.SoapAddressBinding ();
  281. soap_address.Location = context.Endpoint.Address.Uri.AbsoluteUri;
  282. context.WsdlPort.Extensions.Add (soap_address);
  283. }
  284. #endif
  285. }
  286. class HttpBindingProperties : ISecurityCapabilities, IBindingDeliveryCapabilities
  287. {
  288. HttpTransportBindingElement source;
  289. public HttpBindingProperties (HttpTransportBindingElement source)
  290. {
  291. this.source = source;
  292. }
  293. public bool AssuresOrderedDelivery {
  294. get { return false; }
  295. }
  296. public bool QueuedDelivery {
  297. get { return false; }
  298. }
  299. public virtual ProtectionLevel SupportedRequestProtectionLevel {
  300. get { return ProtectionLevel.None; }
  301. }
  302. public virtual ProtectionLevel SupportedResponseProtectionLevel {
  303. get { return ProtectionLevel.None; }
  304. }
  305. public virtual bool SupportsClientAuthentication {
  306. get { return source.AuthenticationScheme != AuthenticationSchemes.Anonymous; }
  307. }
  308. public virtual bool SupportsServerAuthentication {
  309. get {
  310. switch (source.AuthenticationScheme) {
  311. case AuthenticationSchemes.Negotiate:
  312. return true;
  313. default:
  314. return false;
  315. }
  316. }
  317. }
  318. public virtual bool SupportsClientWindowsIdentity {
  319. get {
  320. switch (source.AuthenticationScheme) {
  321. case AuthenticationSchemes.Basic:
  322. case AuthenticationSchemes.Digest: // hmm... why? but they return true on .NET
  323. case AuthenticationSchemes.Negotiate:
  324. case AuthenticationSchemes.Ntlm:
  325. return true;
  326. default:
  327. return false;
  328. }
  329. }
  330. }
  331. }
  332. }