mexhttpbinding issue - c#

I hosted my DLL in IIS 6 and set it to only allow authenticated users (disable anonymous). However, I am facing a problem on mexHttpBinding. It requires anonymous login to publish metadata.
I am doing something like this:
This is the original configuration:
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
This is what I am trying to do:
<endpoint address="mex" binding="wsHttpBinding" contract="IMetadataExchange" bindingConfiguration="wsBinding" />
And this is the binding property:
<bindings>
<wsHttpBinding>
<binding name="wsBinding">
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</wsHttpBinding>
</bindings>
This resolves the issue, but I doubt this will work out actually.
Can I change mexHttpBinding to wsHttpBinding for IMetadataExchange?

Yes, you can use a non-MEX Binding to retrieve metadata. See Retrieve Metadata Over a non-MEX Binding for a sample.

Related

WCF with HTTP and TLS

i have an WCF Service where some commands can run insecure via HTTP, but as soon as payment is done, I need to switch to TLS 1.2.
I see there is no way to get this working, except to add reference to second service with another binding and addionally changing the namespaces.
Is there no other way where I can use the same service and just switch the binding?
I use .NET 4.6.1 in case there is a feature in newer versions...
thx!
You can define the host as having multiple bindings and endpoints and the client too. Something like this in pseudo code, you have to fill in your own settings.
<netTcpbinding>
<binding name="notsecure">
<security mode="None" />
</binding>
<binding name="secure">
<security mode="Transport" /> <!-- desired security settings -->
</binding>
</netTcpBinding>
<services>
<service name="yyy">
<endpoint binding="netTcpbinding" bindingConfiguration="notsecure" name="insecureEnd"
contract="IContract" />
<endpoint binding="netTcpBinding" bindingConfiguration="secure"
name="secureEnd" contract="IContract" />
<host>
<baseAddresses>
<add baseAddress="xxx" />
</baseAddresses>
</host>
</service>
</services>
Then config your client with the same multiple bindings and multiple endpoints.
And in code select the correct endpoint by name
Client secure = new Client("secure");
secure.Call();
Client notsecure = new Client("notsecure");
You can use the PrincipalPermission attribute to let certain functions only be called when they are authenticated with a specific certificate.
From MSDN:
https://msdn.microsoft.com/en-us/library/ms731200(v=vs.110).aspx
[PrincipalPermission(SecurityAction.Demand, Name = "CN=ReplaceWithSubjectName; 123456712345677E8E230FDE624F841B1CE9D41E")]
public double Multiply(double a, double b)
{
return a * b;
}

Consume WCF library functions from browser

I've a WCF library with some functions I use from Powershell and C# clients. Now I would like to use a couple of util functions directly from a browser but I'm not sure how to do.
First I added a webHttpBinding endpoint in the Web.config file, here is a slice
<services>
<service name="MI_lib.MainService">
<endpoint name="basic" address="" binding="basicHttpBinding" bindingConfiguration="MI_lib_http" contract="MI_lib.InterfaceMainService"></endpoint>
<endpoint name="web" address="web" binding="webHttpBinding" bindingConfiguration="MI_lib_web" contract="MI_lib.InterfaceMainService"></endpoint>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="MI_lib_http" />
</basicHttpBinding>
<webHttpBinding>
<binding name="MI_lib_web" crossDomainScriptAccessEnabled="true">
<security mode="None"></security>
</binding>
</webHttpBinding>
</bindings>
A simple function define for test purposes is this
[OperationContract]
[WebGet]
string GetData(int value);
Then if I connect to http://localhost/MI_lib/MI_lib.MainService.svc/web I get the following fault message
<Fault xmlns="http://schemas.microsoft.com/ws/2005/05/envelope/none">
<Code>
<Value>Sender</Value>
<Subcode>
<Value xmlns:a="http://schemas.microsoft.com/ws/2005/05/addressing/none">a:ActionNotSupported</Value>
</Subcode>
</Code>
<Reason>
<Text xml:lang="de-CH">The message with Action '' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).</Text>
</Reason>
</Fault>
Any hint on what to check or which other information to provide?
To define a web endpoint, you need, in addition to using the webHttpBinding, to add a web http behavior to your endpoint, as shown below:
<services>
<service name="MI_lib.MainService">
<endpoint name="basic" address="" binding="basicHttpBinding" bindingConfiguration="MI_lib_http" contract="MI_lib.InterfaceMainService"></endpoint>
<endpoint name="web"
address="web"
binding="webHttpBinding"
bindingConfiguration="MI_lib_web" contract="MI_lib.InterfaceMainService"
behaviorConfiguration="MyWeb">
</endpoint>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="MI_lib_http" />
</basicHttpBinding>
<webHttpBinding>
<binding name="MI_lib_web" crossDomainScriptAccessEnabled="true">
<security mode="None"></security>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="MyWeb">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
Also, the URL that you need to use also includes the method name, so you'll need to connect to
http://localhost/MI_lib/MI_lib.MainService.svc/web/GetData?value=123

