RESTful GET on HTTPS returning bad request 400 error - wcf

I recently needed to change my REST WCF service to use SSL.
It is hosted in IIS 6 and was working fine prior to the SSL requirement.
I am unable to figure out why I'm getting the 400 bad request error.
I have diagnostic logging and it says the
<Message>The body of the message cannot be read because it is empty.</Message>
The web.config looks like:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<webServices>
<protocols>
<add name="HttpGet"/>
</protocols>
</webServices>
<identity impersonate="true"/>
<customErrors mode="Off"/>
</system.web>
<startup>
<supportedRuntime version="v4.0.30319"/>
</startup>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IMessageService">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
</wsHttpBinding>
<webHttpBinding>
<binding name ="webBinding">
</binding>
</webHttpBinding>
<basicHttpBinding>
<binding name="httpBinding">
<security mode="Transport">
<transport clientCredentialType = "None"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="metadataBehavior"
name="XXXDataService.XXXDataService">
<endpoint address=""
binding="wsHttpBinding"
bindingNamespace="http://blah.blah.blah.com/XXXDataService/"
bindingConfiguration="WSHttpBinding_IMessageService"
contract="ZZZDataService.IZZZDataServices">
</endpoint>
<endpoint address="mex"
binding="mexHttpsBinding" contract="IMetadataExchange" />
</service>
</services>
<standardEndpoints>
<webHttpEndpoint>
<standardEndpoint name=""
helpEnabled="true"
automaticFormatSelectionEnabled="true" />
</webHttpEndpoint>
</standardEndpoints>
<behaviors>
<serviceBehaviors>
<behavior name="metadataBehavior">
<serviceMetadata httpsGetEnabled="true" httpGetEnabled="false"/>
<serviceDebug includeExceptionDetailInFaults="True"
httpHelpPageEnabled="True"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
I only removed the diagnostics part and needed to protect the names by replacing with XXX and ZZZ.
Any help or suggestions would be greatly appreciated.
service implementation:
[ServiceBehavior(Namespace="blah.blah.blah.com", Name="XXXDataService")]
public class YYYDataService : IYYYDataService
{
public string GetUser(string id)
{
string result = string.Empty;
using (YYYAdmintTree tree = new YYYAdmintTree()) // used for accessing DB
{
result = tree.GetUserById(id, 1);
}
return result;
}
}
contract:
[ServiceContract(Namespace="https://blah.blah.blah.com", Name="XXXDataService")]
public interface IYYYDataService
{
[OperationContract]
[WebGet(UriTemplate="/GetUser/{id}", ResponseFormat=WebMessageFormat.Json)]
string GetUserById(string id);
}

Error 400 comes when you pass wrong parameter as Input. If you are passing XML or JSON as an input check once again. If server was unable to locate it it would have given you error 404. But 400 indicates surely there is something wrong with input provided.

Related

The protocol 'https' is not supported

