Chapter 9: Intranet - Web to Remote WCF Using Transport Security (Original Caller, TCP)

patterns & practices Developer Center

Applies To

  • Microsoft® Windows Communication Foundation (WCF) 3.5

Scenario

In this scenario, your users have Windows accounts and use a Web client to connect over the intranet to an ASP.NET application on an Internet Information Services (IIS) server that is hosted on an application server. The ASP.NET application makes calls to the WCF service. The business logic called by the WCF service requires fine-grained authorization and is backed by a Microsoft SQL Server® data store. The basic model for this application scenario is shown in the following figure.

Ff648998.CH09-Fig1(en-us,PandP.10).png

Figure 1
Web to Remote WCF Using Transport Security (Original Caller, TCP) – Model

Key Characteristics

This scenario applies to you if:

  • Your users have browsers supporting Windows integrated authentication.
  • Your user accounts are in a Microsoft Active Directory® directory service within a domain.
  • Your user roles are Windows Groups.
  • The business logic behind your WCF service requires fine-grained authorization.
  • Your application transmits sensitive data over the network that needs to be protected.
  • A high-performance connection between the ASP.NET application and the WCF service is more important than the ability to host the WCF service in IIS.

Solution

Ff648998.CH09-Fig2(en-us,PandP.10).png

Figure 2
Web to Remote WCF Using Transport Security (Original Caller, TCP) – Solution

Solution Summary Table

In this solution, you will:

  • Use domain credentials to authenticate clients against an Active Directory user store.
  • Impersonate the original caller when calling methods on the WCF service from the ASP.NET application.
  • Use a service account to call the SQL Server from WCF (without impersonation).
  • Use Secure Sockets Layer (SSL) encryption to protect sensitive data between the Web client and IIS.
  • Use transport security to protect sensitive data between the ASP.NET application and the WCF service.
  • Use netTcpBinding to support the TCP transport for improved performance.
  • Host WCF in a Windows Service because IIS does not support the TCP transport (prior to IIS 7.0).

Web Server

Checks / more information

Example

IIS—configuration

A dedicated application pool is created and configured to run under a custom service account.

Use a domain account.

 

The Web application is configured to run under the service account.

Assign the Web application to the custom application pool.

 

A Service Principal Name (SPN) is created if the domain identity is used in the ASP.NET application pool.

Create an SPN for both the DNS and NETBIOS machine name.

        
setspn -a HTTP//WebServer.domain.com customDomainAccount
setspn -a HTTP//WebServer customDomainAccount

      

The ASP.NET Process identity is configured as Trusted for delegation.

If you use a network service account, enable the computer account for “trusted for delegation.” If you use a domain user account, enable the domain account for “trusted for delegation.”

 

IIS—authentication

The IIS virtual directory is configured to use Windows integrated authentication.

Users will be authenticated with Windows authentication.

Anonymous access is disabled.

Checks / more information

Example

ASP.NET—authentication

ASP.NET is configured for Windows integrated authentication.

The Web application will authenticate the users.

        
<authentication mode = "Windows" >

      

ASP.NET—authorization

If you have role segmentation in your application, use URL authorization.

The authorized users have access to specific pages.

        
<authorization>
  <allow roles="domainName\RoleName" />
  <deny users="*" />
</authorization>

      

Role Manager is enabled and role checks are performed using the Role Manager API.

Original users are authorized using the Windows groups before calling an WCF service.

        
<roleManager enabled="true"
             defaultProvider= "AspNetWindowsTokenRoleProvider"/>

if (Roles.IsUserInRole(@"npscode\Accounting")) {

}

WCF proxy

ASP.NET has a proxy reference to the WCF service.

The application has access to the WCF service metadata in order to create a service reference.

        
WCFTestService.MyServiceClient proxy = new WCFTestService.MyServiceClient();

      

ASP.NET impersonates the original callers before calling the WCF operation.

Used for downstream authorization.

        
using (((WindowsIdentity)HttpContext.Current.User.Identity).Impersonate())
 {
  WCFTestService.MyServiceClient proxy 
    = new    WCFTestService.MyServiceClient();
     proxy.GetData("data");
     proxy.Close();
 }

      

Application Server

Checks / more information

Example

Windows service—configuration

The Windows service is configured to run under a custom domain service account.

Use a domain account if possible.

 

The WCF service is hosted in a Windows service.

