Home > Uncategorized > Consuming Web Services with SSL and HTTP Basic

Consuming Web Services with SSL and HTTP Basic

 

Consuming WebServices with SSL And HTTP BASIC Authentication

by Peter A. Bromberg, Ph.D.

 

    Peter Bromberg

 

I have to admit that I thought this one was going to be easy, and it ended up taking several frustrating hours to get it all “right”, mostly due to a lack of quality documentation on the subject, and secondarily because of some seemingly logical assumptions that any developer would make, which turned out to be false, as we will soon see.

Accepting Server SSL Certificates Gracefully

 

First, let’s deal with the SSL issue. This is not particularly odd, many vendors run their webservices under Apache with modSSL while requiring HTTP BASIC authentication “under the hood”, and the .NET Framework does not provide an easy – to – use, out of the box way to accept Server Certificates on a normal WebService proxy method call.

Ads by Google

Vacation Certificates     Free guide filled with ideas on growing your business.     www.SunrisePremiums.net

Ssl Certificate Authority     Get the strongest SSL from VeriSign Protect Important Data – Learn More     www.VeriSign.com

SSL Certificates – thawte     Choose from a complete range of certificates with the strongest SSL     www.thawte.com

SOAP Test Client     Send and Recieve SOAP Messages Test your Web Services Today!     www.IntegrationCentral.com

SSL Certificates $27.95     Simple low priced SSL 24/7 Live Customer Support     www.skysoftinc.com

 

The trick to the SSL issue is that we must override the default System.Net.ServicePointManager’s CertificatePolicy, which underlies every SOAP call, with a custom class derived from ICertificatePolicy. Essentially what this class will do when it’s revised boolean CheckValidationResult is automatically called, is return true (accept any Server Certificate) regardless of whether or what errors may exist. The class I present here (which can be found on MSDN) also allows to return a problem message based on a standardized enumeration:

 

//SSL Certificate code

public enum CertificateProblem : long

{

CertEXPIRED = 0x800B0101,

CertVALIDITYPERIODNESTING = 0x800B0102,

CertROLE = 0x800B0103,

CertPATHLENCONST = 0x800B0104,

CertCRITICAL = 0x800B0105,

CertPURPOSE = 0x800B0106,

CertISSUERCHAINING = 0x800B0107,

CertMALFORMED = 0x800B0108,

CertUNTRUSTEDROOT = 0x800B0109,

CertCHAINING = 0x800B010A,

CertREVOKED = 0x800B010C,

CertUNTRUSTEDTESTROOT = 0x800B010D,

CertREVOCATION_FAILURE = 0x800B010E,

CertCN_NO_MATCH = 0x800B010F,

CertWRONG_USAGE = 0x800B0110,

CertUNTRUSTEDCA = 0x800B0112

}

 

public class TrustAllCertificatePolicy : ICertificatePolicy

{

// Default policy for certificate validation.

public static bool DefaultValidate = false; // set to true for testing

 

public bool CheckValidationResult(ServicePoint sp, X509Certificate cert,

WebRequest request, int problem)

{

bool ValidationResult=false;

Console.WriteLine(“Certificate Problem with accessing ” +

request.RequestUri);

// Console.Write(“Problem code 0x{0:X8},”,(int)problem);

//Syslog send-

Sender.Send( GetProblemMessage((CertificateProblem)problem));

 

ValidationResult = DefaultValidate;

return ValidationResult;

}

 

private String GetProblemMessage(CertificateProblem Problem)

{

String ProblemMessage = “”;

CertificateProblem problemList = new CertificateProblem();

String ProblemCodeName = Enum.GetName(problemList.GetType(),Problem);

if(ProblemCodeName != null)

ProblemMessage = ProblemMessage + “-Certificateproblem:” +

ProblemCodeName;

else

ProblemMessage = “Unknown Certificate Problem”;

return ProblemMessage;

}

}

 

You can place this class in the same namespace as your WebService proxy WSDL – generated code, and that makes it easier. To use it, you would use the following sample code:

 

MyWebServiceProxy myWebServiceProxy = new MyWebServiceProxy();

// set a default CertificatePolicy that accepts ALL Server certificates�.

System.Net.ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();

