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.
Related
im trying to implement simple secured client server communiction using WCF.
when im launching mt server everty thing is OK , But when im launching my client im getting this error:
Error : An error occurred while making the HTTP request to https://localhost:800
0/ExchangeService. This could be due to the fact that the server certificate is
not configured properly with HTTP.SYS in the HTTPS case. This could also be caus
ed by a mismatch of the security binding between the client and the server.
this is the server code :
Uri address = new Uri("https://localhost:8000/ExchangeService");
WSHttpBinding binding = new WSHttpBinding();
//Set Binding Params
binding.Security.Mode = SecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
Type contract = typeof(ExchangeService.ServiceContract.ITradeService);
ServiceHost host = new ServiceHost(typeof(TradeService));
host.AddServiceEndpoint(contract, binding, address);
host.Open();
this is the client configuration (app.config):
</client>
<bindings>
<wsHttpBinding>
<binding name="TradeWsHttpBinding">
<security mode="Transport">
<transport clientCredentialType="None"
proxyCredentialType ="None"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
the security configuration at both the client and the server are the same , and i dont need certificate for the server in that kind of security (transport) so why do i get
this exception ????
thanks...
Well looking at your code:
Uri address = new Uri("https://localhost:8000/ExchangeService");
You're specifying that the address is using SSL (https) so it would require a certificate for that purpose. Either use a http binding or install a certificate.
I'd check out the Application Scenarios and How Tos section on this CodePlex Link for different configurations and details of how to configure them.
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 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?
I have a WCF service that uses basicHttpbinding in development.
Now in product we want to use SSL, what changes do I have to make to force SSL connections only?
This page on MSDN explains WCF Binding Security.
http://msdn.microsoft.com/en-us/library/ms729700.aspx
The BasicHttpBinding class is
primarily used to interoperate with
existing Web services, and many of
those services are hosted by Internet
Information Services (IIS).
Consequently, the transport security
for this binding is designed for
seamless interoperation with IIS
sites. This is done by setting the
security mode to Transport and then
setting the client credential type.
The credential type values correspond
to IIS directory security mechanisms.
The following code shows the mode
being set and the credential type set
to Windows. You can use this
configuration when both client and
server are on the same Windows domain.
C#
BasicHttpBinding b = new BasicHttpBinding();
b.Security.Mode = BasicHttpSecurityMode.Transport ;
b.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
Or, in configuration:
<bindings>
<basicHttpBinding>
<binding name="SecurityByTransport">
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
To enable ssl, without a login, set clientCredentialType to "None".
Options for security mode are:
None, Transport, Message, TransportWithMessageCredential and TransportCredentialOnly
You can find more details at: http://msdn.microsoft.com/en-us/library/system.servicemodel.basichttpsecuritymode.aspx
I just faced the same problem and found this MSDN article:
How to: Configure an IIS-hosted WCF service with SSL
At the end of the article you will find the xml configuration of the WebConfig file.
The solution worked just fine for me. One more thing to say, keep in mind that you need a REAL certificate for your release!
I think that if under your bindings where you have the <Security mode="Transport">, if you would change it to be <security mode="None">, you would be ok.
This is a copy of a code base that I'm working on and I tried that in-code, and it appears to be working.
I get the WSDL at least when I call the service, if that helps at all.
BasicHttpBinding basicBinding = new BasicHttpBinding();
if (RegistryConnectionStringFactory.UseSslForCommunications)
{
basicBinding.Security.Mode = BasicHttpSecurityMode.TransportWithMessageCredential;
basicBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
}
else
{
basicBinding.Security.Mode = BasicHttpSecurityMode.None;
basicBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
}