Export (0) Print
Expand All

How to: Specify Client Credentials for a Data Service Request (WCF Data Services/Silverlight)

You can specify the credentials that are used when making a request to a data service that implements the Open Data Protocol (OData). To do this, you must be making a cross-domain request, be running out of the browser, or you must explicitly set the value of the HttpStack property to ClientHttp. In these cases, the default credentials from the credential cache are used. You can also supply non-default credentials by setting the UseDefaultCredentials property to false and supplying a NetworkCredential for the Credentials property of the DataServiceContext. The example in this topic shows how to explicitly provide credentials that are used by the Silverlight client when requesting data from the data service.

The Northwind sample data service accessed by the application is created when you complete the procedures in the topic How to: Create the Northwind Data Service (WCF Data Services/Silverlight). You can also use the Northwind sample data service that is published on the OData Web site; this sample data service is read-only and attempting to save changes returns an error. The sample data services on the OData Web site allow anonymous authentication.

The following example is from the code-behind page for an Extensible Application Markup Language (XAML) file that is the main page of the Silverlight application. This example displays a LoginWindow instance to collect authentication credentials from the user, and then uses these non-default credentials when making a request to the data service by using the Silverlight client HTTP implementation.


using System;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using ClientCredentials.Northwind;
using System.Data.Services.Client;

namespace ClientCredentials
{
    public partial class MainPage : UserControl
    {
        // Create the binding collections and the data service context.
        private DataServiceCollection<Customer> binding;
        NorthwindEntities context;
        CollectionViewSource customerAddressViewSource;

        // Instantiate the service URI and credentials.
        Uri serviceUri = new Uri("http://localhost:12345/Northwind.svc/");
        NetworkCredential credentials = new NetworkCredential();

        public MainPage()
        {
            InitializeComponent();
        }

        private void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            // Get credentials for authentication.
            LoginWindow login = new LoginWindow();
            login.Closed += new EventHandler(loginWindow_Closed);
            login.Show();
        }

        private void loginWindow_Closed(object sender, EventArgs e)
        {
            string userName = string.Empty;
            string domain = string.Empty;
            string password = string.Empty;

            // Get back the LoginWindow instance.
            LoginWindow login = (LoginWindow)sender;

            if (login.DialogResult == true && login.userNameBox.Text != string.Empty)
            {
                // Instantiate the binding collection.
                binding = new DataServiceCollection<Customer>();

                // Instantiate the context.
                context =
                    new NorthwindEntities(serviceUri);

                // Register the LoadCompleted event for the binding collection.
                binding.LoadCompleted += new EventHandler<LoadCompletedEventArgs>(binding_LoadCompleted);

                // Define an anonymous LINQ query that returns a collection of Customer types.
                var query = from c in context.Customers
                            where c.Country == "Germany"
                            select c;


                // Get the user name and domain from the login.
                string[] qualifiedUserName = login.userNameBox.Text.Split(new char[] {'\\'});
                if (qualifiedUserName.Length == 2)
                {
                    domain = qualifiedUserName[0];
                    userName = qualifiedUserName[1];
                }
                else
                {
                    userName = login.userNameBox.Text;
                }
                password = login.passwordBox.Password;

                // Select the client HTTP stack and set the credentials.
                context.HttpStack = HttpStack.ClientHttp;
                context.UseDefaultCredentials = false;
                context.Credentials = 
                    new NetworkCredential(userName, password, domain);

                try
                {
                    // Execute the query asynchronously.
                    binding.LoadAsync(query);
                }
                catch (Exception ex)
                {
                    ChildWindow cw = new ChildWindow();
                    cw.Content = ex.Message;
                    cw.Show();
                }
            }
            else if (login.DialogResult == false)
            {
                ChildWindow cw = new ChildWindow();
                cw.Content = "Login cancelled.";
                cw.Show();
            }
        }

        private void binding_LoadCompleted(object sender, LoadCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                serviceUriLabel.Content = serviceUri.ToString();

                // Load all pages of Customers before binding.
                if (binding.Continuation != null)
                {
                    binding.LoadNextPartialSetAsync();
                }
                else
                {
                    // Load your data here and assign the result to the CollectionViewSource.
                    customerAddressViewSource =
                        (CollectionViewSource)this.Resources["customerViewSource"];
                    customerAddressViewSource.Source = binding;
                }
            }
            else
            {
                // Display the error message from the data service.
                ChildWindow cw = new ChildWindow();
                cw.Content = e.Error.Message;
                cw.Show();
            }
        }
    }
}