myWebServiceProxy.MyMethod(myparam1,myparam2) ;

 

Everything else with the WebService call over SSL is a no-brainer. Provided that the Url Property has “https://” at the beginning, it will automatically negotiate transmission over the default port of 443.

Negotiating HTTP BASIC “true” Pre-Authentication

 

That takes care of the SSL issue. Now let’s deal with the HTTP BASIC issue:

 

The “Gotcha” for the average developer is that the WebService Proxy class has UserName, Password, etc. properties and this leads us to believe we can simply set these properties and get “Authentication”. It also sports a PreAuthenticate property that fills in the puzzle. Unfortunately, it’s just not that simple.

 

HTTP Webservers support multiple authentication options. On Windows, IIS supports Basic, NTLM, Digest, and Negotiate (a.k.a. Integrated Windows Authentication). Of these, Basic & Kerberos both support “PreAuthentication”.

 

However, “PreAuthentication” is often misunderstood to mean “Send the credentials on the very first request”. That is not true. For Preauthenticate to work, the following must occur:

 

1) You make a webrequest to a server (a SOAP Call). You may or may not have specified credentials on the first request.

 

2) The server, which is configured for BASIC auth, wants to authenticate the request you are making, so it replies with a 401.

 

3) The client does the authentication handshake with the server, and sends your credential (a Base64 encoded string consisting basically of “username:password”).

 

4) If “Basic” was chosen as the authentication scheme by the client, then Pre-Authentication is enabled for this request. So, every subsequent request from now on to the same Uri-Prefix will result in the credentials being sent without any challenge required.

 

The main point to note here is that there must be at least one request before the client can expect pre-authentication. Credentials are not automatically sent on the first request just because PreAuthenticate is set to true. I figure that if this was a wakeup call for me (which it was) , then I am probably far from alone!

 

To force credentials to be sent on the first request (and thus avoid the first authenticate handshake), you can set credentials manually on the request:

 

MyWebServiceProxy myWebServiceProxy = new MyWebServiceProxy();

myWebServiceProxy.Url =this.endpointUrl; //items from your appConfig

NetworkCredential netCredential = new NetworkCredential(this.endpointUserName,this.endpointPassword );

Uri uri = new Uri(this.endpointUrl);

ICredentials credentials = netCredential.GetCredential(uri, “Basic”);

myWebServiceProxy.Credentials = credentials;

// Be sure to set PreAuthenticate to true or else authentication will not be sent.

mMyWebServiceProxy.PreAuthenticate = true;

 

What this does is set the authorization header on the request, and send it on the first request itself. If the credentials are correct, the first handshake will not occur. However, remember that unless you have set Preauthenticate to true, you have to use this code to set the authorization header on every request. This is because you have bypassed the authentication handshake, and the SOAP HttpWebRequest has no knowledge that the server requires authentication. So it won’t do pre-authentication by itself anymore.

 

The recommended way to get preauthentication is to set the credentials on the request, set PreAuthenticate=true, and send the request. Once the first authentication handshake happens, and credentials are accepted by the server, preauthentication will happen behind the scenes for every request to the same Uri-Prefix.

 

Now here is a final block of sample code that combines both the HTTP BASIC with PreAuthenticate along with the SSL “Accept all certificates” code that (at least for me) got me onto first base:

 

MyWebServiceProxy myWebServiceProxy = new MyWebServiceProxy();

// set a default CertificatePolicy that accepts ALL Server certificates

System.Net.ServicePointManager.CertificatePolicy =

new TrustAllCertificatePolicy();

 

myWebServiceProxy.Url =this.endpointUrl; //items from your appConfig

NetworkCredential netCredential = new NetworkCredential(this.endpointUserName,this.endpointPassword );

Uri uri = new Uri(this.endpointUrl);

ICredentials credentials = netCredential.GetCredential(uri, “Basic”);

myWebServiceProxy.Credentials = credentials;

// Be sure to set PreAuthenticate to true or else authentication will not be sent.

myWebServiceProxy.PreAuthenticate = true;

myWebServiceProxy.MyMethod(myparam1,myparam2) ;

 

Good Luck!

Advertisements
Categories: Uncategorized
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: