| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086 |
- //------------------------------------------------------------
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //------------------------------------------------------------
- namespace System.ServiceModel.Dispatcher
- {
- using System.ServiceModel.Channels;
- using System.ServiceModel;
- using System.ServiceModel.Description;
- using System.ServiceModel.Security;
- using System.ServiceModel.Security.Tokens;
- using System.IdentityModel.Tokens;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Runtime.CompilerServices;
- using System.Net.Security;
- using System.Security.Principal;
- class SecurityValidationBehavior : IEndpointBehavior, IServiceBehavior
- {
- static SecurityValidationBehavior instance;
- public static SecurityValidationBehavior Instance
- {
- get
- {
- if (instance == null)
- instance = new SecurityValidationBehavior();
- return instance;
- }
- }
- class ValidationBinding : Binding
- {
- Binding binding;
- BindingElementCollection elements;
- public ValidationBinding(Binding binding)
- : base(binding.Name, binding.Namespace)
- {
- this.binding = binding;
- }
- public override string Scheme
- {
- get { return this.binding.Scheme; }
- }
- public override BindingElementCollection CreateBindingElements()
- {
- if (this.elements == null)
- {
- this.elements = this.binding.CreateBindingElements();
- }
- return this.elements;
- }
- public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingParameterCollection parameters)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
- }
- public override IChannelListener<TChannel> BuildChannelListener<TChannel>(params object[] parameters)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
- }
- public override IChannelListener<TChannel> BuildChannelListener<TChannel>(Uri listenUriBaseAddress, params object[] parameters)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
- }
- public override IChannelListener<TChannel> BuildChannelListener<TChannel>(Uri listenUriBaseAddress, string listenUriRelativeAddress, params object[] parameters)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
- }
- public override IChannelListener<TChannel> BuildChannelListener<TChannel>(Uri listenUriBaseAddress, string listenUriRelativeAddress, ListenUriMode listenUriMode, params object[] parameters)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
- }
- public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingParameterCollection parameters)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
- }
- public override IChannelListener<TChannel> BuildChannelListener<TChannel>(Uri listenUriBaseAddress, BindingParameterCollection parameters)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
- }
- public override IChannelListener<TChannel> BuildChannelListener<TChannel>(Uri listenUriBaseAddress, string listenUriRelativeAddress, BindingParameterCollection parameters)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
- }
- public override IChannelListener<TChannel> BuildChannelListener<TChannel>(Uri listenUriBaseAddress, string listenUriRelativeAddress, ListenUriMode listenUriMode, BindingParameterCollection parameters)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
- }
- public override bool CanBuildChannelFactory<TChannel>(BindingParameterCollection parameters)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
- }
- public override bool CanBuildChannelListener<TChannel>(BindingParameterCollection parameters)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
- }
- }
- void IEndpointBehavior.Validate(ServiceEndpoint serviceEndpoint)
- {
- if (serviceEndpoint == null)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("serviceEndpoint");
- SecurityBindingElement sbe;
- Binding binding = new ValidationBinding(serviceEndpoint.Binding);
- ValidateBinding(binding, serviceEndpoint.Contract, out sbe);
- }
- void IEndpointBehavior.AddBindingParameters(ServiceEndpoint serviceEndpoint, BindingParameterCollection parameters)
- {
- }
- void IEndpointBehavior.ApplyDispatchBehavior(ServiceEndpoint serviceEndpoint, EndpointDispatcher endpointDispatcher)
- {
- }
- void IEndpointBehavior.ApplyClientBehavior(ServiceEndpoint serviceEndpoint, ClientRuntime behavior)
- {
- }
- void IServiceBehavior.AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters)
- {
- }
- void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
- {
- }
- void IServiceBehavior.Validate(ServiceDescription description, ServiceHostBase serviceHostBase)
- {
- if (description == null)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("description");
- for (int i = 0; i < description.Endpoints.Count; i++)
- {
- ServiceEndpoint endpoint = description.Endpoints[i];
- Binding binding = new ValidationBinding(endpoint.Binding);
- SecurityBindingElement sbe;
- ValidateBinding(binding, endpoint.Contract, out sbe);
- if (sbe != null)
- {
- SecurityTokenParameterInclusionModeRule.Validate(sbe, binding, endpoint.Contract, description.Behaviors);
- }
- }
- WindowsIdentitySupportRule.Validate(description);
- UsernameImpersonationRule.Validate(description);
- MissingClientCertificateRule.Validate(description);
- }
- void ValidateBinding(Binding binding, ContractDescription contract, out SecurityBindingElement securityBindingElement)
- {
- securityBindingElement = SecurityValidationBehavior.GetSecurityBinding(binding, contract);
- if (securityBindingElement != null)
- ValidateSecurityBinding(securityBindingElement, binding, contract);
- else
- ValidateNoSecurityBinding(binding, contract);
- }
- void ValidateSecurityBinding(SecurityBindingElement sbe, Binding binding, ContractDescription contract)
- {
- ContractProtectionRequirementsRule.ValidateSecurityBinding(sbe, binding, contract);
- CookieAndSessionProtectionRequirementsRule.ValidateSecurityBinding(sbe, binding, contract);
- SoapOverSecureTransportRequirementsRule.ValidateSecurityBinding(sbe, binding, contract);
- SecurityVersionSupportForEncryptedKeyBindingRule.ValidateSecurityBinding(sbe, binding, contract);
- SecurityVersionSupportForThumbprintKeyIdentifierClauseRule.ValidateSecurityBinding(sbe, binding, contract);
- SecurityBindingSupportForOneWayOnlyRule.ValidateSecurityBinding(sbe, binding, contract);
- IssuedKeySizeCompatibilityWithAlgorithmSuiteRule.ValidateSecurityBinding(sbe, binding, contract);
- MessageSecurityAndManualAddressingRule.ValidateSecurityBinding(sbe, binding, contract);
- NoStreamingWithSecurityRule.ValidateSecurityBinding(sbe, binding, contract);
- UnknownHeaderProtectionRequirementsRule.ValidateSecurityBinding(sbe, binding, contract);
- BearerKeyTypeIssuanceRequirementRule.ValidateSecurityBinding(sbe, binding, contract);
- }
- void ValidateNoSecurityBinding(Binding binding, ContractDescription contract)
- {
- ContractProtectionRequirementsRule.ValidateNoSecurityBinding(binding, contract);
- CookieAndSessionProtectionRequirementsRule.ValidateNoSecurityBinding(binding, contract);
- SoapOverSecureTransportRequirementsRule.ValidateNoSecurityBinding(binding, contract);
- SecurityVersionSupportForEncryptedKeyBindingRule.ValidateNoSecurityBinding(binding, contract);
- SecurityVersionSupportForThumbprintKeyIdentifierClauseRule.ValidateNoSecurityBinding(binding, contract);
- SecurityBindingSupportForOneWayOnlyRule.ValidateNoSecurityBinding(binding, contract);
- IssuedKeySizeCompatibilityWithAlgorithmSuiteRule.ValidateNoSecurityBinding(binding, contract);
- MessageSecurityAndManualAddressingRule.ValidateNoSecurityBinding(binding, contract);
- UnknownHeaderProtectionRequirementsRule.ValidateNoSecurityBinding(binding, contract);
- BearerKeyTypeIssuanceRequirementRule.ValidateNoSecurityBinding(binding, contract);
- }
- static SecurityBindingElement GetSecurityBinding(Binding binding, ContractDescription contract)
- {
- SecurityBindingElement sbe = null;
- BindingElementCollection elements = binding.CreateBindingElements();
- for (int i = 0; i < elements.Count; i++)
- {
- BindingElement element = elements[i];
- if (element is SecurityBindingElement)
- {
- if (sbe != null)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
- SR.GetString(SR.MoreThanOneSecurityBindingElementInTheBinding, binding.Name, binding.Namespace, contract.Name, contract.Namespace)));
- sbe = (SecurityBindingElement)element;
- }
- }
- return sbe;
- }
- internal void AfterBuildTimeValidation(ServiceDescription description)
- {
- S4UImpersonationRule.Validate(description);
- }
- // We do not allow streaming with message security which makes our service vulnerable
- // for example, GetWhitespace may be a problem if it’s called on unbounded data.
- static class NoStreamingWithSecurityRule
- {
- static public void ValidateSecurityBinding(SecurityBindingElement sbe, Binding binding, ContractDescription contract)
- {
- // check to see if we are doing message security
- // if transport security, the sbe would be transportsecuritybindingelement
- if (sbe is SymmetricSecurityBindingElement || sbe is AsymmetricSecurityBindingElement)
- {
- // check to see if we are streaming
- // ([....] 53690): need to have a general way get the transfer Mode from the binding
- // TransferMode transferMode = binding.GetProperty<TransferMode>(new BindingParameterCollection());
- if (GetTransferMode(binding) != TransferMode.Buffered)
- {
- // throw
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.NoStreamingWithSecurity, binding.Name, binding.Namespace)));
- }
- }
- }
- static TransferMode GetTransferMode(Binding binding)
- {
- TransferMode mode = TransferMode.Buffered;
- BindingElementCollection elements = binding.CreateBindingElements();
- TransportBindingElement element = elements.Find<TransportBindingElement>();
- if (element is ConnectionOrientedTransportBindingElement)
- {
- mode = ((ConnectionOrientedTransportBindingElement)element).TransferMode;
- }
- else if (element is HttpTransportBindingElement)
- {
- mode = ((HttpTransportBindingElement)element).TransferMode;
- }
- return mode;
- }
- }
- static class WindowsIdentitySupportRule
- {
- static public void Validate(ServiceDescription description)
- {
- bool impersonateCallerForAllServiceMethods = false;
- ServiceAuthorizationBehavior authorizationBehavior = description.Behaviors.Find<ServiceAuthorizationBehavior>();
- if (authorizationBehavior != null)
- {
- impersonateCallerForAllServiceMethods = authorizationBehavior.ImpersonateCallerForAllOperations;
- }
- else
- {
- impersonateCallerForAllServiceMethods = false;
- }
- for (int i = 0; i < description.Endpoints.Count; i++)
- {
- ServiceEndpoint endpoint = description.Endpoints[i];
- if (endpoint.InternalIsSystemEndpoint(description))
- {
- continue;
- }
- for (int j = 0; j < endpoint.Contract.Operations.Count; j++)
- {
- OperationDescription operation = endpoint.Contract.Operations[j];
- OperationBehaviorAttribute operationBehavior = operation.Behaviors.Find<OperationBehaviorAttribute>();
- if (impersonateCallerForAllServiceMethods &&
- !operation.IsServerInitiated() &&
- (operationBehavior == null || operationBehavior.Impersonation == ImpersonationOption.NotAllowed))
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.OperationDoesNotAllowImpersonation, operation.Name, endpoint.Contract.Name, endpoint.Contract.Namespace)));
- }
- if (impersonateCallerForAllServiceMethods || (operationBehavior != null && operationBehavior.Impersonation == ImpersonationOption.Required))
- {
- ValidateWindowsIdentityCapability(endpoint.Binding, endpoint.Contract, operation);
- }
- }
- }
- }
- static void ValidateWindowsIdentityCapability(Binding binding, ContractDescription contract, OperationDescription operation)
- {
- bool windowsIdentityProvided = false;
- ISecurityCapabilities capabilities = binding.GetProperty<ISecurityCapabilities>(new BindingParameterCollection());
- if (capabilities != null && capabilities.SupportsClientWindowsIdentity)
- {
- windowsIdentityProvided = true;
- }
- if (!windowsIdentityProvided)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
- SR.GetString(SR.BindingDoesNotSupportWindowsIdenityForImpersonation, operation.Name, binding.Name, binding.Namespace, contract.Name, contract.Namespace)));
- }
- }
- }
- static class S4UImpersonationRule
- {
- const int WindowsServerMajorNumber = 5;
- const int WindowsServerMinorNumber = 2;
- static bool IsS4URequiredForImpersonation(SecurityBindingElement sbe)
- {
- foreach (SecurityTokenParameters stp in new SecurityTokenParametersEnumerable(sbe, true))
- {
- if (stp is SecureConversationSecurityTokenParameters)
- {
- SecureConversationSecurityTokenParameters scstp = (SecureConversationSecurityTokenParameters)stp;
- if (scstp.RequireCancellation == false)
- return true;
- if (scstp.BootstrapSecurityBindingElement != null)
- {
- return IsS4URequiredForImpersonation(scstp.BootstrapSecurityBindingElement);
- }
- }
- if (stp is SspiSecurityTokenParameters
- && ((SspiSecurityTokenParameters)stp).RequireCancellation == false)
- return true;
- if (stp is X509SecurityTokenParameters)
- return true;
- }
- return false;
- }
- static public void Validate(ServiceDescription description)
- {
- ServiceAuthorizationBehavior behavior = description.Behaviors.Find<ServiceAuthorizationBehavior>();
- bool impersonateCallerForAllMethods = (behavior != null) ? behavior.ImpersonateCallerForAllOperations : false;
- for (int i = 0; i < description.Endpoints.Count; i++)
- {
- ServiceEndpoint endpoint = description.Endpoints[i];
- if (endpoint.InternalIsSystemEndpoint(description))
- {
- continue;
- }
- bool isImpersonationRequested = impersonateCallerForAllMethods;
- if (!isImpersonationRequested)
- {
- isImpersonationRequested = ValidatorUtils.EndpointRequiresImpersonation(endpoint);
- }
- if (isImpersonationRequested)
- {
- ICollection<BindingElement> bindingElements = endpoint.Binding.CreateBindingElements();
- foreach (BindingElement element in bindingElements)
- {
- SecurityBindingElement sbe = (element as SecurityBindingElement);
- if (sbe != null)
- {
- if (IsS4URequiredForImpersonation(sbe))
- {
- Version osVersion = Environment.OSVersion.Version;
- if ((osVersion.Major < WindowsServerMajorNumber)
- || ((osVersion.Major == WindowsServerMajorNumber) && (osVersion.Minor < WindowsServerMinorNumber)))
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
- SR.GetString(SR.CannotPerformS4UImpersonationOnPlatform, endpoint.Binding.Name, endpoint.Binding.Namespace, endpoint.Contract.Name, endpoint.Contract.Namespace)));
- }
- }
- break;
- }
- }
- }
- }
- }
- }
- static class UnknownHeaderProtectionRequirementsRule
- {
- static public void ValidateSecurityBinding(SecurityBindingElement sbe, Binding binding, ContractDescription contract)
- {
- if (sbe is SymmetricSecurityBindingElement || sbe is AsymmetricSecurityBindingElement)
- ValidateContract(binding, contract, sbe.GetIndividualProperty<ISecurityCapabilities>().SupportedRequestProtectionLevel, sbe.GetIndividualProperty<ISecurityCapabilities>().SupportedResponseProtectionLevel);
- else
- ValidateContract(binding, contract, ProtectionLevel.None, ProtectionLevel.None);
- }
- static public void ValidateNoSecurityBinding(Binding binding, ContractDescription contract)
- {
- ValidateContract(binding, contract, ProtectionLevel.None, ProtectionLevel.None);
- }
- static void ValidateContract(Binding binding, ContractDescription contract, ProtectionLevel defaultRequestProtectionLevel, ProtectionLevel defaultResponseProtectionLevel)
- {
- if (contract == null)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("contract"));
- ProtectionLevel contractScopeDefaultRequestProtectionLevel;
- ProtectionLevel contractScopeDefaultResponseProtectionLevel;
- if (contract.HasProtectionLevel)
- {
- contractScopeDefaultRequestProtectionLevel = contract.ProtectionLevel;
- contractScopeDefaultResponseProtectionLevel = contract.ProtectionLevel;
- }
- else
- {
- contractScopeDefaultRequestProtectionLevel = defaultRequestProtectionLevel;
- contractScopeDefaultResponseProtectionLevel = defaultResponseProtectionLevel;
- }
- foreach (OperationDescription operation in contract.Operations)
- {
- ProtectionLevel operationScopeDefaultRequestProtectionLevel;
- ProtectionLevel operationScopeDefaultResponseProtectionLevel;
- if (operation.HasProtectionLevel)
- {
- operationScopeDefaultRequestProtectionLevel = operation.ProtectionLevel;
- operationScopeDefaultResponseProtectionLevel = operation.ProtectionLevel;
- }
- else
- {
- operationScopeDefaultRequestProtectionLevel = contractScopeDefaultRequestProtectionLevel;
- operationScopeDefaultResponseProtectionLevel = contractScopeDefaultResponseProtectionLevel;
- }
- foreach (MessageDescription message in operation.Messages)
- {
- ProtectionLevel messageScopeDefaultProtectionLevel;
- if (message.HasProtectionLevel)
- {
- messageScopeDefaultProtectionLevel = message.ProtectionLevel;
- }
- else if (message.Direction == MessageDirection.Input)
- {
- messageScopeDefaultProtectionLevel = operationScopeDefaultRequestProtectionLevel;
- }
- else
- {
- messageScopeDefaultProtectionLevel = operationScopeDefaultResponseProtectionLevel;
- }
- foreach (MessageHeaderDescription header in message.Headers)
- {
- ProtectionLevel headerScopeDefaultProtectionLevel;
- if (header.HasProtectionLevel)
- headerScopeDefaultProtectionLevel = header.ProtectionLevel;
- else
- headerScopeDefaultProtectionLevel = messageScopeDefaultProtectionLevel;
- //
- // Finally we figured out the protection level for the individual header.
- // We need to throw if the header is some unknown header, i.e., user can stick any Xml frag
- // at the runtime, AND, its protection level is not ProtectionLevel.None
- //
- if (header.IsUnknownHeaderCollection && headerScopeDefaultProtectionLevel != ProtectionLevel.None)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.UnknownHeaderCannotProtected, contract.Name, contract.Namespace, header.Name, header.Namespace)));
- }
- }
- }
- }
- }
- }
- static class ContractProtectionRequirementsRule
- {
- static public void ValidateSecurityBinding(SecurityBindingElement sbe, Binding binding, ContractDescription contract)
- {
- if (sbe is SymmetricSecurityBindingElement || sbe is AsymmetricSecurityBindingElement)
- ValidateContract(binding, contract, sbe.GetIndividualProperty<ISecurityCapabilities>().SupportedRequestProtectionLevel, sbe.GetIndividualProperty<ISecurityCapabilities>().SupportedResponseProtectionLevel);
- else
- ValidateContract(binding, contract, ProtectionLevel.None, ProtectionLevel.None);
- }
- static public void ValidateNoSecurityBinding(Binding binding, ContractDescription contract)
- {
- ValidateContract(binding, contract, ProtectionLevel.None, ProtectionLevel.None);
- }
- static void ValidateContract(Binding binding, ContractDescription contract, ProtectionLevel defaultRequestProtectionLevel, ProtectionLevel defaultResponseProtectionLevel)
- {
- ProtectionLevel requestProtectionLevel;
- ProtectionLevel responseProtectionLevel;
- GetRequiredProtectionLevels(contract, defaultRequestProtectionLevel, defaultResponseProtectionLevel, out requestProtectionLevel, out responseProtectionLevel);
- ValidateBindingProtectionCapability(binding, contract, requestProtectionLevel, responseProtectionLevel);
- }
- static internal void GetRequiredProtectionLevels(ContractDescription contract, ProtectionLevel defaultRequestProtectionLevel, ProtectionLevel defaultResponseProtectionLevel, out ProtectionLevel request, out ProtectionLevel response)
- {
- ChannelProtectionRequirements requirements = ChannelProtectionRequirements.CreateFromContract(contract, defaultRequestProtectionLevel, defaultResponseProtectionLevel, false);
- if (requirements.IncomingSignatureParts.IsEmpty())
- {
- request = ProtectionLevel.None;
- }
- else if (requirements.IncomingEncryptionParts.IsEmpty())
- {
- request = ProtectionLevel.Sign;
- }
- else
- {
- request = ProtectionLevel.EncryptAndSign;
- }
- if (requirements.OutgoingSignatureParts.IsEmpty())
- {
- response = ProtectionLevel.None;
- }
- else if (requirements.OutgoingEncryptionParts.IsEmpty())
- {
- response = ProtectionLevel.Sign;
- }
- else
- {
- response = ProtectionLevel.EncryptAndSign;
- }
- }
- static void ValidateBindingProtectionCapability(Binding binding, ContractDescription contract, ProtectionLevel request, ProtectionLevel response)
- {
- bool requestValidated = request == ProtectionLevel.None;
- bool responseValidated = response == ProtectionLevel.None;
- if (!requestValidated || !responseValidated)
- {
- ISecurityCapabilities capabilities = binding.GetProperty<ISecurityCapabilities>(new BindingParameterCollection());
- if (capabilities != null)
- {
- if (!requestValidated)
- {
- requestValidated = ProtectionLevelHelper.IsStrongerOrEqual(capabilities.SupportedRequestProtectionLevel, request);
- }
- if (!responseValidated)
- {
- responseValidated = ProtectionLevelHelper.IsStrongerOrEqual(capabilities.SupportedResponseProtectionLevel, response);
- }
- }
- }
- if (!requestValidated)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
- SR.GetString(SR.AtLeastOneContractOperationRequestRequiresProtectionLevelNotSupportedByBinding, contract.Name, contract.Namespace, binding.Name, binding.Namespace)));
- }
- if (!responseValidated)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
- SR.GetString(SR.AtLeastOneContractOperationResponseRequiresProtectionLevelNotSupportedByBinding, contract.Name, contract.Namespace, binding.Name, binding.Namespace)));
- }
- }
- }
- static class BearerKeyTypeIssuanceRequirementRule
- {
- static public void ValidateSecurityBinding(SecurityBindingElement sbe, Binding binding, ContractDescription contract)
- {
- foreach (SecurityTokenParameters stp in new SecurityTokenParametersEnumerable(sbe, true))
- {
- if (stp is IssuedSecurityTokenParameters)
- {
- IssuedSecurityTokenParameters issuedParameters = stp as IssuedSecurityTokenParameters;
- if (issuedParameters.KeyType == System.IdentityModel.Tokens.SecurityKeyType.BearerKey)
- {
- // The issued Bearer token cannot be used as the primary protection token and it cannot be
- // used as a Endorsing or Signed Endorsing token.
- if ((sbe is SymmetricSecurityBindingElement) && IsBearerKeyType(((SymmetricSecurityBindingElement)sbe).ProtectionTokenParameters))
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidBearerKeyUsage, binding.Name, binding.Namespace)));
- }
- if ((sbe is AsymmetricSecurityBindingElement) && (IsBearerKeyType(((AsymmetricSecurityBindingElement)sbe).InitiatorTokenParameters) || IsBearerKeyType(((AsymmetricSecurityBindingElement)sbe).RecipientTokenParameters)))
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidBearerKeyUsage, binding.Name, binding.Namespace)));
- }
- foreach (SecurityTokenParameters tokenParam in sbe.EndpointSupportingTokenParameters.Endorsing)
- {
- if (IsBearerKeyType(tokenParam))
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidBearerKeyUsage, binding.Name, binding.Namespace)));
- }
- }
- foreach (SecurityTokenParameters tokenParam in sbe.EndpointSupportingTokenParameters.SignedEndorsing)
- {
- if (IsBearerKeyType(tokenParam))
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidBearerKeyUsage, binding.Name, binding.Namespace)));
- }
- }
- }
- if (issuedParameters.IssuerBinding != null)
- {
- SecurityBindingElement secBindingEle = SecurityValidationBehavior.GetSecurityBinding(issuedParameters.IssuerBinding, contract);
- if (secBindingEle != null)
- ValidateSecurityBinding(secBindingEle, issuedParameters.IssuerBinding, contract);
- }
- }
- else if (stp is SecureConversationSecurityTokenParameters)
- {
- SecureConversationSecurityTokenParameters scParameters = stp as SecureConversationSecurityTokenParameters;
- ValidateSecurityBinding(scParameters.BootstrapSecurityBindingElement, binding, contract);
- }
- }
- }
- static public void ValidateNoSecurityBinding(Binding binding, ContractDescription contract)
- {
- }
- static bool IsBearerKeyType(SecurityTokenParameters tokenParameters)
- {
- if (!(tokenParameters is IssuedSecurityTokenParameters))
- return false;
- return ((IssuedSecurityTokenParameters)tokenParameters).KeyType == SecurityKeyType.BearerKey;
- }
- }
- static class CookieAndSessionProtectionRequirementsRule
- {
- static public void ValidateSecurityBinding(SecurityBindingElement sbe, Binding binding, ContractDescription contract)
- {
- if (!(sbe is TransportSecurityBindingElement))
- foreach (SecurityTokenParameters stp in new SecurityTokenParametersEnumerable(sbe, true))
- {
- SecureConversationSecurityTokenParameters scstp = stp as SecureConversationSecurityTokenParameters;
- if (scstp != null)
- {
- ISecurityCapabilities bootstrapSecurityCapabilities = scstp.BootstrapSecurityBindingElement.GetIndividualProperty<ISecurityCapabilities>();
- if (bootstrapSecurityCapabilities != null
- && bootstrapSecurityCapabilities.SupportedRequestProtectionLevel == ProtectionLevel.EncryptAndSign
- && bootstrapSecurityCapabilities.SupportedResponseProtectionLevel == ProtectionLevel.EncryptAndSign)
- {
- continue;
- }
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
- SR.GetString(SR.BindingDoesNotSupportProtectionForRst, binding.Name, binding.Namespace, contract.Name, contract.Namespace)));
- }
- }
- }
- static public void ValidateNoSecurityBinding(Binding binding, ContractDescription contract)
- {
- }
- }
- static class SoapOverSecureTransportRequirementsRule
- {
- static public void ValidateSecurityBinding(SecurityBindingElement securityBindingElement, Binding binding, ContractDescription contract)
- {
- if (securityBindingElement is TransportSecurityBindingElement && !securityBindingElement.AllowInsecureTransport)
- {
- // ensure that if soap security cookie/session is configured, then the authentication mode supports encryption
- IEnumerable<BindingElement> elements = binding.CreateBindingElements();
- Collection<BindingElement> bindingElementStack = new Collection<BindingElement>();
- bool isBelowSecurity = false;
- foreach (BindingElement element in elements)
- {
- SecurityBindingElement sbe = element as SecurityBindingElement;
- if (sbe != null)
- {
- isBelowSecurity = true;
- }
- else if (isBelowSecurity)
- {
- bindingElementStack.Add(element);
- }
- }
- bool isTransportProtected = false;
- if (bindingElementStack.Count != 0)
- {
- BindingContext context = new BindingContext(new CustomBinding(bindingElementStack), new BindingParameterCollection());
- ISecurityCapabilities transportCapabilities = context.GetInnerProperty<ISecurityCapabilities>();
- if (transportCapabilities != null
- && transportCapabilities.SupportsServerAuthentication
- && transportCapabilities.SupportedRequestProtectionLevel == ProtectionLevel.EncryptAndSign
- && transportCapabilities.SupportedResponseProtectionLevel == ProtectionLevel.EncryptAndSign)
- {
- isTransportProtected = true;
- }
- }
- if (!isTransportProtected)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
- SR.GetString(SR.TransportDoesNotProtectMessage, binding.Name, binding.Namespace, contract.Name, contract.Namespace)));
- }
- }
- }
- static public void ValidateNoSecurityBinding(Binding binding, ContractDescription contract)
- {
- }
- }
- static class IssuedKeySizeCompatibilityWithAlgorithmSuiteRule
- {
- static public void ValidateSecurityBinding(SecurityBindingElement sbe, Binding binding, ContractDescription contract)
- {
- SecurityAlgorithmSuite algorithmSuite = sbe.DefaultAlgorithmSuite;
- foreach (SecurityTokenParameters stp in new SecurityTokenParametersEnumerable(sbe, true))
- {
- if (stp is IssuedSecurityTokenParameters)
- {
- IssuedSecurityTokenParameters issuedParameters = stp as IssuedSecurityTokenParameters;
- if (issuedParameters.KeySize != 0)
- {
- bool isCompatible = true;
- if (issuedParameters.KeyType == System.IdentityModel.Tokens.SecurityKeyType.SymmetricKey &&
- !sbe.DefaultAlgorithmSuite.IsSymmetricKeyLengthSupported(issuedParameters.KeySize))
- {
- isCompatible = false;
- }
- else if (issuedParameters.KeyType == System.IdentityModel.Tokens.SecurityKeyType.AsymmetricKey &&
- !sbe.DefaultAlgorithmSuite.IsAsymmetricKeyLengthSupported(issuedParameters.KeySize))
- {
- isCompatible = false;
- }
- if (!isCompatible)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.IssuedKeySizeNotCompatibleWithAlgorithmSuite, binding.Name, binding.Namespace, sbe.DefaultAlgorithmSuite, issuedParameters.KeySize)));
- }
- }
- }
- else if (stp is SecureConversationSecurityTokenParameters)
- {
- SecureConversationSecurityTokenParameters scParameters = stp as SecureConversationSecurityTokenParameters;
- ValidateSecurityBinding(scParameters.BootstrapSecurityBindingElement, binding, contract);
- }
- }
- }
- static public void ValidateNoSecurityBinding(Binding binding, ContractDescription contract)
- {
- }
- }
- static class SecurityTokenParameterInclusionModeRule
- {
- static void EnforceInclusionMode(Binding binding, SecurityTokenParameters stp, params SecurityTokenInclusionMode[] allowedInclusionModes)
- {
- bool isMatch = false;
- for (int i = 0; i < allowedInclusionModes.Length; ++i)
- {
- if (stp.InclusionMode == allowedInclusionModes[i])
- {
- isMatch = true;
- break;
- }
- }
- if (!isMatch)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SecurityTokenParametersHasIncompatibleInclusionMode, binding.Name, binding.Namespace, stp.GetType(), stp.InclusionMode, allowedInclusionModes[0])));
- }
- }
- static public void Validate(SecurityBindingElement sbe, Binding binding, ContractDescription contract, KeyedByTypeCollection<IServiceBehavior> behaviors)
- {
- if (behaviors != null)
- {
- ServiceCredentials serviceCredentials = behaviors.Find<ServiceCredentials>();
- if (serviceCredentials != null && serviceCredentials.GetType() != typeof(ServiceCredentials))
- {
- // A custom service credentials has been plugged in. Dont validate the binding
- return;
- }
- }
- SymmetricSecurityBindingElement ssbe = (sbe as SymmetricSecurityBindingElement);
- AsymmetricSecurityBindingElement asbe = (sbe as AsymmetricSecurityBindingElement);
- foreach (SecurityTokenParameters stp in new SecurityTokenParametersEnumerable(sbe, true))
- {
- if (stp is RsaSecurityTokenParameters)
- {
- // rsa keys can only be referred to using keyinfo. There's no wire format for
- // serializing them
- EnforceInclusionMode(binding, stp, SecurityTokenInclusionMode.Never);
- continue;
- }
- if (stp is SecureConversationSecurityTokenParameters)
- {
- Validate(((SecureConversationSecurityTokenParameters)stp).BootstrapSecurityBindingElement, binding, contract, behaviors);
- }
- if (ssbe != null)
- {
- // for the protection token, if it is asymmetric inclusion mode should be Never
- // all other cases inclusion mode should be AlwaysToRecipient/Once
- if (ssbe.ProtectionTokenParameters == stp && stp.HasAsymmetricKey)
- {
- EnforceInclusionMode(binding, stp, SecurityTokenInclusionMode.Never);
- }
- else
- {
- EnforceInclusionMode(binding, stp, SecurityTokenInclusionMode.AlwaysToRecipient, SecurityTokenInclusionMode.Once);
- }
- }
- else if (asbe != null)
- {
- if (asbe.InitiatorTokenParameters == stp && stp.HasAsymmetricKey)
- {
- // allow AlwaysToRecipient, Once and AlwaysToInitiator in this case since the duplex binding
- // configures AlwaysToInitiator in this case
- EnforceInclusionMode(binding, stp, SecurityTokenInclusionMode.AlwaysToRecipient, SecurityTokenInclusionMode.AlwaysToInitiator, SecurityTokenInclusionMode.Once);
- }
- else
- {
- EnforceInclusionMode(binding, stp, SecurityTokenInclusionMode.AlwaysToRecipient, SecurityTokenInclusionMode.Once);
- }
- }
- else
- {
- EnforceInclusionMode(binding, stp, SecurityTokenInclusionMode.AlwaysToRecipient, SecurityTokenInclusionMode.Once);
- }
- }
- }
- }
- static class SecurityVersionSupportForEncryptedKeyBindingRule
- {
- static public void ValidateSecurityBinding(SecurityBindingElement sbe, Binding binding, ContractDescription contract)
- {
- SymmetricSecurityBindingElement ssbe = sbe as SymmetricSecurityBindingElement;
- if (sbe.MessageSecurityVersion.SecurityVersion == SecurityVersion.WSSecurity10
- && ssbe != null
- && ssbe.ProtectionTokenParameters != null
- && ssbe.ProtectionTokenParameters.HasAsymmetricKey)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
- SR.GetString(SR.SecurityVersionDoesNotSupportEncryptedKeyBinding, binding.Name, binding.Namespace, contract.Name, contract.Namespace, SecurityVersion.WSSecurity11)));
- }
- }
- static public void ValidateNoSecurityBinding(Binding binding, ContractDescription contract)
- {
- }
- }
- static class SecurityVersionSupportForThumbprintKeyIdentifierClauseRule
- {
- static public void ValidateSecurityBinding(SecurityBindingElement sbe, Binding binding, ContractDescription contract)
- {
- if (sbe.MessageSecurityVersion.SecurityVersion == SecurityVersion.WSSecurity10)
- {
- foreach (SecurityTokenParameters stp in new SecurityTokenParametersEnumerable(sbe))
- {
- X509SecurityTokenParameters x509 = stp as X509SecurityTokenParameters;
- if (x509 != null && x509.X509ReferenceStyle == X509KeyIdentifierClauseType.Thumbprint)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
- SR.GetString(SR.SecurityVersionDoesNotSupportThumbprintX509KeyIdentifierClause, binding.Name, binding.Namespace, contract.Name, contract.Namespace, SecurityVersion.WSSecurity11)));
- }
- }
- }
- static public void ValidateNoSecurityBinding(Binding binding, ContractDescription contract)
- {
- }
- }
- static class MessageSecurityAndManualAddressingRule
- {
- static public void ValidateSecurityBinding(SecurityBindingElement sbe, Binding binding, ContractDescription contract)
- {
- TransportBindingElement transport = binding.CreateBindingElements().Find<TransportBindingElement>();
- if (transport != null && transport.ManualAddressing)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
- SR.GetString(SR.MessageSecurityDoesNotWorkWithManualAddressing, binding.Name, binding.Namespace)));
- }
- }
- static public void ValidateNoSecurityBinding(Binding binding, ContractDescription contract)
- {
- }
- }
- static class SecurityBindingSupportForOneWayOnlyRule
- {
- static public void ValidateSecurityBinding(SecurityBindingElement sbe, Binding binding, ContractDescription contract)
- {
- if (sbe is AsymmetricSecurityBindingElement && ((AsymmetricSecurityBindingElement)sbe).IsCertificateSignatureBinding)
- {
- for (int i = 0; i < contract.Operations.Count; i++)
- {
- OperationDescription operation = contract.Operations[i];
- if (!operation.IsOneWay)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
- SR.GetString(SR.SecurityBindingSupportsOneWayOnly, binding.Name, binding.Namespace, contract.Name, contract.Namespace)));
- }
- }
- }
- static public void ValidateNoSecurityBinding(Binding binding, ContractDescription contract)
- {
- }
- }
- static class MissingClientCertificateRule
- {
- static void ValidateCore(ServiceDescription description, ServiceCredentials credentials)
- {
- for (int i = 0; i < description.Endpoints.Count; i++)
- {
- ServiceEndpoint endpoint = description.Endpoints[i];
- BindingElementCollection elements = endpoint.Binding.CreateBindingElements();
- SecurityBindingElement security = elements.Find<SecurityBindingElement>();
- CompositeDuplexBindingElement duplex = elements.Find<CompositeDuplexBindingElement>();
- if (security != null && duplex != null && SecurityBindingElement.IsMutualCertificateDuplexBinding(security))
- {
- //
- // We only throw when we have
- // 1. a MutualCertificateDuplexBindingElement,
- // 2. missing client certificate on the service side
- // 3. The server will encrypt the response, or the message going from server to client
- //
- if (credentials.ClientCertificate.Certificate == null)
- {
- ProtectionLevel requestProtectionLevel;
- ProtectionLevel responseProtectionLevel;
- ContractProtectionRequirementsRule.GetRequiredProtectionLevels(endpoint.Contract, security.GetIndividualProperty<ISecurityCapabilities>().SupportedRequestProtectionLevel, security.GetIndividualProperty<ISecurityCapabilities>().SupportedResponseProtectionLevel,
- out requestProtectionLevel, out responseProtectionLevel);
- if (responseProtectionLevel == ProtectionLevel.EncryptAndSign)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.NoClientCertificate, endpoint.Binding.Name, endpoint.Binding.Namespace)));
- }
- }
- }
- }
- static public void Validate(ServiceDescription description)
- {
- //
- // Verify if the service credentials are not customized
- //
- if (!description.Behaviors.Contains(typeof(ServiceCredentials)))
- return;
- ValidateCore(description, description.Behaviors.Find<ServiceCredentials>());
- }
- }
- static class UsernameImpersonationRule
- {
- [MethodImpl(MethodImplOptions.NoInlining)]
- static void ValidateCore(ServiceDescription description, ServiceCredentials credentials)
- {
- if (credentials.UserNameAuthentication.UserNamePasswordValidationMode == UserNamePasswordValidationMode.Windows)
- {
- return;
- }
- ServiceAuthorizationBehavior behavior = description.Behaviors.Find<ServiceAuthorizationBehavior>();
- bool impersonateCallerForAllMethods = (behavior != null) ? behavior.ImpersonateCallerForAllOperations : false;
- for (int i = 0; i < description.Endpoints.Count; i++)
- {
- ServiceEndpoint endpoint = description.Endpoints[i];
- if (endpoint.InternalIsSystemEndpoint(description))
- {
- continue;
- }
- if (ValidatorUtils.IsStandardBinding(endpoint.Binding))
- {
- bool isImpersonationRequested = impersonateCallerForAllMethods;
- if (!isImpersonationRequested)
- {
- isImpersonationRequested = ValidatorUtils.EndpointRequiresImpersonation(endpoint);
- }
- if (isImpersonationRequested)
- {
- ICollection<BindingElement> bindingElements = endpoint.Binding.CreateBindingElements();
- foreach (BindingElement element in bindingElements)
- {
- SecurityBindingElement sbe = (element as SecurityBindingElement);
- if (sbe != null)
- {
- ValidateSecurityBindingElement(sbe, endpoint);
- break;
- }
- }
- }
- }
- }
- }
- static public void Validate(ServiceDescription description)
- {
- ServiceCredentials credentials = description.Behaviors.Find<ServiceCredentials>();
- if (credentials == null)
- return;
- ValidateCore(description, credentials);
- }
- static private void ValidateSecurityBindingElement(SecurityBindingElement sbe, ServiceEndpoint endpoint)
- {
- if (sbe == null)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("sbe");
- if (endpoint == null)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("endpoint");
- foreach (SecurityTokenParameters stp in new SecurityTokenParametersEnumerable(sbe, true))
- {
- if (stp is UserNameSecurityTokenParameters)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.CannotPerformImpersonationOnUsernameToken, endpoint.Binding.Name, endpoint.Binding.Namespace, endpoint.Contract.Name, endpoint.Contract.Namespace)));
- }
- else if (stp is SecureConversationSecurityTokenParameters)
- {
- ValidateSecurityBindingElement(((SecureConversationSecurityTokenParameters)stp).BootstrapSecurityBindingElement, endpoint);
- }
- }
- }
- }
- static class ValidatorUtils
- {
- static public bool EndpointRequiresImpersonation(ServiceEndpoint endpoint)
- {
- if (endpoint == null)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("endpoint");
- for (int i = 0; i < endpoint.Contract.Operations.Count; ++i)
- {
- OperationDescription operation = endpoint.Contract.Operations[i];
- OperationBehaviorAttribute operationBehavior = operation.Behaviors.Find<OperationBehaviorAttribute>();
- if (operationBehavior != null && (operationBehavior.Impersonation == ImpersonationOption.Required))
- {
- return true;
- }
- }
- return false;
- }
- static public bool IsStandardBinding(Binding binding)
- {
- return (binding is BasicHttpBinding) ||
- (binding is BasicHttpsBinding) ||
- (binding is NetTcpBinding) ||
- (binding is NetMsmqBinding) ||
- (binding is NetNamedPipeBinding) ||
- #pragma warning disable 0618
- (binding is NetPeerTcpBinding) ||
- #pragma warning restore 0618
- (binding is WSDualHttpBinding) ||
- (binding is WSFederationHttpBinding) ||
- (binding is WSHttpBinding) ||
- (binding is NetHttpBinding) ||
- (binding is NetHttpsBinding);
- }
- }
- }
- }
|