I'm working with a WCF Service hosted in IIS however when i try navigate to the endpoint i receive the error "The protocol 'https' is not supported". It's hosted in IIS 10 locally running Windows 10.
The service is using wsHttpBinding with TransportWithMessageCredential.
Is this error something to do with the SSL certificate or IIS?
I already have a valid localhost certificate in my Local Machine > Personal certificate store.
What I've tried so far
Set the httpsGetUrl attribute to the .svc endpoint.
Checked IIS setting and default protocols is set to "http" which means
both http and https protocols are enabled.
Checked that the Application Pool is using .NET Framework 4.0
Restarted the application pool
I appreciate if someone can assist me.
Here is the current config:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="XXX.Zoo.WebServices.ZooServices_3_0"
behaviorConfiguration="ZooServices_3_0_Behavior">
<endpoint
address="https://localhost/Zootest_3_0/ZooServices_3_0.svc"
binding="wsHttpBinding"
bindingConfiguration="ZooServices_3_0_Binding"
contract="XXX.Zoo.WebServices.IZooServices_3_0" />
<endpoint
address="https://localhost/Zootest_3_0/ZooServices_3_0.svc/mex"
binding="mexHttpsBinding"
contract="IMetadataExchange" />
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="ZooServices_3_0_Binding"
maxReceivedMessageSize="2147483647"
maxBufferPoolSize="2147483647" >
<readerQuotas
maxDepth="2147483647"
maxStringContentLength="2147483646"
maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647"/>
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None"
proxyCredentialType="None" realm="" />
<message clientCredentialType="Certificate"
negotiateServiceCredential="true" algorithmSuite="Default"
establishSecurityContext="true" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="ZooServices_3_0_Behavior">
<serviceMetadata httpsGetEnabled="true"
httpsGetUrl="https://localhost/Zootest_3_0/ZooServices_3_0.svc" />
<serviceDebug includeExceptionDetailInFaults="False" />
<!--The serviceCredentials behavior defines a service
certificate which is used by the service to authenticate
itself to its clients and to provide message protection. -->
<serviceCredentials>
<serviceCertificate
findValue="localhost"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName" />
<clientCertificate>
<authentication
certificateValidationMode="ChainTrust"/>
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
This particular error was resolved by removing the httpsGetUrl attribute from the configuration:
httpsGetUrl="https://localhost/Zootest_3_0/ZooServices_3_0.svc
So the end result looks like this:
<serviceMetadata httpsGetEnabled="true"/>
If you want to enable the https protocol support, you should add the https endpoint which use transport transfer mode to the service. Then we should set up the https protocol site binding in the IIS site binding module.
I have made a demo, wish it is useful to you.
Server end.
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(int value);
}
public class Service1 : IService1
{
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
}
Web.config
<system.serviceModel>
<services>
<service name="WcfService1.Service1" behaviorConfiguration="mybehavior">
<endpoint address="" binding="basicHttpBinding" contract="WcfService1.IService1" bindingConfiguration="https"></endpoint>
<endpoint address="" binding="basicHttpBinding" contract="WcfService1.IService1" bindingConfiguration="http"></endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"></endpoint>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="https">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None"></transport>
</security>
</binding>
<binding name="http">
<security mode="None">
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="mybehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
IIS.
Here are some links, wish it is useful to you.
WCF Service not hitting from postman over https
https://social.msdn.microsoft.com/Forums/vstudio/en-US/d42fc165-052d-476a-9580-1240b3d0293d/specify-endpoint-in-wcf-webconfig?forum=wcf
Feel free to let me know if there is anything I can help with.

Custom UserNamePasswordValidator not called

I am trying to set up a WCF webservice with BasicHttpBinding and authentication using username/password. I made custom authentication class. However, it is never called (verified by debugging). This is my web.config:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<behaviors>
<serviceBehaviors>
<behavior>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Compareware_WebApp.webservices.AuthenticationValidator, Compareware_WebApp" />
</serviceCredentials>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding">
<security mode="TransportCredentialOnly">
<message clientCredentialType="UserName" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="Compareware_WebApp.webservices.Accounts">
<endpoint address="/webservices/Accounts.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding" name="BasicEndpoint"
contract="Compareware_WebApp.webservices.IAccounts" />
</service>
</services>
<client />
This is my authentication class:
namespace Compareware_WebApp.webservices
{
public class AuthenticationValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (null == userName || null == password)
{
throw new ArgumentNullException();
}
if (!Membership.ValidateUser(userName, password))
{
// This throws an informative fault to the client.
throw new FaultException("Unknown Username or Incorrect Password");
}
}
}
}
What am I doing wrong?
I also stuck in this problem, And I got the solutions. If you want to call the Validate method of the UserNamePasswordValidator So, you must be have to use the TransportWithMessageCredential security.
NOTE: You must be have to host the WCF Services at the IIS server and have to enable the SSL for you website otherwise it will be not work. If we use the TransportWithMessageCredential than we have to enable the SSL for the our website.
WCF Server Web.config file
<?xml version="1.0"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
</startup>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttp">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="TransportWithMessageCredential.Service1" behaviorConfiguration="wsHttpBehavior">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttp" contract="TransportWithMessageCredential.IService1">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<host>
<baseAddresses>
<add baseAddress="https://localhost:8080/WCFDemo"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="wsHttpBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="TransportWithMessageCredential.ServiceAuthanticator, TransportWithMessageCredential"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<system.web>
<compilation debug="true"/>
</system.web>
</configuration>
Service Authentication class
public class ServiceAuthanticator : UserNamePasswordValidator
{
/// <summary>
///
/// </summary>
/// <param name="userName"></param>
/// <param name="password"></param>
public override void Validate(string userName, string password)
{
if (String.IsNullOrEmpty(userName) || String.IsNullOrEmpty(password))
{
throw new FaultException("Please, Provide the username and password!!!");
}
if (userName != "abc" || password != "abc")
{
throw new FaultException("Sorry, Invalid username or password!!!");
}
}
}
WCF Client app.config file
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IService1">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://kalpesh-pc/WCFAuth/Service1.svc" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IService1" contract="ServiceReference1.IService1"
name="WSHttpBinding_IService1">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>
Client Program to call the WCF Services
try
{
Service1Client objClient = new Service1Client();
objClient.ClientCredentials.UserName.UserName = "abc";
objClient.ClientCredentials.UserName.Password = "abc";
objClient.Open();
string strData = objClient.GetData(10);
}
catch (FaultException ex)
{
Console.WriteLine(ex.Message);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadKey();
Happy Coding...
:)
Transport, as far as I understand, requires HTTPS to encrypt credentials and throws an exception if there is no SSL. TransportCredentialOnly will send the credentials in plain text and unencrypted and is recommended for testing ONLY.
Therefore, your credentials are send via transport. So <Transport> tag must be adjusted, not <Message>.
The following works for me:
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic"/>
</security>

