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.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Rex Morgan
  • 2,979
  • 2
  • 21
  • 32

3 Answers3

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

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • Marc, Can you show me how to code and config if it is REST based Java service ? – rajibdotnet Dec 04 '12 at 15:19
  • 3
    The property ClientCredentials is not at all appearing for me after I typed proxy. – rajibdotnet Dec 04 '12 at 15:29
  • 1
    @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 ... – marc_s Dec 04 '12 at 15:32
  • @marc_s 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 Java – Sergiu Sep 21 '13 at 15:10
  • @Sergiu: sorry, I don't know Java enough to convert this for you – marc_s Sep 21 '13 at 15:11
  • What to give at place of "MyService" in "ChannelFactory". – Mayur Patel Jun 28 '16 at 14:43
  • 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" – Mayur Patel Jun 28 '16 at 14:45
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();
                }
            }
jaxxbo
  • 7,314
  • 4
  • 35
  • 48
  • 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 or – SoftwareSavant Jun 25 '15 at 19:39
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.

Ethan J. Brown
  • 2,308
  • 3
  • 20
  • 27
  • I get "unrecognized attribute 'algorithmSuite' and it does not work for me. Visual Studio 2017 on Windows 10 client side, server side unknown. – gridtrak Dec 09 '18 at 14:10