I need to consume a WCF service but I'm behind a proxy server and this proxy server requires a username and password.
I can't find a way to set it, if it was a Web Service, I could just do something like
ws.Proxy = myProxyServer;
How can I do this with a WCF service?
In the WCF binding config, use the useDefaultWebProxy property to make WCF use the windows default proxy (which can be set from IE network config):
<bindings>
<basicHttpBinding>
<binding name="ESBWSSL" ...everything... useDefaultWebProxy="true">
Then in the code, before you use the connection, do this:
WebProxy wproxy = new WebProxy("new proxy",true);
wproxy.Credentials = new NetworkCredential("user", "pass");
and with your webrequest object, before you execute the call:
WebRequest.DefaultWebProxy = wproxy;
I have not tested the code, but I believe this should work.
Note replaced previous answer based on comment
There was actually another stackoverflow answer that covered setting credentials on a proxy.
Is it possible to specify proxy credentials in your web.config?
Related
I built a WCF Service in one of my machines of my local network, it has both http and net.tcp (htpp,net.tcp) as enabled protocols in IIS manager.
From another machine a build a client app, and define the endpoints automatically using the Add Service Reference... dialog, I type the service address and when it appears I set the name and click OK. The App.config is updated with two endpoints, one for http (BasicHttpBinding) and the other for net.tcp (NetTcpBinding) as expected.
When running the client app, if I use the BasicHttpBinding:
"using (var proxy = new ProductsServiceClient("BasicHttpBinding_IProductsService"))"
it runs OK, and shows the expected data.
But when I use the NetTcpBinding:
"using (var proxy = new ProductsServiceClient("NetTcpBinding_IProductsService"))"
It throws a SecurityNegotiationException saying that:
"A remote side security requirement was not fulfilled during authentication. Try increasing the ProtectionLevel and/or ImpersonationLevel."
If I do it all in the same machine, I don´t get any exception.
What should I do?
Rafael
By default, the BasicHttpBinding supports no security. So when calling the service from another computer, it will work also.
But by default, NetTcpBinding requires a secure channel. And the default security mode is Transport, so when calling the service from another computer, it will throw a security exception.
The most easy way to solve it is to set the security mode to None as following:
<bindings>
<netTcpBinding>
<binding name="netTcpBindingConfiguration" >
<security mode="None" />
</binding>
</netTcpBinding>
Then we use it in the endpoint
<endpoint address="net.tcp://nelson-laptop:8080/Whatever"
binding="netTcpBinding"
bindingConfiguration="netTcpBindingConfiguration"
contract="ProductsService.IProductsService"
name="NetTcpBinding_IProductsService" />
In Your question you are using the default net.tcp port 808 but have opened port 80 in the firewall. If it is not a typo in the question it could be why it fails.
I have this setup that works perfectly when using http.
A silverlight 3 client
.net 4 WCF service hosted in IIS with basicHttpBinding and using integrated security on the site
When setting https to required on the website the setup stops working.
Using the wcftestclient on the uri I get the message:
The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'Negotiate,NTLM'. The remote server returned an error: (401) Unauthorized.
Maybe this makes sense because the wcftestclient does not pass credentials?
in the web.config the security mode for the service binding is set is set to 'Transport'.
The silverlight client is created like this:
BasicHttpBinding basicHttpBinding = new BasicHttpBinding();
basicHttpBinding.Security.Mode = BasicHttpSecurityMode.Transport;
var serviceClient = new ImportServiceClient(basicHttpBinding, serviceAddress);
The service address is ofcourse starting with https://
And the silverlight client reports this error:
The provided URI scheme 'https' is invalid; expected 'http'.
Parameter name: via
Remember, switching it back to http (and setting security mode to 'TransportCredentialOnly' makes everything working again.
Is the setup I want even supported? If so, how should it be configured?
Turns out that the above setup does work. The key is
basicHttpBinding.Security.Mode = BasicHttpSecurityMode.Transport;
In de client code, and
<binding name="silverlightBinding" maxReceivedMessageSize="10485760">
<security mode="Transport">
<transport clientCredentialType="Windows"/>
</security>
</binding>
at the service end.
Somehow I was working with a xap file without the changes in the security mode. As soon as I used the newly compiled xap it started working.
I'm having difficulty connecting to a 3rd party WSE 3.0 web service from a WCF client. I have implemented the custom binding class as indicated in this KB article:
http://msdn.microsoft.com/en-us/library/ms734745.aspx
The problem seems to have to do with the security assertion used by the web service - UsernameOverTransport.
When I attempt to call a method, I get the following exception:
System.InvalidOperationException: The
'WseHttpBinding'.'[namespace]'
binding for the
'MyWebServiceSoap'.'[namespace]'
contract is configured with an
authentication mode that requires
transport level integrity and
confidentiality. However the transport
cannot provide integrity and
confidentiality..
It is expecting a username, password, and CN number. In the example code supplied to us by the vendor, these credentials are bundled in a Microsoft.Web.Services3.Security.Tokens.UsernameToken. Here's the example supplied by the vendor:
MyWebServiceWse proxy = new MyWebServiceWse();
UsernameToken token = new UsernameToken("Username", "password", PasswordOption.SendPlainText);
token.Id = "<supplied CN Number>";
proxy.SetClientCredential(token);
proxy.SetPolicy(new Policy(new UsernameOverTransportAssertion(), new RequireActionHeaderAssertion()));
MyObject mo = proxy.MyMethod();
This works fine from a 2.0 app w/ WSE 3.0 installed. Here is a snippet of the code from my WCF client:
EndpointAddress address = new EndpointAddress(new Uri("<web service uri here>"));
WseHttpBinding binding = new WseHttpBinding(); // This is the custom binding I created per the MS KB article
binding.SecurityAssertion = WseSecurityAssertion.UsernameOverTransport;
binding.EstablishSecurityContext = false;
// Not sure about the value of either of these next two
binding.RequireDerivedKeys = true;
binding.MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncrypt;
MembershipServiceSoapClient proxy = new MembershipServiceSoapClient(binding, address);
// This is where I believe the problem lies – I can’t seem to properly setup the security credentials the web service is expecting
proxy.ClientCredentials.UserName.UserName = "username";
proxy.ClientCredentials.UserName.Password = "pwd";
// How do I supply the CN number?
MyObject mo = proxy.MyMethod(); // this throws the exception
I've scoured the web looking for an answer to this question. Some sources get me close (like the MS KB article), but I can't seem to get over the hump. Can someone help me out?
I had success in a similar case with the following binding configuration:
<bindings>
<customBinding>
<binding name="FNCEWS40MTOMBinding">
<security enableUnsecuredResponse="true" authenticationMode="UserNameOverTransport"
allowInsecureTransport="true" messageProtectionOrder="SignBeforeEncrypt">
<secureConversationBootstrap />
</security>
<mtomMessageEncoding messageVersion="Soap12WSAddressingAugust2004"
maxBufferSize="2147483647" />
<httpTransport maxReceivedMessageSize="2147483647" />
</binding>
</customBinding>
</bindings>
Hope it works for you too.
The error message is refering to Transport Level Security, this usually means https.
You have not shown your configuration files. But I am guessing that you have configured security to be transport (or it is required as a consiquence of another choice) and used an address that is http instead of https.
I've been given a web service written in Java that I'm not able to make any changes to. It requires the user authenticate with basic authentication to access any of the methods. The suggested way to interact with this service in .NET is by using Visual Studio 2005 with WSE 3.0 installed.
This is an issue, since the project is already using Visual Studio 2008 (targeting .NET 2.0). I could do it in VS2005, however I do not want to tie the project to VS2005 or do it by creating an assembly in VS2005 and including that in the VS2008 solution (which basically ties the project to 2005 anyway for any future changes to the assembly). I think that either of these options would make things complicated for new developers by forcing them to install WSE 3.0 and keep the project from being able to use 2008 and features in .NET 3.5 in the future... ie, I truly believe using WCF is the way to go.
I've been looking into using WCF for this, however I'm unsure how to get the WCF service to understand that it needs to send the authentication headers along with each request. I'm getting 401 errors when I attempt to do anything with the web service.
This is what my code looks like:
WebHttpBinding webBinding = new WebHttpBinding();
ChannelFactory<MyService> factory =
new ChannelFactory<MyService>(webBinding, new EndpointAddress("http://127.0.0.1:80/Service/Service/"));
factory.Endpoint.Behaviors.Add(new WebHttpBehavior());
factory.Credentials.UserName.UserName = "username";
factory.Credentials.UserName.Password = "password";
MyService proxy = factory.CreateChannel();
proxy.postSubmission(_postSubmission);
This will run and throw the following exception:
The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server
was 'Basic realm=realm'.
And this has an inner exception of:
The remote server returned an error: (401) Unauthorized.
Any thoughts about what might be causing this issue would be greatly appreciated.
First question: is this a SOAP or a REST based Java service you're trying to call?
Right now, with the "webHttpBinding", you're using a REST-based approach. If the Java service is a SOAP service, then you'd need to change your binding to be "basicHttpBinding" instead.
IF it's a SOAP based service, you should try this:
BasicHttpBinding binding = new BasicHttpBinding();
binding.SendTimeout = TimeSpan.FromSeconds(25);
binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType =
HttpClientCredentialType.Basic;
EndpointAddress address = new EndpointAddress(your-url-here);
ChannelFactory<MyService> factory =
new ChannelFactory<MyService>(binding, address);
MyService proxy = factory.CreateChannel();
proxy.ClientCredentials.UserName.UserName = "username";
proxy.ClientCredentials.UserName.Password = "password";
I've used this with various web services and it works - most of the time.
If that doesn't work, you'll have to find out more about what that Java webservice expects and how to send that relevant info to it.
Marc
First of all put the following in your app.config or your web.config. (no need to change this as you move it through environments):
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IConfigService">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:55283/ConfigService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IConfigService"
contract="IConfigService" name="BasicHttpBinding_IService" />
</client>
</system.serviceModel>
Change the contract attribute to the the Namespace.Interface name accordingly.
Note the security mode = TransportCredentialOnly
Now to programmatically change the endpoint and pass the credentials, use the following code:
var myBinding = new BasicHttpBinding("BasicHttpBinding_IConfigService");
var myEndpoint = new EndpointAddress("http://yourbaseurl/configservice.svc");
var myChannelFactory = new ChannelFactory<IConfigService>(myBinding, myEndpoint);
var credentialBehaviour = myChannelFactory.Endpoint.Behaviors.Find<ClientCredentials>();
credentialBehaviour.UserName.UserName = #"username";
credentialBehaviour.UserName.Password = #"password";
IConfigService client = null;
try
{
client = myChannelFactory.CreateChannel();
var brands = client.YourServiceFunctionName();
((ICommunicationObject)client).Close();
}
catch (Exception ex)
{
if (client != null)
{
((ICommunicationObject)client).Abort();
}
}
I will add to this as well based on a similar problem I just experienced. I auto-generated the config / proxy with VS -- but the config it created didn't actually work.
Although it had security mode="Transport" set correctly, it didn't have clientCredentialType="Basic" set. I added to that my config and it still didn't work. Then I actually removed the message security that the tool created since the service I'm contacting is SSL + Basic only:
<message clientCredentialType="UserName" algorithmSuite="Default" />
Voila -- it worked.
I'm not sure why this had an effect considering the element did not specify message level security... but it did.
I encounter a problem with using the WebServiceHostFactory in IIS.
"IIS specified authentication schemes 'IntegratedWindowsAuthentication, Anonymous', but the binding only supports specification of exactly one authentication scheme. Valid authentication schemes are Digest, Negotiate, NTLM, Basic, or Anonymous. Change the IIS settings so that only a single authentication scheme is used."
I wanted to keep both authentication schemes and managed to do so by not using the factory but setting up the endpoint manualy in web.config.
My question is what is WebServiceHostFactory doing to get this result? I was under the impression that WebServiceHostFactory would set the binding to the same webHttpBinding that I used in my config.
Edit:
I have looked at WebServiceHostFactory in reflector and it is not doing anything clever. It is just a simple factory for the WebServiceHost.
Does IIS still use a service host if you set up the endpoint in config? Or is the WebServiceHost setting things up differently.
This is what worked for me. Adding a dummy endpoint early on (before the service host is opened) as shown below seems to have done the trick. (This MSDN article hinted at this http://msdn.microsoft.com/en-us/library/bb412178.aspx.)
public class MyWebServiceHost : WebServiceHost
{
public MyWebServiceHost (Type serviceType, params Uri[] baseAddresses) : base(serviceType, baseAddresses)
{
// Inserting this dummy endpoint config seemingly does the trick:
AddServiceEndpoint(typeof(IMyContract), new WebHttpBinding(), string.Empty);
}
protected override void ApplyConfiguration()
{
// Typical programmatic configuration here per:
// http://msdn.microsoft.com/en-us/library/aa395224.aspx
}
}
I'm guessing this prevents WebServiceHost from creating a default endpoint, and thus shutting down a bunch of functionality.
I'm not sure about the WebServiceHostFactory, but it sounds like you're hosting the service inside IIS and it's got more than one authentication method selected. If you've got IIS 5 or 6, try going into IIS and viewing the properties for the website or virtual directory containing your service. Go to the Directory Security tab, click the Edit button under "Anonymous access and authentication control", and then un-tick either "Anonymous access" or "Integrated Windows authentication". I'm not sure about IIS7.
Under IIS7 you might not find where you can manage the Integrated Windows Authentication setting. In order to see the setting in IIS7 management console, you need to follow steps described in the following article: http://msdn.microsoft.com/en-us/library/x8a5axew.aspx (titled as "Error: Debugging Failed Because Integrated Windows Authentication Is Not Enabled", if link is not functional).
Hope it helps.
disable security in web.config-> configuration tag
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding>
<security mode="None">
<transport clientCredentialType="Windows"/>
</security>
</binding>
</webHttpBinding>
</bindings>
</system.serviceModel>
then your wcf service doesn't need authentication...