Since IIS does not support netTcpBinding, host in a Windows service.

 

An SPN is created because a custom domain account is used for the Windows service, and the ASP.NET application needs to restrict trust for delegation to the WCF service only.

Create an SPN for both the DNS and NETBIOS machine name.

        
setspn -a WCFServiceHost//WebServer.domain.com customDomainAccount
setspn -a WCFServiceHost//WebServer customDomainAccount

      

WCF service—configuration

Configure the WCF service to use netTcpBinding.

NetTcpBinding uses the TCP protocol and provides full support for SOAP security, transactions, and reliability. Because the client and WCF service are both on an intranet, this is a good choice from a performance perspective.

        
<endpoint 
   address=""    
   binding="netTcpBinding"  
   bindingConfiguration=""
   name="TcpBinding" 
contract="WCFServicecHost.IMyService"
/>

      

A metadata exchange (mex) endpoint is created for publishing the metadata.

This is required so that the client can add a reference to the WCF service using the SvcUtil utility.

        
<endpoint 
   address="Mex"     
   binding="mexTcpBinding" 
   bindingConfiguration=""
   name="MexEndpoint" 
   contract="IMetadataExchange" />

      

Service metadata is configured in the service behavior.

The service metadata entry is required for the Windows service host to start. Both HTTP and HTTPS get are disabled.

        
<serviceMetadata />

      

WCF service—authentication

netTcpBinding is configured to use Windows authentication and transport security.

netTcpBinding supports Windows authentication and transport security by default.

        
<endpoint 
  address=""   
  binding="netTcpBinding"
  bindingConfiguration=""
/>

      

WCF service—authorization

The Role Manager feature is enabled and WindowsTokenRoleProvider is configured for roles authorization.

Roles authorization can be performed either declaratively or imperatively in the operation contract.

        
<serviceAuthorization  
 principalPermissionMode="UseAspNetRoles"        roleProviderName="AspNetWindowsTokenRoleProvider" />

      

Perform role checks declaratively using the PrinciplePermission attribute.

Use a declarative check to authorize the user on individual methods.

        
[PrincipalPermission(SecurityAction.Demand, 
Role = "npscode\\accounting")]

public string GetData(string message) { return "hello"; }

Perform role-checks imperatively using the IsUserInRole() method.

Use a programmatic check to authorize the user based on business logic.

        
if(Roles.IsUserInRole(@"npscode\Accounting"))
{
 //business operation for accounting 
}
else
{
 //business operation for others 
}            

      

WCF service—SQL

The connection string for the database is configured to use Windows authentication. The service does not impersonate the original caller to benefit from connection pooling.

The database connection string includes Integrated Security=SSPI or Trusted Connection=Yes.

        
SqlConnection sqlcon = new SqlConnection("Server=10.3.19.11;Database=Northwind;IntegratedSecurity=SSPI");

      

The database connection is opened by using the WCF process identity’s security context.

Service does not impersonate the original caller to benefit from connection pooling.

 

Database Server

Checks / more information

Example

Configuration

A SQL Server login is created for the WCF service account (process identity).

This grants access to the SQL Server.

        
exec sp_grantlogin 'Custom Service Account'

      

The login is mapped to a database user for the Web application.

This grants access to the specified database.

        
use targetDatabase 
go 
exec sp_grantdbaccess ' Custom Service Account' 
go 

      

A database role is created in the target database.

This allows access control and authorization to the database.

        
use targetDatabase 
go 
exec sp_addrole 'DB Role Name' 
go 

      

The login is added to the database role.

Grant minimum permissions. For example, grant execute permissions to selected stored procedures and provide no direct table access.

        
use targetDatabase
go
exec sp_addrolemember 'DB Role Name', 'Custom Service Account'
go

      

Authentication

SQL Server is configured to use Windows authentication.

Communication Security

Checks / more information

Browser to Web server

Use SSL between the browser and Web server to protect sensitive data on the wire.

Install certificate in the Web site. Configure the virtual directory of the Web application to use SSL.

Application server to database server

You can use IPSec or SSL between the application server and the database server to protect sensitive data on the wire.

Analysis

Web Server

Authentication

  • To prevent unauthenticated and unauthorized users from accessing pages, anonymous access is disabled in IIS.
  • Windows integrated authentication is a good choice for this scenario because all users have Windows accounts. Windows integrated authentication provides the benefit of preventing the user’s password from ever being sent over the network. Additionally, the logon is transparent for the user because Windows uses the current user’s logon session.

