Authentication failed between client and WCF service - c#

This a question that already has been discussed a couple of times on SO but I couldn't find any suitable solution to my problem. I have a WCF service hosted on an external server (other domain) and I'm trying to consume it from a command line application. I receive the following error:
The request for security token could not be satisfied because authentication failed.
The service is configured inside a web.config file:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttpBinding_IRun">
<security mode="None">
<message clientCredentialType="None" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<serviceHostingEnvironment>
<baseAddressPrefixFilters>
<add prefix="http://www.domain.net"/>
</baseAddressPrefixFilters>
</serviceHostingEnvironment>
<behaviors>
<serviceBehaviors>
<behavior name="calculadora.SOA.RunBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="calculadora.SOA.RunBehavior" name="calculadora.SOA.Run">
<endpoint address="http://www.domain.net/calculadora/SOA/run.svc" binding="wsHttpBinding" contract="calculadora.SOA.IRun">
<identity>
<dns value="domain.net"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
</system.serviceModel>
On the client side, I create a custom binding to connect to the service. Here is the security configuration:
standardBinding.Security.Mode = SecurityMode.None;
standardBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
standardBinding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
standardBinding.Security.Transport.Realm = "";
standardBinding.Security.Message.ClientCredentialType = MessageCredentialType.None;
standardBinding.Security.Message.NegotiateServiceCredential = false;
standardBinding.Security.Message.EstablishSecurityContext = false;
standardBinding.Security.Message.AlgorithmSuite = SecurityAlgorithmSuite.Default;
I'm not using any security mechanism for authentification but still, the service seems to be expecting one. When working on different domains, is it mandatory to use a basic authentification?
EDIT: I wasn't referencing any binding configuration at my endpoint. Once the reference was set, I received another message error:
{"The message with Action 'http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue' 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)."}
The issue was caused by my client's binding. While I was creating my custom binding using the standard 'WSHttpBinding', the 'SecurityMode' property was set to 'Message' instead of 'None'. Now the code looks like the following and the service finally works:
WSHttpBinding standardBinding = new WSHttpBinding(SecurityMode.None, false);
CustomBinding myCustomBinding = new CustomBinding(standardBinding);
Many thanks to marc_s!

I think the problem is your service endpoint definition:
<endpoint address="http://www.domain.net/calculadora/SOA/run.svc"
binding="wsHttpBinding" contract="calculadora.SOA.IRun">
You are using the standard wsHttpBinding - which defaults to integrated Windows security as message security.
While you do define a binding configuration (called wsHttpBinding_IRun), you're not referencing it in your endpoint definition - thus it doesn't come into play. You need to extend your service endpoint definition with a bindingConfiguration attribute like so:
<endpoint address="http://www.domain.net/calculadora/SOA/run.svc"
binding="wsHttpBinding"
bindingConfiguration="wsHttpBinding_IRun"
contract="calculadora.SOA.IRun">
in order to actually use your defined binding configuration (including the security settings).

I ran into the same issue and after a whole day invested, finally I figure out how to fix. The key is put establishSecurityContext="false" into message tag.
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName" establishSecurityContext="false" />
</security>

Related

WCF Service Authorizing with Active Directory - Access Denied Error

