Can not call web service with basic authentication using WCF
Asked Answered
N

3

17

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.

Ninny answered 1/9, 2009 at 23:32 Comment(0)
L
29

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

Lick answered 2/9, 2009 at 5:5 Comment(7)
Marc, Can you show me how to code and config if it is REST based Java service ?Neurotomy
The property ClientCredentials is not at all appearing for me after I typed proxy.Neurotomy
@rajibdotnet: well, the code in the question is basically what you need to call a REST-based service.... if that's not helping: please ask your own question so folks can answer ...Lick
@Lick what would be the equivalent of this in java ... I've also been given a sample web-service client that uses this cand of authentication ... and I need to convert it in JavaJeanette
@Sergiu: sorry, I don't know Java enough to convert this for youLick
What to give at place of "MyService" in "ChannelFactory<MyService>".Kinross
It is giving me "The type argument passed to the generic ChannelFactory class must be an interface type." when i use it for Barcode web service for swiss post api "BarcodeWebService"Kinross
G
8

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();
                }
            }
Groundless answered 16/10, 2013 at 15:22 Comment(1)
I don't get how the credentialBehavior is being applied to the Channel? It looks like you just Find<> the client credentials and apply it to a new Var credentialBehavior. You then set the username and password of that variable... If I am not mistaken, that doesn't have anything to do with the bindings orSinglefoot
S
3

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.

Sile answered 6/5, 2010 at 21:6 Comment(1)
I get "unrecognized attribute 'algorithmSuite' and it does not work for me. Visual Studio 2017 on Windows 10 client side, server side unknown.Hardbitten

© 2022 - 2024 — McMap. All rights reserved.