Authorization

  • Use URL authorization to perform role checks against the original caller and restrict access to pages based on role permissions.
  • The Role Manager is a good choice for this scenario because it allows your service code to look up users’ roles without writing and maintaining custom code.
  • The original caller is passed to the WCF service to allow authorization decisions downstream.

WCF Proxy

  • Because the original user’s credentials are passed to WCF for authentication and authorization, the original caller is impersonated before making calls into the WCF service. All calls routed through the WCF proxy and into the WCF service use the original user’s security context.

Configuration

  • In order to reduce attack surface and minimize the impact of a compromise, the ASP.NET application on the Web server runs under the security context of the service account, using a least-privileged account.
  • In order to support Kerberos mutual authentication, an SPN is created for your custom domain account running the ASP.NET application.
  • Configure the custom domain account in Active Directory to trust for delegation. This allows ASP.NET to flow the original caller credentials to the WCF service.

Application Server

Authentication

  • In order to authenticate the original caller in the WCF service, WCF uses Windows authentication.

Authorization

  • For coarse-grained access control, the WCF service manages authorization checks declaratively at the operation level.
  • For fine-grained access control, authorization checks are made programmatically within the operations.
  • The Role Manager is a good choice for this scenario because it allows your service code to look up users’ roles without writing and maintaining custom code.

Data Access

  • To reduce the risk of stolen database credentials, the database connection string is configured to use Windows authentication. This choice avoids storing credentials in files and passing credentials over the network to the database server.
  • The WCF service accesses the database using the WCF process identity. As a result, all calls use the single process account and designated database connection pooling.

Configuration

  • This scenario is optimized around transmission performance at the expense of interoperability with clients that expect a legacy Web service and the ability to host the service in IIS. For this reason, the best binding choice is netTcpBinding. By default, netTcpBinding supports Windows authentication with transport security.
  • Because IIS 6.0 does not support netTcpBinding, the WCF service is hosted in a Windows service.
  • In order to reduce attack surface and minimize the impact of a compromise, the Windows service runs under the security context of the service account, using a least-privileged account.
  • A metadata exchange (mex) endpoint is exposed to make it possible for the client to generate a proxy based on the service definition.

Database Server

  • SQL Server database user roles are preferred over SQL Server application roles in order to avoid the password management and connection pooling issues associated with the use of SQL application roles. Applications activate SQL application roles by calling a built-in stored procedure with a role name and a password. Therefore, you must securely store the password. You must also disable database connection pooling when you use SQL application roles, which severely impacts application scalability.
  • Creating a new user-defined database role and adding the database user to the role lets you give specific minimum permissions to the role. In this way, if the database account changes, you don't have to change the permissions on all database objects.

Communication Security

  • SSL protects sensitive data on the wire between the browser and Web server.
  • Transport security protects sensitive data between the Web server and the application server.
  • You can use IPSec or SSL between the application server and the database server to protect sensitive data on the wire.

Example

Domain Controller

Configuration

Create an SPN based on the following rules:

  1. If the ASP.NET application runs in an application pool with a custom domain identity, create an SPN and map the custom domain identity with the HTTP service class and both the DNS machine name and the NETBIOS machine name:

    setspn -a HTTP//WebServer.domain.com customDomainAccount
    setspn -a HTTP//WebServer customDomainAccount
    
  2. If the service runs under a custom domain identity:

    setspn -a ServiceNameofWcfService//WebServer.domain.com customDomainAccount
    setspn -a ServiceNameofWcfService//WebServer customDomainAccount
    
  3. If the service runs under the network service account:

    setspn -a ServiceNameofWcfService//WebServer.domain.com computerName
    setspn -a ServiceNameofWcfService//WebServer computerName
    

    Note

    You should specify the service name as it is displayed in the Microsoft Management Console (MMC) services console.

  4. Additionally:

    • The machine account of the Web application is configured to be trusted for delegation if the ASP.NET application runs under the network service account.
    • The domain account is configured to be trusted for delegation if the ASP.NET application runs under a custom domain identity.

Web Server

Code

  • Role authorization occurs before WCF service invocation.
  • ASP.NET impersonates the original caller if it is authorized.
