How do you pass user credentials from WebClient to a WCF REST service?

13,461

Since you are using 'Basic' authentication you need to send the username and password in the request header. The example of manually adding the credentials to the header is displayed below:

HttpWebRequest req = (HttpWebRequest)WebRequest.Create(@"https://localhost:6600/MyWCFService/GetData");
//Add a header to the request that contains the credentials
//DO NOT HARDCODE IN PRODUCTION!! Pull credentials real-time from database or other store.
string svcCredentials = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes("userName" + ":" + "password"));
req.Headers.Add("Authorization", "Basic " + svcCredentials);
//Parse the response and do something with it...
using (WebResponse svcResponse = (HttpWebResponse)req.GetResponse())
{
  using (StreamReader sr = new StreamReader(svcResponse.GetResponseStream()))
  {
    //Sample parses json response; your code here may be different
    JavaScriptSerializer js = new JavaScriptSerializer();
    string jsonTxt = sr.ReadToEnd();
  }
}
Share:
13,461
Admin
Author by

Admin

Updated on June 26, 2022

Comments

  • Admin
    Admin almost 2 years

    I am trying to expose a WCT REST service and only users with valid username and password would be able to access it. The username and password are stored in a SQL database.

    Here is the service contract:

    public interface IDataService
    {
        [OperationContract]
        [WebGet(ResponseFormat = WebMessageFormat.Json)]
        byte[] GetData(double startTime, double endTime);
    }
    

    Here is the WCF configuration:

    <bindings>
      <webHttpBinding>
        <binding name="SecureBinding">
          <security mode="Transport">
            <transport clientCredentialType="Basic"/>
          </security>
        </binding>
      </webHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="DataServiceBehavior">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceCredentials>
            <userNameAuthentication
               userNamePasswordValidationMode="Custom"
               customUserNamePasswordValidatorType=
                     "CustomValidator, WCFHost" />
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service behaviorConfiguration="DataServiceBehavior" name="DataService">
        <endpoint address="" binding="webHttpBinding"
                  bindingConfiguration="SecureBinding" contract="IDataService" />
      </service>
    </services>
    

    I am accessing the service via the WebClient class within a Silverlight application. However, I have not been able to figure out how to pass the user credentials to the service. I tried various values for client.Credentials but none of them seems to trigger the code in my custom validator. I am getting the following error: The underlying connection was closed: An unexpected error occurred on a send.

    Here is some sample code I have tried:

       WebClient client = new WebClient();
       client.Credentials = new NetworkCredential("name", "password", "domain");
       client.OpenReadCompleted += new OpenReadCompletedEventHandler(GetData);
       client.OpenReadAsync(new Uri(uriString));
    

    If I set the security mode to None, the whole thing works. I also tried other clientCredentialType values and none of them worked. I also self-hosted the WCF service to eliminate the issues related to IIS trying to authenticate a user before the service gets a chance.

    Any comment on what the underlying issues may be would be much appreciated. Thanks.

    Update: Thanks to Mehmet's excellent suggestions. Here is the tracing configuration I had:

     <system.diagnostics>
        <sources>
          <source name="System.ServiceModel"
                  switchValue="Information, ActivityTracing"
                  propagateActivity="true">
            <listeners>
              <add name="xml" />
            </listeners>
          </source>
          <source name="System.IdentityModel" switchValue="Information, 
                   ActivityTracing" propagateActivity="true">
            <listeners>
              <add name="xml" />
            </listeners>
          </source>
        </sources>
        <sharedListeners>
          <add name="xml"
               type="System.Diagnostics.XmlWriterTraceListener"
               initializeData="c:\Traces.svclog" />
        </sharedListeners>
      </system.diagnostics>
    

    But I did not see any message coming from my Silverlight client. As for https vs http, I used https as follows:

    string baseAddress = "https://localhost:6600/";
    _webServiceHost = new WebServiceHost(typeof(DataServices), 
                    new Uri(baseAddress));
    _webServiceHost.Open();
    

    However, I did not configure any SSL certificate. Is this the problem?

  • Mahmoud Farahat
    Mahmoud Farahat about 11 years
    how can i implement this with NTLM authentication ?
  • atconway
    atconway about 11 years
    Look at this: allen-conway-dotnet.blogspot.com/2010/01/… or this msdn.microsoft.com/en-us/library/ff648505.aspx for examples on doing Windows Style authentication with WCF.