Protecting WCF Service Over Internet : Authenticating and Authorizing Users by Using the ASP.NET Membership Provider and Role Provider

Table of Contents

  • WCF Security – Basics
  • Background
  • Configure IIS Bindings to Support SSL
  • Create ProductsService Web Application
  • Create an ASP.NET Web Site to Host the WCF Service
  • Define Users and Roles for the WCF Service
  • Sample Code for WCF Service
  • Configure the Activation and Binding for the WCF Service
  • Modify the WCF Client Application to Connect to the Updated WCF Service
  • Test the WCF Service
  • Summary
  • References

WCF Security – Basics

WCF security is divided into three functional areas: transfer security, access control, and auditing.

Transfer Security

Transfer security encompasses three major security functions: integrity, confidentiality, and authentication. Integrity is the ability to detect whether a message has been tampered with. Confidentiality is the ability to keep a message unreadable by anyone other than the intended recipient; this is achieved through cryptography. Authentication is the ability to verify a claimed identity.

Together, these three functions help to ensure that messages securely arrive from one point to another.

Two main mechanisms are used to implement transfer security in WCF: transport security mode and message security mode.

1. Transport security mode uses a transport-level protocol, such as HTTPS, to achieve transfer security. It has the disadvantage of securing messages only from point-to-point.

2. Message security mode uses WS-Security (and other specifications) to implement transfer security. Because the message security is applied directly to the SOAP messages and is contained inside the SOAP envelopes, together with the application data, it has the advantage of being transport protocol-independent, more extensible, and ensuring end-to-end security (versus point-to-point); it has the disadvantage of being several times slower than transport security mode because it has to deal with the XML nature of the SOAP messages.

3. TransportWithMessageCredential message security is used to authenticate the client and transport security is used to authenticate the server and provide message confidentiality and integrity.

Access Control

Access control is also known as authorization. Authorization allows different users to have different privileges to view data.

In WCF, access control features are provided through integration with the common language runtime (CLR) PrincipalPermissionAttribute and through a set of APIs known as the identity model.

Auditing

Auditing is the logging of security events to the Windows event log. You can log security-related events, such as authentication failures or successes.

For more information, click here

Background

When you start connecting client applications and services across a public network such as the Internet, you can no longer make any guarantee that client applications are always genuine.

Few questions comes in mind:

How does a client application verify that the service to which it is sending messages is the real service and not?

How does a service distinguish genuine requests sent by an authenticated client application from those generated by an attacker?

Maintaining information about the users who can legitimately access a service and their credentials typically requires some form of database.

In a Windows environment, Active Directory provides such a database. A WCF service can use Windows Integrated Security to help authenticate users who are part of the same Windows domain as the service. When client applications connect to the service across the Internet, this approach is not always feasible; a client application will probably not be running using the same security domain as the service or it might not even be a Windows application.

You can use several alternative approaches for maintaining a list of authenticated users for a WCF service. For example, you can employ the ASP.NET Membership Provider (to store a list of users and their credentials in a SQL Server database) together with the ASP.NET Role Provider (to associate users with roles). In this article we will see how it works.

To make a WCF service available across the Internet, you would typically host it by using IIS.

By hosting a WCF service using IIS, you can use the ASP.NET Web Site Administration Tool to easily create a SQL Server database containing the security information for the service and, manage users and roles. You can then configure the WCF service to use the ASP.NET Membership Provider to authenticate users, and the ASP.NET Role Provider to retrieve role information for authorizing users.

Configure IIS Bindings to Support SSL

It is good practice to use the Secure Sockets Layer (SSL) to protect communications when you build a service that is exposed to the Internet. Therefore, the first task is to configure IIS to support SSL by adding a certificate to identify the service and encrypt information passing to and from client applications. You can then bind this certificate to the Web site that hosts your WCF services. Below are the steps to configure IIS bindings to support SSL:

1. Open the Internet Information Services Manager console as an administrator.

