wcf NetworkCredential with empty user name and password - wcf

I created a WCF service and the security mode has been set to Transport and ClientCredentialType is Windows. Below is my client side code:
NetTcpBinding binding = new NetTcpBinding();
binding.Security.Mode = SecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;
binding.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign;
ChannelFactory<IServices> factory factory = new ChannelFactory<IServices>(binding, service);
NetworkCredential credential = factory.Credentials.Windows.ClientCredential;
credential.UserName = string.Empty;
credential.Password = string.Empty;
IServices connect = factory.CreateChannel();
bResult = connect.IsServerOnline();
Server config:
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="tcpConSecure" />
<security mode="Transport">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
</security>
</binding>
</netTcpBinding>
</bindings>
<services>
<service name="TestService.Services">
<endpoint address="tcp" behaviorConfiguration="EndpointBe" binding="netTcpBinding" bindingConfiguration="tcpConSecure" contract="TestServiceInterface.IServices" />
</service>
</services>
</system.serviceModel>
In theory, I should input the correct windows account name and password, but during test, I found I could set the UserName and Password as empty, and channel still could be created. Why?
Client and Server are not on the same machine, but they are in same domain. The logon account of Client machine could login Server machine. In this case, I could use empty user name and password to create connection and call WCF service.

The channel factory created by the client has nothing to do with the WCF server. Even if the server closes the client, the channel factory can be created successfully, but an error will occur when the method is called.
If you only create a channel, then you set the Username and Password in the credential has nothing to do with the WCF Service. Only when the call is made, the client will pass the Username and Password to the server, and the value of Username and Password will be verified.
This is the explanation in the Microsoft documentation:
UPDATE:
There is another possibility that can cause this problem. If the client and server are on the same machine, the client does not need to provide windows credentials.

Related

Trouble connecting to API

I am new to WCF/APIs and know little to nothing about security. Let me know if I need to provide any more information.
I am trying to connect to a service using
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_ISalesOrderService">
<security mode="Transport" >
<transport clientCredentialType="Basic"></transport>
</security>
</binding>
<binding name="BasicHttpBinding_IDocumentationService">
<security mode="TransportCredentialOnly" >
<transport clientCredentialType="Basic"></transport>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="address1"
name="BasicHttpBinding_ISalesOrderService"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_ISalesOrderService"
contract="SoCalls.ISalesOrderService" />
<endpoint address="address2"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IDocumentationService"
contract="DocCalls.IDocumentationService"
name="BasicHttpBinding_IDocumentationService" />
</client>
</system.serviceModel>
With this, I get this error:
'System.ServiceModel.Security.MessageSecurityException'
The HTTP request is unauthorized with client authentication scheme 'Basic'.
The authentication header received from the server was 'Basic Realm'.
Edit
I followed the instructions suggested in the link provided in the comments, still is giving me this error. I updated my code but I think I am still a bit confused on whether to use HTTP/HTTPS due to lack of knowledge of either service.
Here is how I instantiate my service:
private static SoCalls.SalesOrderServiceClient CreateSalesOrderServiceClient()
{
BasicHttpBinding myBinding = new BasicHttpBinding();
myBinding.MaxReceivedMessageSize = 10000 * 2;
myBinding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
EndpointAddress ea = new EndpointAddress("address1");
SoCalls.SalesOrderServiceClient client = new SoCalls.SalesOrderServiceClient();
client.ClientCredentials.UserName.UserName = ("username");
client.ClientCredentials.UserName.Password = ("password");
return client;
}
As it seems, I did not have access to the API with this specific database which is what was giving me my error. I tried sending other credentials for a separate database from the same server and it worked perfectly fine. Purchased the license required and the code works as expected.

connect programmatically to a WCF service through HTTPS