I have a question around WCF authorization against a domain account over HTTP traffic hosted on IIS (none production so no ssl cert was available to use over the internet)
I'd like to know how to set up windows authentication from a client to my web service. currently I'm testing on the same LAN so proxies are not a problem
I have included a list of tried steps at the end of this post
Edit: The error that is occurring is just Access is denied, nothing else, given from the
try, catch in the Client Application. If there is a way to get more detailed information, please let me know and ill add the result to the post.
WCF Service code:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single, IncludeExceptionDetailInFaults = true)]
public class Data : IData
{
[PrincipalPermission(SecurityAction.Demand, Role=#"Administrators")]
public List<Incident> GetCases()
{
Queries query = new Queries();
List<Incident> iList = query.CallCases();
return iList;
}
}
WCF Web Config Bindings:
<wsHttpBinding>
<binding name="TransportSecurity">
<security mode="None">
<message clientCredentialType="Windows" algorithmSuite="Default"/>
</security>
</binding>
</wsHttpBinding>
WCF Web Config Behavior:
<behavior name="Behaviour1">
<serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
<serviceDebug includeExceptionDetailInFaults="true" />
<useRequestHeadersForMetadataAddress>
<defaultPorts>
<add scheme="http" port="9577" /> ///This port is correct
</defaultPorts>
</useRequestHeadersForMetadataAddress>
</behavior>
WCF Web Config Service:
<service behaviorConfiguration="Behaviour1" name="WebService1.Data">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="TransportSecurity" contract="WebService1.IData">
<identity>
<dns value="demo.DomainName.co.uk" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
Client Application (Has Service reference added)
DataClient client = new DataClient();
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
PrincipalPermission principalPerm = new PrincipalPermission(null, "Administrators");
principalPerm.Demand();
Console.WriteLine("Demand succeeded.");
client.ClientCredentials.Windows.ClientCredential.Domain = "Domain Name";
client.ClientCredentials.Windows.ClientCredential.UserName = "User Account";
client.ClientCredentials.Windows.ClientCredential.Password = "Password";
//client.ClientCredentials.UserName.UserName = #"UserAccount#domain.com";
//client.ClientCredentials.UserName.Password = "Password";
//client.ClientCredentials.UseIdentityConfiguration = true;
try
{
List<Incident> cases = client.GetCases().ToList();
foreach (Incident Inc in cases)
{
Console.WriteLine(Inc.CaseID);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Attempted Resolutions:
Using Domain and Local Users
Modifying the Client Credential type to basic, NTLM and Windows
using setting IIS to use
IIS has Basic and Windows Authentication Enabled
if you need any more information please don't hesitate to ask.
Thanks for any help you can provide
#Tim pointed me in the right direction, this was the resolution:
<wsHttpBinding>
<binding name="TransportSecurity">
<security mode="Message">
<message clientCredentialType="Windows" algorithmSuite="Default"/>
</security>
</binding>
</wsHttpBinding>
Because I have no SSL Certificate I needed to set the security mode to Message, I was getting confused as most people test using SSL, which would require transport security as well I had set it to None for testing.
Thanks for the help Tim

BTS 2013 - The message has a bad message signature

I've a problem with BizTalk Server 2013 and a WCF Service. BizTalk needs to consume the WCF Service. BizTalk needs to sign the message with a X509 certificate and I receive the following error message:
There was a failure executing the send pipeline: "BizTalkUtilities.SignPipeline,
BizTalkUtilities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d749e81ab815db56" Source:
"MIME/SMIME encoder" Send Port: "SndPort_Sign_V2" URI: "http://XXXX/DemoServiceSigned
/DemoService.svc" Reason: The message has a bad message signature.
First I've created the service without security, everything works. Once I've setup my security (message security, Sign) it didn't work anymore. To be sure my service was fine, I've created a test WCF client which consumes the service with the security - no problem.
The message needs to be signed using a X509 certificate. All the certificates are in the correct place. I followed the info stated on MSDN.
Service config:
<bindings>
<wsHttpBinding>
<binding name="clientSignConfig">
<security mode="Message">
<message clientCredentialType="Certificate"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="SignServiceBL.DemoService" behaviorConfiguration="DemoServiceBehavior">
<endpoint address=""
binding="wsHttpBinding"
bindingConfiguration="clientSignConfig"
contract="SignServiceBL.IDemoService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="DemoServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="PeerTrust" trustedStoreLocation="LocalMachine"/>
</clientCertificate>
<serviceCertificate findValue="CN=DemoServiceServerCertificate"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
Client config (this works for a WCF Client, but doesn't work in BizTalk)
<bindings>
<customBinding>
<binding name="demoService_CustomBinding">
<transactionFlow />
<security authenticationMode="SecureConversation" messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">
<secureConversationBootstrap authenticationMode="MutualSslNegotiated" messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10" />
</security>
<textMessageEncoding />
<httpTransport />
</binding>
</customBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="signingBehavior">
<clientCredentials>
<clientCertificate findValue="CN=DemoServiceSigning"
storeLocation="CurrentUser" storeName="My"/>
<serviceCertificate>
<authentication certificateValidationMode="PeerTrust" trustedStoreLocation="LocalMachine"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint address="http://XXXX/DemoServiceSigned/DemoService.svc"
binding="customBinding" bindingConfiguration="demoService_CustomBinding" behaviorConfiguration="signingBehavior"
contract="DemoService.IDemoService" name="WSHttpBinding_IDemoService">
<identity>
<dns value="DemoServiceServerCertificate"/>
</identity>
</endpoint>
</client>
I've setup tracing, but BizTalk isn't even sending a message to my service. It's like the sendpipeline is blocking my request.
Any ideas?
EDIT
You don't need the pipeline with a MIME/SMIME encoder to sign WCF messages. You should use this pipeline if you need to sign emails... See the first sentence of MSDN
BizTalk Server supports signing outbound messages and signature verification for inbound Secure Multipurpose Internet Mail Extensions (S/MIME) messages
Once I remove the pipeline, BizTalk sends a message to the service. The problem now is that it's signed and encrypted. I am figuring out how to tell BizTalk to only sign the message. If you have any ideas, feel free to post them. If I find it, I will post it ;-)
It wasn't easy, but I was able to solve my issue :-)
I wrote a blogpost about it, because it's a bit to complicated to create an answer here.
So check it out!

WCF Windows Authentication, local debug ok but not work on server

On my Server, running a Windows Authentication WCF application hosted in IIS 7:
IIS Config: Windows Auth : disabled; anonymous: enabled
<system.serviceModel>
<services>
<service name="Services.AccountService" behaviorConfiguration="MyServiceTypeBehaviors">
<endpoint address="" binding="ws2007HttpBinding" bindingConfiguration="AccountServiceBinding"
contract="Contracts.IAccountService" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceTypeBehaviors" >
<!--<serviceDebug includeExceptionDetailInFaults="true"/>-->
<serviceMetadata httpGetEnabled="true" httpGetUrl="" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<ws2007HttpBinding>
<binding name="AccountServiceBinding" >
<security mode="Message">
<message clientCredentialType="Windows" />
</security>
</binding>
</ws2007HttpBinding>
</bindings>
</system.serviceModel>
and then I create a MVC4 Application with following code to call WCF service:
WS2007HttpBinding myBinding = new WS2007HttpBinding();
myBinding.Security.Mode = SecurityMode.Message;
EndpointAddress endpoint = new EndpointAddress("http://server/accountservice.svc");
AccountServiceClient _client = new AccountServicesObjects.AccountServiceClient(myBinding, endpoint);
_client.ClientCredentials.Windows.ClientCredential.UserName = "username";
_client.ClientCredentials.Windows.ClientCredential.Password = "password";
var user = _client.GetUserInformation(); // works fine
After I finished this mvc4 application, I deploy this website to the Same server which is running WCF one, when I login, occurs:
System.ServiceModel.Security.SecurityNegotiationException: The caller was not authenticated by the service.
System.ServiceModel.FaultException:The request for security token could not be satisfied because authentication failed.
on System.ServiceModel.Security.SecurityUtils.ThrowIfNegotiationFault(Message message, EndpointAddress target)
on System.ServiceModel.Security.SspiNegotiationTokenProvider.GetNextOutgoingMessageBody(Message incomingMessage, SspiNegotiationTokenProviderState sspiState)
how this happend?
It seems your service hasn't been started at all. If you enable tracing you can find an exception. There is an error in your configuration - you have no base address, but you have set HttpGetUrl to true (for that option you have to set base address)
This should work for you:
<service name="Services.AccountService" behaviorConfiguration="MyServiceTypeBehaviors">
<endpoint address="accountservice.svc" binding="ws2007HttpBinding"
bindingConfiguration="AccountServiceBinding"
contract="Services.IAccountService" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8000/"/>
</baseAddresses>
</host>
</service>

Configure WCF Client to consume a WCF Service using HTTP GET

I have a WCF Service which allows only HTTP GET requests:
[WebInvoke(Method="GET", ResponseFormat=WebMessageFormat.Json)]
public string GetAppData()
The service is exposed using webHttpBinding
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="AppSvcBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
I have my client whose config looks like
<system.serviceModel>
<client>
<endpoint address="http://localhost/AppService/Service.svc"
binding="webHttpBinding"
bindingConfiguration="webHttpBindingConfig"
contract="AppSvc.IService"
behaviorConfiguration="AppSvcBehavior"
name="AppSvcClient">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
</client>
<bindings>
<webHttpBinding>
<binding name="webHttpBindingConfig">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="AppSvcBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
My client code is a simple
ServiceClient client = new ServiceClient("AppSvcClient");
String result = client.GetAppData();
On executing this code I get the error:
The remote server returned an unexpected response: (405) Method Not Allowed.
I checked with fiddler and found that my client is sending a POST message whereas the service expects a GET hence the error.
I wish to know how to configure the client so that is sends GET request to the service.
Use WebGet instead of WebInvoke
Edit
Start by changing your method to this:
[WebInvoke(Method="GET", ResponseFormat=WebMessageFormat.Json,UriTemplate = "/")]
public string GetAppData()
Make sure that webhttpbinding is specified on the server side.
This fixes it on the server side.
Take a backup of your client code.
On the client side delete the service reference. Make sure that all config is removed.
Then add the service reference again. Now it shoud be OK.
I had a similar problem where the generated proxy service interface on the client was missing the WebGet attribute on my methods.
I added the attribute manually and it resolved the problem.
So it seems like the best current solution is to extract the service interfaces into a separate assembly and then share this assembly between the server and its clients.
The automatic proxy generator seems to be buggy.

baseAddresses supplied to ServiceHost are not Https

I am trying to configure my WCF Service to be HTTPS. I have configured the behaviors and the services with the relevant addresses but I cannot understand why the address which is supplied to the service host is still http.
The behavior I am using is here:
<behavior name="RequestProcessorBehavior">
<serviceCredentials>
<userNameAuthentication
userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="ServiceAuthentication,Services"/>
</serviceCredentials>
<serviceMetadata httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
<serviceThrottling maxConcurrentCalls="500" maxConcurrentInstances="500"/>
</behavior>
The service element is here
<service name="MyNamespace.WcfRequestProcessor" behaviorConfiguration="RequestProcessorBehavior">
<host>
<baseAddresses>
<add baseAddress="https://xxxxxxxxxxxxxx/Services/"/>
</baseAddresses>
</host>
<!--
Use the listenUri attribute if this causes a problem with the load balancer.
The url of the listenUri should be that of the load balancer
-->
<endpoint address=""
bindingNamespace="https://xxxxxxxxxxxxxx/Services/"
contract="MyNamespace.IWcfRequestProcessor"
binding="basicHttpBinding"
bindingConfiguration="RequestProcessorBinding">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="wsHttpBinding"
bindingNamespace="https://xxxxxxxxxxxxxx/Services/"
contract="MyNamespace.IWcfRequestProcessor"
binding="wsHttpBinding"
bindingConfiguration="wsBinding">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
</service>
When I add a breakpoint onto the constructor of the ServiceHost I can see that the baseAddresses parameter contains only one address and that is http and not https. When i try to visit the svc page I get the following error and I can see why it would show that but I cannot see what I can change to make the baseAddress which gets passed to the ServiceHost constructor https and not http.
Could not find a base address that
matches scheme https for the endpoint
with binding BasicHttpBinding.
Registered base address schemes are
[http].
Any help would be greatly appreciated.
UPDATE #1
The binding configuration section which I left out of the original question:
<bindings>
<basicHttpBinding>
<binding name="RequestProcessorBinding" maxReceivedMessageSize="2147483647" receiveTimeout="00:30:00" sendTimeout="00:30:00">
<readerQuotas maxStringContentLength="2147483647" maxArrayLength="2147483647"/>
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
This is currently inside a development environment and in IIS6. This is inside the Default Website.
Are you running on IIS or self hosted? If it's IIS, you need to have IIS configured correctly for SSL. Also, you don't mention what your binding configuration looks like, but it needs to be set to enable transport security as well.

Categories