Difference in authentication of WCF Channel Factory vs Service Reference - c#

I am consuming a 3rd party https web service in a WCF service using the 2 ways described below.
Using Service Reference
ServiceClient client=new ServiceClient();
client.ClientCredentials.UserName.UserName ="xxx";
client.ClientCredentials.UserName.Password = "pwd";
ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
ServiceResponse response=client.GetData();
2.Using channel factory
ChannelFactory<IService> client = new ChannelFactory<IService>(binding, address);
var proxy = client.CreateChannel();
client.Credentials.UserName.UserName ="xxx";
client.Credentials.UserName.Password ="pwd";
ServiceResponse response=client.GetData();
I am able to pass the security credentials using the first approach and i am able to get the respone back from the 3rd party web service.But I am unable to get the response when i use the second approach. I can see that the username,password are added in the security header of the outoing SOAP message with the first approach but not with the second approach.I would be glad if some one can throw some suggestion here about the channel factory approach.

The issue is when you're assigning the credentials - in your current code, you're creating the proxy after you create the factory, and then you assign the credentials to the factory. But that has no effect on the created channel:
ChannelFactory<IService> client = new ChannelFactory<IService>(binding, address);
var proxy = client.CreateChannel();
client.Credentials.UserName.UserName ="xxx";
client.Credentials.UserName.Password ="pwd";
var proxy is a an implementation of IChannel - setting the credentials on the factory (client) has no effect on the already created channels - just the ones created later.
Try setting the credentials and then calling CreateChannel():
ChannelFactory<IService> client = new ChannelFactory<IService>(binding, address);
client.Credentials.UserName.UserName ="xxx";
client.Credentials.UserName.Password ="pwd";
var proxy = client.CreateChannel();
ServiceResponse response=client.GetData();

Related

How to set different credentials of c# wcf client for proxy and service endpoint?

Can somebody tell me how, in a generated wcf client, to set separate credentials for the network proxy and the actual service endpoint? So I have a simlar situation as in How to set proxy credentials to specific wcf client?, but I need to authenticate differently to the proxy than to the web service endpoint:
var b = client.Endpoint.Binding as BasicHttpBinding;
/// [...]
b.Security.Mode = BasicHttpSecurityMode.Transport;
b.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic; // !!!
b.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.Basic; // !!!
client.ClientCredentials.UserName.UserName = login;
client.ClientCredentials.UserName.Password = password;
So where to put my proxyLogin and proxyPassword? Any ideas?

Programmatically implement WCF with Certificate