The following XAML defines the main page of the Silverlight application.


    <UserControl x:Class="ClientCredentials.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="312" d:DesignWidth="577" 
             xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" 
             xmlns:my="clr-namespace:ClientCredentials" Loaded="MainPage_Loaded">
    <UserControl.Resources>
        <CollectionViewSource x:Key="customerViewSource" 
                              d:DesignSource="{d:DesignInstance my:Northwind.Customer, CreateList=True}" />
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White" DataContext="" Height="312" Width="577"
          VerticalAlignment="Top" HorizontalAlignment="Left">
        <Grid.RowDefinitions>
            <RowDefinition Height="203*" />
            <RowDefinition Height="119*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="336*" />
        </Grid.ColumnDefinitions>
        <sdk:DataGrid AutoGenerateColumns="False" Height="213" HorizontalAlignment="Left" 
                      ItemsSource="{Binding Source={StaticResource customerViewSource}}" 
                      Name="customerDataGrid" RowDetailsVisibilityMode="VisibleWhenSelected" 
                      VerticalAlignment="Top" Width="553" Margin="12,44,0,0" 
                      Grid.RowSpan="2" Grid.ColumnSpan="1">
            <sdk:DataGrid.Columns>
                <sdk:DataGridTextColumn x:Name="customerIDColumn" Binding="{Binding Path=CustomerID}" 
                                        Header="Customer" Width="80" />
                <sdk:DataGridTextColumn x:Name="addressColumn" Binding="{Binding Path=Address}" 
                                        Header="Address" Width="180" />
                <sdk:DataGridTextColumn x:Name="cityColumn" Binding="{Binding Path=City}" 
                                        Header="City" Width="120" />
                <sdk:DataGridTextColumn x:Name="countryColumn" Binding="{Binding Path=Country}" 
                                        Header="Country" Width="80" />
                <sdk:DataGridTextColumn x:Name="postalCodeColumn" Binding="{Binding Path=PostalCode}" 
                                        Header="Postal Code" Width="90" />
                <sdk:DataGridTextColumn Binding="{Binding Path=CompanyName}" Header="CompanyName" />
                <sdk:DataGridTextColumn Binding="{Binding Path=ContactName}" Header="ContactName" />
                <sdk:DataGridTextColumn Binding="{Binding Path=Phone}" Header="Phone" />
            </sdk:DataGrid.Columns>
        </sdk:DataGrid>
        <sdk:Label Grid.Row="0" Grid.Column="0" Height="26" HorizontalAlignment="Left" Margin="16,12,0,0" 
                   Name="serviceUriLabel" VerticalAlignment="Top" Width="550"  />
    </Grid>
</UserControl>


The following example is from the code-behind page for the ChildWindow that is used to collect the authentication credentials from the user before making a request to the data service.


using System;
using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;

namespace ClientCredentials
{
    public partial class LoginWindow : ChildWindow
    {
        public LoginWindow()
        {
            InitializeComponent();
        }

        private void OKButton_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = true;
        }

        private void CancelButton_Click(object sender, RoutedEventArgs e)
        {
             this.DialogResult = false;
        }

        private void LoginWindow_Closing(object sender, CancelEventArgs e)
        {
            if (this.DialogResult == true &&
                    (this.userNameBox.Text == string.Empty || this.passwordBox.Password == string.Empty))
            {
                e.Cancel = true;
                ChildWindow cw = new ChildWindow();
                cw.Content = "Please enter name and password or click Cancel.";
                cw.Show();
            }
        }

    }
}


The following XAML defines the login window that is a ChildWindow of the Silverlight application.


    <controls:ChildWindow x:Class="ClientCredentials.LoginWindow"
           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
           xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
           Width="400" Height="200" 
           Title="LoginWindow" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" Closing="LoginWindow_Closing">
    <StackPanel Name="LayoutRoot" Orientation="Vertical" VerticalAlignment="Top">
        <StackPanel Orientation="Horizontal">
            <TextBlock Height="25" HorizontalAlignment="Left" Margin="10,20,0,0" Name="userNameLabel" VerticalAlignment="Top" 
                       Width="80" Text="User name:"/>
            <TextBox Height="23" HorizontalAlignment="Left" Margin="10,20,0,0"  Name="userNameBox" VerticalAlignment="Top" 
                     Width="150" Text="DOMAIN\login"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal" VerticalAlignment="Top">
            <TextBlock Height="25" HorizontalAlignment="Left" Margin="10,20,0,0" Name="pwdLabel" Width="80" Text="Password:"/>
            <PasswordBox Height="23" HorizontalAlignment="Left" Margin="10,20,0,0" Name="passwordBox" Width="150" />
        </StackPanel>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Height="80" VerticalAlignment="Top">
            <Button x:Name="CancelButton" Content="Cancel" Click="CancelButton_Click" Width="75" Height="23" 
                HorizontalAlignment="Right" Margin="8" />
            <Button x:Name="OKButton" Content="OK" Click="OKButton_Click" Width="75" Height="23" 
                HorizontalAlignment="Right" Margin="8" />
        </StackPanel>
    </StackPanel>
</controls:ChildWindow>


The following security considerations apply to the example in this topic:

  • To verify that the credentials supplied in this sample work, the Northwind data service must use an authentication scheme other than anonymous access. Otherwise, the Web site hosting the data service will not request credentials.

  • User credentials should only be requested during execution and should not be cached. Credentials must always be stored securely.

  • Data sent with Basic and Digest Authentication is not encrypted, so the data can be seen by an adversary. Additionally, Basic Authentication credentials (user name and password) are sent in cleartext and can be intercepted.

Community Additions

ADD
Show:
© 2014 Microsoft