|
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.ServiceModel.Description
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Diagnostics;
using System.IdentityModel.Selectors;
using System.Reflection;
using System.Runtime;
using System.Runtime.Diagnostics;
using System.Security;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel.Activation;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Diagnostics;
using System.ServiceModel.Security;
using System.Text;
using System.Runtime.CompilerServices;
class ConfigLoader
{
//resolvedBindings will be initialized to null on all threads
//ThreadStatic gives each thread own copy of object
[ThreadStatic]
static List<string> resolvedBindings;
//resolvedEndpoints will be initialized to null on all threads
//ThreadStatic gives each thread own copy of object
[ThreadStatic]
static List<string> resolvedEndpoints;
static readonly object[] emptyObjectArray = new object[] { };
static readonly Type[] emptyTypeArray = new Type[] { };
Dictionary<string, Binding> bindingTable;
IContractResolver contractResolver;
ContextInformation configurationContext;
public ConfigLoader()
: this((IContractResolver)null)
{
}
public ConfigLoader(ContextInformation configurationContext)
: this((IContractResolver)null)
{
this.configurationContext = configurationContext;
}
public ConfigLoader(IContractResolver contractResolver)
{
this.contractResolver = contractResolver;
this.bindingTable = new Dictionary<string, Binding>();
}
[Fx.Tag.SecurityNote(Critical = "Handles config objects, which should not be leaked.",
Safe = "Doesn't leak config objects out of SecurityCritical code.")]
[SecuritySafeCritical]
internal static EndpointIdentity LoadIdentity(IdentityElement element)
{
EndpointIdentity identity = null;
PropertyInformationCollection properties = element.ElementInformation.Properties;
if (properties[ConfigurationStrings.UserPrincipalName].ValueOrigin != PropertyValueOrigin.Default)
{
identity = EndpointIdentity.CreateUpnIdentity(element.UserPrincipalName.Value);
}
else if (properties[ConfigurationStrings.ServicePrincipalName].ValueOrigin != PropertyValueOrigin.Default)
{
identity = EndpointIdentity.CreateSpnIdentity(element.ServicePrincipalName.Value);
}
else if (properties[ConfigurationStrings.Dns].ValueOrigin != PropertyValueOrigin.Default)
{
identity = EndpointIdentity.CreateDnsIdentity(element.Dns.Value);
}
else if (properties[ConfigurationStrings.Rsa].ValueOrigin != PropertyValueOrigin.Default)
{
identity = EndpointIdentity.CreateRsaIdentity(element.Rsa.Value);
}
else if (properties[ConfigurationStrings.Certificate].ValueOrigin != PropertyValueOrigin.Default)
{
X509Certificate2Collection collection = new X509Certificate2Collection();
collection.Import(Convert.FromBase64String(element.Certificate.EncodedValue));
if (collection.Count == 0)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.UnableToLoadCertificateIdentity)));
}
// We assume the first certificate in the list is the primary
// certificate.
X509Certificate2 primaryCert = collection[0];
collection.RemoveAt(0);
identity = EndpointIdentity.CreateX509CertificateIdentity(primaryCert, collection);
}
else if (properties[ConfigurationStrings.CertificateReference].ValueOrigin != PropertyValueOrigin.Default)
{
X509CertificateStore store = new X509CertificateStore(element.CertificateReference.StoreName, element.CertificateReference.StoreLocation);
X509Certificate2Collection collection = null;
try
{
store.Open(OpenFlags.ReadOnly);
collection = store.Find(element.CertificateReference.X509FindType, element.CertificateReference.FindValue, false);
if (collection.Count == 0)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.UnableToLoadCertificateIdentity)));
}
// Just select the first certificate.
X509Certificate2 primaryCert = new X509Certificate2(collection[0]);
if (element.CertificateReference.IsChainIncluded)
{
// Build the chain.
X509Chain chain = new X509Chain();
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
chain.Build(primaryCert);
identity = EndpointIdentity.CreateX509CertificateIdentity(chain);
}
else
{
identity = EndpointIdentity.CreateX509CertificateIdentity(primaryCert);
}
}
finally
{
SecurityUtils.ResetAllCertificates(collection);
store.Close();
}
}
return identity;
}
[Fx.Tag.SecurityNote(Critical = "Handles config objects, which should not be leaked.",
Safe = "Doesn't leak config objects out of SecurityCritical code.")]
[SecuritySafeCritical]
internal void LoadChannelBehaviors(ServiceEndpoint serviceEndpoint, string configurationName)
{
ServiceEndpoint standardEndpoint;
bool wildcard = IsWildcardMatch(configurationName);
ChannelEndpointElement channelElement = LookupChannel(this.configurationContext, configurationName, serviceEndpoint.Contract, null, wildcard, false, out standardEndpoint);
if (channelElement == null)
{
if (wildcard)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxConfigContractNotFound, serviceEndpoint.Contract.ConfigurationName)));
}
else
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxConfigChannelConfigurationNotFound, configurationName, serviceEndpoint.Contract.ConfigurationName)));
}
}
if (serviceEndpoint.Binding == null && !string.IsNullOrEmpty(channelElement.Binding))
{
serviceEndpoint.Binding = ConfigLoader.LookupBinding(channelElement.Binding, channelElement.BindingConfiguration, ConfigurationHelpers.GetEvaluationContext(channelElement));
}
if (serviceEndpoint.Address == null && channelElement.Address != null && channelElement.Address.OriginalString.Length > 0)
{
serviceEndpoint.Address = new EndpointAddress(channelElement.Address, LoadIdentity(channelElement.Identity), channelElement.Headers.Headers);
}
CommonBehaviorsSection commonBehaviors = ConfigLoader.LookupCommonBehaviors(ConfigurationHelpers.GetEvaluationContext(channelElement));
if (commonBehaviors != null && commonBehaviors.EndpointBehaviors != null)
{
LoadBehaviors<IEndpointBehavior>(commonBehaviors.EndpointBehaviors, serviceEndpoint.Behaviors, true/*commonBehaviors*/);
}
EndpointBehaviorElement behaviorElement = ConfigLoader.LookupEndpointBehaviors(channelElement.BehaviorConfiguration, ConfigurationHelpers.GetEvaluationContext(channelElement));
if (behaviorElement != null)
{
LoadBehaviors<IEndpointBehavior>(behaviorElement, serviceEndpoint.Behaviors, false/*commonBehaviors*/);
}
}
[Fx.Tag.SecurityNote(Critical = "Handles config objects, which should not be leaked.",
Safe = "Doesn't leak config objects out of SecurityCritical code.")]
[SecuritySafeCritical]
internal void LoadCommonClientBehaviors(ServiceEndpoint serviceEndpoint)
{
// just load commonBehaviors
CommonBehaviorsSection commonBehaviors = ConfigLoader.LookupCommonBehaviors(this.configurationContext);
if (commonBehaviors != null && commonBehaviors.EndpointBehaviors != null)
{
LoadBehaviors<IEndpointBehavior>(commonBehaviors.EndpointBehaviors, serviceEndpoint.Behaviors, true/*commonBehaviors*/);
}
}
[Fx.Tag.SecurityNote(Critical = "Handles config objects, which should not be leaked.",
Safe = "Doesn't leak config objects out of SecurityCritical code.")]
[SecuritySafeCritical]
static void LoadBehaviors<T>(ServiceModelExtensionCollectionElement<BehaviorExtensionElement> behaviorElement, KeyedByTypeCollection<T> behaviors, bool commonBehaviors)
{
Nullable<bool> isPT = new Nullable<bool>();
KeyedByTypeCollection<T> tempBehaviors = new KeyedByTypeCollection<T>();
for (int i = 0; i < behaviorElement.Count; i++)
{
BehaviorExtensionElement behaviorExtension = behaviorElement[i];
object behaviorObject = behaviorExtension.CreateBehavior();
if (behaviorObject == null)
{
continue;
}
Type type = behaviorObject.GetType();
if (!typeof(T).IsAssignableFrom(type))
{
TraceBehaviorWarning(behaviorExtension, TraceCode.SkipBehavior, SR.GetString(SR.TraceCodeSkipBehavior), type, typeof(T));
continue;
}
if (commonBehaviors)
{
if (ShouldSkipCommonBehavior(type, ref isPT))
{
TraceBehaviorWarning(behaviorExtension, TraceCode.SkipBehavior, SR.GetString(SR.TraceCodeSkipBehavior), type, typeof(T));
continue;
}
}
// if, at this scope, we try to add same type of behavior twice, throw
tempBehaviors.Add((T)behaviorObject);
// but if the same type of behavior was present from an old scope, just remove the old one
if (behaviors.Contains(type))
{
TraceBehaviorWarning(behaviorExtension, TraceCode.RemoveBehavior, SR.GetString(SR.TraceCodeRemoveBehavior), type, typeof(T));
behaviors.Remove(type);
}
behaviors.Add((T)behaviorObject);
}
}
// special processing for common behaviors:
// if:
// 1. the behavior type (returned from the config element) is in a signed, non-APTCA assembly
// 2. the caller stack does not have ConfigurationPermission(Unrestricted)
// .. exclude the behavior from the collection and trace a warning
[Fx.Tag.SecurityNote(Critical = "Calls SecurityCritical helpers, makes a security decision.")]
[SecurityCritical]
static bool ShouldSkipCommonBehavior(Type behaviorType, ref Nullable<bool> isPT)
{
bool skip = false;
if (!isPT.HasValue)
{
if (!PartialTrustHelpers.IsTypeAptca(behaviorType))
{
isPT = !ThreadHasConfigurationPermission();
skip = isPT.Value;
}
}
else if (isPT.Value)
{
skip = !PartialTrustHelpers.IsTypeAptca(behaviorType);
}
return skip;
}
[Fx.Tag.SecurityNote(Critical = "Handles config objects, which should not be leaked.",
Safe = "Doesn't leak config objects out of SecurityCritical code.")]
[SecuritySafeCritical]
static void TraceBehaviorWarning(BehaviorExtensionElement behaviorExtension, int traceCode, string traceDescription, Type type, Type behaviorType)
{
if (DiagnosticUtility.ShouldTraceWarning)
{
Hashtable h = new Hashtable(3)
{
{ "ConfigurationElementName", behaviorExtension.ConfigurationElementName },
{ "ConfigurationType", type.AssemblyQualifiedName },
{ "BehaviorType", behaviorType.AssemblyQualifiedName }
};
TraceUtility.TraceEvent(TraceEventType.Warning, traceCode, traceDescription,
new DictionaryTraceRecord(h), null, null);
}
}
[Fx.Tag.SecurityNote(Critical = "Handles config objects, which should not be leaked.",
Safe = "Doesn't leak config objects out of SecurityCritical code.")]
[SecuritySafeCritical]
static void LoadChannelBehaviors(EndpointBehaviorElement behaviorElement, KeyedByTypeCollection<IEndpointBehavior> channelBehaviors)
{
if (behaviorElement != null)
{
LoadBehaviors<IEndpointBehavior>(behaviorElement, channelBehaviors, false/*commonBehaviors*/
);
}
}
[Fx.Tag.SecurityNote(Critical = "Handles config objects, which should not be leaked.",
Safe = "Doesn't leak config objects out of SecurityCritical code.")]
[SecuritySafeCritical]
internal static void LoadChannelBehaviors(string behaviorName, ContextInformation context, KeyedByTypeCollection<IEndpointBehavior> channelBehaviors)
{
LoadChannelBehaviors(
LookupEndpointBehaviors(behaviorName, context),
channelBehaviors
);
}
[Fx.Tag.SecurityNote(Critical = "Handles config objects, which should not be leaked.",
Safe = "Doesn't leak config objects out of SecurityCritical code.")]
[SecuritySafeCritical]
internal static Collection<IWsdlImportExtension> LoadWsdlImporters(WsdlImporterElementCollection wsdlImporterElements, ContextInformation context)
{
Collection<IWsdlImportExtension> wsdlImporters = new Collection<IWsdlImportExtension>();
foreach (WsdlImporterElement wsdlImporterElement in wsdlImporterElements)
{
// Verify that the type implements IWsdlImporter
Type wsdlImporterType = Type.GetType(wsdlImporterElement.Type, true, true);
if (!typeof(IWsdlImportExtension).IsAssignableFrom(wsdlImporterType))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidWsdlExtensionTypeInConfig, wsdlImporterType.AssemblyQualifiedName)));
}
// Verify that the type has a default constructor
ConstructorInfo constructorInfo = wsdlImporterType.GetConstructor(emptyTypeArray);
if (constructorInfo == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.WsdlExtensionTypeRequiresDefaultConstructor, wsdlImporterType.AssemblyQualifiedName)));
}
wsdlImporters.Add((IWsdlImportExtension)constructorInfo.Invoke(emptyObjectArray));
}
return wsdlImporters;
}
[Fx.Tag.SecurityNote(Critical = "Handles config objects, which should not be leaked.",
Safe = "Doesn't leak config objects out of SecurityCritical code.")]
[SecuritySafeCritical]
internal static Collection<IPolicyImportExtension> LoadPolicyImporters(PolicyImporterElementCollection policyImporterElements, ContextInformation context)
{
Collection<IPolicyImportExtension> policyImporters = new Collection<IPolicyImportExtension>();
foreach (PolicyImporterElement policyImporterElement in policyImporterElements)
{
// Verify that the type implements IPolicyImporter
Type policyImporterType = Type.GetType(policyImporterElement.Type, true, true);
if (!typeof(IPolicyImportExtension).IsAssignableFrom(policyImporterType))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidPolicyExtensionTypeInConfig, policyImporterType.AssemblyQualifiedName)));
}
// Verify that the type has a default constructor
ConstructorInfo constructorInfo = policyImporterType.GetConstructor(emptyTypeArray);
if (constructorInfo == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.PolicyExtensionTypeRequiresDefaultConstructor, policyImporterType.AssemblyQualifiedName)));
}
policyImporters.Add((IPolicyImportExtension)constructorInfo.Invoke(emptyObjectArray));
}
return policyImporters;
}
[Fx.Tag.SecurityNote(Critical = "Handles config objects, which should not be leaked.",
Safe = "Doesn't leak config objects out of SecurityCritical code.")]
[SecuritySafeCritical]
internal static EndpointAddress LoadEndpointAddress(EndpointAddressElementBase element)
{
return new EndpointAddress(element.Address, LoadIdentity(element.Identity), element.Headers.Headers);
}
[Fx.Tag.SecurityNote(Critical = "Handles config objects, which should not be leaked.",
Safe = "Doesn't leak config objects out of SecurityCritical code.")]
[SecuritySafeCritical]
public void LoadHostConfig(ServiceElement serviceElement, ServiceHostBase host, System.Action<Uri> addBaseAddress)
{
HostElement hostElement = serviceElement.Host;
if (hostElement != null)
{
if (!AspNetEnvironment.Enabled)
{
foreach (BaseAddressElement bae in hostElement.BaseAddresses)
{
string cookedAddress = null;
string rawAddress = bae.BaseAddress;
int colonIndex = rawAddress.IndexOf(':');
if (colonIndex != -1 && rawAddress.Length >= colonIndex + 4)
{
if (rawAddress[colonIndex + 1] == '/' &&
rawAddress[colonIndex + 2] == '/' &&
rawAddress[colonIndex + 3] == '*')
{
string beforeAsterisk = rawAddress.Substring(0, colonIndex + 3);
string rest = rawAddress.Substring(colonIndex + 4);
StringBuilder sb = new StringBuilder(beforeAsterisk);
sb.Append(System.Net.Dns.GetHostName());
sb.Append(rest);
cookedAddress = sb.ToString();
}
}
if (cookedAddress == null)
{
cookedAddress = rawAddress;
}
Uri uri;
if (!Uri.TryCreate(cookedAddress, UriKind.Absolute, out uri))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.BaseAddressMustBeAbsolute)));
}
addBaseAddress(uri);
}
}
HostTimeoutsElement hte = hostElement.Timeouts;
if (hte != null)
{
if (hte.OpenTimeout != TimeSpan.Zero)
{
host.OpenTimeout = hte.OpenTimeout;
}
if (hte.CloseTimeout != TimeSpan.Zero)
{
host.CloseTimeout = hte.CloseTimeout;
}
}
}
}
[Fx.Tag.SecurityNote(Critical = "Handles config objects, which should not be leaked.",
Safe = "Doesn't leak config objects out of SecurityCritical code.")]
[SecuritySafeCritical]
public void LoadServiceDescription(ServiceHostBase host, ServiceDescription description, ServiceElement serviceElement, System.Action<Uri> addBaseAddress, bool skipHost = false)
{
CommonBehaviorsSection commonBehaviors = ConfigLoader.LookupCommonBehaviors(
serviceElement == null ? null : ConfigurationHelpers.GetEvaluationContext(serviceElement));
if (commonBehaviors != null && commonBehaviors.ServiceBehaviors != null)
{
LoadBehaviors<IServiceBehavior>(commonBehaviors.ServiceBehaviors, description.Behaviors, true/*commonBehaviors*/);
}
string behaviorConfigurationName = ConfigurationStrings.DefaultName;
if (serviceElement != null)
{
if (!skipHost)
{
this.LoadHostConfig(serviceElement, host, addBaseAddress);
}
behaviorConfigurationName = serviceElement.BehaviorConfiguration;
}
ServiceBehaviorElement behaviorElement = ConfigLoader.LookupServiceBehaviors(behaviorConfigurationName, ConfigurationHelpers.GetEvaluationContext(serviceElement));
if (behaviorElement != null)
{
LoadBehaviors<IServiceBehavior>(behaviorElement, description.Behaviors, false/*commonBehaviors*/);
}
ServiceHostBase.ServiceAndBehaviorsContractResolver resolver = this.contractResolver as ServiceHostBase.ServiceAndBehaviorsContractResolver;
if (resolver != null)
{
resolver.AddBehaviorContractsToResolver(description.Behaviors);
}
if (serviceElement != null)
{
foreach (ServiceEndpointElement endpointElement in serviceElement.Endpoints)
{
if (String.IsNullOrEmpty(endpointElement.Kind))
{
ContractDescription contract = LookupContract(endpointElement.Contract, description.Name);
// binding
Binding binding;
string bindingKey = endpointElement.Binding + ":" + endpointElement.BindingConfiguration;
if (bindingTable.TryGetValue(bindingKey, out binding) == false)
{
binding = ConfigLoader.LookupBinding(endpointElement.Binding, endpointElement.BindingConfiguration, ConfigurationHelpers.GetEvaluationContext(serviceElement));
bindingTable.Add(bindingKey, binding);
}
if (!string.IsNullOrEmpty(endpointElement.BindingName))
{
binding.Name = endpointElement.BindingName;
}
if (!string.IsNullOrEmpty(endpointElement.BindingNamespace))
{
binding.Namespace = endpointElement.BindingNamespace;
}
// address
Uri address = endpointElement.Address;
ServiceEndpoint serviceEndpoint;
if (null == address)
{
serviceEndpoint = new ServiceEndpoint(contract);
serviceEndpoint.Binding = binding;
}
else
{
Uri via = ServiceHost.MakeAbsoluteUri(address, binding, host.InternalBaseAddresses);
serviceEndpoint = new ServiceEndpoint(contract, binding, new EndpointAddress(via, LoadIdentity(endpointElement.Identity), endpointElement.Headers.Headers));
serviceEndpoint.UnresolvedAddress = endpointElement.Address;
}
if (endpointElement.ListenUri != null)
{
serviceEndpoint.ListenUri = ServiceHost.MakeAbsoluteUri(endpointElement.ListenUri, binding, host.InternalBaseAddresses);
serviceEndpoint.UnresolvedListenUri = endpointElement.ListenUri;
}
serviceEndpoint.ListenUriMode = endpointElement.ListenUriMode;
if (!string.IsNullOrEmpty(endpointElement.Name))
{
serviceEndpoint.Name = endpointElement.Name;
}
KeyedByTypeCollection<IEndpointBehavior> behaviors = serviceEndpoint.Behaviors;
EndpointBehaviorElement behaviorEndpointElement = ConfigLoader.LookupEndpointBehaviors(endpointElement.BehaviorConfiguration, ConfigurationHelpers.GetEvaluationContext(endpointElement));
if (behaviorEndpointElement != null)
{
LoadBehaviors<IEndpointBehavior>(behaviorEndpointElement, behaviors, false/*commonBehaviors*/);
}
if (endpointElement.ElementInformation.Properties[ConfigurationStrings.IsSystemEndpoint].ValueOrigin != PropertyValueOrigin.Default)
{
serviceEndpoint.IsSystemEndpoint = endpointElement.IsSystemEndpoint;
}
description.Endpoints.Add(serviceEndpoint);
}
else
{
ServiceEndpoint endpoint = LookupEndpoint(endpointElement, ConfigurationHelpers.GetEvaluationContext(serviceElement), host, description);
description.Endpoints.Add(endpoint);
}
}
}
}
[Fx.Tag.SecurityNote(Critical = "Handles config objects, which should not be leaked.",
Safe = "Doesn't leak config objects out of SecurityCritical code.")]
[SecuritySafeCritical]
public static void LoadDefaultEndpointBehaviors(ServiceEndpoint endpoint)
{
EndpointBehaviorElement behaviorEndpointElement = ConfigLoader.LookupEndpointBehaviors(ConfigurationStrings.DefaultName, ConfigurationHelpers.GetEvaluationContext(null));
if (behaviorEndpointElement != null)
{
LoadBehaviors<IEndpointBehavior>(behaviorEndpointElement, endpoint.Behaviors, false);
}
}
[Fx.Tag.SecurityNote(Critical = "Handles config objects, which should not be leaked.")]
[SecurityCritical]
static EndpointCollectionElement LookupEndpointCollectionElement(string endpointSectionName, ContextInformation context)
{
if (string.IsNullOrEmpty(endpointSectionName))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ConfigurationErrorsException(SR.GetString(SR.ConfigEndpointTypeCannotBeNullOrEmpty)));
}
EndpointCollectionElement endpointCollectionElement = null;
if (context == null)
{
// If no context is passed in, assume that the caller can consume the AppDomain's
// current configuration file.
endpointCollectionElement = (EndpointCollectionElement)ConfigurationHelpers.UnsafeGetEndpointCollectionElement(endpointSectionName);
}
else
{
// Use the configuration file associated with the passed in context.
// This may or may not be the same as the file for the current AppDomain.
endpointCollectionElement = (EndpointCollectionElement)ConfigurationHelpers.UnsafeGetAssociatedEndpointCollectionElement(context, endpointSectionName);
}
return endpointCollectionElement;
}
[Fx.Tag.SecurityNote(Critical = "Handles config objects, which should not be leaked.",
Safe = "Doesn't leak config objects out of SecurityCritical code.")]
[SecuritySafeCritical]
internal static ServiceEndpoint LookupEndpoint(string configurationName, EndpointAddress address, ContractDescription contract)
{
return LookupEndpoint(configurationName, address, contract, null);
}
[Fx.Tag.SecurityNote(Critical = "Handles config objects, which should not be leaked.",
Safe = "Doesn't leak config objects out of SecurityCritical code.")]
[SecuritySafeCritical]
internal static ServiceEndpoint LookupEndpoint(string configurationName, EndpointAddress address, ContractDescription contract, ContextInformation configurationContext)
{
bool wildcard = IsWildcardMatch(configurationName);
ServiceEndpoint serviceEndpoint;
LookupChannel(configurationContext, configurationName, contract, address, wildcard, true, out serviceEndpoint);
return serviceEndpoint;
}
internal static ServiceEndpoint LookupEndpoint(ChannelEndpointElement channelEndpointElement, ContextInformation context)
{
return LookupEndpoint(channelEndpointElement, context, null /*address*/, null /*contractDescription*/);
}
// This method should only return null when endpointConfiguration is specified on the ChannelEndpointElement and no ChannelEndpointElement matching the
// endpointConfiguration name is found. All other error conditions should throw.
[Fx.Tag.SecurityNote(Critical = "Handles config objects, which should not be leaked.",
Safe = "Doesn't leak config objects out of SecurityCritical code.")]
[SecuritySafeCritical]
static ServiceEndpoint LookupEndpoint(ChannelEndpointElement channelEndpointElement, ContextInformation context, EndpointAddress address, ContractDescription contract)
{
EndpointCollectionElement endpointCollectionElement = LookupEndpointCollectionElement(channelEndpointElement.Kind, context);
ServiceEndpoint retval = null;
string endpointConfiguration = channelEndpointElement.EndpointConfiguration ?? String.Empty;
// We are looking for a specific instance, not the default.
bool configuredEndpointFound = false;
// The Endpoints property is always public
foreach (StandardEndpointElement standardEndpointElement in endpointCollectionElement.ConfiguredEndpoints)
{
if (standardEndpointElement.Name.Equals(endpointConfiguration, StringComparison.Ordinal))
{
if (null == ConfigLoader.resolvedEndpoints)
{
ConfigLoader.resolvedEndpoints = new List<string>();
}
string resolvedEndpointID = channelEndpointElement.Kind + "/" + endpointConfiguration;
if (ConfigLoader.resolvedEndpoints.Contains(resolvedEndpointID))
{
ConfigurationElement configErrorElement = (ConfigurationElement)standardEndpointElement;
System.Text.StringBuilder detectedCycle = new System.Text.StringBuilder();
foreach (string resolvedEndpoint in ConfigLoader.resolvedEndpoints)
{
detectedCycle = detectedCycle.AppendFormat("{0}, ", resolvedEndpoint);
}
detectedCycle = detectedCycle.Append(resolvedEndpointID);
// Clear list in case application is written to handle exception
// by not starting up channel, etc...
ConfigLoader.resolvedEndpoints = null;
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ConfigurationErrorsException(SR.GetString(SR.ConfigEndpointReferenceCycleDetected, detectedCycle.ToString()),
configErrorElement.ElementInformation.Source,
configErrorElement.ElementInformation.LineNumber));
}
try
{
CheckAccess(standardEndpointElement as IConfigurationContextProviderInternal);
ConfigLoader.resolvedEndpoints.Add(resolvedEndpointID);
ConfigureEndpoint(standardEndpointElement, channelEndpointElement, address, context, contract, out retval);
ConfigLoader.resolvedEndpoints.Remove(resolvedEndpointID);
}
catch
{
// Clear list in case application is written to handle exception
// by not starting up channel, etc...
if (null != ConfigLoader.resolvedEndpoints)
{
ConfigLoader.resolvedBindings = null;
}
throw;
}
if (null != ConfigLoader.resolvedEndpoints &&
0 == ConfigLoader.resolvedEndpoints.Count)
{
ConfigLoader.resolvedEndpoints = null;
}
configuredEndpointFound = true;
}
}
if (!configuredEndpointFound)
{
// We expected to find an instance, but didn't.
// Return null.
retval = null;
}
if (retval == null && String.IsNullOrEmpty(endpointConfiguration))
{
StandardEndpointElement standardEndpointElement = endpointCollectionElement.GetDefaultStandardEndpointElement();
ConfigureEndpoint(standardEndpointElement, channelEndpointElement, address, context, contract, out retval);
}
if (DiagnosticUtility.ShouldTraceVerbose)
{
Dictionary<string, object> values = new Dictionary<string, object>(3);
values["FoundEndpoint"] = retval != null;
bool usingDefault = string.IsNullOrEmpty(endpointConfiguration);
int traceCode;
string traceDescription;
if (usingDefault)
{
traceCode = TraceCode.GetDefaultConfiguredEndpoint;
traceDescription = SR.GetString(SR.TraceCodeGetDefaultConfiguredEndpoint);
}
else
{
traceCode = TraceCode.GetConfiguredEndpoint;
traceDescription = SR.GetString(SR.TraceCodeGetConfiguredEndpoint);
values["Name"] = endpointConfiguration;
}
values["Endpoint"] = channelEndpointElement.Kind;
TraceUtility.TraceEvent(TraceEventType.Verbose, traceCode, traceDescription,
new DictionaryTraceRecord(values), null, null);
}
if (retval != null)
{
retval.IsFullyConfigured = true;
}
return retval;
}
[Fx.Tag.SecurityNote(Critical = "Handles config objects, which should not be leaked.",
Safe = "Doesn't leak config objects out of SecurityCritical code.")]
[SecuritySafeCritical]
static void ConfigureEndpoint(StandardEndpointElement standardEndpointElement, ChannelEndpointElement channelEndpointElement,
EndpointAddress address, ContextInformation context, ContractDescription contract, out ServiceEndpoint endpoint)
{
// copy channelEndpointElement so that it can potentially be modified by the StandardEndpointElement
// the properties collection of the instance seviceEndpointElement created by System.Configuration is read-only.
// keeping original serviceEndpointElement so that its context can be used for the lookups.
ChannelEndpointElement channelEndpointElementCopy = new ChannelEndpointElement();
channelEndpointElementCopy.Copy(channelEndpointElement);
standardEndpointElement.InitializeAndValidate(channelEndpointElementCopy);
endpoint = standardEndpointElement.CreateServiceEndpoint(contract);
if (endpoint == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ConfigNoEndpointCreated, standardEndpointElement.GetType().AssemblyQualifiedName,
(standardEndpointElement.EndpointType == null) ? string.Empty : standardEndpointElement.EndpointType.AssemblyQualifiedName)));
}
//binding
if (!string.IsNullOrEmpty(channelEndpointElementCopy.Binding))
{
endpoint.Binding = ConfigLoader.LookupBinding(channelEndpointElementCopy.Binding, channelEndpointElementCopy.BindingConfiguration, ConfigurationHelpers.GetEvaluationContext(channelEndpointElement));
}
//name
if (!string.IsNullOrEmpty(channelEndpointElementCopy.Name))
{
endpoint.Name = channelEndpointElementCopy.Name;
}
//address
if (address != null)
{
endpoint.Address = address;
}
if (endpoint.Address == null && channelEndpointElementCopy.Address != null && channelEndpointElementCopy.Address.OriginalString.Length > 0)
{
endpoint.Address = new EndpointAddress(channelEndpointElementCopy.Address, LoadIdentity(channelEndpointElementCopy.Identity), channelEndpointElementCopy.Headers.Headers);
}
//behaviors
CommonBehaviorsSection commonBehaviors = ConfigLoader.LookupCommonBehaviors(ConfigurationHelpers.GetEvaluationContext(channelEndpointElement));
if (commonBehaviors != null && commonBehaviors.EndpointBehaviors != null)
{
LoadBehaviors<IEndpointBehavior>(commonBehaviors.EndpointBehaviors, endpoint.Behaviors, true/*commonBehaviors*/);
}
EndpointBehaviorElement behaviorElement = ConfigLoader.LookupEndpointBehaviors(channelEndpointElementCopy.BehaviorConfiguration, ConfigurationHelpers.GetEvaluationContext(channelEndpointElement));
if (behaviorElement != null)
{
LoadBehaviors<IEndpointBehavior>(behaviorElement, endpoint.Behaviors, false/*commonBehaviors*/);
}
standardEndpointElement.ApplyConfiguration(endpoint, channelEndpointElementCopy);
}
[Fx.Tag.SecurityNote(Critical = "Handles config objects, which should not be leaked.",
Safe = "Doesn't leak config objects out of SecurityCritical code.")]
[SecuritySafeCritical]
internal ServiceEndpoint LookupEndpoint(ServiceEndpointElement serviceEndpointElement, ContextInformation context,
ServiceHostBase host, ServiceDescription description, bool omitSettingEndpointAddress = false)
{
EndpointCollectionElement endpointCollectionElement = LookupEndpointCollectionElement(serviceEndpointElement.Kind, context);
ServiceEndpoint retval = null;
string endpointConfiguration = serviceEndpointElement.EndpointConfiguration ?? String.Empty;
// We are looking for a specific instance, not the default.
bool configuredEndpointFound = false;
// The Endpoints property is always public
foreach (StandardEndpointElement standardEndpointElement in endpointCollectionElement.ConfiguredEndpoints)
{
if (standardEndpointElement.Name.Equals(endpointConfiguration, StringComparison.Ordinal))
{
if (null == ConfigLoader.resolvedEndpoints)
{
ConfigLoader.resolvedEndpoints = new List<string>();
}
string resolvedEndpointID = serviceEndpointElement.Kind + "/" + endpointConfiguration;
if (ConfigLoader.resolvedEndpoints.Contains(resolvedEndpointID))
{
ConfigurationElement configErrorElement = (ConfigurationElement)standardEndpointElement;
System.Text.StringBuilder detectedCycle = new System.Text.StringBuilder();
foreach (string resolvedEndpoint in ConfigLoader.resolvedEndpoints)
{
detectedCycle = detectedCycle.AppendFormat("{0}, ", resolvedEndpoint);
}
detectedCycle = detectedCycle.Append(resolvedEndpointID);
// Clear list in case application is written to handle exception
// by not starting up channel, etc...
ConfigLoader.resolvedEndpoints = null;
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ConfigurationErrorsException(SR.GetString(SR.ConfigEndpointReferenceCycleDetected, detectedCycle.ToString()),
configErrorElement.ElementInformation.Source,
configErrorElement.ElementInformation.LineNumber));
}
try
{
CheckAccess(standardEndpointElement as IConfigurationContextProviderInternal);
ConfigLoader.resolvedEndpoints.Add(resolvedEndpointID);
ConfigureEndpoint(standardEndpointElement, serviceEndpointElement, context, host, description, out retval);
ConfigLoader.resolvedEndpoints.Remove(resolvedEndpointID);
}
catch
{
// Clear list in case application is written to handle exception
// by not starting up channel, etc...
if (null != ConfigLoader.resolvedEndpoints)
{
ConfigLoader.resolvedBindings = null;
}
throw;
}
if (null != ConfigLoader.resolvedEndpoints &&
0 == ConfigLoader.resolvedEndpoints.Count)
{
ConfigLoader.resolvedEndpoints = null;
}
configuredEndpointFound = true;
}
}
if (!configuredEndpointFound)
{
// We expected to find an instance, but didn't.
// Return null.
retval = null;
}
if (retval == null && String.IsNullOrEmpty(endpointConfiguration))
{
StandardEndpointElement standardEndpointElement = endpointCollectionElement.GetDefaultStandardEndpointElement();
ConfigureEndpoint(standardEndpointElement, serviceEndpointElement, context, host, description, out retval, omitSettingEndpointAddress);
}
if (DiagnosticUtility.ShouldTraceVerbose)
{
Dictionary<string, object> values = new Dictionary<string, object>(3);
values["FoundEndpoint"] = retval != null;
bool usingDefault = string.IsNullOrEmpty(endpointConfiguration);
int traceCode;
string traceDescription;
if (usingDefault)
{
traceCode = TraceCode.GetDefaultConfiguredEndpoint;
traceDescription = SR.GetString(SR.TraceCodeGetDefaultConfiguredEndpoint);
}
else
{
traceCode = TraceCode.GetConfiguredEndpoint;
traceDescription = SR.GetString(SR.TraceCodeGetConfiguredEndpoint);
values["Name"] = endpointConfiguration;
}
values["Endpoint"] = serviceEndpointElement.Kind;
TraceUtility.TraceEvent(TraceEventType.Verbose, traceCode, traceDescription,
new DictionaryTraceRecord(values), null, null);
}
return retval;
}
[Fx.Tag.SecurityNote(Critical = "Handles config objects, which should not be leaked.",
Safe = "Doesn't leak config objects out of SecurityCritical code.")]
[SecuritySafeCritical]
void ConfigureEndpoint(StandardEndpointElement standardEndpointElement, ServiceEndpointElement serviceEndpointElement,
ContextInformation context, ServiceHostBase host, ServiceDescription description, out ServiceEndpoint endpoint, bool omitSettingEndpointAddress = false)
{
// copy serviceEndpointElement so that it can potentially be modified by the StandardEndpointElement
// the properties collection of the instance seviceEndpointElement created by System.Configuration is read-only.
// keeping original serviceEndpointElement so that its context can be used to lookup endpoint behaviors.
ServiceEndpointElement serviceEndpointElementCopy = new ServiceEndpointElement();
serviceEndpointElementCopy.Copy(serviceEndpointElement);
standardEndpointElement.InitializeAndValidate(serviceEndpointElementCopy);
//contract
ContractDescription contract = null;
if (!string.IsNullOrEmpty(serviceEndpointElementCopy.Contract))
{
contract = LookupContractForStandardEndpoint(serviceEndpointElementCopy.Contract, description.Name);
}
endpoint = standardEndpointElement.CreateServiceEndpoint(contract);
if (endpoint == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ConfigNoEndpointCreated, standardEndpointElement.GetType().AssemblyQualifiedName,
(standardEndpointElement.EndpointType == null) ? string.Empty : standardEndpointElement.EndpointType.AssemblyQualifiedName)));
}
//binding
Binding binding = null;
if (!string.IsNullOrEmpty(serviceEndpointElementCopy.Binding))
{
string bindingKey = serviceEndpointElementCopy.Binding + ":" + serviceEndpointElementCopy.BindingConfiguration;
if (bindingTable.TryGetValue(bindingKey, out binding) == false)
{
binding = ConfigLoader.LookupBinding(serviceEndpointElementCopy.Binding, serviceEndpointElementCopy.BindingConfiguration, context);
bindingTable.Add(bindingKey, binding);
}
}
else
{
binding = endpoint.Binding;
}
if (binding != null)
{
if (!string.IsNullOrEmpty(serviceEndpointElementCopy.BindingName))
{
binding.Name = serviceEndpointElementCopy.BindingName;
}
if (!string.IsNullOrEmpty(serviceEndpointElementCopy.BindingNamespace))
{
binding.Namespace = serviceEndpointElementCopy.BindingNamespace;
}
endpoint.Binding = binding;
if (!omitSettingEndpointAddress)
{
ConfigureEndpointAddress(serviceEndpointElementCopy, host, endpoint);
ConfigureEndpointListenUri(serviceEndpointElementCopy, host, endpoint);
}
}
//listenUriMode
endpoint.ListenUriMode = serviceEndpointElementCopy.ListenUriMode;
//name
if (!string.IsNullOrEmpty(serviceEndpointElementCopy.Name))
{
endpoint.Name = serviceEndpointElementCopy.Name;
}
//behaviors
KeyedByTypeCollection<IEndpointBehavior> behaviors = endpoint.Behaviors;
EndpointBehaviorElement behaviorEndpointElement = ConfigLoader.LookupEndpointBehaviors(serviceEndpointElementCopy.BehaviorConfiguration, ConfigurationHelpers.GetEvaluationContext(serviceEndpointElement));
if (behaviorEndpointElement != null)
{
LoadBehaviors<IEndpointBehavior>(behaviorEndpointElement, behaviors, false/*commonBehaviors*/);
}
//isSystemEndpoint
if (serviceEndpointElementCopy.ElementInformation.Properties[ConfigurationStrings.IsSystemEndpoint].ValueOrigin != PropertyValueOrigin.Default)
{
endpoint.IsSystemEndpoint = serviceEndpointElementCopy.IsSystemEndpoint;
}
standardEndpointElement.ApplyConfiguration(endpoint, serviceEndpointElementCopy);
}
internal static void ConfigureEndpointAddress(ServiceEndpointElement serviceEndpointElement, ServiceHostBase host, ServiceEndpoint endpoint)
{
Fx.Assert(endpoint.Binding != null, "The endpoint must be set by the caller.");
if (serviceEndpointElement.Address != null)
{
Uri via = ServiceHost.MakeAbsoluteUri(serviceEndpointElement.Address, endpoint.Binding, host.InternalBaseAddresses);
endpoint.Address = new EndpointAddress(via, LoadIdentity(serviceEndpointElement.Identity), serviceEndpointElement.Headers.Headers);
endpoint.UnresolvedAddress = serviceEndpointElement.Address;
}
}
internal static void ConfigureEndpointListenUri(ServiceEndpointElement serviceEndpointElement, ServiceHostBase host, ServiceEndpoint endpoint)
{
Fx.Assert(endpoint.Binding != null, "The endpoint must be set by the caller.");
if (serviceEndpointElement.ListenUri != null)
{
endpoint.ListenUri = ServiceHost.MakeAbsoluteUri(serviceEndpointElement.ListenUri, endpoint.Binding, host.InternalBaseAddresses);
endpoint.UnresolvedListenUri = serviceEndpointElement.ListenUri;
}
}
internal static Binding LookupBinding(string bindingSectionName, string configurationName)
{
return ConfigLoader.LookupBinding(bindingSectionName, configurationName, null);
}
internal static ComContractElement LookupComContract(Guid contractIID)
{
ComContractsSection comContracts = (ComContractsSection)ConfigurationHelpers.GetSection(ConfigurationStrings.ComContractsSectionPath);
foreach (ComContractElement contract in comContracts.ComContracts)
{
Guid interfaceID;
if (DiagnosticUtility.Utility.TryCreateGuid(contract.Contract, out interfaceID))
{
if (interfaceID == contractIID)
{
return contract;
}
}
}
return null;
}
/// <SecurityNote>
/// Critical - handles config objects, which should not be leaked
/// Safe - doesn't leak config objects out of SecurityCritical code
/// </SecurityNote>
[SecuritySafeCritical]
internal static ProtocolMappingItem LookupProtocolMapping(String scheme)
{
ProtocolMappingSection protocolMapping = (ProtocolMappingSection)ConfigurationHelpers.UnsafeGetSection(ConfigurationStrings.ProtocolMappingSectionPath);
foreach (ProtocolMappingElement pm in protocolMapping.ProtocolMappingCollection)
{
if (pm.Scheme == scheme)
{
return new ProtocolMappingItem(pm.Binding, pm.BindingConfiguration);
}
}
return null;
}
[Fx.Tag.SecurityNote(Critical = "Leaks config objects, caller must ensure that these don't leak to user code.")]
[SecurityCritical]
static BindingCollectionElement GetBindingCollectionElement(string bindingSectionName, ContextInformation context)
{
if (string.IsNullOrEmpty(bindingSectionName))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ConfigurationErrorsException(SR.GetString(SR.ConfigBindingTypeCannotBeNullOrEmpty)));
}
if (context == null)
{
// If no context is passed in, assume that the caller can consume the AppDomain's
// current configuration file.
return (BindingCollectionElement)ConfigurationHelpers.UnsafeGetBindingCollectionElement(bindingSectionName);
}
else
{
// Use the configuration file associated with the passed in context.
// This may or may not be the same as the file for the current AppDomain.
return (BindingCollectionElement)ConfigurationHelpers.UnsafeGetAssociatedBindingCollectionElement(context, bindingSectionName);
}
}
// This method should only return null when bindingConfiguration is specified on the BindingElement and no BindingElement matching the
// bindingConfiguration name is found. All other error conditions should throw.
[Fx.Tag.SecurityNote(Critical = "Handles config objects, which should not be leaked.",
Safe = "Doesn't leak config objects out of SecurityCritical code.")]
[SecuritySafeCritical]
internal static Binding LookupBinding(string bindingSectionName, string configurationName, ContextInformation context)
{
BindingCollectionElement bindingCollectionElement = GetBindingCollectionElement(bindingSectionName, context);
Binding retval;
if (configurationName == null)
{
retval = bindingCollectionElement.GetDefault();
}
else
{
Binding defaultBinding = bindingCollectionElement.GetDefault();
retval = LookupBinding(bindingSectionName, configurationName, bindingCollectionElement, defaultBinding);
if (retval == null && configurationName == ConfigurationStrings.DefaultName)
{
retval = defaultBinding;
}
}
if (DiagnosticUtility.ShouldTraceVerbose)
{
Dictionary<string, object> values = new Dictionary<string, object>(3);
values["FoundBinding"] = retval != null;
bool usingDefault = string.IsNullOrEmpty(configurationName);
int traceCode;
string traceDescription;
if (usingDefault)
{
traceCode = TraceCode.GetDefaultConfiguredBinding;
traceDescription = SR.GetString(SR.TraceCodeGetDefaultConfiguredBinding);
}
else
{
traceCode = TraceCode.GetConfiguredBinding;
traceDescription = SR.GetString(SR.TraceCodeGetConfiguredBinding);
values["Name"] = string.IsNullOrEmpty(configurationName) ?
SR.GetString(SR.Default) : configurationName;
}
values["Binding"] = bindingSectionName;
TraceUtility.TraceEvent(TraceEventType.Verbose, traceCode, traceDescription,
new DictionaryTraceRecord(values), null, null);
}
return retval;
}
static Binding LookupBinding(string bindingSectionName, string configurationName, BindingCollectionElement bindingCollectionElement, Binding defaultBinding)
{
Binding retval = defaultBinding;
if (configurationName != null)
{
// We are looking for a specific instance, not the default.
bool configuredBindingFound = false;
// The Bindings property is always public
foreach (object configElement in bindingCollectionElement.ConfiguredBindings)
{
IBindingConfigurationElement bindingElement = configElement as IBindingConfigurationElement;
if (bindingElement != null)
{
if (bindingElement.Name.Equals(configurationName, StringComparison.Ordinal))
{
if (null == ConfigLoader.resolvedBindings)
{
ConfigLoader.resolvedBindings = new List<string>();
}
string resolvedBindingID = bindingSectionName + "/" + configurationName;
if (ConfigLoader.resolvedBindings.Contains(resolvedBindingID))
{
ConfigurationElement configErrorElement = (ConfigurationElement)configElement;
System.Text.StringBuilder detectedCycle = new System.Text.StringBuilder();
foreach (string resolvedBinding in ConfigLoader.resolvedBindings)
{
detectedCycle = detectedCycle.AppendFormat("{0}, ", resolvedBinding);
}
detectedCycle = detectedCycle.Append(resolvedBindingID);
// Clear list in case application is written to handle exception
// by not starting up channel, etc...
ConfigLoader.resolvedBindings = null;
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ConfigurationErrorsException(SR.GetString(SR.ConfigBindingReferenceCycleDetected, detectedCycle.ToString()),
configErrorElement.ElementInformation.Source,
configErrorElement.ElementInformation.LineNumber));
}
try
{
CheckAccess(configElement as IConfigurationContextProviderInternal);
ConfigLoader.resolvedBindings.Add(resolvedBindingID);
bindingElement.ApplyConfiguration(retval);
ConfigLoader.resolvedBindings.Remove(resolvedBindingID);
}
catch
{
// Clear list in case application is written to handle exception
// by not starting up channel, etc...
if (null != ConfigLoader.resolvedBindings)
{
ConfigLoader.resolvedBindings = null;
}
throw;
}
if (null != ConfigLoader.resolvedBindings &&
0 == ConfigLoader.resolvedBindings.Count)
{
ConfigLoader.resolvedBindings = null;
}
configuredBindingFound = true;
}
}
}
if (!configuredBindingFound)
{
// We expected to find an instance, but didn't.
// Return null.
retval = null;
}
}
return retval;
}
[Fx.Tag.SecurityNote(Critical = "Leaks config objects, caller must ensure that these don't leak to user code.")]
[SecurityCritical]
static EndpointBehaviorElement LookupEndpointBehaviors(string behaviorName, ContextInformation context)
{
EndpointBehaviorElement retval = null;
if (behaviorName != null)
{
if (DiagnosticUtility.ShouldTraceVerbose)
{
TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.GetBehaviorElement,
SR.GetString(SR.TraceCodeGetBehaviorElement),
new StringTraceRecord("BehaviorName", behaviorName), null, null);
}
BehaviorsSection behaviors = null;
if (context == null)
{
behaviors = BehaviorsSection.UnsafeGetSection();
}
else
{
behaviors = BehaviorsSection.UnsafeGetAssociatedSection(context);
}
if (behaviors.EndpointBehaviors.ContainsKey(behaviorName))
{
retval = behaviors.EndpointBehaviors[behaviorName];
}
}
if (retval != null)
{
CheckAccess(retval);
}
return retval;
}
[Fx.Tag.SecurityNote(Critical = "Leaks config objects, caller must ensure that these don't leak to user code.")]
[SecurityCritical]
static ServiceBehaviorElement LookupServiceBehaviors(string behaviorName, ContextInformation context)
{
ServiceBehaviorElement retval = null;
if (behaviorName != null)
{
if (DiagnosticUtility.ShouldTraceVerbose)
{
TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.GetBehaviorElement,
SR.GetString(SR.TraceCodeGetBehaviorElement),
new StringTraceRecord("BehaviorName", behaviorName), null, null);
}
BehaviorsSection behaviors = null;
if (context == null)
{
behaviors = BehaviorsSection.UnsafeGetSection();
}
else
{
behaviors = BehaviorsSection.UnsafeGetAssociatedSection(context);
}
if (behaviors.ServiceBehaviors.ContainsKey(behaviorName))
{
retval = behaviors.ServiceBehaviors[behaviorName];
}
}
if (retval != null)
{
CheckAccess(retval);
}
return retval;
}
[Fx.Tag.SecurityNote(Critical = "Leaks config objects, caller must ensure that these don't leak to user code.")]
[SecurityCritical]
static CommonBehaviorsSection LookupCommonBehaviors(ContextInformation context)
{
if (DiagnosticUtility.ShouldTraceVerbose)
{
TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.GetCommonBehaviors,
SR.GetString(SR.TraceCodeGetCommonBehaviors), (object)null);
}
return context == null
? CommonBehaviorsSection.UnsafeGetSection()
: CommonBehaviorsSection.UnsafeGetAssociatedSection(context);
}
static bool IsChannelElementMatch(ChannelEndpointElement channelElement, ContractDescription contract, EndpointAddress address, bool useChannelElementKind, out ServiceEndpoint serviceEndpoint)
{
serviceEndpoint = null;
if (string.IsNullOrEmpty(channelElement.Kind))
{
return channelElement.Contract == contract.ConfigurationName;
}
if (useChannelElementKind)
{
serviceEndpoint = LookupEndpoint(channelElement, null, address, contract);
if (serviceEndpoint != null)
{
if (serviceEndpoint.Contract.ConfigurationName == contract.ConfigurationName &&
(string.IsNullOrEmpty(channelElement.Contract) || contract.ConfigurationName == channelElement.Contract))
{
return true;
}
else
{
serviceEndpoint = null;
return false;
}
}
else
{
return false; // this should not happen with a valid client section since serviceEndpoint will never be null.
}
}
else
{
// A standard endpoint should not be returned in the case of useChannelElementKind = false.
// This is because useChannelElementKind = false only when this method is called by
// LoadChannelBehaviors (the overload that takes a ServiceEndpoint and a string(configurationName)).
// LoadChannelBehaviors is called for the purposes of applying channel behaviors to a newly created service endpoint.
// In the case of standard endpoints, the service endpoints are already fully configured.
// Reapplying behaviors would not only be redundant but may cause exceptions to be thrown.
return false;
}
}
[Fx.Tag.SecurityNote(Critical = "Leaks config objects, caller must ensure that these don't leak to user code.")]
[SecurityCritical]
static ChannelEndpointElement LookupChannel(ContextInformation configurationContext, string configurationName, ContractDescription contract,
EndpointAddress address, bool wildcard, bool useChannelElementKind, out ServiceEndpoint serviceEndpoint)
{
serviceEndpoint = null;
ClientSection clientSection = (configurationContext == null ? ClientSection.UnsafeGetSection() : ClientSection.UnsafeGetSection(configurationContext));
ChannelEndpointElement retval = null;
ServiceEndpoint standardEndpoint;
foreach (ChannelEndpointElement channelElement in clientSection.Endpoints)
{
if (IsChannelElementMatch(channelElement, contract, address, useChannelElementKind, out standardEndpoint))
{
if (channelElement.Name == configurationName || wildcard) // match name (or wildcard)
{
if (retval != null) // oops: >1
{
if (wildcard)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxConfigLoaderMultipleEndpointMatchesWildcard1, contract.ConfigurationName)));
}
else
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxConfigLoaderMultipleEndpointMatchesSpecified2, contract.ConfigurationName, configurationName)));
}
}
retval = channelElement;
serviceEndpoint = standardEndpoint;
}
}
}
if (retval != null)
{
CheckAccess(retval);
}
if (DiagnosticUtility.ShouldTraceInformation)
{
Dictionary<string, object> values = new Dictionary<string, object>(8);
values["FoundChannelElement"] = retval != null;
values["Name"] = configurationName;
values["ContractName"] = contract.ConfigurationName;
if (null != retval)
{
if (!string.IsNullOrEmpty(retval.Binding))
{
values["Binding"] = retval.Binding;
}
if (!string.IsNullOrEmpty(retval.BindingConfiguration))
{
values["BindingConfiguration"] = retval.BindingConfiguration;
}
if (retval.Address != null)
{
values["RemoteEndpointUri"] = retval.Address.ToString();
}
if (!string.IsNullOrEmpty(retval.ElementInformation.Source))
{
values["ConfigurationFileSource"] = retval.ElementInformation.Source;
values["ConfigurationFileLineNumber"] = retval.ElementInformation.LineNumber;
}
}
TraceUtility.TraceEvent(TraceEventType.Information,
TraceCode.GetChannelEndpointElement,
SR.GetString(SR.TraceCodeGetChannelEndpointElement),
new DictionaryTraceRecord(values), null, null);
}
return retval;
}
internal ContractDescription LookupContract(string contractName, string serviceName)
{
ContractDescription contract = LookupContractForStandardEndpoint(contractName, serviceName);
if (contract == null)
{
if (contractName == String.Empty)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SfxReflectedContractKeyNotFoundEmpty, serviceName)));
}
else
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SfxReflectedContractKeyNotFound2, contractName, serviceName)));
}
}
return contract;
}
internal ContractDescription LookupContractForStandardEndpoint(string contractName, string serviceName)
{
ContractDescription contract = contractResolver.ResolveContract(contractName);
if (contract == null)
{
if (contractName == ServiceMetadataBehavior.MexContractName)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SfxReflectedContractKeyNotFoundIMetadataExchange, serviceName)));
}
}
return contract;
}
[Fx.Tag.SecurityNote(Critical = "Leaks config objects, caller must ensure that these don't leak to user code.")]
[SecurityCritical]
public ServiceElement LookupService(string serviceConfigurationName)
{
ServicesSection servicesSection = ServicesSection.UnsafeGetSection();
return LookupService(serviceConfigurationName, servicesSection);
}
public ServiceElement LookupService(string serviceConfigurationName, ServicesSection servicesSection)
{
ServiceElement retval = null;
ServiceElementCollection services = servicesSection.Services;
for (int i = 0; i < services.Count; i++)
{
ServiceElement serviceElement = services[i];
if (serviceElement.Name == serviceConfigurationName)
{
retval = serviceElement;
}
}
if (retval != null)
{
CheckAccess(retval);
}
if (DiagnosticUtility.ShouldTraceInformation)
{
TraceUtility.TraceEvent(TraceEventType.Information,
TraceCode.GetServiceElement,
SR.GetString(SR.TraceCodeGetServiceElement),
new ServiceConfigurationTraceRecord(retval), null, null);
}
return retval;
}
static bool IsWildcardMatch(string endpointConfigurationName)
{
return String.Equals(endpointConfigurationName, "*", StringComparison.Ordinal);
}
[Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - used in a security decision.")]
static bool IsConfigAboveApplication(ContextInformation contextInformation)
{
if (contextInformation != null)
{
if (contextInformation.IsMachineLevel)
{
return true;
}
bool isAppConfig = contextInformation.HostingContext is ExeContext;
if (isAppConfig)
{
return false; // for app.config, the only higher-scope config file is machine.config
}
else
{
return IsWebConfigAboveApplication(contextInformation);
}
}
return true; // err on the safe side: absent context information assume a PT app doesn't have access
}
[Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - used in a security decision.")]
[MethodImpl(MethodImplOptions.NoInlining)]
static bool IsWebConfigAboveApplication(ContextInformation contextInformation)
{
return AspNetEnvironment.Current.IsWebConfigAboveApplication(contextInformation.HostingContext);
}
[Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - enforces a security decision.")]
static void CheckAccess(IConfigurationContextProviderInternal element)
{
if (IsConfigAboveApplication(ConfigurationHelpers.GetOriginalEvaluationContext(element)))
{
ConfigurationPermission.Demand();
}
}
[Fx.Tag.SecurityNote(Critical = "Used in a security decision.")]
[SecurityCritical]
static ConfigurationPermission configurationPermission;
static ConfigurationPermission ConfigurationPermission
{
[Fx.Tag.SecurityNote(Critical = "Inits the configurationPermission field.",
Safe = "Safe for readonly access.")]
[SecuritySafeCritical]
get
{
if (configurationPermission == null)
{
configurationPermission = new ConfigurationPermission(System.Security.Permissions.PermissionState.Unrestricted);
}
return configurationPermission;
}
}
[Fx.Tag.SecurityNote(Critical = "Uses critical field configurationPermission.")]
[SecurityCritical]
static bool ThreadHasConfigurationPermission()
{
try
{
ConfigurationPermission.Demand();
}
catch (SecurityException)
{
return false;
}
return true;
}
}
class ProtocolMappingItem
{
public ProtocolMappingItem(string binding, string bindingConfiguration)
{
this.Binding = binding;
this.BindingConfiguration = bindingConfiguration;
}
public string Binding { get; set; }
public string BindingConfiguration { get; set; }
}
}
|