2. In the Internet Information Services (IIS) Manager console window, in the Connections pane, click the node that corresponds to your computer.

3. In the middle pane, click the Features View tab.

4. In the Features View pane, in the IIS section, double-click Server Certificates. The Server Certificates pane appears, displaying possible certificates that you can use to configure IIS to use to implement SSL.

5. In the Actions pane, click Create Self-Signed Certificate. The Create Self-Signed Certificate dialog box appears. You should not use a self-signed certificate in a production environment. If you require a commercial-grade certificate, you should click the Create Certificate Request link in the Actions pane, create a certificate request that identifies your organization, and then send this request to a certificate provider, such as Active Directory Certificate Services or a trusted third-party organization to generate the certificate.

6. In the Create Self-Signed Certificate dialog box, in the Specify A Friendly Name For The Certificate box, type the name of your computer, and then click OK.

Note It is important that you give the certificate a friendly name that is the same as your computer, otherwise you may run into some security errors later on when you attempt to access the Web site.

7. In the Connections pane, expand the node that corresponds to your computer, expand Sites, right-click Default Web Site, and then click Edit Bindings. The Site Bindings dialog box appears, as shown in the following image, listing the protocols that IIS and WAS support for the Web site.

8. In the Site Bindings dialog box, if https is not configured, click Add; otherwise, select https, and then click edit.

9. In the Add (or Edit) Site Binding dialog box, set Type to https, select the SSL certificate that is named after your computer, and then click OK.

10. Click Close.

Create the ProductsService Web Application

1. Start Windows Explorer as an administrator and create the following folder:
C:\inetpub\wwwroot\ProductsService

2. Return to IIS Manager console. In the Connections pane, right-click Default Web Site, and then click Add Application.

3. In the Add Application dialog box, specify the values shown in the following table, and then click OK.

———————————————————————————–
Item                           Value
————————————————————————————–
Alias                           ProductsService
Application Pool      ASP.NET v4.0
Physical Path           C:\inetpub\wwwroot\ProductsService
————————————————————————————–

4. In the Connections pane, click the ProductsService application.

5. In the middle pane, click the Features View tab, and then double-click SSL Settings in the IIS section.

6. In the SSL Settings pane, check Require SSL, and then in the Actions pane, click Apply.

Create ASP.NET Web Site to Host the WCF Service

1. Using Visual Studio, create a new Web site.

2. In the New Web Site dialog box, click the WCF Service template. Set the Web location to HTTP, and type https://YourComputer/ProductsService, where YourComputer is the name of your computer, and then click OK.

Note Make sure that you specify https as the scheme in this address.

3. In Solution Explorer, delete the Service.svc file and the Web.config file, and the IService.cs and Service.cs files in the App_Code folder.

Note Although the Web site is configured to use SSL and support transport-level security, you can still perform message-level encryption as well if you need to provide end-to-end security rather than point-to-point. However, remember that encryption is a necessarily expensive operation. Encrypting at two levels will impact performance. Transport-level encryption tends to be much faster than message-level encryption. So, if performance is a limiting factor and you have to make a choice, go for transport-level security.

Define Users and Roles for the WCF Service

1. In Visual Studio, from the Website menu, choose ASP.NET Configuration. The ASP.NET Web Site Administration Tool starts. This is actually another Web application that runs by using the ASP.NET Development Server.

This tool provides pages with which you can add and manage users for your Web site, specify Web application settings that you want to be stored in the application configuration file (not WCF settings), and indicate how security information such as user names and passwords are stored. By default, the ASP.NET Web Site Administration Tool stores security information in a local SQL Server database called ASPNETDB.MDF that it creates in the App_Data folder of your Web site.

2. Click the Security tab.

You can use this page to manage users, specify the authentication mechanism that the Web site uses, define roles for users, and specify access rules for controlling access to the Web site.