I am working on a project that uses WCF service. I have built the service, configured the web.config file, deployed it on a IIS 7 server. The service is accesed through HTTPS (on my dev machine, i have self-created the certificate).
Everything is fine when a create the ServiceReference in Visual Studio 2010, it creates the client and it works fine.
What i need is to create a client programatically (need a little flexibility), so when i try to connect "manually", it gives me a error like this:
The provided URI scheme 'https' is invalid; expected 'http'.
Parameter name: via
The code for web.config is: (i hope there is nothing wrong in it)
<system.serviceModel>
<services>
<service name="WcfService1.Service1" behaviorConfiguration="WcfService1.Service1Behavior">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="TransportSecurity" contract="WcfService1.IService1" />
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WcfService1.Service1Behavior">
<serviceMetadata httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="True"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="TransportSecurity">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
The procedure i wrote to access the WCF service is:
void proc()
{
string ADRESASSL = "https://localhost/ServiciuSSLwsBind/Service1.svc";
WSHttpBinding bind= new WSHttpBinding();
EndpointAddress ea = new EndpointAddress(ADRESASSL);
var myChannelFactory = new ChannelFactory<IService1>(bind, ea);
IService1 client = null;
try
{
client = myChannelFactory.CreateChannel();
client.RunMethod1();
client.Close();
//((ICommunicationObject)client).Close();
}
catch (Exception exc)
{
MessageBox.Show(exc.Message);
if (client != null)
client.Close();
}
}
The code for IService1
[ServiceContract]
public interface IService1 : IClientChannel
{
[OperationContract]
int RunMethod1();
//....................................
}
It seems i am doing something wrong here, the procedure raises the Exception i mentioned. Something more i must do to work, but i didn't figured it out.
Thanks in advance for any advice you can give me.
I haven't tested this, but I believe you need to set the security mode for the binding before you create the factory. The default mode for security for WSHttpBinding is SecurityMode.Message, and you want SecurityMode.Transport.
You can resolve this one of three ways, as follows.
First, you can use the overloaded version of the WSHttpBinding constructor to specify the security mode, like this:
WSHttpBinding bind= new WSHttpBinding(SecurityMode.Transport);
bind.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
Secondly, you can use the parameterless constructor and specify the security mode (and the client credential type) like this:
WSHttpBinding bind= new WSHttpBinding();
bind.Security.Mode = SecurityMode.Transport;
bind.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
Third, you can place a binding configuration section in the client config and reference that section in the constructor, like this:
WSHttpBinding bind = new WSHttpBinding("TransportSecurity");
The third example assumes a wsHttpBinding section with the name "TransportSecurity" in the client config file.
For more information, check these MSDN articles:
How to: Set the Security Mode
WSHttpBinding Constructor
Well, solved the problem with the self created certificate.
I have changed the endpoint adress for both the programatically connection and the service reference in Viosual Studio 2010.
string ADRESASSL = "https://localhost/ServiciuSSLwsBind/Service1.svc";
now is
string ADRESASSL = "https://eu-pc/ServiciuSSLwsBind/Service1.svc";
I have changed the adress from localhost to the name of pc "eu-pc". It has to do with the domain the certificate was issued.
Using localhost or 127.0.0.1 worked only for one method or the other.
Hope this will help other guys who might run into this.

How to use a Service Reference with a basic authentication WCF SOAP Service

I have a WCF SOAP service that uses basic access authentication. SSL is not being used - I understand the security issues here.
Using the WCFTestClient application I have verified the service works by temporarily hard coding into the service a user name and password to use when the Authorization header is not present.
I am now trying to write a test application that passes the credentials via the Authorization header. I've added a service reference to my service in my test app but the Authorization header is not present in the http request. The generated MyServiceClient class uses System.ServiceModel.ClientBase
In my test app I am setting the credentials as follows
MyServiceClient client = new MyServiceClient("BasicHttpBinding_MyService");
client.ClientCredentials.UserName.UserName = "WebServiceUsername";
client.ClientCredentials.UserName.Password = "WebServicepassword";
I have also tried as follows
MyServiceClient client = new MyServiceClient();
ClientCredentials loginCredentials = new ClientCredentials();
loginCredentials.UserName.UserName = "WebServiceUsername";
loginCredentials.UserName.Password = "WebServicepassword";
client.Endpoint.Behaviors.Remove(client.Endpoint.Behaviors.Find<ClientCredentials>());
client.Endpoint.Behaviors.Add(loginCredentials);
The service web.config is as follows
<services>
<service name="MyService" behaviorConfiguration="MyBehavior" >
<endpoint contract="MyService" binding="basicHttpBinding" />
<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" />
</service>
</services>
The test app.config is as follows
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_MyService">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:55314/MyService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_MyService"
contract="MyService" name="BasicHttpBinding_MyService" />
</client>
</system.serviceModel>
</configuration>
Any thoughts on what I am missing?
This is a good starting point, move your binding and endpoint info from config file to your class:
protected BasicHttpBinding binding = new BasicHttpBinding()
{
Name = "Name your binding here",
CloseTimeout = new TimeSpan(0, 1, 0),
OpenTimeout = new TimeSpan(0, 1, 0),
ReceiveTimeout = new TimeSpan(0, 10, 0),
SendTimeout = new TimeSpan(0, 1, 0),
AllowCookies = false,
BypassProxyOnLocal = false,
HostNameComparisonMode = HostNameComparisonMode.StrongWildcard,
MaxBufferSize = 65536,
MaxBufferPoolSize = 524288,
MaxReceivedMessageSize = 65536,
MessageEncoding = WSMessageEncoding.Text,
TransferMode = TransferMode.Buffered,
UseDefaultWebProxy = true,
Security = new BasicHttpSecurity()
{
Mode = BasicHttpSecurityMode.Transport,
Message = new BasicHttpMessageSecurity() { AlgorithmSuite = SecurityAlgorithmSuite.Default, ClientCredentialType = BasicHttpMessageCredentialType.UserName},
Transport = new HttpTransportSecurity() { ClientCredentialType = HttpClientCredentialType.Digest }
},
};
protected EndpointAddress endPoint = new EndpointAddress("http://localhost:55314/MyService.svc");
and then
MyServiceClient client = new MyServiceClient(binding, endpont);
Try this, and tweak the binding into your needs, especially "Security".
BasicHttpBinding doesn't seem to have a Security Property in WP8, I am very frustrated with trying to access a sharepoint list under WP8. Xamarin IOS/Android it is no problem.

