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