| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468 |
- //-----------------------------------------------------------------------------
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //-----------------------------------------------------------------------------
- namespace System.ServiceModel.Channels
- {
- using System;
- using System.ServiceModel.Description;
- using System.Collections.Generic;
- using System.Runtime.Serialization;
- using System.ServiceModel;
- using System.ServiceModel.Security;
- using System.ComponentModel;
- using System.ServiceModel.Transactions;
- using System.Xml;
- public sealed class TransactionFlowBindingElement : BindingElement, IPolicyExportExtension
- {
- bool transactions;
- TransactionFlowOption issuedTokens;
- TransactionProtocol transactionProtocol;
- public TransactionFlowBindingElement()
- : this(true, TransactionFlowDefaults.TransactionProtocol)
- {
- }
- public TransactionFlowBindingElement(TransactionProtocol transactionProtocol)
- : this(true, transactionProtocol)
- {
- }
- internal TransactionFlowBindingElement(bool transactions)
- : this(transactions, TransactionFlowDefaults.TransactionProtocol)
- {
- }
- internal TransactionFlowBindingElement(bool transactions, TransactionProtocol transactionProtocol)
- {
- this.transactions = transactions;
- this.issuedTokens = transactions ? TransactionFlowOption.Allowed : TransactionFlowOption.NotAllowed;
- if (!TransactionProtocol.IsDefined(transactionProtocol))
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.ConfigInvalidTransactionFlowProtocolValue, transactionProtocol.ToString()));
- }
- this.transactionProtocol = transactionProtocol;
- }
- TransactionFlowBindingElement(TransactionFlowBindingElement elementToBeCloned)
- : base(elementToBeCloned)
- {
- this.transactions = elementToBeCloned.transactions;
- this.issuedTokens = elementToBeCloned.issuedTokens;
- if (!TransactionProtocol.IsDefined(elementToBeCloned.transactionProtocol))
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.ConfigInvalidTransactionFlowProtocolValue, elementToBeCloned.transactionProtocol.ToString()));
- }
- this.transactionProtocol = elementToBeCloned.transactionProtocol;
- this.AllowWildcardAction = elementToBeCloned.AllowWildcardAction;
- }
- internal bool Transactions
- {
- get
- {
- return this.transactions;
- }
- set
- {
- this.transactions = value;
- this.issuedTokens = value ? TransactionFlowOption.Allowed : TransactionFlowOption.NotAllowed;
- }
- }
- internal TransactionFlowOption IssuedTokens
- {
- get
- {
- return this.issuedTokens;
- }
- set
- {
- ValidateOption(value);
- this.issuedTokens = value;
- }
- }
- public override BindingElement Clone()
- {
- return new TransactionFlowBindingElement(this);
- }
- bool IsFlowEnabled(Dictionary<DirectionalAction, TransactionFlowOption> dictionary)
- {
- if (this.issuedTokens != TransactionFlowOption.NotAllowed)
- {
- return true;
- }
- if (!this.transactions)
- {
- return false;
- }
- foreach (TransactionFlowOption option in dictionary.Values)
- {
- if (option != TransactionFlowOption.NotAllowed)
- {
- return true;
- }
- }
- return false;
- }
- internal bool IsFlowEnabled(ContractDescription contract)
- {
- if (this.issuedTokens != TransactionFlowOption.NotAllowed)
- {
- return true;
- }
- if (!this.transactions)
- {
- return false;
- }
- foreach (OperationDescription operation in contract.Operations)
- {
- TransactionFlowAttribute parameter = operation.Behaviors.Find<TransactionFlowAttribute>();
- if (parameter != null)
- {
- if (parameter.Transactions != TransactionFlowOption.NotAllowed)
- {
- return true;
- }
- }
- }
- return false;
- }
- public TransactionProtocol TransactionProtocol
- {
- get
- {
- return this.transactionProtocol;
- }
- set
- {
- if (!TransactionProtocol.IsDefined(value))
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
- this.transactionProtocol = value;
- }
- }
- [DefaultValue(false)]
- public bool AllowWildcardAction
- {
- get;
- set;
- }
- internal static void ValidateOption(TransactionFlowOption opt)
- {
- if (!TransactionFlowOptionHelper.IsDefined(opt))
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.TransactionFlowBadOption)));
- }
- [EditorBrowsable(EditorBrowsableState.Never)]
- public bool ShouldSerializeTransactionProtocol()
- {
- return this.TransactionProtocol != TransactionProtocol.Default;
- }
- public override bool CanBuildChannelFactory<TChannel>(BindingContext context)
- {
- if (context == null)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("context"));
- }
- if (typeof(TChannel) == typeof(IOutputChannel)
- || typeof(TChannel) == typeof(IDuplexChannel)
- || typeof(TChannel) == typeof(IRequestChannel)
- || typeof(TChannel) == typeof(IOutputSessionChannel)
- || typeof(TChannel) == typeof(IRequestSessionChannel)
- || typeof(TChannel) == typeof(IDuplexSessionChannel))
- {
- return context.CanBuildInnerChannelFactory<TChannel>();
- }
- return false;
- }
- // The BuildChannelFactory and BuildListenerFactory methods looks for this BindingParameter
- // in the BindingContext:
- // - Dictionary<DirectionalAction, TransactionFlowOption>
- // which has the per-operation TransactionFlowOptions
- public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
- {
- if (context == null)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
- }
- if (!this.CanBuildChannelFactory<TChannel>(context))
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("TChannel", SR.GetString(SR.ChannelTypeNotSupported, typeof(TChannel)));
- }
- Dictionary<DirectionalAction, TransactionFlowOption> dictionary = GetDictionary(context);
- if (!this.IsFlowEnabled(dictionary))
- {
- return context.BuildInnerChannelFactory<TChannel>();
- }
- if (this.issuedTokens == TransactionFlowOption.NotAllowed)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.TransactionFlowRequiredIssuedTokens)));
- }
- TransactionChannelFactory<TChannel> channelFactory =
- new TransactionChannelFactory<TChannel>(this.transactionProtocol, context, dictionary, this.AllowWildcardAction);
- channelFactory.FlowIssuedTokens = this.IssuedTokens;
- return channelFactory;
- }
- public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
- {
- if (context == null)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("context"));
- }
- if (!context.CanBuildInnerChannelListener<TChannel>())
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("TChannel", SR.GetString(SR.ChannelTypeNotSupported, typeof(TChannel)));
- }
- Dictionary<DirectionalAction, TransactionFlowOption> dictionary = GetDictionary(context);
- if (!this.IsFlowEnabled(dictionary))
- {
- return context.BuildInnerChannelListener<TChannel>();
- }
- if (this.issuedTokens == TransactionFlowOption.NotAllowed)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.TransactionFlowRequiredIssuedTokens)));
- }
- IChannelListener<TChannel> innerListener = context.BuildInnerChannelListener<TChannel>();
- TransactionChannelListener<TChannel> listener = new TransactionChannelListener<TChannel>(this.transactionProtocol, context.Binding, dictionary, innerListener);
- listener.FlowIssuedTokens = this.IssuedTokens;
- return listener;
- }
- public override bool CanBuildChannelListener<TChannel>(BindingContext context)
- {
- if (!context.CanBuildInnerChannelListener<TChannel>())
- return false;
- return (typeof(TChannel) == typeof(IInputChannel) ||
- typeof(TChannel) == typeof(IReplyChannel) ||
- typeof(TChannel) == typeof(IDuplexChannel) ||
- typeof(TChannel) == typeof(IInputSessionChannel) ||
- typeof(TChannel) == typeof(IReplySessionChannel) ||
- typeof(TChannel) == typeof(IDuplexSessionChannel));
- }
- Dictionary<DirectionalAction, TransactionFlowOption> GetDictionary(BindingContext context)
- {
- Dictionary<DirectionalAction, TransactionFlowOption> dictionary =
- context.BindingParameters.Find<Dictionary<DirectionalAction, TransactionFlowOption>>();
- if (dictionary == null)
- dictionary = new Dictionary<DirectionalAction, TransactionFlowOption>();
- return dictionary;
- }
- internal static MessagePartSpecification GetIssuedTokenHeaderSpecification(SecurityStandardsManager standardsManager)
- {
- MessagePartSpecification result;
- if (standardsManager.TrustDriver.IsIssuedTokensSupported)
- result = new MessagePartSpecification(new XmlQualifiedName(standardsManager.TrustDriver.IssuedTokensHeaderName, standardsManager.TrustDriver.IssuedTokensHeaderNamespace));
- else
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.TrustDriverVersionDoesNotSupportIssuedTokens)));
- }
- return result;
- }
- public override T GetProperty<T>(BindingContext context)
- {
- if (typeof(T) == typeof(ChannelProtectionRequirements))
- {
- ChannelProtectionRequirements myRequirements = this.GetProtectionRequirements();
- if (myRequirements != null)
- {
- myRequirements.Add(context.GetInnerProperty<ChannelProtectionRequirements>() ?? new ChannelProtectionRequirements());
- return (T)(object)myRequirements;
- }
- else
- {
- return (T)(object)context.GetInnerProperty<ChannelProtectionRequirements>();
- }
- }
- else
- {
- return context.GetInnerProperty<T>();
- }
- }
- ChannelProtectionRequirements GetProtectionRequirements()
- {
- if (this.Transactions || (this.IssuedTokens != TransactionFlowOption.NotAllowed))
- {
- ChannelProtectionRequirements requirements = new ChannelProtectionRequirements();
- if (this.Transactions)
- {
- MessagePartSpecification p = new MessagePartSpecification(
- new XmlQualifiedName(CoordinationExternalStrings.CoordinationContext, CoordinationExternal10Strings.Namespace),
- new XmlQualifiedName(CoordinationExternalStrings.CoordinationContext, CoordinationExternal11Strings.Namespace),
- new XmlQualifiedName(OleTxTransactionExternalStrings.OleTxTransaction, OleTxTransactionExternalStrings.Namespace));
- p.MakeReadOnly();
- requirements.IncomingSignatureParts.AddParts(p);
- requirements.OutgoingSignatureParts.AddParts(p);
- requirements.IncomingEncryptionParts.AddParts(p);
- requirements.OutgoingEncryptionParts.AddParts(p);
- }
- if (this.IssuedTokens != TransactionFlowOption.NotAllowed)
- {
- MessagePartSpecification trustParts = GetIssuedTokenHeaderSpecification(SecurityStandardsManager.DefaultInstance);
- trustParts.MakeReadOnly();
- requirements.IncomingSignatureParts.AddParts(trustParts);
- requirements.IncomingEncryptionParts.AddParts(trustParts);
- requirements.OutgoingSignatureParts.AddParts(trustParts);
- requirements.OutgoingEncryptionParts.AddParts(trustParts);
- }
- MessagePartSpecification body = new MessagePartSpecification(true);
- body.MakeReadOnly();
- requirements.OutgoingSignatureParts.AddParts(body, FaultCodeConstants.Actions.Transactions);
- requirements.OutgoingEncryptionParts.AddParts(body, FaultCodeConstants.Actions.Transactions);
- return requirements;
- }
- else
- {
- return null;
- }
- }
- XmlElement GetAssertion(XmlDocument doc, TransactionFlowOption option, string prefix, string name, string ns, string policyNs)
- {
- if (doc == null)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("doc");
- XmlElement result = null;
- switch (option)
- {
- case TransactionFlowOption.NotAllowed:
- // Don't generate an assertion
- break;
- case TransactionFlowOption.Allowed:
- result = doc.CreateElement(prefix, name, ns);
- // Always insert the real wsp:Optional attribute
- XmlAttribute attr = doc.CreateAttribute(TransactionPolicyStrings.OptionalPrefix11,
- TransactionPolicyStrings.OptionalLocal, policyNs);
- attr.Value = TransactionPolicyStrings.TrueValue;
- result.Attributes.Append(attr);
- // For legacy protocols, also insert the legacy attribute for backward compat
- if (this.transactionProtocol == TransactionProtocol.OleTransactions ||
- this.transactionProtocol == TransactionProtocol.WSAtomicTransactionOctober2004)
- {
- XmlAttribute attrLegacy = doc.CreateAttribute(TransactionPolicyStrings.OptionalPrefix10,
- TransactionPolicyStrings.OptionalLocal, TransactionPolicyStrings.OptionalNamespaceLegacy);
- attrLegacy.Value = TransactionPolicyStrings.TrueValue;
- result.Attributes.Append(attrLegacy);
- }
- break;
- case TransactionFlowOption.Mandatory:
- result = doc.CreateElement(prefix, name, ns);
- break;
- }
- return result;
- }
- void IPolicyExportExtension.ExportPolicy(MetadataExporter exporter, PolicyConversionContext context)
- {
- if (exporter == null)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("exporter");
- }
- if (context == null)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
- }
- TransactionFlowBindingElement bindingElement = context.BindingElements.Find<TransactionFlowBindingElement>();
- if (bindingElement == null || !bindingElement.Transactions)
- return;
- XmlDocument doc = new XmlDocument();
- XmlElement assertion = null;
- foreach (OperationDescription operation in context.Contract.Operations)
- {
- TransactionFlowAttribute contextParam = operation.Behaviors.Find<TransactionFlowAttribute>();
- TransactionFlowOption txFlowOption = contextParam == null ? TransactionFlowOption.NotAllowed : contextParam.Transactions;
- // Transactions
- if (bindingElement.TransactionProtocol == TransactionProtocol.OleTransactions)
- {
- assertion = GetAssertion(doc, txFlowOption,
- TransactionPolicyStrings.OleTxTransactionsPrefix, TransactionPolicyStrings.OleTxTransactionsLocal,
- TransactionPolicyStrings.OleTxTransactionsNamespace, exporter.PolicyVersion.Namespace);
- }
- else if (bindingElement.TransactionProtocol == TransactionProtocol.WSAtomicTransactionOctober2004)
- {
- assertion = GetAssertion(doc, txFlowOption,
- TransactionPolicyStrings.WsatTransactionsPrefix, TransactionPolicyStrings.WsatTransactionsLocal,
- TransactionPolicyStrings.WsatTransactionsNamespace10, exporter.PolicyVersion.Namespace);
- }
- else if (bindingElement.TransactionProtocol == TransactionProtocol.WSAtomicTransaction11)
- {
- assertion = GetAssertion(doc, txFlowOption,
- TransactionPolicyStrings.WsatTransactionsPrefix, TransactionPolicyStrings.WsatTransactionsLocal,
- TransactionPolicyStrings.WsatTransactionsNamespace11, exporter.PolicyVersion.Namespace);
- }
- if (assertion != null)
- context.GetOperationBindingAssertions(operation).Add(assertion);
- }
- }
- internal override bool IsMatch(BindingElement b)
- {
- if (b == null)
- return false;
- TransactionFlowBindingElement txFlow = b as TransactionFlowBindingElement;
- if (txFlow == null)
- return false;
- if (this.transactions != txFlow.transactions)
- return false;
- if (this.issuedTokens != txFlow.issuedTokens)
- return false;
- if (this.transactionProtocol != txFlow.transactionProtocol)
- return false;
- return true;
- }
- }
- }
|