WCF hosted on SharePoint - Need to enable https

I have a WCF hosted in SharePoint 2013 with two methods GET and SET send JSON data. The WCF worked fine under HTTP servers but now we need to move it to production and run it under SSL where we have a certificate installed on the server.
I made changes to the web.config file but I'm getting error 404 Not Found when I try to call the GET method.
Here is my Web.Config (working on HTTP before the change)
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<services>
<service name="WCF.Service" behaviorConfiguration="WCF.ServiceBehavior" >
<endpoint address=""
binding="webHttpBinding"
contract="WCF.IService"
/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WCF.ServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior >
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="NoSecurityHttpBinding">
<security mode="None">
<transport clientCredentialType="None" />
</security>
</binding>
</webHttpBinding>
</bindings>
</system.serviceModel>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>
Here is what I tried to make the code work:
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<services>
<service name="WCF.Service" behaviorConfiguration="WCF.ServiceBehavior" >
<endpoint address=""
binding="webHttpBinding"
contract="WCF.IService"
/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WCF.ServiceBehavior">
<serviceMetadata **httpsGetEnabled**="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior >
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="NoSecurityHttpBinding">
<security mode="**Transport**">
<transport clientCredentialType="None" />
</security>
</binding>
</webHttpBinding>
</bindings>
</system.serviceModel>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>
Here is my C# Code on the service interface:
[ServiceContract]
public interface IService
{
[OperationContract]
[WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "Get/{Code}")]
Stream Get(string Code);
}
Method code
public class Service : IService
{
public Stream Get(string Code)
{
string strOutPut = "";
WebOperationContext.Current.OutgoingResponse.ContentType = "application/json;charset=utf8";
try
{
/// geting data
return new MemoryStream(Encoding.UTF8.GetBytes(strOutPut));
}
catch (Exception e)
{
// error handler
}
}
}
Any Ideas? What am I missing to enable this method on HTTPS as a SharePoint ISAPI hosted service?
You define security for your binding, but you never assign that binding to your endpoint:
<service name="WCF.Service" behaviorConfiguration="WCF.ServiceBehavior" >
<endpoint address=""
binding="webHttpBinding"
contract="WCF.IService" />
</service>
All your service endpoint says is use webHttpBinding - since you didn't specify a configuration for the binding, the defaults are used, and the default transport for webHttpBinding is None.
Use the bindingConfiguration attribute to tell the endpoint which binding configuration to use:
<endpoint address=""
binding="webHttpBinding"
bindingConfiguration="NoSecurityHttpBinding"
contract="WCF.IService" />
I'd suggest changing the name of your configuration to something other than "NoSecurityHttpBinding" if you're adding security to it.
There may be other issues as well, but you won't even get out of the door until you assign the binding configuration to your endpoint.

