Hi Patrick,
The reason you are not seeing the credentials passed on the
inital request to the web server is because Microsoft is following
section 2 of RFC 2617(
http://www.faqs.org/rfcs/rfc2617.html)
Here’s the main benefit of using pre-authenticate. Suppose I’m going to
make 50
requests to <http://server/path/> and this URL is protected with Basic
authentication. On the first request, the client gets challenged by the
server and
sends back a second request which contains information that the server
accepts
(assuming auth succeeds) so it can send back the requested resource.
With the pre-authenticate property set to true:
The remaining 49 requests will include the authorization information in the
first
request they send to the server so the server will not challenge the client
and
force it to do another round trip before getting the resource.
The total number of roundtrips between client and server will be 51.
With the pre-authenticate property set to false:
The remaining 49 requests will not include the authorization information in
the
first request and will therefore be challenged by the server on each first
request
and will only get the desired resource after sending the authorization
header in
the second request.
The total number of roundtrips between client and server will be 100.
In other words, pre-authenticate=true is one request shy of taking half the
time of
pre-authenticate=false. Note that pre-authentication only works for Digest
and
Basic in v1.0. It can’t work for NTLM because it is connection-based
however the
fact that it is connection based means that you’ll only get challenged once
per
connection so it isn’t an issue if you are caching connections. In the
Whidbey
release of the .NET Framework we’ll also support pre-authentication for
Kerberos.
In order to get the inital request to send credentials, you will need to
use the
workaround of overriding the GetWebRequest method in the proxy code.
(Hack code obtained from the Internet)
The PreAuthenticate property on .NET's
System.Web.Services.Protocols.SoapHttpClientProtoc ol is supposed to force
the SOAP
client proxy to send credentials with the first request, rather than doing
the
challenge/response exchange. If you add the following code to your SOAP
Client
proxy, you can make PreAuthenticate work (this example is for basic
authentication):
protected override System.Net.WebRequest
GetWebRequest(Uri uri) {
System.Net.HttpWebRequest request =
(System.Net.HttpWebRequest)base.GetWebRequest(uri) ;
if (this.PreAuthenticate) {
System.Net.NetworkCredential nc =
this.Credentials.GetCredential(uri,"Basic");
if (nc != null) {
byte[] credBuf =
new System.Text.UTF8Encoding().
GetBytes(nc.UserName + ":" + nc.Password);
request.Headers["Authorization"] =
"Basic " + Convert.ToBase64String(credBuf);
}
}
return request;
}
This work around modifies the web service proxy class which is
automatically generated. This means every time someone updates a "web
reference" in
Dev Studio, they would need to reinsert the "hack" code.
Let me know if you have any questions or conerns.
Regards,
Peter Huang
Microsoft Online Partner Support
Get Secure!
www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
--------------------[color=blue]
>From: "Patrick Fogarty" <padraig_fogarty@spam.hotmail.no.com>
>Subject: Authentication not working on HTTP-POST using NetworkCredential
>Date: Mon, 25 Aug 2003 13:49:49 -0400
>Lines: 82
>X-Priority: 3
>X-MSMail-Priority: Normal
>X-Newsreader: Microsoft Outlook Express 6.00.2800.1158
>X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1165
>Message-ID: <evY7KFzaDHA.1272@TK2MSFTNGP12.phx.gbl>
>Newsgroups:[/color]
microsoft.public.dotnet.framework.aspnet.webservic es,microsoft.public.dotnet
framework.webservices,microsoft.public.dotnet.gene ral[color=blue]
>NNTP-Posting-Host: ool-182e5a0b.dyn.optonline.net 24.46.90.11
>Path: cpmsftngxa06.phx.gbl!TK2MSFTNGP08.phx.gbl!TK2MSFTN GP12.phx.gbl
>Xref: cpmsftngxa06.phx.gbl[/color]
microsoft.public.dotnet.framework.webservices:1297
microsoft.public.dotnet.general:105997
microsoft.public.dotnet.framework.aspnet.webservic es:19007[color=blue]
>X-Tomcat-NG: microsoft.public.dotnet.general
>
>
>I am programming what is to be a web service client that will use an
>HTTP-POST to request and retrieve data. The remote server (written in java
>for what it's worth) requires basic authentication as per RFC 2617
>(
http://www.faqs.org/rfcs/rfc2617.html). My attempts to authenticate are
>failing. The server requires the header to be present with the request.
>For security reasons, it will not reply in any way if the header is not
>present.
>
>More specifically, my attempts fail when attempting to attach a
>'NetworkCredential' object to the 'Credentials' property of a
>'HttpWebRequest' object. If I create the header manually, everything works
>fine. When attempting to do it 'the Microsoft Way' no authentication
>information is sent in the header, even if I set 'PreAuthenticate' = true.
>
>What am I missing? Below are two examples. Each has the code to send the
>request followed by the captured request header.
>
>
>- Patrick
>
>------------------------------------------------------------
><< the code that fails >>
>
>(( assume reqBytes and SomeURI already set ))
>
>request = (HttpWebRequest) WebRequest.Create(SomeURI);
>
>request.PreAuthenticate = true;
>request.Credentials = new NetworkCredential("JoeBlow","MountainHo");
>
>request.Timeout = 20 * 1000;
>request.Method = "POST";
>request.ContentType = "application/x-www-form-urlencoded";
>request.ContentLength = reqBytes.Length;
>
>Stream reqStream = request
>reqStream.Write(reqBytes,0,reqBytes.Length);
>reqStream.Close();
>
>------------------------------
>POST / HTTP/1.1
>Content-Type: application/x-www-form-urlencoded
>Content-Length: 1718
>Expect: 100-continue
>Connection: Keep-Alive
>Host: me:10000
>
>
>
>------------------------------------------------------------
><< the code that works>>
>
>(( assume reqBytes and SomeURI already set ))
>
>request = (HttpWebRequest) WebRequest.Create(SomeURI);
>
>// 'GetManualAuthorization' written by me to generate RFC2617-compliant
>basic authentication header
>request.Headers.Add("Authorization", GetManualAuthorization("JoeBlow",
>"MountainHo"));
>
>
>request.Timeout = 20 * 1000;
>request.Method = "POST";
>request.ContentType = "application/x-www-form-urlencoded";
>request.ContentLength = reqBytes.Length;
>
>Stream reqStream = request
>reqStream.Write(reqBytes,0,reqBytes.Length);
>reqStream.Close();
>
>------------------------------
>POST / HTTP/1.1
>Authorization: BASIC Sm9lQmxvdzpNb3VudGFpbkhv
>Content-Type: application/x-www-form-urlencoded
>Content-Length: 1718
>Expect: 100-continue
>Connection: Keep-Alive
>Host: me:10000
>
>
>[/color]