Wednesday, August 29, 2007

4349.aspx

Real PreAuthenticate for .NET Web Services

.NET Web Service clients do not send authentication details with the requests so you get a traffic pattern like this


Request 1:



Client: GET someUrl
Server: 401 WWW-Authenticate Basic
Client: GET with Authorization header
Server: 200 OK


Request 2:



Client: GET someUrl
Server: 401 WWW-Authenticate Basic
Client: GET with Authorization header
Server: 200 OK


The PreAuthenticate property improves the situation if you make many repeated calls to a web service.


Request 1:



Client: GET someUrl
Server: 401 WWW-Authenticate Basic
Client: GET with Authorization header
Server: 200 OK


Request 2:



Client: GET someUrl with Authorization header
Server: 200 OK


The first request does not contain the Authorization header but the subsequent requests do. I do not like this feature as the systems I work on usually make one single web service request per client request so I always get 401 errors.


You can fix the problem by manually inserting the Authorization header in the requests. Do not modify the Web Service client generated by Visual Studio as you will loose your changes if you update the Web Reference.  Extend the Web Service client instead and override the GetWebRequest method:


public class WSTestPreAuthenticate : WSTest


{


    protected override System.Net.WebRequest GetWebRequest(Uri uri)


    {


        HttpWebRequest request;


        request = (HttpWebRequest)base.GetWebRequest(uri);


 


        if (PreAuthenticate)


        {


            NetworkCredential networkCredentials =


                Credentials.GetCredential(uri, "Basic");


 


 


            if (networkCredentials != null)


            {


                byte[] credentialBuffer = new UTF8Encoding().GetBytes(


                    networkCredentials.UserName + ":" +


                    networkCredentials.Password);


                request.Headers["Authorization"] = "Basic " + Convert.ToBase64String(credentialBuffer);


            }


        }


        return request;


    }


}



The change above means that PreAuthentication works as it should since it always sends the Authorization header


Request 1:



Client: GET someUrl with Authorization header
Server: 200 OK


The client has to set the PreAuthenticate header and any custom credentials:


WSTestPreAuthenticate test = new WSTestPreAuthenticate ();


test.PreAuthenticate = true;


test.Url = "http://localhost/WSTest/WSTest.asmx";


test.Credentials =


new System.Net.NetworkCredential("user", "password");


int ret = test.Method("test");

No comments:

Post a Comment