Make Wcf Service IntegratedWindowsAuthentication

I m getting the following error when I did set the Windows Authentication enable and anonymous to disabled in IIS.
The authentication schemes configured on the host
('IntegratedWindowsAuthentication') do not allow those configured on
the binding 'BasicHttpBinding' ('Anonymous'). Please ensure that the
SecurityMode is set to Transport or TransportCredentialOnly.
Additionally, this may be resolved by changing the authentication
schemes for this application through the IIS management tool, through
the ServiceHost.Authentication.AuthenticationSchemes property, in the
application configuration file at the
element, by updating the ClientCredentialType property on the
binding, or by adjusting the AuthenticationScheme property on the
HttpTransportBindingElement.
My Wcf Service's web.config is as follows...
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5"/>
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpEndpointBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint binding="basicHttpBinding"
bindingConfiguration="BasicHttpEndpointBinding"
contract="Test.IService1" name="BasicHttpEndpoint" />
</client>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceAuthenticationManager
authenticationSchemes="IntegratedWindowsAuthentication"/>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="false"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpBinding" scheme="http" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
Please advice..
In .Net 4.0+, Simplified WCF configuration uses the 'anonymous' configurations when configurations are not explicitly set on a per-services basis in the <services> section. If you remove the name="BasicHttpEndpointBinding" from the <binding> element, or if you duplicate that <binding> element as a new element with no name attribute, it will become the default, anonymous binding that your WCF services will use. This is often useful in cases where you need to serve as well as consume WCF services that may not all have the same config - but at least you can set a default config for the services that do not have a specific config set. The default/anonymous concept is also applicable to <behavior> elements.
<bindings>
<basicHttpBinding>
<binding> <!--Notice, no name attribute set-->
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
Also, I might add that if your WCF services require authentication, this means that you will either need to consume the service using a real user account, or you will need to grant the the DOMAIN\CLIENTCOMPUTERNAME$ account access to the service - so, perhaps the proper solution for many people may be to alter the configuration to instead allow anonymous access (which is not discussed in my answer). Still, I do sometimes actually elect to secure my WCF services with Windows (Kerberos) authentication.
Adding this worked for me.
<bindings>
<webHttpBinding>
<binding>
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</webHttpBinding>
</bindings>
I got this error when updating from .NET 4.0 to .NET 4.5.2. I changed the clientCredentialType from
<security mode="TransportCredentialOnly">
<transport clientCredentialType="None"/>
</security>
to
<security mode="TransportCredentialOnly">
<transport clientCredentialType="InheritedFromHost"/>
</security>
However, setting clientCredentialType="Windows" works equally well.
I had the same issue when consuming already existing WCF web URL.
I tried all the answers mentioned here , but all in all finally only two things helped.
Changing the setting in "Turn windows Features on and off".
Enabling Anonymous authentication along with Windows Authentication in Local IIS server.
<services>
<service name="Test.Service1" behaviorConfiguration="TestName">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="BasicHttpEndpointBinding" contract="Test.IService1" />
</service>
</services>
It solved my problem.
Like the other answers, I needed to update the binding in my Web.config to this:
<basicHttpBinding>
<binding name="basicHttpBindin1">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
But I also needed to update my binding's instantiation:
var binding = new BasicHttpBinding { MaxReceivedMessageSize = 1000000, ReaderQuotas = { MaxDepth = 200 } };
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
I had add a webHttpBinding and point my endpoint to that, which the security settings needed to work. Without that my endpoint used the default WCF config bindings:
<services>
<service behaviorConfiguration="ServiceBehavior" name="Service">
<endpoint address="" binding="webHttpBinding" contract="IService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<bindings>
<webHttpBinding>
<binding>
<!--Notice, no name attribute set-->
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</webHttpBinding>
</bindings>
I'm not entirely sure why, but when I added the 'Factory' attribute to my .SVC file (you need to explicitly drag it to Visual Studio), everything just works - without any changes to default settings in Web.config!
I added Factory="System.ServiceModel.Activation.WebServiceHostFactory" so my .SVC file went from this:
<%# ServiceHost Language="C#" Debug="true" Service="ServiceNameSpace.ServiceName" CodeBehind="ServiceName.svc.cs" %>
to this:
<%# ServiceHost Language="C#" Debug="true" Service="ServiceNameSpace.ServiceName" CodeBehind="ServiceName.svc.cs" Factory="System.ServiceModel.Activation.WebServiceHostFactory" %>
The only side effect seems to be that when you click on the .SVC file in the browser, you get an 'Endpoint not found' error, but the service works fine when you invoke it correctly anyway. As mentioned previously, I'm using a default Web.config with .NET 4.6 (Simplified WCF configuration), so I may yet need to add endpoint details for that to work again.