3. In the Users section of the page, click the Select Authentication Type link. A new page appears asking how users will access your Web site. You have two options available:

  • From The Internet: You can define users and roles in the SQL Server database. Users accessing your application must provide an identity that maps to a valid user.
  • From A Local Network: This option is selected by default. It configures the Web site to use Windows authentication; all users must be members of a Windows domain that your Web site can access.

4. Select the From The Internet option, and then click Done.

5. In the Users section, notice that the number of existing users that can access your Web site is currently zero. Click the Create User link.

6. In the Create User page, add a new user. {User Name : Sandeep}

7. Ensure that the Active User check box is selected, and then click Create User.

8. Click Continue. The Create User page reappears, in which you can add more users. {User Name : Ajit}

9. Again, ensure that the Active User check box is selected, and then click Create User.

10. Click Back to return to the Security page. Verify that the number of existing users is now set to 2.

11. In the Roles section of the page, click the Enable Roles link.

12. When roles have been enabled, click the Create Or Manage roles link.

13. In the New Role Name text box, type WarehouseStaff, and then click Add Role. The new role appears on the page, together with links which you can use to add and remove users to or from this role.

14. Click the Manage link. Here you can specify the users that are members of this role.

15. Select the User Is In Role check box for Sandeep and Ajit.

16. Then click Back.

17. In the Create New Role page, in the New Role Name text box, type StockControllers, and then click Add Role.

18. Click the Manage link for the StockControllers role. Add Ajit to the StockControllers role and then click Back.

19. Close the ASP.NET Web Site Administration Tool.

The next step is to modify the behavior of the WCF service to perform authorization by using the users and roles defined in the SQL Server database created by the ASP.NET Role Provider and the Membership Provider, rather than by using Windows users and groups.

Sample Code for the WCF Service

Right-click the App_Code folder, and then click Add New class file with filename ProductsService.cs, and then click Add. Repeat this process for the IProductsService.cs file. The ProductsService.cs file contains the code for the ProductsService service.

Note Code in these files are just for reference purpose not complete code. you can use your existing application code for WCF Service and modify it.