using System.Security.Principal;
…
protected void Button1_Click(object sender, EventArgs e)
{
  if (Roles.IsUserInRole(@"npscode\Business Represenatatives"))
   {
   using (((WindowsIdentity)HttpContext.Current.User.Identity).Impersonate())
      {
        WCFTestService.MyServiceClient proxy 
          = new WCFTestService.MyServiceClient();
        proxy.GetData("data");
        proxy.Close();
       } //end using
    } //end if
 } //end function

Web.config Configuration

  • Windows authentication is enabled.
  • URL authorization check is enabled.
  • Role Manager is enabled.
<system.web>
   <assemblies>
     <add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
     <add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
     <add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
     <add assembly="System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
    </assemblies>

   <authentication mode="Windows" />
      <authorization>
        <allow roles="npscode\BusinessDivision" />
        <deny users="*" />
   </authorization>

   <roleManager enabled="true" 
        defaultProvider= "AspNetWindowsTokenRoleProvider"/>
   <pages>
      <controls>
        <add tagPrefix="asp" namespace="System.Web.UI" 
             assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        <add tagPrefix="asp" namespace="System.Web.UI.WebControls" 
             assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      </controls>
   </pages>

   <httpHandlers>
     <remove verb="*" path="*.asmx"/>

     <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

     <add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

     <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false"/>
    </httpHandlers>

    <httpModules>
       <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
    </httpModules>

</system.web>

Application Server

Code

  • The service performs imperative authorization checks calling Roles.IsUserInRole.
  • The service calls SQL by using the security context of the WCF service and Windows authentication.
using System.Data.SqlClient;
using System.Web.Security;

public string GetData(string myValue)
{
  if(Roles.IsUserInRole(@"npscode\Accounting"))
  {

    SqlConnection sqlcon = new SqlConnection("Server=SQLserver;Database=Northwind;IntegratedSecurity=SSPI");

    sqlcon.Open();
    //do the business operation
    return "Authorization succeeded ";
  }
  else return "authorization failure";
}

Configuration

  • The service has a binding endpoint that uses netTcpbinding with the default settings.
  • The service has a mex endpoint in order to publish metadata.
  • The service has a base address configured.
  • The service configuration file has an entry for the AspNetWindowsTokenRoleProvider under system.web.
  • The service behavior is configured with the serviceAuthorization element to allow the use of WindowsTokenRoleProvider as the authorization provider.
  • The service behavior is configured with the serviceMedata element to allow metadata to be published.
<system.web>
    <roleManager enabled="true"
             defaultProvider="AspNetWindowsTokenRoleProvider" />
</system.web>

<system.serviceModel>
    <behaviors>
        <serviceBehaviors>
            <behavior name="BehaviorConfiguration">
                <serviceAuthorization 
                    principalPermissionMode="UseAspNetRoles"
                    roleProviderName="AspNetWindowsTokenRoleProvider" />
                <serviceMetadata />
            </behavior>
        </serviceBehaviors>
    </behaviors>

    <bindings />

    <services>
        <service 
          behaviorConfiguration="BehaviorConfiguration" 
          name="WCFServicecHost.MyService">
            <endpoint address="Mex" 
                      binding="mexTcpBinding" 
                      bindingConfiguration=""
                      name="MexEndpoint" 
                      contract="IMetadataExchange" />

            <endpoint address="" 
                      binding="netTcpBinding" 
                      bindingConfiguration=""
                      name="TcpBinding" 
                      contract="WCFServicecHost.IMyService" />
            <host>
                <baseAddresses>
                    <add baseAddress=
                        "net.tcp://perfpres02.npscode.com/MyService" />
                </baseAddresses>
            </host>
        </service>
    </services>
</system.serviceModel>

Database Server

Configuration

  • A SQL Server login is created for the WCF service account.
  • The WCF login name is given access to the database.
  • The role is created in the database.
  • The WCF login name is added to the role.
-- Create a SQL Server login that matches the WCF machine name
EXEC SP_GRANTLOGIN 'npscode\perfpres02$'

-- Grant the login access to the application database
use testdb 
go 
exec sp_grantdbaccess 'npscode\perfpres02$' 

-- Create the new database role
use testdb
go
exec sp_addrole 'myrole2','db_owner' 

-- Add the new login to the role
use testdb
go
exec sp_addrolemember 'myrole2','npscode\aspnethost' 

Additional Resources