Impersionation like in ASP.NET for WCF Service

I've got a WebService with ASP.NET sites and WCF services in the same web.config. Until now, I was able to use the ASP.NET impersionation in the WCF services by setting
<system.web>
<compilation targetFramework="4.0" debug="false"/>
<!-- switch custom errors of-->
<identity impersonate="true"/>
<customErrors mode="Off"/>
</system.web>
However, now (for other reasons-> Cookieless Session state for the ASP.NET part) I have to set the
aspNetCompatibilityEnabled="true"
option to false. With this I loose the ASP.NET impersionation for the WCF services.
One of my WCF services needs impersionation for IO operations on the server...
I would like to know how to get the same impersionation I had before by directly defining it on the WCF service configuration.
What I have tried (unsucessfully) is to set
[OperationBehavior(Impersonation = ImpersonationOption.Required)]
on the implementation of the methods in the WCF service and then specifying
<endpoint address="" binding="wsHttpBinding" contract="IService">
<identity>
<servicePrincipalName value="HOST/YourMachineName" />
<dns value="" />
</identity>
</endpoint>
in the web.config (obviously with the correct values for my service), as described in http://msdn.microsoft.com/en-us/library/ff650591.aspx.
However, the WCF service can not be called anymore after this... It tells me that the WsHttpBinding does not offer an identity for the contract.
Am I missing something important?
Edit: Translation of the error message:
: The contract operation '{0}' requires Windows identity for automatic impersonation. A Windows identity that represents the caller is not provided by binding ('{1}','{2}') for contract ('{3}','{4}'.
(The original error message was german...)
Try adding someting similar to this
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="DelegationBehaviour">
<clientCredentials>
<windows allowNtlm="false" allowedImpersonationLevel="Delegation"></windows>
</clientCredentials>
<dataContractSerializer maxItemsInObjectGraph="4194304"></dataContractSerializer>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_SampleWebService" >
<readerQuotas maxArrayLength="16384" maxBytesPerRead="4096" maxDepth="32" maxNameTableCharCount="16384" maxStringContentLength="8192"></readerQuotas>
<security mode="TransportCredentialOnly">
<message algorithmSuite="Default" clientCredentialType="UserName"></message>
<transport clientCredentialType="Windows" proxyCredentialType="None" realm=""></transport>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://server/WebServices/Service/Service.svc" behaviorConfiguration="DelegationBehaviour" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_SampleWebService" contract="SampleWS" name="BasicHttpBinding_SampleEndpoint"></endpoint>
</client>
</system.serviceModel>
This is the server side code
<system.serviceModel>
<services>
<service behaviorConfiguration="CustomBehavior" name="CustomWebService">
<endpoint address="" behaviorConfiguration="" binding="basicHttpBinding" bindingConfiguration="basicHttpBinding_Service" contract="WebService"/>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="basicHttpBinding_Service" maxReceivedMessageSize="4194304" receiveTimeout="00:30:00">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"/>
<message clientCredentialType="UserName"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="CustomBehavior">
<dataContractSerializer maxItemsInObjectGraph="4194304" ignoreExtensionDataObject="True"/>
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug httpHelpPageEnabled="true" includeExceptionDetailInFaults="true"/>
<serviceAuthorization impersonateCallerForAllOperations="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
As well as having these over our WebMethods
<WebMethod(), OperationContract(), OperationBehavior(Impersonation:=ImpersonationOption.Required)> _
Works for us
Well, in the end I just made the binding use Windows authentication:
<security mode="TransportWithMessageCredential">
<message negotiateServiceCredential="false" clientCredentialType="Windows" algorithmSuite="Default"/>
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
</security>
and passed a specific Windows user/pwd combination in the client:
channelFactory.Credentials.Windows.ClientCredential = new NetworkCredential(#"", "", "");
channelFactory.Credentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
Additionally I had to specifically use the newly impersonated user in the code of the web service:
using (var imp = ServiceSecurityContext.Current.WindowsIdentity.Impersonate())
{
// do IO here
}
Well, the actual (underlying) question still remains:
How is it possible to emulate the ASP.NET functionality correctly...
For the moment I'm ok with the solution, however I've got the feeling that I've missed an important point about the ASP.NET impersonation.
Thanks a lot to Iain, although it wasn't exactly the correct answer, it at least got me on the right track!

WCF wsHttpBinding 'algorithmSuite' cannot be parsed error

I am using VSTS 2008 + C# + .Net 3.0. I am using self-hosted WCF. When executing the following statement (host.Open()), there is the following binding not found error. I have posted my whole app.config file, any ideas what is wrong?
ServiceHost host = new ServiceHost(typeof(MyWCFService));
host.Open();
Error message,
The value of the property 'algorithmSuite' cannot be parsed. The error is: The value 'Aes128' is not a valid instance of type 'System.ServiceModel.Security.SecurityAlgorithmSuite'.
EDIT1: I have changed the algorithm suit option value to Default, but met with a new error when executing Open(), error message is, any ideas what is wrong,
Binding validation failed because the WSHttpBinding does not support reliable sessions over transport security (HTTPS). The channel factory or service host could not be opened. Use message security for secure reliable messaging over HTTP.
Full app.config,
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="MyBinding"
closeTimeout="00:00:10"
openTimeout="00:00:20"
receiveTimeout="00:00:30"
sendTimeout="00:00:40"
bypassProxyOnLocal="false"
transactionFlow="false"
hostNameComparisonMode="WeakWildcard"
maxReceivedMessageSize="100000000"
messageEncoding="Mtom"
proxyAddress="http://foo/bar"
textEncoding="utf-16"
useDefaultWebProxy="false">
<reliableSession
enabled="false" />
<security mode="Transport">
<transport clientCredentialType="Digest"
proxyCredentialType="None"
realm="someRealm" />
<message clientCredentialType="Windows"
negotiateServiceCredential="false"
algorithmSuite="Default"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="MyWCFService"
behaviorConfiguration="mexServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="https://localhost:9090/MyService"/>
</baseAddresses>
</host>
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="MyBinding" contract="IMyService"/>
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="mexServiceBehavior">
<serviceMetadata httpsGetEnabled="True"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<startup><supportedRuntime version="v2.0.50727"/></startup></configuration>
thanks in advance,
George
You need to update your service behavior, too, if you change the MEX endpoint from http to https - you need to enable the httpsGetEnabled setting (not the httpGetEnabled):
<behaviors>
<serviceBehaviors>
<behavior name="mexServiceBehavior">
<serviceMetadata httpsGetEnabled="True"/>
</behavior>
</serviceBehaviors>
</behaviors>
UPDATE:
George, check out this MSDN link - there is no "Aes128" algorithm - you must pick one of the existing ones.
UPDATE 2:
Can you try this config - reduce to the max! :-)
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="MyBinding"
maxReceivedMessageSize="100000000"
messageEncoding="Mtom"
proxyAddress="http://foo/bar"
textEncoding="utf-16"
useDefaultWebProxy="false">
<reliableSession enabled="false" />
<security mode="None" />
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="MyWCFService"
behaviorConfiguration="mexServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="https://localhost:9090/MyService"/>
</baseAddresses>
</host>
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="MyBinding" contract="IMyService"/>
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="mexServiceBehavior">
<serviceMetadata httpsGetEnabled="True"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Can you start up your service,and can you add service reference from Visual Studio?
UPDATE 3:
George, I'd recommend you have a look at those security-related links and get some feel for what you really need and want - and how to achieve it.
WCF Security Guide
WCF Security Fundamentals
Fundamentals of WCF Security
MSDN Webcast Series "WCF Top To Bottom"
esp. Episode 10 - Security Fundamentals
Marc
The error message is correct, you don't get reliable messages over WSHttp, you need to use a custom binding and protocol.

Categories

Resources