Cannot connect to a WCF service hosted in a Worker Role

I've created a WCF service and hosted it in cloud through a worker role. Unfortunately when I try to connect to the worker role service I get an exception with the message:
"No DNS entries exist for host 3a5c0cdffcf04d069dbced5e590bca70.cloudapp.net."
3a5c0cdffcf04d069dbced5e590bca70.cloudapp.net is the address for the worker role deployed in azure staging environment.
The workerrole.cs has the following code to expose the WCF service:
public override void Run()
{
using (ServiceHost host = new ServiceHost(typeof(MyService)))
{
string ip = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["tcppoint"].IPEndpoint.Address.ToString();
int tcpport = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["tcppoint"].IPEndpoint.Port;
int mexport = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["mexinput"].IPEndpoint.Port;
// Add a metadatabehavior for client proxy generation
// The metadata is exposed via net.tcp
ServiceMetadataBehavior metadatabehavior = new ServiceMetadataBehavior();
host.Description.Behaviors.Add(metadatabehavior);
Binding mexBinding = MetadataExchangeBindings.CreateMexTcpBinding();
string mexlistenurl = string.Format("net.tcp://{0}:{1}/MyServiceMetaDataEndpoint", ip, mexport);
string mexendpointurl = string.Format("net.tcp://{0}:{1}/MyServiceMetaDataEndpoint", RoleEnvironment.GetConfigurationSettingValue("Domain"), 8001);
host.AddServiceEndpoint(typeof(IMetadataExchange), mexBinding, mexendpointurl, new Uri(mexlistenurl));
// Add the endpoint for MyService
string listenurl = string.Format("net.tcp://{0}:{1}/MyServiceEndpoint", ip, tcpport);
string endpointurl = string.Format("net.tcp://{0}:{1}/MyServiceEndpoint", RoleEnvironment.GetConfigurationSettingValue("Domain"), 9001);
host.AddServiceEndpoint(typeof(IMyService), new NetTcpBinding(SecurityMode.None), endpointurl, new Uri(listenurl));
host.Open();
while (true)
{
Thread.Sleep(100000);
Trace.WriteLine("Working", "Information");
}
}
}
The tcppoint and mexinput are configured with the ports 8001 and 9001. Also Domain is configured with worker role deployment url:3a5c0cdffcf04d069dbced5e590bca70.cloudapp.net
On the client part(a console app), we are using the following configuration in app.config::
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding_IMyService" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions"
hostNameComparisonMode="StrongWildcard" listenBacklog="10"
maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10"
maxReceivedMessageSize="65536">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:50:00"
enabled="false" />
<security mode="None">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
<message clientCredentialType="Windows" />
</security>
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="httpp:\\3a5c0cdffcf04d069dbced5e590bca70.cloudapp.net:9001/MyServiceEndpoint" binding="netTcpBinding"
bindingConfiguration="NetTcpBinding_IMyService" contract="ServiceReference1.IMyService"
name="NetTcpBinding_IMyService" />
</client>
<behaviors>
<serviceBehaviors>
<behavior name="behave">
<serviceMetadata httpGetEnabled="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<system.net>
<defaultProxy useDefaultCredentials="true">
<proxy autoDetect="False" usesystemdefault="False" bypassonlocal="True" />
</defaultProxy>
The following code is built using the sample code available in msdn as background. Locally it is working fine. Unfortunately when i deploy it to cloud, the exception occurs. Moreover, when i use the virtual ip instead of the url, a connection time out occurs with the exception the remote machine did not respond.
Looks like you have your service setup to listen on net.tcp (TCP) and your client using http bindings. I would not expect that to work even locally. I am assuming you have actually opened port 9000 in the ServiceDefinition. Remember that will be a load-balanced endpoint. Are you trying to communicate to this instance from within the deployment (inter-role) or from outside the cloud?
I have found it is a lot easier to setup the host and client (when communicating within a role) through code. Try this:
http://dunnry.com/blog/2010/05/28/HostingWCFInWindowsAzure.aspx
If you are trying to hit the service from a client outside the deployment, this still applies, but for the client building part. You will need to use the external DNS name and port defined in ServiceDefinition.
I have also seen DNS errors if you try to hit the endpoint too soon before the role was ready. It can take a bit to propogate the DNS and you should try not to resolve it until it is ready, lest you cache a bogus DNS entry. If you can resolve that DNS name however to your VIP address, that is not the issue.
public void CallWebService(string data)
{
try
{
string uri = "url"+data;
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream str = response.GetResponseStream();
StreamReader sr = new StreamReader(str);
String IResponse = sr.ReadToEnd();
}
catch (Exception ex)
{
System.Console.WriteLine("Message: "+ex.Message);
}
}
Hope it helps you.

