text: //-----------------------------------------------------------------------------
  // Copyright (c) Microsoft Corporation.  All rights reserved.
  //-----------------------------------------------------------------------------
  namespace System.ServiceModel.Security
  {
      using System.Runtime;
      using System.ServiceModel;
      using System.ServiceModel.Channels;
      using System.ServiceModel.Description;
      using System.ServiceModel.Dispatcher;
      using System.Xml;
  
      // This is the base class for all token providers that negotiate an SCT from
      // the target service.
      abstract class NegotiationTokenProvider<T> : IssuanceTokenProviderBase<T>
          where T : IssuanceTokenProviderState
      {
          IChannelFactory<IRequestChannel> rstChannelFactory;
          bool requiresManualReplyAddressing;
          BindingContext issuanceBindingContext;
          MessageVersion messageVersion;
  
          protected NegotiationTokenProvider()
              : base()
          {
          }
  
          public BindingContext IssuerBindingContext
          {
              get { return this.issuanceBindingContext; }
              set
              {
                  this.CommunicationObject.ThrowIfDisposedOrImmutable();
                  if (value == null)
                  {
                      throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
                  }
                  this.issuanceBindingContext = value.Clone();
              }
          }
  
          public override XmlDictionaryString RequestSecurityTokenAction
          {
              get 
              {
                  return this.StandardsManager.TrustDriver.RequestSecurityTokenAction;
              }
          }
  
          public override XmlDictionaryString RequestSecurityTokenResponseAction
          {
              get 
              {
                  return this.StandardsManager.TrustDriver.RequestSecurityTokenResponseAction;
              }
          }
  
          protected override MessageVersion MessageVersion
          {
              get
              {
                  return this.messageVersion;
              }
          }
  
          protected override bool RequiresManualReplyAddressing
          {
              get 
              {
                  ThrowIfCreated();
                  return this.requiresManualReplyAddressing;
              }
          }
  
          public override void OnClose(TimeSpan timeout)
          {
              TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
              if (this.rstChannelFactory != null)
              {
                  this.rstChannelFactory.Close(timeout);
                  this.rstChannelFactory = null;
              }
              base.OnClose(timeoutHelper.RemainingTime());
          }
  
          public override void OnAbort()
          {
              if (this.rstChannelFactory != null)
              {
                  this.rstChannelFactory.Abort();
                  this.rstChannelFactory = null;
              }
              base.OnAbort();
          }
  
          public override void OnOpen(TimeSpan timeout)
          {
              if (this.IssuerBindingContext == null)
              {
                  throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.IssuerBuildContextNotSet, this.GetType())));
              }
              TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
              this.SetupRstChannelFactory();
              this.rstChannelFactory.Open(timeout);
              base.OnOpen(timeoutHelper.RemainingTime());
          }
  
          protected abstract IChannelFactory<IRequestChannel> GetNegotiationChannelFactory(IChannelFactory<IRequestChannel> transportChannelFactory, ChannelBuilder channelBuilder);
  
          void SetupRstChannelFactory()
          {
              IChannelFactory<IRequestChannel> innerChannelFactory = null;
              ChannelBuilder channelBuilder = new ChannelBuilder(this.IssuerBindingContext.Clone(), true);
              // if the underlying transport does not support request/reply, wrap it inside
              // a service channel factory.
              if (channelBuilder.CanBuildChannelFactory<IRequestChannel>())
              {
                  innerChannelFactory = channelBuilder.BuildChannelFactory<IRequestChannel>();
                  this.requiresManualReplyAddressing = true;
              }
              else
              {
                  ClientRuntime clientRuntime = new ClientRuntime("RequestSecurityTokenContract", NamingHelper.DefaultNamespace);
                  clientRuntime.ValidateMustUnderstand = false;
                  ServiceChannelFactory serviceChannelFactory = ServiceChannelFactory.BuildChannelFactory(channelBuilder, clientRuntime);
  
                  serviceChannelFactory.ClientRuntime.UseSynchronizationContext = false;
                  serviceChannelFactory.ClientRuntime.AddTransactionFlowProperties = false;
                  ClientOperation rstOperation = new ClientOperation(serviceChannelFactory.ClientRuntime, "RequestSecurityToken", this.RequestSecurityTokenAction.Value);
                  rstOperation.Formatter = MessageOperationFormatter.Instance;
                  serviceChannelFactory.ClientRuntime.Operations.Add(rstOperation);
  
                  if (this.IsMultiLegNegotiation)
                  {
                      ClientOperation rstrOperation = new ClientOperation(serviceChannelFactory.ClientRuntime, "RequestSecurityTokenResponse", this.RequestSecurityTokenResponseAction.Value);
                      rstrOperation.Formatter = MessageOperationFormatter.Instance;
                      serviceChannelFactory.ClientRuntime.Operations.Add(rstrOperation);
                  }
                  // service channel automatically adds reply headers
                  this.requiresManualReplyAddressing = false;
                  innerChannelFactory = new SecuritySessionSecurityTokenProvider.RequestChannelFactory(serviceChannelFactory);
              }
  
              this.rstChannelFactory = GetNegotiationChannelFactory(innerChannelFactory, channelBuilder);
              this.messageVersion = channelBuilder.Binding.MessageVersion;
          }
         
          // negotiation message processing overrides
          protected override bool WillInitializeChannelFactoriesCompleteSynchronously(EndpointAddress target)
          {
              return true;
          }
  
          protected override void InitializeChannelFactories(EndpointAddress target, TimeSpan timeout)
          {
          }
  
          protected override IAsyncResult BeginInitializeChannelFactories(EndpointAddress target, TimeSpan timeout, AsyncCallback callback, object state)
          {
              return new CompletedAsyncResult(callback, state);
          }
  
          protected override void EndInitializeChannelFactories(IAsyncResult result)
          {
              CompletedAsyncResult.End(result);
          }
  
          protected override IRequestChannel CreateClientChannel(EndpointAddress target, Uri via)
          {
              if (via != null)
              {
                  return this.rstChannelFactory.CreateChannel(target, via);
              }
              else
              {
                  return this.rstChannelFactory.CreateChannel(target);
              }
          }
      }
  }
  