I am quite new to WCF and trying to get my head around the security. I am still reading and learning, but I came to a point where I got a working version of WCF with Certificate authentication. I know that the code has some weaknesses; however, my initial goal was to create communication using certificate authentication. Also, I wanted to create everything programmatically (no Web.config configurations for the services or clients). The reason for this is that the client should be able to link an Assembly (Class Library) and get access to the server. Also, I am loading the certificates from the file system (again, I know this is not secure). I would like to get a little bit feedback.
The following client snippet is creating an object that I can use to connect to the server. The anonymous type T is my service interface e.g. IService.
Here is my client implementation:
var url = "URL TO WS";
var binding = new WSHttpBinding
{
Security =
{
Mode = SecurityMode.Message,
Message = {ClientCredentialType = MessageCredentialType.Certificate}
}
};
var endpoint = new EndpointAddress(url);
var channelFactory = new ChannelFactory<T>(binding, endpoint);
if (channelFactory.Credentials != null)
{
channelFactory.Credentials.ClientCertificate.Certificate =
new X509Certificate2(#"PATH\TO\Client.pfx"); // Client Certificate PRIVATE & PUBLIC Key
channelFactory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None; // I know this is not good, but I dont have a valid certificate from a trusted entity
}
wcfClient = channelFactory.CreateChannel();
return wcfClient;
The service is a bit more complex. I use .svc files with their code-behind. If I understand the use of .svc files correctly, then I believe this is the entry point where the .NET framework creates a ServiceHost and automatically opens it? In my implementation I do not open the ServiceHost, I only implemented a ServiceHostFactoryBase and referenced it in the .svc Markup language. Look at the Factory section - this is the part where I implement my custom Host Factory.
<%# ServiceHost Language="C#" Debug="true"
Service="Service.Services.LevelService" CodeBehind="LevelService.svc.cs"
Factory="Service.Security.ServiceHostFactory.HostFactory" %>
And my custom Host Factory looks like this:
public class HostFactory : ServiceHostFactoryBase
{
public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
{
var serviceType = Type.GetType(constructorString);
if (serviceType.GetInterfaces().Count() != 1)
throw new NotImplementedException("The service can only have one implemented interface");
var interfaceType = serviceType.GetInterfaces()[0];
var myServiceHost = new ServiceHost(serviceType, baseAddresses);
var httpBinding = new WSHttpBinding();
httpBinding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
httpBinding.Security.Mode = SecurityMode.Message;
myServiceHost.Credentials.ServiceCertificate.Certificate = new X509Certificate2(#"PATH\TO\Server.pfx");
myServiceHost.Credentials.ClientCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.Custom;
myServiceHost.Credentials.ClientCertificate.Authentication.CustomCertificateValidator = new MyX509CertificateValidator();
myServiceHost.Credentials.ClientCertificate.Certificate = new X509Certificate2(#"PATH\TO\Client.cer");
myServiceHost.AddServiceEndpoint(interfaceType, httpBinding, String.Empty);
return myServiceHost;
}
}
The custom validator doess't do much yet, but here it is as well:
public class MyX509CertificateValidator : X509CertificateValidator
{
public override void Validate(X509Certificate2 certificate)
{
// Check that there is a certificate.
if (certificate == null)
{
throw new ArgumentNullException("certificate");
}
// Check that the certificate issuer matches the configured issuer.
//throw new SecurityTokenValidationException("Certificate was not issued by a trusted issuer");
}
}
If I understand correctly, the Server has ONLY the PUBLIC key of the client registered since I only reference the .cer file.
My big question is now, if I would like to get anything like this on a production server - and lets assume nobody will actually get the executables (including the certificates), would this be a possible solution to keep unwanted people out of my webservice? Basically, I don't want anybody else consuming my webservice - only if you have the proper certificate. Also, how much of an issue is the part where I set on the client:
CertificateValidationMode = X509CertificateValidationMode.None
I know there are many questions - but overall, I would like to know if I made some fundamental mistakes in this implementation.
Ok,
after going through a lot of tutorials and demo applications, I figured out that the best way to go ahead is actually using the Certificate Store on Windows. However, I still might consider a hybrid solution where the Server has the certificates in the Certificate store and the client has it embedded in a resource. If you are struggling with WCF and Certificates, have a look at those links:
IIS7 Permissions Overview - ApplicationPoolIdentity
I was able to create Transport as well as Message secured WCF web services. I would suggest to READ the linked articles because there is so much information that will make you understand certificates and their usage. Especially when dealing with self-singed certificates!
I ended up implementing wsHttpBinding using Message Security Mode + Client Certificate with ChainTrust.
Hope this will help someone else!

Programmatically create a secure web http rest service

I would like to programmatically create a secure webhttp REST service in a self host environment i.e in a Console Application but i cannot find any tutorials which allow me to do this.
However i have created secure webhttp rest service using the WCF service library project without any C# code. I used netsh command to insert the certficiate that i had made and updated my config appropriately.
Can anyone advise please?
Just a quick update, I got it working but only http side as of yet.
Here is my service side code:
WebServiceHost serviceHost = new WebServiceHost(typeof(ProductServiceTest), new Uri("http://localhost:9000/"));
WebHttpBinding webHttpBinding = new WebHttpBinding();
webHttpBinding.MaxReceivedMessageSize = 65536 * 2;
webHttpBinding.MaxBufferPoolSize=2147483647L;
webHttpBinding.MaxBufferSize=2147483647;
webHttpBinding.MaxReceivedMessageSize = 2147483647L;
serviceHost.AddServiceEndpoint(typeof(IProductServiceTest), webHttpBinding, "");
// Check to see if the service host already has a ServiceMetadataBehavior
ServiceMetadataBehavior smb = serviceHost.Description.Behaviors.Find<ServiceMetadataBehavior>();
// If not, add one
if (smb == null)
smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
serviceHost.Description.Behaviors.Add(smb);
serviceHost.Open();
Console.WriteLine("Press <ENTER> to terminate the service host");
Console.ReadLine();
serviceHost.Close();
I created a console app for the client side and got my client side working by doing this:
ChannelFactory<IProductServiceTest> cf = new ChannelFactory<IProductServiceTest>(new WebHttpBinding(), "http://localhost:9000");
cf.Endpoint.Behaviors.Add(new WebHttpBehavior());
IProductServiceTest channel = cf.CreateChannel();
var test = channel.GetProductData("8");
Console.WriteLine(test.ProductDescription);
Console.Read();

WCF Client Side Configuration for different Endpoint URI

I am in a situation where I need to develop a WCF Client which will have different EndPoint URI but other settings would remain same. I would get the EndPoint URI from the user.
So I wanted to know if I consume the WCF service using ChannelFactory, then do I need to have app.config file which would contain the WCF Client side configuration with only one endpoint and the address attribute would be blank (which I would get as input from the user) Or do I need to go for programmatically consuming the service.
Leave the endpoint blank in config file. In your code add a method like the one below that takes endpointAddress as a parameter which can come from the user. Use this method to create the channelfactory that you will eventually use to create proxy
private ChannelFactory<IService1> GetChannelFactory(string endpointAddress)
{
// create a binding that will be common
BasicHttpBinding myBinding = new BasicHttpBinding();
//get your uri from the user
EndpointAddress myEndpoint = new EndpointAddress(endpointAddress);
ChannelFactory<IService1> myChannelFactory = new ChannelFactory<IService1>(myBinding, myEndpoint);
return myChannelFactory;
}

Dynamically switch WCF Web Service Reference URL path through config file

How do you dynamically switch WCF Web Service Reference URL path through config file ?
Are you just wanting to override the URL that is in the config to a different url. Say you have a test service and a live service. You can just do this.
client.Endpoint.Address = new EndpointAddress(Server.IsLiveServer() ?
#"LiveUrl" : #"TestURl");
Where those url come from wherever you want
Just to expand on the answer from Erin: -
MyClient client = new MyService.MyClient();
client.Endpoint.Address = new EndpointAddress(new Uri("insert new url here"),
client.Endpoint.Address.Identity, client.Endpoint.Address.Headers);
client.Open();
HTH!
There is no dynamic switching. Each time you want to use another URL you must create new instance of service proxy (client) and pass EndpointAddress or enpoint configuration name to the constructor.
I have been trying to do the same thing but most of the accepted answers in various posts just change the address. Currently under .net 4.7, simply changing the address itself does not work. If you have two different servers and wanting it to switch from one to the other, you have to do this:
var client = new MyService.Service1Client();
var newAdrEndpoint = new EndpointAddress(new Uri("second server address"));
client = new MyService.Service1Client(client.Endpoint.Binding, newAdrEndpoint);
Essentially you need to create a new service using the same binding from the first server and passing in the new address. This is the simplest method I have found.
sure you can do this, have a look here: How to config clients for a wcf service?
it is absolutely normal to point to localhost in development and to change the address (url) in production in the web.config
you canĀ“t chance endpoint url after any calling.
E.G.
in that case, you will get answer from NEWURL:
MyClient client = new MyService.MyClient();
client.Endpoint.Address = new EndpointAddress("NEWURL");
client.Hello(); //return is hello response from NEWURL
but if you will call any method before changing url, the url will be used from app.config, like next example:
MyClient client = new MyService.MyClient();
client.Endpoint.Address = new EndpointAddress("NEWURL");
client.Hello(); //return is hello response from BASEURL

Categories