ProductService.cs

     // WCF Service that implements the service contract
    // This implementation performs minimal error checking and exception handling
    public class ProductsServiceImpl : IProductsService
    {
        [PrincipalPermission(SecurityAction.Demand, Role="WarehouseStaff")]
        public List ListProducts()
        {

            // Create a list for holding product numbers
            List productsList = new List();

            try
            {
                // Connect to the AdventureWorks database by using the Entity Framework
                using (AdventureWorksEntities database = new AdventureWorksEntities())
                {
                    /// Fetch the product number of every product in the database
                    var products = from product in database.Products
                                   select product.ProductNumber;

                    productsList = products.ToList();
                }
            }
            catch (Exception e)
            {
                // Edit the Initial Catalog in the connection string in app.config to trigger this exception
                if (e.InnerException is System.Data.SqlClient.SqlException)
                {
                    DatabaseFault dbf = new DatabaseFault
                    {
                        DbOperation = "Connect to database",
                        DbReason = "Exception accessing database",
                        DbMessage = e.InnerException.Message
                    };

                    throw new FaultException(dbf);
                }
                else
                {
                    SystemFault sf = new SystemFault
                    {
                        SystemOperation = "Iterate through products",
                        SystemReason = "Exception reading product numbers",
                        SystemMessage = e.Message
                    };

                    throw new FaultException(sf);
                }
            }

            // Return the list of product numbers
            return productsList;
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "WarehouseStaff")]
        public ProductData GetProduct(string productNumber)
        {
            // Create a reference to a ProductData object
            // This object will be instantiated if a matching product is found
            ProductData productData = null;

            try
            {
                // Connect to the AdventureWorks database by using the Entity Framework
                using (AdventureWorksEntities database = new AdventureWorksEntities())
                {
                    // Find the first product that matches the specified product number
                    Product matchingProduct = database.Products.First(
                        p => String.Compare(p.ProductNumber, productNumber) == 0);

                    productData = new ProductData()
                    {
                        Name = matchingProduct.Name,
                        ProductNumber = matchingProduct.ProductNumber,
                        Color = matchingProduct.Color,
                        ListPrice = matchingProduct.ListPrice
                    };
                }
            }
            catch
            {
                // Ignore exceptions in this implementation
            }

            // Return the product
            return productData;
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "WarehouseStaff")]
        public int CurrentStockLevel(string productNumber)
        {
            // Obtain the total stock level for the specified product.
            // The stock level is calculated by summing the quantity of the product
            // available in all the bins in the ProductInventory table.

            // The Product and ProductInventory tables are joined over the
            // ProductID column.

            int stockLevel = 0;

            try
            {
                // Connect to the AdventureWorks database by using the Entity Framework
                using (AdventureWorksEntities database = new AdventureWorksEntities())
                {
                    // Calculate the sum of all quantities for the specified product
                    stockLevel = (from pi in database.ProductInventories
                                  join p in database.Products
                                  on pi.ProductID equals p.ProductID
                                  where String.Compare(p.ProductNumber, productNumber) == 0
                                  select (int)pi.Quantity).Sum();
                }
            }
            catch
            {
                // Ignore exceptions in this implementation
            }

            // Return the stock level
            return stockLevel;
        }

        public bool ChangeStockLevel(string productNumber, short newStockLevel, string shelf, int bin)
        {
            // Determine whether the user is a member of the StockControllers role
            WindowsPrincipal user = new WindowsPrincipal((WindowsIdentity)Thread.CurrentPrincipal.Identity);
            if (!(user.IsInRole("StockControllers")))
            {
                // If the user is not in the StockControllers role,
                // throw a SecurityException
                throw new SecurityException("Access denied");
            }

            // Modify the current stock level of the selected product
            // in the ProductInventory table.
            // If the update is successful then return true, otherwise return false.

            // The Product and ProductInventory tables are joined over the
            // ProductID column.

            try
            {
                // Connect to the AdventureWorks database by using the Entity Framework
                using (AdventureWorksEntities database = new AdventureWorksEntities())
                {
                    // Find the ProductID for the specified product

                    int productID =
                        (from p in database.Products
                         where String.Compare(p.ProductNumber, productNumber) == 0
                         select p.ProductID).First();

                    // Find the ProductInventory object that matches the parameters passed
                    // in to the operation
                    ProductInventory productInventory = database.ProductInventories.First(
                        pi => String.Compare(pi.Shelf, shelf) == 0 && pi.Bin == bin &&
                              pi.ProductID == productID);

                    // Update the stock level for the ProductInventory object
                    productInventory.Quantity += newStockLevel;

                    // Save the change back to the database
                    database.SaveChanges();
                }
            }
            catch
            {
                // If an exception occurs, return false to indicate failure
                return false;
            }

            // Return true to indicate success
            return true;
        }
    }

IProductsService.cs :

    // Classes for passing fault information back to client applications
    [DataContract]
    public class SystemFault
    {
        [DataMember]
        public string SystemOperation { get; set; }

        [DataMember]
        public string SystemReason { get; set; }

        [DataMember]
        public string SystemMessage { get; set; }
    }

    [DataContract]
    public class DatabaseFault
    {
        [DataMember]
        public string DbOperation { get; set; }

        [DataMember]
        public string DbReason { get; set; }

        [DataMember]
        public string DbMessage { get; set; }
    }

    // Data contract describing the details of a product passed to client applications
    [DataContract]
    public class ProductData
    {
        [DataMember]
        public string Name;

        [DataMember]
        public string ProductNumber;

        [DataMember]
        public string Color;

        [DataMember]
        public decimal ListPrice;
    }

    // Service contract describing the operations provided by the WCF service
    [ServiceContract]
    public interface IProductsService
    {
        // Get the product number of every product
        [FaultContract(typeof(SystemFault))]
        [FaultContract(typeof(DatabaseFault))]
        [OperationContract]
        List ListProducts();

        // Get the details of a single product
        [OperationContract]
        ProductData GetProduct(string productNumber);

        // Get the current stock level for a product
        [OperationContract]
        int CurrentStockLevel(string productNumber);

        // Change the stock level for a product
        [OperationContract]
        bool ChangeStockLevel(string productNumber, short newStockLevel, string shelf, int bin);
    }

