views:

1882

answers:

5

I'm trying to use HTTPWebRequest to access a REST service, and am having problems passing credentials in, see code below. I've read that NetworkCredential doesn't support SSL, and I'm hitting an https site. Does anyone know of a class similar to NetworkCredential that does support SSL?

    Uri requestUri = null;
    Uri.TryCreate("https://mywebserver/webpage"), 
        UriKind.Absolute, out requestUri);

    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create
        (requestUri);

    NetworkCredential nc =
        new NetworkCredential("user", "password");

    request.Credentials = nc;

    request.Method = WebRequestMethods.Http.Get;
    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
+2  A: 

If your server uses NTLM authentication you may try this:

CredentialCache cc = new CredentialCache();
cc.Add(
    new Uri("https://mywebserver/webpage"), 
    "NTLM", 
    new NetworkCredential("user", "password"));
request.Credentials = cc;
Darin Dimitrov
This worked for me, thanks.
Mark Allen
A: 

Try setting request.PreAuthenticate to true.

David
+4  A: 

What kind of authentication mechanism is protecting the web service? The credentials set on HttpWebRequest will only be passed through HTTP's Authorization header via Basic, Digest or NTLM. So, if your web service is protected with WS-Security, the NetworkCredentials will probably not be passed on to the authentication scheme at all, because WS-Security doesn't operate at the HTTP level.

What you should do is create a Web Service client proxy for the web service through the command line tool wsdl.exe or something similar. That will give you access to Web Service aware authentication schemes.

Update after comments:

It seems like HttpWebRequest needs to receive the WWW-Authenticate challenge with a 401 Unauthorized before it can authenticate properly over SSL. I guess there's two separate code paths in HttpWebRequests handling regular HTTP traffic and encrypted HTTPS traffic. Anyway, what you should try, is:

  1. Execute an unauthenticated HttpWebRequest to the https://.../ URI.
  2. Receive the 401 Unauthorized response.
  3. Execute the same request, now with both Credentials set (not sure if PreAuthenticate should be true or false; test both).
  4. You should now get 200 OK or whatever it is your Web Service responds with.

Another option is to build the Authorization header yourself on the initial request:

string credentials = String.Format("{0}:{1}", username, password);
byte[] bytes = Encoding.ASCII.GetBytes(credentials);
string base64 = Convert.ToBase64String(bytes);
string authorization = String.Concat("basic ", base64);
request.Headers.Add("Authorization", authorization);
asbjornu
Sorry, I didn't realize until now that it is a REST Service I'm calling, so there is now wsdl file. Also, I'm able to walk the code in the debugger, and I can see it build up the NetworkCredentials object properly, but it just doesn't seem to be getting passed in with the HttpWebRequest. One more thing - I can successully call the REST service by typing it in to my browser address bar, so it must be using my credentials that way.
Russ Clark
You haven't written what authentication scheme you're using and where you have your credentials from. Plus, if this is a REST service, it shouldn't have a WSDL file. A Web Service with a WSDL file is usually a SOAP Web Service which is the direct opposite of a REST Web Service.Being able to access the Web Service with a browser (without typing in any credentials?) sounds like it's protected with HTTP authentication, possibly NTLM. Is this true?
asbjornu
Also, what is the response you get? Is it a `401 Unauthorized`, `403 Forbidden` or something else?
asbjornu
It's an https site, so the authentication mechanism is SSL - the MSDN online documentation for the NetworkCredential class says it doesn't suport SSL, so I'm thinking that is the problem. The error I'm getting back is 401 Unauthorized.
Russ Clark
SSL is not an authentication mechanism, it's a cryptographic protocol that provide end-to-end security between the browser and the server. Authentication is orthogonal to SSL and can be done in a number of ways regardless of whether you use SSL or not.Do you need to enter a username and password when visiting this web service in a browser?
asbjornu
Thanks for the clarification, I'm clearly not an expert at this. I've found out that we are using Basic authentication. The message I get back when I try to use the NetworkCredential class directly is 401 Unauthorized. If I try to create a CredentialCache object and add the NetworkCredential object to that, then assign it to the HttpWebRequest.Credentials, then I get a 403 Forbidden error message. If I hit the service directly in the browser I'm not prompted for credentials, it just works, so I assume the browser is passing my credentials in for me.
Russ Clark
Are your credentials cached in the browser? Which browser are you using? I'm only familiar with one authentication scheme that doesn't actually challenge the user for the credentials like you explain, and that's NTLM, because it can use pre authentication invisibly by sending your Windows credentials to the server. I believe Internet Explorer does this automatically, for instance.
asbjornu
+2  A: 

See if it shows up when you use the old-fashioned method:

string credentials = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes("user"+ ":" + "password"));
request.Headers.Add("Authorization", "Basic " + credentials);
ebpower
this just worked for me.
ryancammer
A: 

Try and create a tracelog for your application. See http://ferozedaud.blogspot.com/2009/08/tracing-with-systemnet.html

The credentials wont be sent unless the server asks for it. The server asks for it by replying to your request with a 401 status code, and sending a WWW-Authenticate header that contains the authentication schemes supported.

Also, you may be able to force the app to send credentials in the first request itself, by setting PreAuthenticate=true.

feroze
@feroze, I don't understand, does this mean that the NetworkCredential class does support SSL and can be used to access an https site? I've tried using PreAuthenticate = true, but that doesn't help. What will a tracelog provide me?
Russ Clark
NetworkCredential is just a holder class for credentials. Creds can be sent for both HTTP as well as HTTP requests, if the server needs them, or if the request forces that by "Preauthenticate = true". However, note that even preauthentication does not guarantee that creds will always be sent on the first request. For eg, some challenge hanshake auth protocols like NTLM/Digest/Kerberos can only work if the server first sends the challenge, and client cannot preauthenticate unless it has done atleast one successful auth with the server.Tracelog will show what is happening.
feroze