At least one security token in the message could not be validated

Server config:
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceCredentialsBehavior">
<serviceCredentials>
<serviceCertificate findValue="cn=cool" storeName="TrustedPeople" storeLocation="CurrentUser" />
</serviceCredentials>
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="ServiceCredentialsBehavior" name="Service">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="MessageAndUserName" name="SecuredByTransportEndpoint" contract="IService"/>
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="MessageAndUserName">
<security mode="Message">
<message clientCredentialType="UserName"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<client/>
</system.serviceModel>
<system.web>
<compilation debug="true"/>
</system.web>
My client config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="LocalCertValidation">
<clientCredentials>
<serviceCertificate>
<authentication certificateValidationMode="PeerTrust" trustedStoreLocation="CurrentUser" />
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IService" >
<security mode="Message">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:48097/WCFServer/Service.svc"
binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IService"
contract="ServiceReference1.IService"
name="WSHttpBinding_IService" behaviorConfiguration="LocalCertValidation">
<identity>
<dns value ="cool" />
</identity>
</endpoint>
</client>
</system.serviceModel>
Service:
public string TestAccess()
{
return OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name;
}
Client:
ServiceClient client = new ServiceClient();
client.ClientCredentials.UserName.UserName = "Admin";
client.ClientCredentials.UserName.Password = "123";
Console.WriteLine(client.TestAccess());
Console.ReadLine();
Error:
An unsecured or incorrectly secured fault was received from the other party. See the inner FaultException for the fault code and detail.
Inner exception:
At least one security token in the message could not be validated.
How do I resolve this exception?
I think the problem is your user name and password. With default configuration user name and password is validated as windows account. If you want other validation you must either use membership provider or custom user name password validator.
Since the error message is rather obscure, thought I would put it out there as another possible solution.
My environment uses Single Sign On (or STS if you prefer) to authenticate a user through ASP.NET MVC site. MVC site in turn makes a service call to my service endpoint by passing bearer token which it requested from STS server with Bootstrap token previously. The error I got was when I made a service call from MVC site.
In my case, this is caused by my Service's configuration as stated below. Particularly audienceUris node, it must exactly match the service endpoint:
<system.identityModel>
<identityConfiguration>
<audienceUris>
<add value="https://localhost/IdpExample.YService/YService.svc" />
</audienceUris>
....
</identityConfiguration>
</system.identityModel>
HTH.

WCF service hosted in IIS with netTCP binding

I have a WCF service hosted in IIS7 with netTCP enabled.
This is my web.config in %apppath%\ , where the SVC file is.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="Search.Querier.WCF.Querier" behaviorConfiguration="SearcherServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8050/SearcherService"/>
</baseAddresses>
</host>
<endpoint address="net.tcp://localhost:9000/SearcherService"
binding="netTcpBinding"
bindingConfiguration="Binding1"
contract="Search.Querier.WCF.IQuerier" />
</service>
</services>
<bindings>
<netTcpBinding>
<binding name="Binding1"
hostNameComparisonMode="StrongWildcard"
sendTimeout="00:10:00"
maxReceivedMessageSize="65536"
transferMode="Buffered"
portSharingEnabled="false">
<security mode="None">
<transport clientCredentialType="None" />
<message clientCredentialType="None" />
</security>
</binding>
</netTcpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="SearcherServiceBehavior">
<serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<system.web>
<compilation debug="true" />
</system.web>
</configuration>
For some reason, instead of loading on port 8050 as I specified, I see the blue and beige site showing the site at:
http://localhost/SearcherService/searcherservice.svc
and not
http://localhost:8050/SearcherService/searcherservice.svc
Additionally, when I try to run
svcutil.exe http://process.mycomp.com/SearcherService/SearcherService.svc?wsdl
as the page rendered on the URL says, I get an error:
Metadata contains a reference that cannot be resolved: 'http://process.mycomp.com/SearcherService/SearcherService.svc?wsdl'
But I have that specified nowhere else in my web.config
Is there anywhere else it could be?
You are missing a MEX endpoint, have a look at this link:
http://bloggingabout.net/blogs/dennis/archive/2006/11/09/WCF-Part-4-3A00-Make-your-service-visible-through-metadata.aspx