For this service, you will use a WS2007HttpBinding binding that supports transport-level security for protecting messages, but with message-level credentials for authenticating and authorizing because this is the level at which the ASP.NET Role Provider operates. You will implement configuration-based activation for the service so that you do not need to add a .svc file.

Configure the Activation and Binding for the WCF Service

Open Web.Config file in WCF Service – ProductsService project and update configuration details as per below:

Web.Config

<configuration>
	....
 <system.web>
	<roleManager enabled="true" />
	<authentication mode="Forms" />
	.............
 </system.web>

 <system.serviceModel>

  <bindings>
     <ws2007HttpBinding>
	<binding name="ProductsServiceWS2007HttpBindingConfig">
	     <security mode="TransportWithMessageCredential">
	          <transport clientCredentialType="None" />
	          <message clientCredentialType="UserName" />
	     </security>
	</binding>
      </ws2007HttpBinding>
   </bindings>

  <services>
   <service name="Products.ProductsServiceImpl">
        <endpoint address="https://localhost/ProductsService/Service.svc"
                         binding="ws2007HttpBinding"
                         bindingConfiguration="ProductsServiceWS2007HttpBindingConfig"
                         contract="Products.IProductsService" />
    </service>
  </services>

  <behaviors>
   <serviceBehaviors>
       <behavior name="">
             <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
             <serviceDebug includeExceptionDetailInFaults="false" />
             <serviceAuthorization principalPermissionMode="UseAspNetRoles"
                       roleProviderName="AspNetSqlRoleProvider" />
             <serviceCredentials>
                  <userNameAuthentication userNamePasswordValidationMode="MembershipProvider"
                           membershipProviderName="AspNetSqlMembershipProvider" />
             </serviceCredentials>
       </behavior>
   </serviceBehaviors>
  </behaviors>

  <serviceHostingEnvironment multipleSiteBindingsEnabled="false">
       <serviceActivations>
            <add relativeAddress="Service.svc" service="Products.ProductsServiceImpl" />
       </serviceActivations>
  </serviceHostingEnvironment>

 </system.serviceModel>

  <system.webServer>
      <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>

</configuration>

The host Web site is configured to use the HTTPS protocol, so the WCF service must be configured to support transport-level security. The TransportWithMessageCredential mode uses HTTPS at the transport level to protect messages traversing the network and uses the server certificate to authenticate with the client. The user’s credentials are authenticated by using message-level security. The credentials are passed as a UserName token.

If you are using the HTTPS protocol and you wish to enable the service to publish metadata, you must set the HttpsGetEnabled property of the serviceMetadata behavior to True. Additionally, you cannot set both the HttpGetEnabled and the HttpsGetEnabled properties to True at the same time (either the service is using HTTPS or it isn’t).

The RoleProviderName property identifies a particular configuration for the identity role provider that will be used to map users to roles. The value “AspNetSqlRoleProvider” is actually defined in the Machine.config file and specifies the version of the ASP.NET Role Provider to use to authorize users, together with information, about how to connect to the database holding the user and role information.

The membership provider is responsible for authenticating users based on their names and passwords stored in the SQL Server database. The value “AspNetSqlMembership Provider” is also defined in the Machine.config file.

Note Try not to get too confused by the role provider and the membership provider. WCF uses the membership provider for authenticating users, and it uses the role provider for authorizing users’ access to resources after they have been authenticated.

To quickly test that you have configured the service correctly, start Internet Explorer and go to the Web site https://YourComputer/ProductsService/Service.svc (where YourComputer is the name of your computer).