Increasing the timeout value in a WCF service

How do I increase the default timeout to larger than 1 minute on a WCF service?
Are you referring to the server side or the client side?
For a client, you would want to adjust the sendTimeout attribute of a binding element. For a service, you would want to adjust the receiveTimeout attribute of a binding elemnent.
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="longTimeoutBinding"
receiveTimeout="00:10:00" sendTimeout="00:10:00">
<security mode="None"/>
</binding>
</netTcpBinding>
</bindings>
<services>
<service name="longTimeoutService"
behaviorConfiguration="longTimeoutBehavior">
<endpoint address="net.tcp://localhost/longtimeout/"
binding="netTcpBinding" bindingConfiguration="longTimeoutBinding" />
</service>
....
Of course, you have to map your desired endpoint to that particular binding.
Under the Tools menu in Visual Studio 2008 (or 2005 if you have the right WCF stuff installed) there is an options called 'WCF Service Configuration Editor'.
From there you can change the binding options for both the client and the services, one of these options will be for time-outs.
You can choose two ways:
1) By code in the client
public static void Main()
{
Uri baseAddress = new Uri("http://localhost/MyServer/MyService");
try
{
ServiceHost serviceHost = new ServiceHost(typeof(CalculatorService));
WSHttpBinding binding = new WSHttpBinding();
binding.OpenTimeout = new TimeSpan(0, 10, 0);
binding.CloseTimeout = new TimeSpan(0, 10, 0);
binding.SendTimeout = new TimeSpan(0, 10, 0);
binding.ReceiveTimeout = new TimeSpan(0, 10, 0);
serviceHost.AddServiceEndpoint("ICalculator", binding, baseAddress);
serviceHost.Open();
// The service can now be accessed.
Console.WriteLine("The service is ready.");
Console.WriteLine("Press <ENTER> to terminate service.");
Console.WriteLine();
Console.ReadLine();
}
catch (CommunicationException ex)
{
// Handle exception ...
}
}
2)By WebConfig in a web server
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding openTimeout="00:10:00"
closeTimeout="00:10:00"
sendTimeout="00:10:00"
receiveTimeout="00:10:00">
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
For more detail view the official documentations
Configuring Timeout Values on a Binding
Class WSHttpBinding
Different timeouts mean different things. When you're working on the client.. you're probably looking mostly at the SendTimeout - check this reference - wonderful and relevant explanation:
http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/84551e45-19a2-4d0d-bcc0-516a4041943d/
It says:
Brief summary of binding timeout knobs...
Client side:
SendTimeout is used to initialize the OperationTimeout, which governs the whole interaction for sending a message (including receiving a reply message in a request-reply case). This timeout also applies when sending reply messages from a CallbackContract method.
OpenTimeout and CloseTimeout are used when opening and closing channels (when no explicit timeout value is passed).
ReceiveTimeout is not used.
Server side:
Send, Open, and Close Timeout same as on client (for Callbacks).
ReceiveTimeout is used by ServiceFramework layer to initialize the session-idle timeout.
In addition to the binding timeouts (which are in Timespans), You may also need this as well. This is in seconds.
<system.web>
<httpRuntime executionTimeout="600"/><!-- = 10 minutes -->