| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511 |
- //------------------------------------------------------------------------------
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //------------------------------------------------------------------------------
- namespace System.ServiceModel.Security
- {
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.IdentityModel.Protocols.WSTrust;
- using System.IdentityModel.Selectors;
- using System.IdentityModel.Tokens;
- using System.Runtime;
- using System.Runtime.InteropServices;
- using System.ServiceModel;
- using System.ServiceModel.Channels;
- using System.ServiceModel.Description;
- using IM = System.IdentityModel;
- /// <summary>
- /// A <see cref="ChannelFactory" /> that produces <see cref="WSTrustChannel" /> objects used to
- /// communicate to a WS-Trust endpoint.
- /// </summary>
- [ComVisible(false)]
- public class WSTrustChannelFactory : ChannelFactory<IWSTrustChannelContract>
- {
- //
- // NOTE: The properties on this class are designed to facilitate ease of use of the component and
- // to reduce the complexity of the constructors. The base class already gifts us with 8 constructor
- // overloads.
- //
- // Therefore, it is advisable that the fields *not* be used unless absolutely required.
- //
- /// <summary>
- /// These fields represent the property values that are "locked down" once the first channel is created.
- /// </summary>
- class WSTrustChannelLockedProperties
- {
- public TrustVersion TrustVersion;
- public WSTrustSerializationContext Context;
- public WSTrustRequestSerializer RequestSerializer;
- public WSTrustResponseSerializer ResponseSerializer;
- }
- //
- // Once we create a channel, our properties can be locked down.
- //
- object _factoryLock = new object();
- bool _locked = false;
- WSTrustChannelLockedProperties _lockedProperties;
- //
- // The TrustVersion property can be set to an instance of TrustVersion.WSTrust13 or TrustVersion.WSTrustFeb2005
- // to generate the built-in serializers for these trust namespaces.
- //
- TrustVersion _trustVersion;
- //
- // These fields contain the values used to construct the WSTrustSerializationContext used by the channels
- // we generate.
- //
- // _securityTokenResolver and _useKeyTokenResolver imply special behavior if they are null; however,
- // _securityTokenHandlerCollectionManager is not permitted to be null.
- //
- SecurityTokenResolver _securityTokenResolver;
- SecurityTokenResolver _useKeyTokenResolver;
- SecurityTokenHandlerCollectionManager _securityTokenHandlerCollectionManager
- = SecurityTokenHandlerCollectionManager.CreateDefaultSecurityTokenHandlerCollectionManager();
- //
- // These serializers determine how the channels serialize RST and RSTR messages.
- //
- WSTrustRequestSerializer _wsTrustRequestSerializer;
- WSTrustResponseSerializer _wsTrustResponseSerializer;
- /// <summary>
- /// Initializes a new instance of the <see cref="WSTrustChannelFactory" /> class.
- /// </summary>
- public WSTrustChannelFactory()
- : base()
- {
- }
- /// <summary>
- /// Initializes a new instance of the <see cref="WSTrustChannelFactory" /> class with a specified endpoint
- /// configuration name.
- /// </summary>
- /// <param name="endpointConfigurationName">The configuration name used for the endpoint.</param>
- public WSTrustChannelFactory(string endpointConfigurationName)
- : base(endpointConfigurationName)
- {
- }
- /// <summary>
- /// Initializes a new instance of the <see cref="WSTrustChannelFactory" /> class.
- /// </summary>
- /// <param name="binding">The <see cref="Binding" /> specified for the channels produced by the factory</param>
- public WSTrustChannelFactory(Binding binding)
- : base(binding)
- {
- }
- /// <summary>
- /// Initializes a new instance of the <see cref="WSTrustChannelFactory" /> class with a specified endpoint.
- /// </summary>
- /// <param name="endpoint">The <see cref="ServiceEndpoint" />for the channels produced by the factory.</param>
- public WSTrustChannelFactory(ServiceEndpoint endpoint)
- : base(endpoint)
- {
- }
- /// <summary>
- /// Initializes a new instance of the <see cref="WSTrustChannelFactory" /> class associated with a specified
- /// name for the endpoint configuration and remote address.
- /// </summary>
- /// <param name="endpointConfigurationName">The configuration name used for the endpoint.</param>
- /// <param name="remoteAddress">The <see cref="EndpointAddress" /> that provides the location of the service.</param>
- public WSTrustChannelFactory(string endpointConfigurationName, EndpointAddress remoteAddress)
- : base(endpointConfigurationName, remoteAddress)
- {
- }
- /// <summary>
- /// Initializes a new instance of the <see cref="WSTrustChannelFactory" /> class with a specified binding
- /// and endpoint address.
- /// </summary>
- /// <param name="binding">The <see cref="Binding" /> specified for the channels produced by the factory</param>
- /// <param name="remoteAddress">The <see cref="EndpointAddress" /> that provides the location of the service.</param>
- public WSTrustChannelFactory(Binding binding, EndpointAddress remoteAddress)
- : base(binding, remoteAddress)
- {
- }
- /// <summary>
- /// Initializes a new instance of the <see cref="WSTrustChannelFactory" /> class with a specified binding
- /// and remote address.
- /// </summary>
- /// <param name="binding">The <see cref="Binding" /> specified for the channels produced by the factory</param>
- /// <param name="remoteAddress">The <see cref="EndpointAddress" /> that provides the location of the service.</param>
- public WSTrustChannelFactory(Binding binding, string remoteAddress)
- : base(binding, remoteAddress)
- {
- }
- /// <summary>
- /// Gets or sets the version of WS-Trust the created channels will use for serializing messages.
- /// </summary>
- /// <remarks>
- /// <para>If this property is not set, created channels will use the <see cref="TrustVersion" /> set on any
- /// <see cref="SecurityBindingElement" /> found on the channel factory's Endpoint object if one exists.
- /// </para>
- /// <para>This class will not support changing the value of this property after a channel is created.</para>
- /// </remarks>
- public TrustVersion TrustVersion
- {
- get
- {
- return _trustVersion;
- }
- set
- {
- lock (_factoryLock)
- {
- if (_locked)
- {
- throw IM.DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID3287));
- }
- _trustVersion = value;
- }
- }
- }
- /// <summary>
- /// Gets or sets the <see cref="SecurityTokenHandlerCollectionManager" /> containing the set of
- /// <see cref="SecurityTokenHandler" /> objects used by created channels for serializing and validating
- /// tokens found in WS-Trust messages.
- /// </summary>
- /// <remarks>
- /// This class will not support changing the value of this property after a channel is created.
- /// </remarks>
- public SecurityTokenHandlerCollectionManager SecurityTokenHandlerCollectionManager
- {
- get
- {
- return _securityTokenHandlerCollectionManager;
- }
- set
- {
- if (value == null)
- {
- throw IM.DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
- }
- lock (_factoryLock)
- {
- if (_locked)
- {
- throw IM.DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID3287));
- }
- _securityTokenHandlerCollectionManager = value;
- }
- }
- }
- /// <summary>
- /// Gets or sets the <see cref="SecurityTokenResolver"/> used to resolve security token references found in most
- /// elements of WS-Trust messages.
- /// </summary>
- /// <remarks>
- /// <para>
- /// If this property is not set created channels will use the ClientCertificate set on the factory's
- /// Endpoint's ClientCredentials behavior to create a resolver. If no such certificate is found, an empty
- /// resolver is used.
- /// </para>
- /// <para>
- /// This class will not support changing the value of this property after a channel is created.
- /// </para>
- /// </remarks>
- public SecurityTokenResolver SecurityTokenResolver
- {
- get
- {
- return _securityTokenResolver;
- }
- set
- {
- lock (_factoryLock)
- {
- if (_locked)
- {
- throw IM.DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID3287));
- }
- _securityTokenResolver = value;
- }
- }
- }
- /// <summary>
- /// The <see cref="SecurityTokenResolver"/> used to resolve security token references found in the
- /// UseKey element of RST messages as well as the RenewTarget element found in RST messages.
- /// </summary>
- /// <remarks>
- /// <para>
- /// If this property is not set an empty resolver is used.
- /// </para>
- /// <para>
- /// This class will not support changing the value of this property after a channel is created.
- /// </para>
- /// </remarks>
- public SecurityTokenResolver UseKeyTokenResolver
- {
- get
- {
- return _useKeyTokenResolver;
- }
- set
- {
- lock (_factoryLock)
- {
- if (_locked)
- {
- throw IM.DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID3287));
- }
- _useKeyTokenResolver = value;
- }
- }
- }
- /// <summary>
- /// Gets or sets the WSTrustRequestSerializer to use for serializing RequestSecurityTokens messages.
- /// </summary>
- /// <remarks>
- /// <para>
- /// If this property is not set, either <see cref="WSTrust13RequestSerializer" /> or
- /// <see cref="WSTrustFeb2005RequestSerializer" /> will be used. The serializer will correspond to the
- /// version of WS-Trust indicated by the <see cref="TrustVersion" /> property.
- /// </para>
- /// <para>
- /// This class will not support changing the value of this property after a channel is created.
- /// </para>
- /// </remarks>
- public WSTrustRequestSerializer WSTrustRequestSerializer
- {
- get
- {
- return _wsTrustRequestSerializer;
- }
- set
- {
- lock (_factoryLock)
- {
- if (_locked)
- {
- throw IM.DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID3287));
- }
- _wsTrustRequestSerializer = value;
- }
- }
- }
- /// <summary>
- /// Gets or sets the WSTrustResponseSerializer to use for serializing RequestSecurityTokensResponse messages.
- /// </summary>
- /// <remarks>
- /// <para>
- /// If this property is not set, either <see cref="WSTrust13ResponseSerializer" /> or
- /// <see cref="WSTrustFeb2005ResponseSerializer" /> will be used. The serializer will correspond to the
- /// version of WS-Trust indicated by the <see cref="TrustVersion" /> property.
- /// </para>
- /// <para>
- /// This class will not support changing the value of this property after a channel is created.
- /// </para>
- /// </remarks>
- public WSTrustResponseSerializer WSTrustResponseSerializer
- {
- get
- {
- return _wsTrustResponseSerializer;
- }
- set
- {
- lock (_factoryLock)
- {
- if (_locked)
- {
- throw IM.DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID3287));
- }
- _wsTrustResponseSerializer = value;
- }
- }
- }
- /// <summary>
- /// Creates a <see cref="WSTrustChannel" /> that is used to send messages to a service at a specific
- /// endpoint address through a specified transport address.
- /// </summary>
- /// <param name="address">The <see cref="EndpointAddress" /> that provides the location of the service.</param>
- /// <param name="via">The <see cref="Uri" /> that contains the transport address to which the channel sends messages.</param>
- /// <returns></returns>
- public override IWSTrustChannelContract CreateChannel(EndpointAddress address, Uri via)
- {
- IWSTrustChannelContract innerChannel = base.CreateChannel(address, via);
- WSTrustChannelLockedProperties lockedProperties = GetLockedProperties();
- return CreateTrustChannel(innerChannel,
- lockedProperties.TrustVersion,
- lockedProperties.Context,
- lockedProperties.RequestSerializer,
- lockedProperties.ResponseSerializer);
- }
- /// <summary>
- /// Creates a <see cref="WSTrustChannel" /> using parameters that reflect the configuration of
- /// this factory.
- /// </summary>
- /// <param name="innerChannel">The channel created by the base class capable of sending and
- /// receiving messages.</param>
- /// <param name="trustVersion">The version of WS-Trust that should be used.</param>
- /// <param name="context">
- /// The <see cref="WSTrustSerializationContext" /> that should be used to serialize WS-Trust messages.
- /// </param>
- /// <param name="requestSerializer">
- /// The <see cref="WSTrustRequestSerializer" /> that should be used to serialize WS-Trust request messages.
- /// </param>
- /// <param name="responseSerializer">
- /// The <see cref="WSTrustResponseSerializer" /> that should be used to serialize WS-Trust response messages.
- /// </param>
- /// <returns></returns>
- protected virtual WSTrustChannel CreateTrustChannel(IWSTrustChannelContract innerChannel,
- TrustVersion trustVersion,
- WSTrustSerializationContext context,
- WSTrustRequestSerializer requestSerializer,
- WSTrustResponseSerializer responseSerializer)
- {
- return new WSTrustChannel(this, innerChannel, trustVersion, context, requestSerializer, responseSerializer);
- }
- private WSTrustChannelLockedProperties GetLockedProperties()
- {
- lock (_factoryLock)
- {
- if (_lockedProperties == null)
- {
- WSTrustChannelLockedProperties tmpLockedProperties = new WSTrustChannelLockedProperties();
- tmpLockedProperties.TrustVersion = GetTrustVersion();
- tmpLockedProperties.Context = CreateSerializationContext();
- tmpLockedProperties.RequestSerializer = GetRequestSerializer(tmpLockedProperties.TrustVersion);
- tmpLockedProperties.ResponseSerializer = GetResponseSerializer(tmpLockedProperties.TrustVersion);
- _lockedProperties = tmpLockedProperties;
- _locked = true;
- }
- return _lockedProperties;
- }
- }
- private WSTrustRequestSerializer GetRequestSerializer(TrustVersion trustVersion)
- {
- Fx.Assert(trustVersion != null, "trustVersion != null");
- if (_wsTrustRequestSerializer != null)
- {
- return _wsTrustRequestSerializer;
- }
- if (trustVersion == TrustVersion.WSTrust13)
- {
- return new WSTrust13RequestSerializer();
- }
- else if (trustVersion == TrustVersion.WSTrustFeb2005)
- {
- return new WSTrustFeb2005RequestSerializer();
- }
- else
- {
- throw IM.DiagnosticUtility.ExceptionUtility.ThrowHelperError( new NotSupportedException(SR.GetString(SR.ID3137, trustVersion.ToString())));
- }
- }
- private WSTrustResponseSerializer GetResponseSerializer(TrustVersion trustVersion)
- {
- Fx.Assert(trustVersion != null, "trustVersion != null");
- if (_wsTrustResponseSerializer != null)
- {
- return _wsTrustResponseSerializer;
- }
- if (trustVersion == TrustVersion.WSTrust13)
- {
- return new WSTrust13ResponseSerializer();
- }
- else if (trustVersion == TrustVersion.WSTrustFeb2005)
- {
- return new WSTrustFeb2005ResponseSerializer();
- }
- else
- {
- throw IM.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.ID3137, trustVersion.ToString())));
- }
- }
- private TrustVersion GetTrustVersion()
- {
- TrustVersion trustVersion = _trustVersion;
- if (trustVersion == null)
- {
- BindingElementCollection elements = Endpoint.Binding.CreateBindingElements();
- SecurityBindingElement sbe = elements.Find<SecurityBindingElement>();
- if (null == sbe)
- {
- throw IM.DiagnosticUtility.ExceptionUtility.ThrowHelperError( new InvalidOperationException( SR.GetString(SR.ID3269)));
- }
- trustVersion = sbe.MessageSecurityVersion.TrustVersion;
- }
- return trustVersion;
- }
- /// <summary>
- /// Creates a <see cref="WSTrustSerializationContext" /> used by <see cref="WSTrustChannel" /> objects created
- /// by this factory.
- /// </summary>
- /// <remarks>
- /// <para>
- /// If <see cref="WSTrustChannelFactory.SecurityTokenResolver" /> is set to null, the
- /// ClientCertificate set on the factory's Endpoint's ClientCredentials behavior will be used to
- /// create a resolver. If no such certificate is found, an empty resolver is used.
- /// </para>
- /// <para>
- /// If <see cref="WSTrustChannelFactory.UseKeyTokenResolver" /> is set to null, an empty resolver
- /// will be used.
- /// </para>
- /// </remarks>
- /// <returns>A WSTrustSerializationContext initialized with the trust client's properties.</returns>
- protected virtual WSTrustSerializationContext CreateSerializationContext()
- {
- //
- // Create a resolver with the ClientCredential's ClientCertificate if a resolver is not set.
- //
- SecurityTokenResolver resolver = _securityTokenResolver;
- if (resolver == null)
- {
- ClientCredentials factoryCredentials = Credentials;
- if (null != factoryCredentials.ClientCertificate && null != factoryCredentials.ClientCertificate.Certificate)
- {
- List<SecurityToken> clientCredentialTokens = new List<SecurityToken>();
- clientCredentialTokens.Add(new X509SecurityToken(factoryCredentials.ClientCertificate.Certificate));
- resolver = SecurityTokenResolver.CreateDefaultSecurityTokenResolver(clientCredentialTokens.AsReadOnly(), false);
- }
- }
- //
- // If it is _still_ null, then make it empty.
- //
- if (resolver == null)
- {
- resolver = EmptySecurityTokenResolver.Instance;
- }
- //
- // UseKeyTokenResolver is empty if null.
- //
- SecurityTokenResolver useKeyResolver = _useKeyTokenResolver ?? EmptySecurityTokenResolver.Instance;
- return new WSTrustSerializationContext(_securityTokenHandlerCollectionManager, resolver, useKeyResolver);
- }
- }
- }
|