Note If your computer is joined to a Windows domain, you may need to specify the fully qualified name of your computer in Internet Explorer. This has the form YourComputer.Your-Domain and may include an extension such as “.net” or “.com”. If you are not sure of the fully qualified name of your computer, consult the system administrator who manages your domain. Internet Explorer opens the page https://YourComputer/ProductsService/ProductsService.svc

Don’t Forget to check this:

Depending on how you have configured the application pool used by the ProductsService Web application in IIS, you may need to amend the identity used by the application pool. The default configuration of the ASP.NET v4.0 application pool will result in a failure when the WCF runtime attempts to access the SQL Server membership database (ASPNETDB.MDF in the App_Data folder of the Web application).

Rather confusingly, the error is reported by the WCF runtime as “An unsecured or incorrectly secured fault was received from the other party,” but if you examine the Windows Application Event Log you will find an exception with the message “Failed to generate a user instance of SQL Server due to a failure in retrieving the user’s local application data path. Please make sure the user has a local profile on the computer.” To circumvent this problem, you can run the ASP.NET v4.0 application pool with the NETWORK SERVICE identity, as follows:

1. IIS Manager console, in the Connections pane, click Application Pools.

2. In the Application Pools pane, right-click the ASP.NET v4.0 application pool, and then click Advanced Settings.

3. In the Advanced Settings dialog box, in the Process Model section, click Identity, and then click the ellipsis button that appears on the right-hand side.

4. In the Application Pool Identity dialog box, click Built-In Account, select NetworkService from the drop-down list, and then click OK.

You must make some changes so that the client application connects to the WCF service by using the correct binding and address.

Modify the WCF Client Application to Connect to the Updated WCF Service

Note we are assuming that we have sample client application ready with us and we just need to modify it for our purpose.

1. In Solution Explorer, open the Program.cs file in the ProductClient project. Modify the statement that creates the proxy to refer to the WS2007HttpBinding_IProductsService endpoint, as shown in the following:

ProductClient —> Program.cs:

static void Main(string[] args)
    {
        Console.WriteLine("Press ENTER when the service has started");
	Console.ReadLine();

	// Create a proxy object and connect to the service
	PermissiveCertificatePolicy.Enact("CN=SandyWorldDesktop");
	ProductsServiceClient proxy = new ProductsServiceClient("WS2007HttpBinding_IProductsService");

        proxy.ClientCredentials.UserName.UserName = "Sandeep";
	proxy.ClientCredentials.UserName.Password = "Password";

         // Test the operations in the service
         // Obtain a list of all products
         Console.WriteLine("Test 1: List all products");
         string[] productNumbers = proxy.ListProducts();
         foreach (string productNumber in productNumbers)
         {
              Console.WriteLine("Number: {0}", productNumber);
         }
         Console.WriteLine();

         Console.WriteLine("Test 2: Display the details of a product");
         ProductData product = proxy.GetProduct("WB-H098");
         Console.WriteLine("Number: {0}", product.ProductNumber);
         Console.WriteLine("Name: {0}", product.Name);
         Console.WriteLine("Color: {0}", product.Color);
         Console.WriteLine("Price: {0}", product.ListPrice);
         Console.WriteLine();

         // Query the stock level of this product
         Console.WriteLine("Test 3: Display the stock level of a product");
         int numInStock = proxy.CurrentStockLevel("WB-H098");
         Console.WriteLine("Current stock level: {0}", numInStock);
         Console.WriteLine();

         // Modify the stock level of this product
         Console.WriteLine("Test 4: Modify the stock level of a product");
         if (proxy.ChangeStockLevel("WB-H098", 100, "N/A", 0))
         {
               numInStock = proxy.CurrentStockLevel("WB-H098");
               Console.WriteLine("Stock changed. Current stock level: {0}", numInStock);
         }
         else
         {
              Console.WriteLine("Stock level update failed");
         }
         Console.WriteLine();

         // Disconnect from the service
         proxy.Close();

         Console.WriteLine("Press ENTER to finish");
         Console.ReadLine();
     }

