Another - HTTP request is unauthorized error - wcf

Whenever I try to consume my web service through WCF, I receive this error:
The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Negotiate,NTLMnProviders'.
I know I have Kerberos setup correctly for this environment (it's calling SharePoint 3.0 services that I use in other applications). Integrated Windows security has been working great but this is the first time I've tried to consume it through WCF.
I've gone through this site many times to ensure I have the right header. Is the above error failing because it's expecting "Negotiate" but it's receiving "Negotiate,NTLMnProviders"? I know I can change my headers through that site but it always has 'Negotiate,NTLMnProviders' for the Kerberos header. Anyone got any ideas?

Not really an answer but here are some more details...
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="ListsSoap">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" proxyCredentialType="Windows"/>
</security>
</binding>
<binding name="SiteDataSoap">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" proxyCredentialType="Windows"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://something.com/_vti_bin/lists.asmx"
binding="basicHttpBinding" bindingConfiguration="ListsSoap"
contract="WSS_Server.ListsSoap" name="ListsSoap">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="http://something.com/_vti_bin/SiteData.asmx"
binding="basicHttpBinding" bindingConfiguration="SiteDataSoap"
contract="WSS_Server_SiteData.SiteDataSoap" name="SiteDataSoap">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</client>
</system.serviceModel>
And then I'm instantiating my proxy and calling this in code...
proxy.ClientCredentials.Windows.AllowedImpersonationLevel =
System.Security.Principal.TokenImpersonationLevel.Impersonation;
proxy.ClientCredentials.Windows.AllowNtlm = false;
// Web service call
proxy.GetWeb(...);

Related

WCF service: The HTTP request is unauthorized with client authentication scheme 'Negotiate'

I have a WCF client in a VS2012 project that has the configuration:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="myServiceBehaviour">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpEndpointBinding">
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<services>
<service behaviorConfiguration="myServiceBehaviour"
name="xxx.Web.Mvc.Client.Services.MyService">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="BasicHttpEndpointBinding" name="BasicHttpEndpoint" contract="xxx.Wcf.IMyService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
Within IIS 7.5, the service is set to use Windows authentication.
I'm using basicHttpBinding over HTTPS. My requirements are SSL, but I've ended up using Windows authentication to get it to work.
I have a quick and dirty console application with the following config:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpEndpoint">
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://dev.xxxx.local/xxxx.Web.Mvc.Client/services/MyService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpEndpoint"
contract="MyService.IMyService" name="BasicHttpEndpoint" />
</client>
</system.serviceModel>
This works fine, like a dream.
The same configuration (I thought) in a VB application:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpEndpoint" sendTimeout="10:00:00"> <!-- See point 1 below -->
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://xxxx.inter.local/xxxx.Web.Mvc.Client/services/MyService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpEndpoint"
contract="MyService.IMyService" name="BasicHttpEndpoint" />
</client>
Doesn't work, instead I get:
MessageSecurityException: The HTTP request is unauthorized with client
authentication scheme 'Negotiate'. The authentication header received
from the server was 'Negotiate
oXIwcKADCg....igAwIBAaERMA8bDWlvbXZuZWRkZXYwMiQ='.
The service is clearly fine, it's just the client (and specifically the web site client) that is struggling.
Seemingly, the server is rejecting the authorisation from the web site client. The Negotiate response includes the token, I've ommitted for obvious reasons here, but you can see the structure.
How can I get this working? With the only requirement being it needs to be over SSL. I'd prefer to send credentials, but I'm not bothered. I didn't get very far using anonymous, anyway.
Points:
The sendTimeout setting is applied because for some reason when being called remotely from the web site client, execution takes over 1 minute and times out.
by this: http://blogs.msmvps.com/alvin/2008/11/14/net-3-5-sp1-breaking-change-to-wcf/
you may need to add this block to your endpoint-identity node
<servicePrincipalName value=""/>
turning it to:
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="BasicHttpEndpointBinding" name="BasicHttpEndpoint" contract="xxx.Wcf.IMyService">
<identity>
<dns value="localhost" />
<servicePrincipalName value=""/>
</identity>
</endpoint>

Issue with multiple interfaces in a single service

I am using WCF with NetTcpBinding on a solution where both client and server are windows forms. The service is hosted by one of them. I am using VS.2012.
On the server side I have several service contracts (related) all of which are implemented in a single service class. Like this:
public class MyService : IServiceA, IServiceB
{
}
and they should be accessible via net.tcp://localhost:4545/control/ which would lead to the following service addresses:
IServiceA (endpoint alphaEP) : net.tcp://localhost:4545/control/ASvc/
IServiceB (endpoint betaEP) : net.tcp://localhost:4545/control/BSvc/
And when I use svcutil.exe to generate the client stuff I see that it generates TWO service client classes, one for each interface, so when I use the ServiceBClient it generates an exception inidicating it could not find a 'betaEP' with contract 'IServiceB' even though the app.config has the same binding configuration and has both endpoints defined
<bindings>
<netTcpBinding>
<binding name="alphaEP">
<reliableSession enabled="true" />
<security mode="None" />
</binding>
<binding name="betaEP">
<reliableSession enabled="true" />
<security mode="None" />
</binding>
</netTcpBinding>
</bindings>
and this
<client>
<endpoint address="net.tcp://localhost:4545/control/ASvc"
binding="netTcpBinding" bindingConfiguration="alphaEP"
contract="CodeDom.IServiceA" name="alphaEP">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="net.tcp://localhost:4545/control/BSvc"
binding="netTcpBinding" bindingConfiguration="betaEP" contract="CodeDom.IServiceB"
name="betaEP">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</client>
Why can't it find the endpoint if this client app.config was generated by svcutil.exe based on the server configuration?
Why does it generates two client classes instead of a single one? would that be the source of the problem? I have multiple related services to expose and I don't want to occupy more than one port on that. Do note, this is Net TCP Binding.

Access to WCF service with service client generated on different developer computer

I work together with a different developer on a WCF service
if the service client reference is generated by the other developer, after I update from SVN and I try to run, the application accessing the service fails with exception:
The caller was not authenticated by the service.
InnerException Message:
The request for security token could not be satisfied because authentication failed.
I noticed, when the client reference is generated on other pc, in client's app.config I have
<endpoint address="http://MyService.svc/ws"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ISqlService"
contract="OneTestModel.ISqlService" name="WSHttpBinding_ISqlService">
<identity>
<servicePrincipalName value="host/alabala" />
</identity>
</endpoint>
If I generate/update the client on my pc, I get
<identity>
<servicePrincipalName value="host/my-pc-name" />
</identity>
and I can access the service
Service uses wsHttpBinding, and in it's web.config I have
<bindings>
<wsHttpBinding>
<binding name="ConfigBinding">
<security mode="Message">
<transport clientCredentialType="Windows" proxyCredentialType="None" realm="" />
<message clientCredentialType="Windows" negotiateServiceCredential="true" algorithmSuite="Default" establishSecurityContext="false" />
</security>
</binding>
</wsHttpBinding>
</bindings>
The service is supposed to run anonymously.
What change should I do in service config to ignore client side's <identity>?
Thanks

WCF method call returning web service disco page

I have a WCF web service and application that works fine in developemnt. I've published the WCF on an IIS Server and am able to use it from the web app inside the firewall addressing it by server name. HOWEVER, now that I've put it out for use externally, it is causing problems.
My web app is getting an error trying to connect. I can see the service, disco, wsdl, etc from inside and outside the firewall, but when I make my first call for authentication from the outside, the service is returning the DISCO page instead of processing the authentication method call. This results in a ProtocolException because as I understand it, the app is expecting xml, not html.
Again, exact same web app works fine interally hitting the IIS server.
One difference being externally I'm getting to it from a web address, internally i'm using the server name. But the service loads in a web browser outside the firewall using the web address.
Partial web app config:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding
name="WSHttpBinding_IWebService"
closeTimeout="00:03:00"
openTimeout="00:03:00"
receiveTimeout="00:10:00"
sendTimeout="00:03:00"
bypassProxyOnLocal="false"
transactionFlow="false"
hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="5000000"
maxReceivedMessageSize="5000000"
useDefaultWebProxy="true"
allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="5000000"
maxArrayLength="5000000"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="Message">
<transport
clientCredentialType="Windows"
proxyCredentialType="None"
realm="" />
<message
clientCredentialType="Windows"
negotiateServiceCredential="true"
algorithmSuite="Default"
establishSecurityContext="true"
/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://<dns address/server address>/WebService.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IWebService"
contract="WebServiceRef.IWebService" name="WSHttpBinding_IWebService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint
address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</client>
Partial service web.config file:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding
name="ServiceBinding"
openTimeout="00:03:00"
sendTimeout="00:03:00"
transactionFlow="false"
maxBufferPoolSize="5000000"
maxReceivedMessageSize="5000000">
</binding>
</wsHttpBinding>
</bindings>
<services>
<service
behaviorConfiguration="xxx.WebServiceBehavior"
name="xxx.WebService">
<endpoint
address="http://<dns address/server address>/WebService.svc"
binding="wsHttpBinding"
bindingConfiguration="ServiceBinding"
contract="xxx.IWebService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint
address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
/WebService.svc"/>

WCF and Kerberos Authentication

I have followed numerous msdn articles and the codeplex guidance but cannot get WCF to work with Kerberos authentication and delegation and would appreciate a little help.
Setup
I have the WCF service in an IIS website on a remote machine
IIS 6.0 on Windows 2003 R2 - SP 2
The SPN for the machine has been added (http/myserver && http/myserver:8080)
An AD account has been created for the IIS app pool
The AD account has the setting, allow delegation (for Kerberos), set to true
I am using Brian Booth's debug site on 8080 and the site passes all requirements for Kerberos delegation. The debug IIS site has anonymous authentication off, and Integrated Windows authentication on.
I have mirrored these settings to the site hosting the WCF service.
Web Service - Web Config (Original)
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WsHttpBindingConfig">
<security>
<message negotiateServiceCredential="true" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="ServiceBehavior" name="Service">
<endpoint address=""
binding="wsHttpBinding"
bindingConfiguration="WsHttpBindingConfig"
contract="IService">
<identity>
<servicePrincipalName value="http/myserver" />
<dns value="" />
</identity>
</endpoint>
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceAuthorization
impersonateCallerForAllOperations="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Web Service - Web Method
[OperationBehavior(Impersonation = ImpersonationOption.Required)]
public string GetCurrentUserName()
{
string name = WindowsIdentity.GetCurrent().Name;
return name;
}
Client App - App Config
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IService"
... />
...
<security mode="Message">
<transport clientCredentialType="Windows"
proxyCredentialType="None"
realm="" />
<message clientCredentialType="Windows"
negotiateServiceCredential="true"
algorithmSuite="Default"
establishSecurityContext="true" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://myserver/Service.svc"
binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IService"
contract="KerberosService.IService"
name="WSHttpBinding_IService">
<identity>
<servicePrincipalName value="http/myserver" />
</identity>
</endpoint>
</client>
</system.serviceModel>
Application Error
The following error occurs when my test application, a WinForms app, tries to call the web method:
"The HTTP request is unauthorized with
client authentication scheme
'Anonymous'. The authentication header
received from the server was
'Negotiate,NTLM'."
Event Log
The following error is in the event log:
Exception:
System.ServiceModel.ServiceActivationException:
The service '/Service.svc' cannot be
activated due to an exception during
compilation. The exception message
is: Security settings for this service
require 'Anonymous' Authentication but
it is not enabled for the IIS
application that hosts this service.
Which I don't understand. The whole point of this service is to not allow anonymous authentication, every user/request must be authenticated using Kerberos tickets, then passing them through to other machines.
How should I configure this WCF service for Kerberos authentication and delegation?
Revision 1
After reading this SO question I removed the metadata endpoint. This has not resolved the issue.
Revision 2
After more researching I found a few posts suggesting to change wsHttpBinding to basicHttpBinding. The modification to that portion of the web.config has been included below, and the service endpoint has been updated to refer to that binding.
Web Service - Web Config (Revised)
<basicHttpBinding>
<binding name="basicBindingConfig">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"
proxyCredentialType="Windows"
realm="" />
</security>
</binding>
</basicHttpBinding>
Client App - App Config (Revised)
<!-- ... -->
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"
proxyCredentialType="Windows"
realm="" />
<message clientCredentialType="UserName"
algorithmSuite="Default" />
</security>
<!-- ... -->
Error (Revised)
The current error looks like it contains a Kerberos authentication header.
The HTTP request is unauthorized with
client authentication scheme
'Negotiate'. The authentication header
received from the server was
'Negotiate SOMEHUGESCARYKEYHERE
For me the current setup does work:
On the Server:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttpBindingConf" useDefaultWebProxy="true"/>
</wsHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="returnFaults" name="Epze.BusinessLayer.ZeitManager">
<endpoint binding="wsHttpBinding" bindingConfiguration="wsHttpBindingConf" contract="Epze.Contract.IZeitManager"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="returnFaults">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceAuthorization impersonateCallerForAllOperations="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Set the following attribute on all methods for the WCF:
[OperationBehavior(Impersonation = ImpersonationOption.Required)]
On the Client:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IZeitManager" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false"/>
<security mode="Message">
<transport clientCredentialType="Windows" proxyCredentialType="None" realm=""/>
<message clientCredentialType="Windows" negotiateServiceCredential="true" algorithmSuite="Default" establishSecurityContext="true"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="Delegation">
<clientCredentials>
<windows allowedImpersonationLevel="Delegation" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint address="http://server.mydomain.net/ePZEsvc/ZeitManager.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IZeitManager"
contract="External.Epze.IZeitManager" name="WSHttpBinding_IZeitManager" behaviorConfiguration="Delegation">
<identity>
<servicePrincipalName value="HOST/localhost"/>
</identity>
</endpoint>
</client>
</system.serviceModel>
HTH, Sven
Something that I notice: the client and server config don't seem to agree on security mode.
In the original section, you have <security>..... in the web.config (omitted the mode="message"), and <security mode="Message"> on the client side.
After your edit, it seems that the client side is unchanged, but the server (web.config) now contains <security mode="TransportCredentialOnly">.
The question really is: can you guarantee that there's only ever going to be one network leg between the client and the server being called? I.e. is this behind a corporate firewall? In that case, I would recommend netTcp binding with <security mode="Transport"> on both ends.
If that's not the case, then you're ok with either wsHttpBinding (which supports more security and reliability features, but is slower and "heavier") or basicHttpBinding. In that case, you would have to use <security mode="Message"> on both ends, and authenticate the service with a certificate (so that the service and client have a common "secret" which to use for encryption).
I would try to leave out the impersonation parts out for the beginning and just get the basic communication and mutual authentication between service and client up and running first - once that's in place, you can start adding the impersonation bits to it, and you can always fall back on a known configuration which works.
David Sackstein has a great series of blog posts explaining the five security scenarios that industry guru Juval Lowy has identified (in his Programming WCF book - the WCF Bible) as the most common and most useful - in order to limit the number of possible combinations of parameters you might want to tweak. One of them is a "Internet" scenario which would probably apply here, if your service is outward facing.
Marc
You need to specify a behaviorConfiguration in your client config. SVCUtil does not auto generate. This resolved my issue and I am now successfully using Kerberos. It was a mission though!
<client>
<endpoint address="..."
binding="customBinding" bindingConfiguration="..."
contract="..." name="..." behaviorConfiguration="ImpersonationBehavior" />
</client>
<behaviors>
<endpointBehaviors>
<behavior name="ImpersonationBehavior">
<clientCredentials>
<windows allowedImpersonationLevel="Impersonation"/> </clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
You should try your initial configuration and make sure to set the IIS to be anonymous and windows authentication at the same time.The reason is when you are using wsHttpBinding default security is message security and there is no transport security defined unless you want to do https. SO Clr states that it needs anonymous authentication turned-on on the IIS.