WSTrustChannelFactory.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. //------------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------------------------
  4. namespace System.ServiceModel.Security
  5. {
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Diagnostics;
  9. using System.IdentityModel.Protocols.WSTrust;
  10. using System.IdentityModel.Selectors;
  11. using System.IdentityModel.Tokens;
  12. using System.Runtime;
  13. using System.Runtime.InteropServices;
  14. using System.ServiceModel;
  15. using System.ServiceModel.Channels;
  16. using System.ServiceModel.Description;
  17. using IM = System.IdentityModel;
  18. /// <summary>
  19. /// A <see cref="ChannelFactory" /> that produces <see cref="WSTrustChannel" /> objects used to
  20. /// communicate to a WS-Trust endpoint.
  21. /// </summary>
  22. [ComVisible(false)]
  23. public class WSTrustChannelFactory : ChannelFactory<IWSTrustChannelContract>
  24. {
  25. //
  26. // NOTE: The properties on this class are designed to facilitate ease of use of the component and
  27. // to reduce the complexity of the constructors. The base class already gifts us with 8 constructor
  28. // overloads.
  29. //
  30. // Therefore, it is advisable that the fields *not* be used unless absolutely required.
  31. //
  32. /// <summary>
  33. /// These fields represent the property values that are "locked down" once the first channel is created.
  34. /// </summary>
  35. class WSTrustChannelLockedProperties
  36. {
  37. public TrustVersion TrustVersion;
  38. public WSTrustSerializationContext Context;
  39. public WSTrustRequestSerializer RequestSerializer;
  40. public WSTrustResponseSerializer ResponseSerializer;
  41. }
  42. //
  43. // Once we create a channel, our properties can be locked down.
  44. //
  45. object _factoryLock = new object();
  46. bool _locked = false;
  47. WSTrustChannelLockedProperties _lockedProperties;
  48. //
  49. // The TrustVersion property can be set to an instance of TrustVersion.WSTrust13 or TrustVersion.WSTrustFeb2005
  50. // to generate the built-in serializers for these trust namespaces.
  51. //
  52. TrustVersion _trustVersion;
  53. //
  54. // These fields contain the values used to construct the WSTrustSerializationContext used by the channels
  55. // we generate.
  56. //
  57. // _securityTokenResolver and _useKeyTokenResolver imply special behavior if they are null; however,
  58. // _securityTokenHandlerCollectionManager is not permitted to be null.
  59. //
  60. SecurityTokenResolver _securityTokenResolver;
  61. SecurityTokenResolver _useKeyTokenResolver;
  62. SecurityTokenHandlerCollectionManager _securityTokenHandlerCollectionManager
  63. = SecurityTokenHandlerCollectionManager.CreateDefaultSecurityTokenHandlerCollectionManager();
  64. //
  65. // These serializers determine how the channels serialize RST and RSTR messages.
  66. //
  67. WSTrustRequestSerializer _wsTrustRequestSerializer;
  68. WSTrustResponseSerializer _wsTrustResponseSerializer;
  69. /// <summary>
  70. /// Initializes a new instance of the <see cref="WSTrustChannelFactory" /> class.
  71. /// </summary>
  72. public WSTrustChannelFactory()
  73. : base()
  74. {
  75. }
  76. /// <summary>
  77. /// Initializes a new instance of the <see cref="WSTrustChannelFactory" /> class with a specified endpoint
  78. /// configuration name.
  79. /// </summary>
  80. /// <param name="endpointConfigurationName">The configuration name used for the endpoint.</param>
  81. public WSTrustChannelFactory(string endpointConfigurationName)
  82. : base(endpointConfigurationName)
  83. {
  84. }
  85. /// <summary>
  86. /// Initializes a new instance of the <see cref="WSTrustChannelFactory" /> class.
  87. /// </summary>
  88. /// <param name="binding">The <see cref="Binding" /> specified for the channels produced by the factory</param>
  89. public WSTrustChannelFactory(Binding binding)
  90. : base(binding)
  91. {
  92. }
  93. /// <summary>
  94. /// Initializes a new instance of the <see cref="WSTrustChannelFactory" /> class with a specified endpoint.
  95. /// </summary>
  96. /// <param name="endpoint">The <see cref="ServiceEndpoint" />for the channels produced by the factory.</param>
  97. public WSTrustChannelFactory(ServiceEndpoint endpoint)
  98. : base(endpoint)
  99. {
  100. }
  101. /// <summary>
  102. /// Initializes a new instance of the <see cref="WSTrustChannelFactory" /> class associated with a specified
  103. /// name for the endpoint configuration and remote address.
  104. /// </summary>
  105. /// <param name="endpointConfigurationName">The configuration name used for the endpoint.</param>
  106. /// <param name="remoteAddress">The <see cref="EndpointAddress" /> that provides the location of the service.</param>
  107. public WSTrustChannelFactory(string endpointConfigurationName, EndpointAddress remoteAddress)
  108. : base(endpointConfigurationName, remoteAddress)
  109. {
  110. }
  111. /// <summary>
  112. /// Initializes a new instance of the <see cref="WSTrustChannelFactory" /> class with a specified binding
  113. /// and endpoint address.
  114. /// </summary>
  115. /// <param name="binding">The <see cref="Binding" /> specified for the channels produced by the factory</param>
  116. /// <param name="remoteAddress">The <see cref="EndpointAddress" /> that provides the location of the service.</param>
  117. public WSTrustChannelFactory(Binding binding, EndpointAddress remoteAddress)
  118. : base(binding, remoteAddress)
  119. {
  120. }
  121. /// <summary>
  122. /// Initializes a new instance of the <see cref="WSTrustChannelFactory" /> class with a specified binding
  123. /// and remote address.
  124. /// </summary>
  125. /// <param name="binding">The <see cref="Binding" /> specified for the channels produced by the factory</param>
  126. /// <param name="remoteAddress">The <see cref="EndpointAddress" /> that provides the location of the service.</param>
  127. public WSTrustChannelFactory(Binding binding, string remoteAddress)
  128. : base(binding, remoteAddress)
  129. {
  130. }
  131. /// <summary>
  132. /// Gets or sets the version of WS-Trust the created channels will use for serializing messages.
  133. /// </summary>
  134. /// <remarks>
  135. /// <para>If this property is not set, created channels will use the <see cref="TrustVersion" /> set on any
  136. /// <see cref="SecurityBindingElement" /> found on the channel factory's Endpoint object if one exists.
  137. /// </para>
  138. /// <para>This class will not support changing the value of this property after a channel is created.</para>
  139. /// </remarks>
  140. public TrustVersion TrustVersion
  141. {
  142. get
  143. {
  144. return _trustVersion;
  145. }
  146. set
  147. {
  148. lock (_factoryLock)
  149. {
  150. if (_locked)
  151. {
  152. throw IM.DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID3287));
  153. }
  154. _trustVersion = value;
  155. }
  156. }
  157. }
  158. /// <summary>
  159. /// Gets or sets the <see cref="SecurityTokenHandlerCollectionManager" /> containing the set of
  160. /// <see cref="SecurityTokenHandler" /> objects used by created channels for serializing and validating
  161. /// tokens found in WS-Trust messages.
  162. /// </summary>
  163. /// <remarks>
  164. /// This class will not support changing the value of this property after a channel is created.
  165. /// </remarks>
  166. public SecurityTokenHandlerCollectionManager SecurityTokenHandlerCollectionManager
  167. {
  168. get
  169. {
  170. return _securityTokenHandlerCollectionManager;
  171. }
  172. set
  173. {
  174. if (value == null)
  175. {
  176. throw IM.DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
  177. }
  178. lock (_factoryLock)
  179. {
  180. if (_locked)
  181. {
  182. throw IM.DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID3287));
  183. }
  184. _securityTokenHandlerCollectionManager = value;
  185. }
  186. }
  187. }
  188. /// <summary>
  189. /// Gets or sets the <see cref="SecurityTokenResolver"/> used to resolve security token references found in most
  190. /// elements of WS-Trust messages.
  191. /// </summary>
  192. /// <remarks>
  193. /// <para>
  194. /// If this property is not set created channels will use the ClientCertificate set on the factory's
  195. /// Endpoint's ClientCredentials behavior to create a resolver. If no such certificate is found, an empty
  196. /// resolver is used.
  197. /// </para>
  198. /// <para>
  199. /// This class will not support changing the value of this property after a channel is created.
  200. /// </para>
  201. /// </remarks>
  202. public SecurityTokenResolver SecurityTokenResolver
  203. {
  204. get
  205. {
  206. return _securityTokenResolver;
  207. }
  208. set
  209. {
  210. lock (_factoryLock)
  211. {
  212. if (_locked)
  213. {
  214. throw IM.DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID3287));
  215. }
  216. _securityTokenResolver = value;
  217. }
  218. }
  219. }
  220. /// <summary>
  221. /// The <see cref="SecurityTokenResolver"/> used to resolve security token references found in the
  222. /// UseKey element of RST messages as well as the RenewTarget element found in RST messages.
  223. /// </summary>
  224. /// <remarks>
  225. /// <para>
  226. /// If this property is not set an empty resolver is used.
  227. /// </para>
  228. /// <para>
  229. /// This class will not support changing the value of this property after a channel is created.
  230. /// </para>
  231. /// </remarks>
  232. public SecurityTokenResolver UseKeyTokenResolver
  233. {
  234. get
  235. {
  236. return _useKeyTokenResolver;
  237. }
  238. set
  239. {
  240. lock (_factoryLock)
  241. {
  242. if (_locked)
  243. {
  244. throw IM.DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID3287));
  245. }
  246. _useKeyTokenResolver = value;
  247. }
  248. }
  249. }
  250. /// <summary>
  251. /// Gets or sets the WSTrustRequestSerializer to use for serializing RequestSecurityTokens messages.
  252. /// </summary>
  253. /// <remarks>
  254. /// <para>
  255. /// If this property is not set, either <see cref="WSTrust13RequestSerializer" /> or
  256. /// <see cref="WSTrustFeb2005RequestSerializer" /> will be used. The serializer will correspond to the
  257. /// version of WS-Trust indicated by the <see cref="TrustVersion" /> property.
  258. /// </para>
  259. /// <para>
  260. /// This class will not support changing the value of this property after a channel is created.
  261. /// </para>
  262. /// </remarks>
  263. public WSTrustRequestSerializer WSTrustRequestSerializer
  264. {
  265. get
  266. {
  267. return _wsTrustRequestSerializer;
  268. }
  269. set
  270. {
  271. lock (_factoryLock)
  272. {
  273. if (_locked)
  274. {
  275. throw IM.DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID3287));
  276. }
  277. _wsTrustRequestSerializer = value;
  278. }
  279. }
  280. }
  281. /// <summary>
  282. /// Gets or sets the WSTrustResponseSerializer to use for serializing RequestSecurityTokensResponse messages.
  283. /// </summary>
  284. /// <remarks>
  285. /// <para>
  286. /// If this property is not set, either <see cref="WSTrust13ResponseSerializer" /> or
  287. /// <see cref="WSTrustFeb2005ResponseSerializer" /> will be used. The serializer will correspond to the
  288. /// version of WS-Trust indicated by the <see cref="TrustVersion" /> property.
  289. /// </para>
  290. /// <para>
  291. /// This class will not support changing the value of this property after a channel is created.
  292. /// </para>
  293. /// </remarks>
  294. public WSTrustResponseSerializer WSTrustResponseSerializer
  295. {
  296. get
  297. {
  298. return _wsTrustResponseSerializer;
  299. }
  300. set
  301. {
  302. lock (_factoryLock)
  303. {
  304. if (_locked)
  305. {
  306. throw IM.DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID3287));
  307. }
  308. _wsTrustResponseSerializer = value;
  309. }
  310. }
  311. }
  312. /// <summary>
  313. /// Creates a <see cref="WSTrustChannel" /> that is used to send messages to a service at a specific
  314. /// endpoint address through a specified transport address.
  315. /// </summary>
  316. /// <param name="address">The <see cref="EndpointAddress" /> that provides the location of the service.</param>
  317. /// <param name="via">The <see cref="Uri" /> that contains the transport address to which the channel sends messages.</param>
  318. /// <returns></returns>
  319. public override IWSTrustChannelContract CreateChannel(EndpointAddress address, Uri via)
  320. {
  321. IWSTrustChannelContract innerChannel = base.CreateChannel(address, via);
  322. WSTrustChannelLockedProperties lockedProperties = GetLockedProperties();
  323. return CreateTrustChannel(innerChannel,
  324. lockedProperties.TrustVersion,
  325. lockedProperties.Context,
  326. lockedProperties.RequestSerializer,
  327. lockedProperties.ResponseSerializer);
  328. }
  329. /// <summary>
  330. /// Creates a <see cref="WSTrustChannel" /> using parameters that reflect the configuration of
  331. /// this factory.
  332. /// </summary>
  333. /// <param name="innerChannel">The channel created by the base class capable of sending and
  334. /// receiving messages.</param>
  335. /// <param name="trustVersion">The version of WS-Trust that should be used.</param>
  336. /// <param name="context">
  337. /// The <see cref="WSTrustSerializationContext" /> that should be used to serialize WS-Trust messages.
  338. /// </param>
  339. /// <param name="requestSerializer">
  340. /// The <see cref="WSTrustRequestSerializer" /> that should be used to serialize WS-Trust request messages.
  341. /// </param>
  342. /// <param name="responseSerializer">
  343. /// The <see cref="WSTrustResponseSerializer" /> that should be used to serialize WS-Trust response messages.
  344. /// </param>
  345. /// <returns></returns>
  346. protected virtual WSTrustChannel CreateTrustChannel(IWSTrustChannelContract innerChannel,
  347. TrustVersion trustVersion,
  348. WSTrustSerializationContext context,
  349. WSTrustRequestSerializer requestSerializer,
  350. WSTrustResponseSerializer responseSerializer)
  351. {
  352. return new WSTrustChannel(this, innerChannel, trustVersion, context, requestSerializer, responseSerializer);
  353. }
  354. private WSTrustChannelLockedProperties GetLockedProperties()
  355. {
  356. lock (_factoryLock)
  357. {
  358. if (_lockedProperties == null)
  359. {
  360. WSTrustChannelLockedProperties tmpLockedProperties = new WSTrustChannelLockedProperties();
  361. tmpLockedProperties.TrustVersion = GetTrustVersion();
  362. tmpLockedProperties.Context = CreateSerializationContext();
  363. tmpLockedProperties.RequestSerializer = GetRequestSerializer(tmpLockedProperties.TrustVersion);
  364. tmpLockedProperties.ResponseSerializer = GetResponseSerializer(tmpLockedProperties.TrustVersion);
  365. _lockedProperties = tmpLockedProperties;
  366. _locked = true;
  367. }
  368. return _lockedProperties;
  369. }
  370. }
  371. private WSTrustRequestSerializer GetRequestSerializer(TrustVersion trustVersion)
  372. {
  373. Fx.Assert(trustVersion != null, "trustVersion != null");
  374. if (_wsTrustRequestSerializer != null)
  375. {
  376. return _wsTrustRequestSerializer;
  377. }
  378. if (trustVersion == TrustVersion.WSTrust13)
  379. {
  380. return new WSTrust13RequestSerializer();
  381. }
  382. else if (trustVersion == TrustVersion.WSTrustFeb2005)
  383. {
  384. return new WSTrustFeb2005RequestSerializer();
  385. }
  386. else
  387. {
  388. throw IM.DiagnosticUtility.ExceptionUtility.ThrowHelperError( new NotSupportedException(SR.GetString(SR.ID3137, trustVersion.ToString())));
  389. }
  390. }
  391. private WSTrustResponseSerializer GetResponseSerializer(TrustVersion trustVersion)
  392. {
  393. Fx.Assert(trustVersion != null, "trustVersion != null");
  394. if (_wsTrustResponseSerializer != null)
  395. {
  396. return _wsTrustResponseSerializer;
  397. }
  398. if (trustVersion == TrustVersion.WSTrust13)
  399. {
  400. return new WSTrust13ResponseSerializer();
  401. }
  402. else if (trustVersion == TrustVersion.WSTrustFeb2005)
  403. {
  404. return new WSTrustFeb2005ResponseSerializer();
  405. }
  406. else
  407. {
  408. throw IM.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.ID3137, trustVersion.ToString())));
  409. }
  410. }
  411. private TrustVersion GetTrustVersion()
  412. {
  413. TrustVersion trustVersion = _trustVersion;
  414. if (trustVersion == null)
  415. {
  416. BindingElementCollection elements = Endpoint.Binding.CreateBindingElements();
  417. SecurityBindingElement sbe = elements.Find<SecurityBindingElement>();
  418. if (null == sbe)
  419. {
  420. throw IM.DiagnosticUtility.ExceptionUtility.ThrowHelperError( new InvalidOperationException( SR.GetString(SR.ID3269)));
  421. }
  422. trustVersion = sbe.MessageSecurityVersion.TrustVersion;
  423. }
  424. return trustVersion;
  425. }
  426. /// <summary>
  427. /// Creates a <see cref="WSTrustSerializationContext" /> used by <see cref="WSTrustChannel" /> objects created
  428. /// by this factory.
  429. /// </summary>
  430. /// <remarks>
  431. /// <para>
  432. /// If <see cref="WSTrustChannelFactory.SecurityTokenResolver" /> is set to null, the
  433. /// ClientCertificate set on the factory's Endpoint's ClientCredentials behavior will be used to
  434. /// create a resolver. If no such certificate is found, an empty resolver is used.
  435. /// </para>
  436. /// <para>
  437. /// If <see cref="WSTrustChannelFactory.UseKeyTokenResolver" /> is set to null, an empty resolver
  438. /// will be used.
  439. /// </para>
  440. /// </remarks>
  441. /// <returns>A WSTrustSerializationContext initialized with the trust client's properties.</returns>
  442. protected virtual WSTrustSerializationContext CreateSerializationContext()
  443. {
  444. //
  445. // Create a resolver with the ClientCredential's ClientCertificate if a resolver is not set.
  446. //
  447. SecurityTokenResolver resolver = _securityTokenResolver;
  448. if (resolver == null)
  449. {
  450. ClientCredentials factoryCredentials = Credentials;
  451. if (null != factoryCredentials.ClientCertificate && null != factoryCredentials.ClientCertificate.Certificate)
  452. {
  453. List<SecurityToken> clientCredentialTokens = new List<SecurityToken>();
  454. clientCredentialTokens.Add(new X509SecurityToken(factoryCredentials.ClientCertificate.Certificate));
  455. resolver = SecurityTokenResolver.CreateDefaultSecurityTokenResolver(clientCredentialTokens.AsReadOnly(), false);
  456. }
  457. }
  458. //
  459. // If it is _still_ null, then make it empty.
  460. //
  461. if (resolver == null)
  462. {
  463. resolver = EmptySecurityTokenResolver.Instance;
  464. }
  465. //
  466. // UseKeyTokenResolver is empty if null.
  467. //
  468. SecurityTokenResolver useKeyResolver = _useKeyTokenResolver ?? EmptySecurityTokenResolver.Instance;
  469. return new WSTrustSerializationContext(_securityTokenHandlerCollectionManager, resolver, useKeyResolver);
  470. }
  471. }
  472. }