I have a load-balanced service that uses Message security:
<wsHttpBinding>
<binding>
<security mode="Message">
<message clientCredentialType="Windows" establishSecurityContext="false" />
</security>
</binding>
</wsHttpBinding>
All of my calls to this service open and close their own channel, so there's no benefit to establishing a security context.
I am calling the service with a WSHttpBinding that matches the service config:
ws.Security.Mode = SecurityMode.Message;
ws.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
ws.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
ws.Security.Message.EstablishSecurityContext = false;
This works sometimes, but sometimes I get errors such as
The security context token is expired or is not valid. The message was not processed.
or
The request for security token has invalid or malformed elements.
I finally found that setting EstablishSecurityContext to false doesn't actually prevent security context tokens from being used. Our load balancer doesn't currently use sticky sessions, and I'm trying to avoid going that route.
I did find that I should be able to set NegotiateServiceCredential to false on the client to allow for the load balancer without sticky sessions. My service is already running under an AD account, and I can see it in the WSDL:
<Upn>User#Domain</Upn>
However, when I try to add the service identity to my client
EndpointIDentity.CreateUpnIdentity("User#Domain")
I get the following error:
Authenticating to a service running under a user account which requires Kerberos multilegs, is not supported.
How do I get past this to be able to make a call to my service through the load balancer?
According to the documentation for NegotiateServiceCredential, you must run the service using an SPN identity instead of UPN:
If this property is set to false, and the binding is configured to use
Windows as a client credential type, the service account must be
associated with a Service Principal Name (SPN). To do this, run the
service under the NETWORK SERVICE account, or LOCAL SYSTEM account.
Alternatively, use the SetSpn.exe tool to create an SPN for the
service account. In either case, the client must use the correct SPN
in the <servicePrincipalName> element, or by using the EndpointAddress
constructor.
Once you configure the SPN that your service is running under, your WSDL should display SPN instead of UPN, then you'll have to modify your client such that: EndpointIdentity.CreateSpnIdentity("service_spn_name")
Update:
The following command should properly configure the SPN:
setspn -A YourSvc/host.server.com domain\AppPoolAcccountName
YourSvc = a name identifying your svc
host.server.com = fully qualified hostname of the server your service is hosted on
See docs for setspn
Related
I built a WCF Service in one of my machines of my local network, it has both http and net.tcp (htpp,net.tcp) as enabled protocols in IIS manager.
From another machine a build a client app, and define the endpoints automatically using the Add Service Reference... dialog, I type the service address and when it appears I set the name and click OK. The App.config is updated with two endpoints, one for http (BasicHttpBinding) and the other for net.tcp (NetTcpBinding) as expected.
When running the client app, if I use the BasicHttpBinding:
"using (var proxy = new ProductsServiceClient("BasicHttpBinding_IProductsService"))"
it runs OK, and shows the expected data.
But when I use the NetTcpBinding:
"using (var proxy = new ProductsServiceClient("NetTcpBinding_IProductsService"))"
It throws a SecurityNegotiationException saying that:
"A remote side security requirement was not fulfilled during authentication. Try increasing the ProtectionLevel and/or ImpersonationLevel."
If I do it all in the same machine, I donĀ“t get any exception.
What should I do?
Rafael
By default, the BasicHttpBinding supports no security. So when calling the service from another computer, it will work also.
But by default, NetTcpBinding requires a secure channel. And the default security mode is Transport, so when calling the service from another computer, it will throw a security exception.
The most easy way to solve it is to set the security mode to None as following:
<bindings>
<netTcpBinding>
<binding name="netTcpBindingConfiguration" >
<security mode="None" />
</binding>
</netTcpBinding>
Then we use it in the endpoint
<endpoint address="net.tcp://nelson-laptop:8080/Whatever"
binding="netTcpBinding"
bindingConfiguration="netTcpBindingConfiguration"
contract="ProductsService.IProductsService"
name="NetTcpBinding_IProductsService" />
In Your question you are using the default net.tcp port 808 but have opened port 80 in the firewall. If it is not a typo in the question it could be why it fails.
I have a WCF web service using basicHttpBinding with NTLM hosted on IIS 7 (anonymous authentication disabled and Windows authentication enabled). AppPool using pass-through authentication. I have a console application remotely connecting to the web service.
If I connect using my domain user, the process connects successfully. If I connect using a new service account created on the domain, I get the following error:
The HTTP request is unauthorized with client authentication scheme
'Ntlm'. The authentication header received from the server was 'NTLM'.
The inner exception is:
The remote server returned an error: (401) Unauthorized.
Is this a problem with the domain account or my authentication scheme? The error message implies it is the authentication scheme, but why would it work under my account and not a service account created on the same domain?
Server Config
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Ntlm" proxyCredentialType="None" realm="" />
</security>
Client Consumption
public static WMServiceClient CreateWMServiceProxy()
{
var proxy = new WMServiceClient();
proxy.Endpoint.Address = new EndpointAddress( ConfigurationCache.WMServiceEndpoint );
proxy.Endpoint.Binding = new BasicHttpBinding( BasicHttpSecurityMode.TransportCredentialOnly )
{
MaxBufferSize = 2147483647,
MaxReceivedMessageSize = 2147483647
};
( (BasicHttpBinding) proxy.Endpoint.Binding ).Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;
return proxy;
}
Solution: This wasn't actually a WCF error like I was initially thinking. When I logged the Inner Exception, I discovered I was getting a '401 - Unauthorized' error. Turns out the service account I created was not given remote connection access to the service host machine. Once we granted access and added the service account as a user, the process connected correctly.
I have a WCF service with Message Security Authentication.
I want to set up a routing service for Load Balancing.
For some reason it doesn't work, I've enabled includeExceptionDetailInFaults to see exceptions, so in the client I see:
The client certificate is not provided. Specify a client certificate
in ClientCredentials.
It seems that the certificate isn't forwarded from router->service.
Currently the client/router/service is on the same machine, so I have all the certificates, but if I deploy them on a different machine will the Router have to have the private keys?
In addition, if I want to establish a non-secured connection between the router and service (offload the security), how can I provide the Identity of the caller?
EDIT :
For all Client/Router(both server&client)/Server the security configured the same :
<security mode="Message">
<message clientCredentialType="Certificate" negotiateServiceCredential="false"
algorithmSuite="Default" establishSecurityContext="false" />
</security>
There are many articles that says Microsoft didn't support this scenario and it is true.
This article explains how to write your own custom solution to provide security to all client/router/service.
The client certificate is not provided. Specify a client certificate in ClientCredentials.
I have seen this error when the service certificate doesn't match the host domain name.
If you are still seeing this issue can you post some of your configuration entries?
1) As first try to set certificate in the client side by code.
ChannelFactory<IService1> factory =
new ChannelFactory<IService1>("Service1_Endpoint");
factory.Credentials.ServiceCertificate.SetDefaultCertificate(
System.Security.Cryptography.X509Certificates.StoreLocation.CurrentUser,
System.Security.Cryptography.X509Certificates.StoreName.My,
System.Security.Cryptography.X509Certificates.X509FindType.FindBySubjectName,
"<SeriveCerificateName>");
If you really have problem with certificate you promptly get exception at the application startup.
2) If there is no exception then check thumbprints of the service certificate on both sides.
This blog post explains that Microsoft didn't support this scenarion-
http://blogs.microsoft.co.il/blogs/applisec/archive/2011/12/12/wcf-routing-and-message-security.aspx
We are currently migrating a WCF service from IIS 6 to IIS 7. The service contains some non-SSL endpoints for internal streaming purposes and some exposed endpoints secured with SSL.
The public, secure endpoints are implemented using wsHttpBinding and security mode="TransportWithMessageCredential". The binding reads as follows:
<wsHttpBinding>
<binding name="CustomSecurityBinding">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
The credentials are authenticated against a custom user repository for validation.
After deploying the service to IIS 7 (64bit Win2k8), all services (basicHttpBindings) respond correctly, expect for the wsHttpBindings. If triggered using https, we always get a HTTP 400 status code (Bad Request).
After enabling tracing in IIS, we could kinda narrow down the problem, although the message from the trace did not really help:
MODULE_SET_RESPONSE_ERROR_STATUS Warning
ModuleName="ManagedPipelineHandler", Notification="EXECUTE_REQUEST_HANDLER",
HttpStatus="400", HttpReason="Bad Request", HttpSubStatus="0", ErrorCode="Der
Vorgang wurde erfolgreich beendet. (0x0)", ConfigExceptionInfo=""
Steps done so far:
re-installed WCF extensions in IIS 7 (ServiceModelReg.exe -r -y)
enabled https protocol for host, added self-signed certificate to host
played around with dns/identity setting in wcf configuration
added a base address to wcf service config
After 2 hours of googling and trying to make this work, i ask you as a last resort of hope: Does anybody know this strange behaviour of IIS 7?
Have you verified that the SSL binding is configured in applicationHost.config (%windir%\system32\inetsrv\config\schema\IIS_Schema.xml) and that the HTTP.sys store contains a valid certificate has and store name for the binding? Secondly, the true error could be masked by the 400 error, have you tried altering your wsHttpBinding in configuration to increase the maxBufferPoolSize and maxReceivedMessageSize to some extremely high values and see if this continues?
I have this setup that works perfectly when using http.
A silverlight 3 client
.net 4 WCF service hosted in IIS with basicHttpBinding and using integrated security on the site
When setting https to required on the website the setup stops working.
Using the wcftestclient on the uri I get the message:
The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'Negotiate,NTLM'. The remote server returned an error: (401) Unauthorized.
Maybe this makes sense because the wcftestclient does not pass credentials?
in the web.config the security mode for the service binding is set is set to 'Transport'.
The silverlight client is created like this:
BasicHttpBinding basicHttpBinding = new BasicHttpBinding();
basicHttpBinding.Security.Mode = BasicHttpSecurityMode.Transport;
var serviceClient = new ImportServiceClient(basicHttpBinding, serviceAddress);
The service address is ofcourse starting with https://
And the silverlight client reports this error:
The provided URI scheme 'https' is invalid; expected 'http'.
Parameter name: via
Remember, switching it back to http (and setting security mode to 'TransportCredentialOnly' makes everything working again.
Is the setup I want even supported? If so, how should it be configured?
Turns out that the above setup does work. The key is
basicHttpBinding.Security.Mode = BasicHttpSecurityMode.Transport;
In de client code, and
<binding name="silverlightBinding" maxReceivedMessageSize="10485760">
<security mode="Transport">
<transport clientCredentialType="Windows"/>
</security>
</binding>
at the service end.
Somehow I was working with a xap file without the changes in the security mode. As soon as I used the newly compiled xap it started working.