The client application uses message-level authentication to send the user’s credentials to the WCF service. You specify the credentials to send by using the ClientCredentials.UserName property of the proxy object.

2. Open the app.config file for the ProductClient project and add new binding configuration and new endpoint as per below:

<configuration>
    <system.serviceModel>
        <bindings>

            <ws2007HttpBinding>
                <binding name="ProductsClientWS2007HttpBindingConfig">
                    <security mode="TransportWithMessageCredential">
                        <transport clientCredentialType="None" />
                        <message clientCredentialType="UserName" />
                    </security>
                </binding>
            </ws2007HttpBinding>
        </bindings>
        <client>

            <endpoint address="https://localhost/ProductsService/Service.svc"
                binding="ws2007HttpBinding" bindingConfiguration="ProductsClientWS2007HttpBindingConfig"
                contract="ProductsClient.ProductsService.IProductsService"
                name="WS2007HttpBinding_IProductsService" />
        </client>
    </system.serviceModel>
</configuration>

3. Save the configuration file.

Test the WCF Service

1. Run the ProductClient project.

2. When the client console window appears, press Enter to connect to the service. The first three tests should run successfully, but the final test fails with the error.

The PrincipalPermission attributes implementing security demands for the first three methods automatically use the currently configured role provider.

The problem is that the method executed by Test 4 does not use the PrincipalPermission attribute—the authorization check is performed by using code. In particular, the following statement attempts to retrieve the identity of the user assuming it was a Windows principal, which it no longer is:

WindowsPrincipal user = new WindowsPrincipal((WindowsIdentity)Thread.CurrentPrincipal.Identity);

3. Edit the ProductsService.cs file. Locate the ChangeStockLevel method and modify the two lines of code that create the user variable; test this variable to determine whether the user is a member of the StockControllers role, as shown in bold in the following:

public bool ChangeStockLevel(string productNumber, short newStockLevel, string shelf, int bin)
{
	// Determine whether the user is a member of the StockControllers role
	IIdentity user = ServiceSecurityContext.Current.PrimaryIdentity;
	if (!(System.Web.Security.Roles.IsUserInRole(user.Name, "StockControllers")))
	{
		...
	}
	...
}

The ServiceSecurityContext class contains information about the current security context for the WCF operation being performed. This security context information includes the identity if the user requesting the operation, which is available in the static Current. PrimaryIdentity property. You can use the name held in this identity object to determine whether the user is a member of a specific role by using the IsInRole method of the
System.Web.Security.Roles class. The Roles class accesses the data in the currently configured role provider for the WCF service to perform its work.

5. Run Client application. Press Enter when the client application window appears. This time, Test 4 fails with the error “Access is denied.” This is because Sandeep is not a member of the StockControllers role.

6. Edit the Program.cs file in the ProductClient project. Change the user name sent to the WCF service through the proxy as follows:

proxy.ClientCredentials.UserName.UserName = "Ajit";

7. Run Client application. Press Enter when the client application window appears. Ajit is a member of both the WarehouseStaff and StockControllers roles, and all tests should run successfully.

Summary

The ASP.NET role provider enables ASP.NET developers to create Web sites that allow users to create an account with a site and assign roles for authorization purpose. With this feature, any user can establish an account with the site, and log in for access to the site and its services. This is in contrast to Windows security, which requires users to have accounts in a Windows domain. Instead, any user who supplies his or her credentials (the user name/password combination) can use the site and its services.

The role provider feature uses a SQL Server database to store user information. Windows Communication Foundation (WCF) developers can take advantage of these features for security purposes. When integrated into a WCF application, users must supply a user name/password combination to the WCF client application.

References :

1) Use the ASP.NET Role Provider with a Service

2) Using ASP.NET Membership Provider authentication in a WCF service

3) Chapter 5 of WCF Step By Step Book

Hope this will help !!!

Jay Ganesh