Chapter 7. Security Basics

<feature><title>In This Chapter</title> </feature>

Introduction

This first chapter on the security facilities provided by the Windows Communication Foundation (WCF) is meant to do two things. First, it is intended to show how to use those facilities to accomplish basic tasks in securing communications. Then the chapter will explain how the various security mechanisms in the Windows Communication Foundation fit together conceptually as part of an ingenious, extensible, and pioneering whole.

Basic Tasks in Securing Communications

Here are the basic tasks involved in securing communication among software entities:

  • The sources of transmissions must be identified, and so must the receivers. The process of determining the identity of a sender or receiver is generally referred to as entity authentication (Tulloch 2003a, 31).

  • Transmissions must be kept safe from interception, viewing, or copying by parties other than the intended receiver. In a word, they must be kept confidential (Tulloch 2003b, 66).

  • The receiver must be assured of the integrity of the transmission; that the data received is the data sent by the identified source (Tulloch 2003c, 147).

  • Entity authentication together with data integrity make a transmission nonrepudiable, providing undeniable evidence that the received data was sent by the identified source (Tulloch 2003d, 216).

  • In responding to a received transmission, the receiving entity might be required to perform operations on behalf of the identified source. In doing so, the receiving entity is said to be impersonating the source (Tulloch 2003e, 141).

  • Communications among software entities invariably have consequences: data gets stored, altered, sent, or deleted. Therefore, it is necessary to ensure that the identified source of a transmission is indeed entitled to cause those effects. The process of doing so is called authorization (Microsoft Press Computer Dictionary 1997, 36).

The Windows Communication Foundation has two primary layers: the Service Model and the Channel Layer. The Service Model translates data items that are to be transmitted into the form of a message, and passes the message to the Channel Layer, which will send the message to its destination. At the destination, the message is received by the Channel Layer and passed to the Service Model.

The Channel Layer of a sending entity authenticates the receiver, provides for the confidentiality and integrity of a message, and facilitates the receiver authenticating the sender. It also grants or denies permission for the receiver to impersonate the sender. The Channel Layer of a receiving entity facilitates the sender authenticating the receiver, confirms the confidentiality and integrity of a message, and authenticates the sending entity. The Service Model on the receiving side does the authorization and, if necessary, the impersonation.

Transport Security and Message Security

The Channel Layers of the sending and receiving entities, which ensure the confidentiality and integrity of messages and which authenticate one another, can be configured to delegate that work to the medium over which the message is transmitted. That option is referred to as transport security. They can also be made to perform operations on the messages themselves to ensure the confidentiality and integrity of the messages and to authenticate the sender and receiver. That option is referred to as message security.

Transport security works more quickly. It is also more widely supported across software communication systems, so if it is necessary to secure communications between a Windows Communication Foundation application and an application that does not use the Windows Communication Foundation, transport security is the approach most likely to work.

Message security can be maintained across any number of intermediate points between the original sender of a message and its ultimate recipient, whereas transport security maintains the security of a transmission only between one point and the next. Message security also provides more options than transport security provides for authenticating the source of a transmission. In particular, it facilitates the federated security scenario described in Chapter 8, “Using Windows CardSpace to Secure Windows Applications.”

Using Transport Security

The Windows Communication Foundation uses the Secure Sockets Layer (SSL) protocol. According to that protocol, a client connecting to a server provides a list of encryption algorithms it supports. The server responds by returning a copy of its certificate, and selects an encryption algorithm from among those that the client claimed to support. The client extracts the server’s public key from the server’s certificate, and uses that key to authenticate the server. The client also uses that key to derive a session key from the server’s response, and the session key is used to encrypt all the data exchanged between the client and the server for the remainder of the session, thereby ensuring its confidentiality (Tulloch 2003f, 299).

Installing Certificates

From the foregoing, it should be apparent that in order to use transport security with the Windows Communication Foundation, it will be necessary to install a certificate. The following steps are for installing certificates for use in the remainder of this chapter, as well as in Chapter 8. The initial steps are for executing a batch file that will create two certificates: one for an organization called FabrikamEnterprises and another for an organization called Woodgrove. The batch file will also make the certificates accessible to the Windows Communication Foundation.

  1. Copy the code associated with this chapter downloaded from http://www.cryptmaker.com/WindowsCommunicationFoundationUnleashed to the folder C:WCFHandsOn. The code is all in a folder called SecurityBasics. The SecurityBasics folder has a subfolder called Certificates.

  2. Open the SDK Command Prompt by choosing All Programs, Microsoft Windows SDK, CMD Shell.

  3. Use the cd command at the prompt to make the Certificates subfolder of the SecurityBasics folder the prompt’s current directory.

  4. On Windows Server 2003 or Windows Vista and later operating systems, execute setup.bat from the prompt. On Windows XP SP2, execute setupxp.bat.

Both of the certificates created by the batch file executed in the preceding step were issued by an organization called Root Agency. For the certificates to be trustworthy, a certificate for Root Agency itself must be installed in the machine’s Trusted Root Certification Authority Certificate Store. These next few steps are for accomplishing that task. The procedure will be to export one of the new certificates along with the certificate for Root Agency that is included in its chain of certification, and then to import the exported certificates into the Trusted Root Certification Authority Store.

  1. Open the Microsoft Management Console by choosing Run from the Windows Start menus, and entering

    mmc
    
  2. Choose File, Add/Remove Snap-In from the Microsoft Management Console menus.

  3. Click Add on the Add/Remove Snap-In dialog that opens.

  4. Choose Certificates from the list of available standalone snap-ins presented, and click the Add button.

  5. Select Computer Account on the Certificates snap-in dialog, and click the Next button.

  6. Accept the default on the Select Computer dialog and click the Finish button.

  7. Click the Close button on the Add Standalone Snap-In dialog.

  8. Click the OK button on the Add/Remove Snap-In dialog.

  9. Expand the Certificates node that now appears in the left panel of the Microsoft Management Console.

  10. Expand the Personal child node of the Certificates node.

  11. Select the Certificates child node of the Personal node.

  12. Right-click on the FabrikamEnterprises certificate that should now have appeared in the right panel, and choose All Tasks, Export from the context menus.

  13. Click Next on the first dialog of the Certificate Export Wizard.

  14. Elect to export the private key on the next dialog.

  15. Choose Personal Certificate Exchange as the format on the Export File Format dialog, and do be certain to choose the option of including all certificates in the certification path. That option will permit access to the Root Agency certificate.

  16. Click Next to advance to the Password dialog.

  17. Leave the password fields blank and simply click Next.

  18. Use the Browse button on the next dialog to select the WCFHandsOnSecurityBasicsCertificates folder, and enter FabrikamEnterprises.pfx as the name of the file to which the certificate is to be exported. Confirm the replacement of any existing file, if necessary.

  19. Click Next to advance to the final dialog of the Certificate Export Wizard.

  20. Click Finish, and then OK on the Export Confirmation dialog.

  21. Right-click on the Trusted Root Certification Authorities node under the Certificates node in the left pane of the Microsoft Management Console, and select All Tasks, Import from the context menus.

  22. Click Next on the first dialog of the Certificate Import Wizard.

  23. On the next dialog, browse for the FabrikamEnterprises.pfx file to which certificates were exported in step 18. Note that the Open dialog that will be presented does not show files with the .pfx extension by default, so it is necessary to select Personal Certificate Exchange from the list of file type options that it offers in order to see the file.

  24. Click Next to advance to the Password dialog.

  25. Click Next to advance to the Certificate Store dialog.

  26. Click Finish to complete the wizard, and then OK on the Import Confirmation dialog.

  27. The preceding steps will have served to import both the FabrikamEnterprises certificate and the Root Agency certificate into the Trusted Root Certification Authorities Store. The former certificate does not belong there. Delete it by expanding the Trusted Root Certification Authorities node in the left pane of the Microsoft Management Console, selecting its Certificates subnode, right-clicking on the FabrikamEnterprises certificate in the list of the certificates in the right pane, and choosing Delete from the context menus.

If the preceding steps were completed successfully, the Fabrikam and Woodgrove certificates created earlier now have valid certification paths. Confirm that with these steps:

  1. Select the Certificates child node of the Personal node in the left pane of the Microsoft Management Console.

  2. Right-click the FabrikamEnterprises certificate in the right panel, and choose Open from the context menus.

  3. Select the Certification Path tab.

  4. Confirm that the certificate is OK in the Certificate Status field at the bottom of the tab.

  5. Click OK to close the Certificate dialog.

  6. Close the Microsoft Management Console.

Identifying the Certificate the Server Is to Provide

Now some certificates have been installed. The next step is to specify a certificate that the server is to present to clients that initiate SSL connections. The process of doing so differs according to whether the server is a Windows Communication Foundation service hosted in IIS (Internet Information Services), or a Windows Communication Foundation service hosted in a .NET application. For a Windows Communication Foundation service hosted in IIS, it is necessary to identify a certificate that IIS is to use for SSL exchanges. For Windows Communication Foundation services hosted in .NET applications that are to use SSL over HTTP, it is necessary to identify a certificate that HTTP.SYS is to use for SSL. HTTP.SYS is the Windows kernel mode driver for HTTP that the Windows Communication Foundation’s HTTP transport channel relies on. For Windows Communication Foundation services hosted in .NET applications that are to use SSL over a transport other than HTTP, a certificate to use for SSL can be identified directly in the Windows Communication Foundation configuration of the service.

Identifying a Certificate for IIS to Use for SSL Exchanges

To specify a certificate that IIS is to use for SSL exchanges, follow these steps:

  1. Choose Control Panel, Administrative Tools, Internet Information Services (IIS) Manager from the Windows Start menus.

  2. Expand the nodes of the tree control in the left pane until the node named Default Web Site becomes visible.

  3. Right-click on that node, and choose Properties from the context menus that appear.

  4. Select the Directory Security tab.

  5. Click the Server Certificate button.

  6. Click Next on the first dialog of the Web Service Certificate Wizard.

  7. Select Assign an Existing Certificate, and click Next.

  8. Select the FabrikamEnterprises certificate from the list of available certificates and click Next.

  9. Click Next on the SSL Port dialog.

  10. Click Next on the Certificate Summary dialog.

  11. Click Finish to complete the wizard.

  12. Click OK on the Web Site Properties dialog.

  13. Close the IIS Manager.

Identifying a Certificate for HTTP.SYS to Use for SSL Exchanges

The easiest tool to use to configure HTTP.SYS is Steve Johnson’s HTTP configuration utility, which has a graphical user interface. His utility is available at http://www.StevesTechSpot.com. Follow these steps to use that tool to identify the certificate that HTTP.SYS is to use for SSL exchanges:

  1. Start the HTTP Configuration Utility.

  2. Choose the SSL Certs tab.

  3. Click the Add button.

  4. On the SSL Configuration dialog, enter 127.0.0.1 in the IP Address field and 8020 in the Port field.

  5. Click the Browse button and select the FabrikamEnterprises certificate in the Select Certificates dialog, and click OK.

  6. Click the OK button on the SSL Configuration dialog.

  7. Click OK on the main window of the HTTP Configuration Utility to close it.

Configuring the Identity of the Server

Remember that according to the SSL protocol, the client uses the certificate provided by the server to authenticate the server to confirm that the server is indeed the server that the client believes it to be. The FabrikamEnterprises certificate has been identified as the certificate that the server will offer to the client. For that certificate to be useful in confirming the identity of the server, it is necessary to make the identity of the server correspond to the name of the certificate. Do that now by executing these steps:

  1. Use Notepad to open the hosts file in the System32driversetc subfolder of the system directory.

  2. By default, that file contains this single entry:

    127.0.0.1       localhost
    

    Add an additional entry like so:

    127.0.0.1       localhost
    127.0.0.1       fabrikamenterprises
    
  3. Save the hosts file.

  4. Close the hosts file.

Transport Security in Action

Follow these steps to observe the application of transport security to the transmission of messages by the Windows Communication Foundation:

  1. Open the Visual Studio 2005 solution, TransportSecurity.sln, in the folder WCFHandsOnSecurityBasicsTransportSecurity. This solution is very similar to the one constructed in Chapter 2, “The Fundamentals.” A derivatives calculator is exposed for use by a client application via a Windows Communication Foundation service. Hosted in IIS, the service will expose an endpoint for communication with SSL over HTTP. Hosted within a .NET application that is named Host, it will expose another endpoint for SSL communication over HTTP, as well as an endpoint for SSL communication over TCP.

  2. Deploy the service into IIS by creating a virtual directory called SecurityBasics that uses WCFHandsOnSecurityBasicsTransportSecurityDerivativesCalculatorService as its content directory. The steps for creating a virtual directory for hosting a Windows Communication Foundation service were provided in Chapter 2.

  3. Examine the code in the static Main() function in the Program.cs file of the Client project of the TransportSecurity solution. It has the client invoke the derivatives calculator hosted by the .NET host application first using the endpoint for SSL over HTTP, and then using the endpoint SSL over TCP. The code ten has the client invoke the derivatives calculator hosted within IIS using SSL over HTTP.

    using (DerivativesCalculatorClient proxy =
        new DerivativesCalculatorClient("SelfHostedHTTPSService"))
    {
        [...]
    }
    ...
    using (DerivativesCalculatorClient proxy =
        new DerivativesCalculatorClient("SelfHostedTCPService"))
    {
        [...]
    }
    ...
    using (DerivativesCalculatorClient proxy =
        new DerivativesCalculatorClient("WebHostedHTTPSService"))
    {
        [...]
    }
    
  4. Look in the app.config file of the Client project of the TransportSecurity solution to see how the client is configured to invoke the calculator using SSL over HTTP. The pertinent elements of the configuration are shown in Listing 7.1. The address of the service has the HTTPS scheme, which is commonly used for SSL over HTTP. The client is configured to use the predefined BasicHttpBinding. That predefined binding is customized, though, to use transport security, and to identify the client to the server with NTLM credentials. NTLM is used here for the sake of readers whose computers are not attached to any domain. Clients on computers that are attached to a Windows 2000 or later domain could offer Kerberos credentials if the client credential type was set to Windows rather than Ntlm, although a matching change would be required in the configuration of the services.

    Example 7.1. Client Configuration for SSL over HTTP

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
          <system.serviceModel>
                <client>
                      <endpoint
                            address=
    "https://fabrikamenterprises:8020/Derivatives/Calculator"
                                 binding="basicHttpBinding"
                            bindingConfiguration="SecureTransport"
                            behaviorConfiguration="HTTPSEndpoint"
                            contract="DerivativesCalculator.IDerivativesCalculator"
                            name="SelfHostedHTTPSService"/>
                </client>
                <bindings>
                       <basicHttpBinding>
                             <binding name="SecureTransport">
                                   <security mode="Transport">
                                         <transport clientCredentialType="Ntlm"/>
                                   </security>
                             </binding>
                       </basicHttpBinding>
                </bindings>
                <behaviors>
                       <endpointBehaviors>
                          <behavior name="HTTPSEndpoint">
                                   <clientCredentials>
                                         <windows allowNtlm="true"
                                   </clientCredentials>
                             </behavior>
                       </endpointBehaviors>
                </behaviors>
          </system.serviceModel>
    </configuration>
    
  5. Also see, in the app.config file of the Client project, how the client is configured to use SSL over TCP. The pertinent elements of the configuration are reproduced in Listing 7.2. The client is configured to use the predefined NetTcpBinding, but that binding is customized to include transport security. In this case, the client is configured to not offer any credentials by which it can be authenticated to the server. Clients on computers that are attached to a Windows 2000 or later domain could offer Kerberos credentials if the client credential type was set to Windows rather than None, although, again, a matching change would be required in the configuration of the service. A behavior is used to control the client’s authentication of the service, bypassing the default check to determine whether the certificate presented by the server to identify itself has been revoked.

    Example 7.2. Client Configuration for SSL over TCP

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
          <system.serviceModel>
            <client>
                      <endpoint
                            address=
    "net.tcp://fabrikamenterprises:8010/Derivatives/Calculator"
                    binding="netTcpBinding"
                            bindingConfiguration="SecureTransport"
                            behaviorConfiguration="TCPEndpoint"
                             contract="DerivativesCalculator.IDerivativesCalculator"
                             name="SelfHostedTCPService"/>
                </client>
                <bindings>
                      <netTcpBinding>
                            <binding name="SecureTransport">
                                  <security mode="Transport">
                                        <transport clientCredentialType="None"/>
                                  </security>
                            </binding>
                      </netTcpBinding>
                </bindings>
                <behaviors>
                      <endpointBehaviors>
                            <behavior name="TCPEndpoint">
                                  <clientCredentials>
                                        <serviceCertificate>
                                              <authentication revocationMode="NoCheck"
    />
                                        </serviceCertificate>
                                  </clientCredentials>
                            </behavior>
                      </endpointBehaviors>
                </behaviors>
          </system.serviceModel>
    </configuration>
    
  6. Examine the app.config file of the Host project of the TransportSecurity solution to see how a service’s endpoint may be configured to receive SSL requests over HTTP. The configuration is reproduced in Listing 7.3. The address for the endpoint has a base address with the scheme HTTPS, which signifies SSL over HTTP. The endpoint is configured to use the predefined BasicHttpBinding. However, that binding is customized to use transport security, and to anticipate clients presenting NTLM credentials by which they can be authenticated. On computers that are attached to a Windows 2000 or later domain, the clients and the service could be configured to use Kerberos credentials instead of NTLM credentials by setting the client credential type to Windows rather than Ntlm.

    Example 7.3. Service Configuration for SSL over HTTP

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.serviceModel>
       <services>
         <service
            name=
    "DerivativesCalculator.DerivativesCalculatorServiceType"
          <host>
            <baseAddresses>
              <add
    baseAddress="https://localhost:8020/Derivatives/"/>
            </baseAddresses>
          </host>
          <endpoint
            address="Calculator"
            binding="basicHttpBinding"
            bindingConfiguration="SecureTransport"
            contract=
    "DerivativesCalculator.IDerivativesCalculator"/>
          </service>
        </services>
        <bindings>
          <basicHttpBinding>
            <binding name="SecureTransport">
              <security mode="Transport">
                <transport clientCredentialType="Ntlm"/>
             </security>
           </binding>
         </basicHttpBinding>
        </bindings>
      </system.serviceModel>
    </configuration>
    
  7. Also study the app.config file of Host project to see how a service’s endpoint can be configured to receive requests via SSL over TCP. The relevant parts of the configuration are reproduced in Listing 7.4. The address for the endpoint has a base address with the scheme, net.tcp, which is the scheme that must be used in conjunction with the Windows Communication Foundation’s predefined NetTcpBinding. That predefined binding is indeed the one that is specified as the binding for the endpoint in this case, and it is customized to use transport security. The customization specifies that the service will not require clients to present credentials by which the service may authenticate them. On computers that are attached to a Windows 2000 or later domain, the clients and the service could be configured so that the clients would present Kerberos credentials that the service would use to authenticate the clients. That modification could be made by setting the value of the clientCredentialType attribute to Windows rather than None. Notice that the service is configured with a behavior that identifies the FabrikamEnterprises certificate as the certificate that the service is to present to the client to authenticate itself.

    Example 7.4. Service Configuration for SSL over TCP

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.serviceModel>
        <bindings>
          <netTcpBinding>
            <binding name="SecureTransport">
              <security mode="Transport">
                <transport clientCredentialType="None"/>
              </security>
            </binding>
          </netTcpBinding>
        </bindings>
        <services>
          <service
             name="DerivativesCalculator.DerivativesCalculatorServiceType"
             behaviorConfiguration="DerivativesCalculatorService">
            <endpoint
              address="Calculator"
              binding="netTcpBinding"
              bindingConfiguration="SecureTransport"
              contract="DerivativesCalculator.IDerivativesCalculator" />
           <host>
             <baseAddresses>
               <add baseAddress="net.tcp://localhost:8010/Derivatives/"/>
             </baseAddresses>
           </host>
         </service>
        </services>
       <behaviors>
         <serviceBehaviors>
           <behavior name="DerivativesCalculatorService">
             <serviceCredentials>
               <serviceCertificate
                 findValue="CN=FabrikamEnterprises" />
               </serviceCredentials>
           </behavior>
          </serviceBehaviors>
        </behaviors>
       </system.serviceModel>
    </configuration>
    
  8. Now look at the code of the service type, which is in the DerivativesCalculatorServiceType file of the DerivativesCalculatorService project of the TransportSecurity solution. As shown in the following snippet, the service type retrieves the identity of the client using the Windows Communication Foundation’s static System.ServiceModel.Security.ServiceSecurityContext class. It outputs that identity to the screen, thereby signifying that the task of authenticating the client’s identity has been accomplished.

    decimal IDerivativesCalculator.CalculateDerivative(
        string[] symbols,
        decimal[] parameters,
        string[] functions)
    {
        WindowsIdentity identity =
                ServiceSecurityContext.Current.WindowsIdentity;
        if (identity != null)
        {
            string name = identity.Name;
            if (!(string.IsNullOrEmpty(name)))
            {
                Console.WriteLine("User is {0}.", name);
            }
        }
        return new Calculator().CalculateDerivative(
            symbols, parameters, functions);
    }
    
  9. Choose Build, Build Solution from the Visual Studio 2005 menus.

  10. Execute TransportSecurityHostinHost.exe.

  11. Execute TransportSecurityClientinClient.exe. In doing so, it would be more effective to right-click on the executable, choose Run As from the context menus that appears, and opt to run the application with the credentials of some user who has permission to log in locally, but who is not the user that is currently logged in.

  12. When the output in the console of the Host application signifies that the service is ready, enter a keystroke into the console of the Client application. The Client application will display results retrieved, first via communication with SSL over HTTP with the service provided by the Host application, and then via communication with SSL over TCP with the same service, and finally via communication with SSL over HTTP with the service hosted in IIS. For cases in which the client is using SSL over HTTP, the client is configured to present credentials to the service, so the output in the console for the Host application will identify the user under whose account the Client application was run.

  13. Close both consoles.

Using Message Security

Message security is the default option for securing messages with all the Windows Communication Foundation’s predefined bindings with one exception: the BasicProfileBinding. Message security is not an option at all with the BasicProfileBinding because that binding implements the WS-I Basic Profile 1.1, which makes no provision for message security.

The WS-Security specification provides a basis for the message security facilities of the Windows Communication Foundation. That specification defines a way of incorporating into SOAP (Simple Object Access Protocol) messages information that can be used to authenticate the senders. The specification also defines how SOAP messages can be encrypted to preserve their confidentiality. The specification provides, too, for the sender of a SOAP message signing the message with a private key so that the receiver can validate the integrity of the message by reproducing the signature from the contents of the message with the sender’s public key.

The Windows Communication Foundation also implements the WS-SecureConversation protocol. That protocol defines how the senders and receivers of SOAP messages can use WS-Security to negotiate the use of session-specific keys for securing their substantive messages.

Here are some steps to follow to see how to make use of the Windows Communication Foundation’s message security capabilities:

  1. Open the Visual Studio 2005 solution, MessageSecurity.sln, in the folder WCFHandsOnSecurityBasicsMessageSecurity. This solution consists of a derivatives calculator service like the one constructed in Chapter 2, as well as a .NET console application for hosting that service, and another .NET console application to serve as the client.

  2. Examine the code in the static Main() function in the Program.cs file of the Client project of the MessageSecurity solution. It has the client invoke the derivatives calculator service twice, using a different endpoint each time. In calling the second endpoint, it offers credentials in the form of a username and password:

    decimal result = 0;
    using (DerivativesCalculatorClient proxy =
        new DerivativesCalculatorClient("DerivativesCalculatorServiceWindows"))
    {
        proxy.Open();
        result = proxy.CalculateDerivative(
        [...]
        proxy.Close();
    }
    [...]
    using (DerivativesCalculatorClient proxy =
        new DerivativesCalculatorClient("DerivativesCalculatorServiceUserName"))
    {
        proxy.ClientCredentials.UserName.UserName = @"don";
        proxy.ClientCredentials.UserName.Password = @"hall";
        proxy.Open();
        result = proxy.CalculateDerivative(
        [...]
        proxy.Close();
    }
    
  3. Look at the app.config file of the Client project in the MessageSecurity solution to see how the first endpoint is configured. The pertinent elements of the configuration are reproduced in Listing 7.5. The endpoint is configured to use the predefined WSHttpBinding. That binding provides message security by default, using Kerberos or NTLM credentials to identify the senders, to sign and encrypt the messages, and to negotiate session-specific keys for a secure conversation.

    Example 7.5. Client Configuration for Message Security with Windows Credentials

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <system.serviceModel>
       <client>
         <endpoint
           address="http://localhost:8000/Derivatives/Calculator"
           binding="wsHttpBinding"
           contract="DerivativesCalculator.IDerivativesCalculator"
           name="DerivativesCalculatorServiceWindows"/>
       </client>
      </system.serviceModel>
    </configuration>
    
  4. Also examine the app.config file of the Client project in the MessageSecurity solution to see how the second endpoint is configured, the endpoint for which a username and password are provided. The relevant portions of the configuration are in Listing 7.6. The predefined WSHttpBinding is used once again, but this time it is customized so as to present for authentication what the WS-Security specification refers to as a UsernameToken: a combination of a username and password (Kaler 2002). Because passing the username and password credentials unencrypted from the client to the service would compromise their security, the Windows Communication Foundation requires that whenever usernames and passwords are used for authentication, the service must provide an X.509 certificate for encrypting them or be configured to use transport security. The behavior that is incorporated into the configuration in Listing 7.6 waives the check that the Windows Communication Foundation would otherwise perform automatically to determine whether the certificate offered by the service had been revoked by the issuer.

    Example 7.6. Client Configuration for Message Security with a Username and Password

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
          <system.serviceModel>
                <client>
                      <endpoint
                            address=
    "http://FabrikamEnterprises:8000/Derivatives/AnotherCalculator"
                    binding="wsHttpBinding"
                    bindingConfiguration="SecureMessageUserName"
                    behaviorConfiguration="UserName"
                            contract="DerivativesCalculator.IDerivativesCalculator"
                            name="DerivativesCalculatorServiceUserName"/>
               </client>
               <bindings>
                     <wsHttpBinding>
                           <binding name="SecureMessageUserName">
                                 <security mode="Message">
                                       <message clientCredentialType="UserName"/>
                                 </security>
                           </binding>
                     </wsHttpBinding>
               </bindings>
               <behaviors>
                   <endpointBehaviors>
                           <behavior name="UserName">
                                <clientCredentials>
                                      <serviceCertificate>
                                            <authentication
                                                     revocationMode="NoCheck"/>
                                      </serviceCertificate>
                                </clientCredentials>
                           </behavior>
                   </endpointBehaviors>
               </behaviors>
          </system.serviceModel>
    </configuration>
    
  5. Look in the app.config file of the Host project of the MessageSecurity solution to see how the service endpoint that uses Kerberos or NTLM credentials to identify the users of clients is configured. The pertinent elements of that configuration are shown in Listing 7.7. The endpoint is simply configured to use the predefined WSHttpBinding, which, by default, anticipates users presenting Kerberos or NTLM to identify themselves.

    Example 7.7. Service Endpoint Configuration for Message Security with Windows Credentials

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.serviceModel>
       <services>
         <service
    name="DerivativesCalculator.DerivativesCalculatorServiceType">
            <endpoint
              address="Calculator"
              binding="wsHttpBinding"
              contract="DerivativesCalculator.IDerivativesCalculator"/>
            <host>
              <baseAddresses>
                <add
                  baseAddress="http://localhost:8000/Derivatives/"/>
              </baseAddresses>
            </host>
          </service>
        </services>
       </system.serviceModel>
    </configuration>
    
  6. Also examine the app.config file of the Host project to see how the service endpoint that employs username and password combinations to identify the users of clients is configured. The relevant parts of the configuration are in Listing 7.8. This configuration also uses the predefined WSHttpBinding, but customizes it to use usernames and passwords to authenticate the users of clients, rather than Kerberos or NTLM credentials. A behavior is used to specify that the FabrikamEnterprises certificate is the certificate that the server is to provide for encrypting the transmission of username and password combinations from the client to the service. The behavior also specifies that a custom class for validating username and password combinations will be used, and identifies that class as the DerivativesCalculator.MyUserNamePasswordValidator class in the Host assembly. Ordinarily, the Windows Communication Foundation validates user names and passwords against Windows account information, but the option of identifying a custom class to validate those credentials against some other store is provided.

    Example 7.8. Service Endpoint Configuration for Message Security with a Username and Password

    <?xml version="1.0" encoding="utf-8" ?>
      <configuration>
        <system.serviceModel>
          <services>
            <service
              name="DerivativesCalculator.DerivativesCalculatorServiceType"
              behaviorConfiguration="DerivativesCalculatorService">
              <endpoint
                address="AnotherCalculator"
                binding="wsHttpBinding"
                bindingConfiguration="SecureMessageUserName"
                contract="DerivativesCalculator.IDerivativesCalculator"/>
              <host>
                <baseAddresses>
                  <add
                    baseAddress="http://localhost:8000/Derivatives/"/>
                </baseAddresses>
              </host>
            </service>
          </services>
          <bindings>
            <wsHttpBinding>
              <binding name="SecureMessageUserName">
                <security mode="Message">
                   <message clientCredentialType="UserName"/>
                </security>
              </binding>
            </wsHttpBinding>
          </bindings>
          <behaviors>
            <serviceBehaviors>
              <behavior name="DerivativesCalculatorService">
                <serviceCredentials>
                  <userNameAuthentication
                    userNamePasswordValidationMode="Custom"
                    customUserNamePasswordValidatorType=
    "DerivativesCalculator.MyUserNamePasswordValidator,Host"/>
                      <serviceCertificate
                        findValue="CN=FabrikamEnterprises"/>
                </serviceCredentials>
              </behavior>
            </serviceBehaviors>
          </behaviors>
       </system.serviceModel>
    </configuration>
    
  7. Look at the code for the custom class for validating user names and passwords in the MyUserNamePasswordValidator file of the Host project. The class derives from the abstract base, System.IdentityModel.Selectors.UserNamePasswordValidator, and overrides that base class’s sole abstract method, Validate(). That method is passed the username and password offered by the client. If the validation of the credentials fails, the Validate() method is expected to throw a System.IdentityModel.Tokens.SecurityTokenException. Otherwise, the client is presumed to have been authenticated by the credentials.

    public class MyUserNamePasswordValidator : UserNamePasswordValidator
    {
        public override void Validate(string userName, string password)
        {
            if ([...])
            {
                throw new SecurityTokenException("Unknown user.");
            }
            Console.Write("Credentials accepted. 
    ");
        }
    }
    
  8. Study the code of the service type, which is in the DerivativesCalculatorServiceType file of the DerivativesCalculatorService project. As the following snippet shows, if the credentials offered by the user map to a Windows account, the service prints out the name of the user of the client before responding to the client’s request.

    decimal IDerivativesCalculator.CalculateDerivative(
        string[] symbols,
        decimal[] parameters,
        string[] functions)
    {
        WindowsIdentity identity = ServiceSecurityContext.Current.WindowsIdentity;
        if (identity != null)
        {
            string name = identity.Name;
            if (!(string.IsNullOrEmpty(name)))
            {
                Console.WriteLine("User is {0}.", name);
            }
        }
        return new Calculator().CalculateDerivative(
            symbols, parameters, functions);
    }
    
  9. Choose Build, Build Solution from the Visual Studio 2005 menus.

  10. Execute MessageSecurityHostinHost.exe.

  11. Execute MessageSecurityClientinClient.exe. Once again, it would be more effective to do so under a different account from the one that is currently logged-in. To do so, right-click on the executable, choose Run As from the context menus that appears, and run the application with the credentials of some user who has permission to log in locally, but who is not the user that is currently logged in.

  12. When the output in the console of the Host application signifies that the service is ready, enter a keystroke into the console of the Client application. The Client application will display results retrieved, first after offering Windows credentials to the service, and then after offering a username and password combination. In the first case, in which the client offers Windows credentials, the output in the console for the Host application will identify the user under whose account the Client application was executed.

  13. Close both consoles.

Impersonation and Authorization

Earlier it was explained that the Windows Communication Foundation’s Channel Layer does the work of entity authentication, ensuring the confidentiality of messages, and confirming their integrity, whereas the Service Model layer on the receiving side does the authorization and the impersonation. Then various options were demonstrated for configuring Windows Communication Foundation bindings to control how the Channel Layer authenticates clients, and preserves the confidentiality and integrity of messages. Now the Service Model’s facilities for impersonation and authorization will be shown.

Impersonation

Impersonation is possible only when the user of the client has been authenticated as a Windows user—when that user’s Windows account has been identified. In addition, the client must have been configured to grant permission to the service to impersonate the user of the client. To see a Windows service impersonate the user of a client application, follow these steps:

  1. Open the Visual Studio 2005 solution, Impersonation.sln, in the folder WCFHandsOnSecurityBasicsImpersonation. Like the solutions used earlier in this chapter, this one contains a .NET console application that uses a derivatives calculator service. That service is hosted, as usual, within a .NET console application called Host. However, the service actually delegates its work of calculating the values of derivatives to another derivatives calculator service hosted by a second .NET console application, which is called BackOfficeHost.

  2. See how the client is configured by examining the app.config file in the Client project of the Impersonation solution. The configuration is shown in Listing 7.9. It incorporates a behavior associated with the endpoint that grants the service permission to impersonate the user of the client. The binding specified for the endpoint is the predefined WSHttpBinding, which by default will identify the user of the client to the service using Windows credentials.

    Example 7.9. Client Configuration to Permit Impersonation

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <system.serviceModel>
        <client>
          <endpoint
            address="http://localhost:8000/Derivatives/Calculator"
            binding="wsHttpBinding"
            contract="DerivativesCalculator.IDerivativesCalculator"
            behaviorConfiguration="Windows"
            name="DerivativesCalculatorServiceWindows"/>
        </client>
        <behaviors>
          <endpointBehaviors>
            <behavior name="Windows">
              <clientCredentials>
                <windows
                  allowedImpersonationLevel="Impersonation"/>
              </clientCredentials>
            </behavior>
          </endpointBehaviors>
        </behaviors>
      </system.serviceModel>
    </configuration>
    
  3. Look at the code of the derivatives calculator service hosted by the Host application. The code for that service is in the DerivativesCalculatorServiceType.cs file in the Host project of the solution. The important parts of the code are in Listing 7.10. This code handles requests from the client, and delegates them to the derivatives calculator service hosted by the BackOfficeHost. The key element of the code is the Impersonation parameter passed to the System.ServiceModel.OperationBehavior attribute. The value of that parameter is set to System.ServiceModel.ImpersonationOption.Required, which signifies that the operation needs to impersonate the user of the client to access resources that it needs. Therefore, the binding of any endpoint that incorporates a contract implemented using this operation must have clients present Windows credentials for the service to authenticate their users because impersonation is possible only when the user of the client has been authenticated as a Windows user. If the binding does not conform to this requirement, the service will not start. Furthermore, in order for a client to invoke this operation through the Windows Communication Foundation, the client must permit the service to impersonate the user of the client.

    Example 7.10. Having a Service Operation Impersonate a Client User

    [OperationBehavior(Impersonation=ImpersonationOption.Required)]
    decimal IDerivativesCalculator.CalculateDerivative(
        string[] symbols,
        decimal[] parameters,
        string[] functions)
    {
        [...]
    
        decimal result = 0;
        using (DerivativesCalculatorClient proxy =
            new DerivativesCalculatorClient("BackOfficeDerivativesCalculator"))
        {
            proxy.Open();
            result = proxy.CalculateDerivative(
                new string[] { "MSFT" },
                new decimal[] { 3 },
                new string[] { });
            proxy.Close();
        }
        return result;
    }
    
  4. Check how the service hosted by the Host application is configured to use the service that is hosted by the BackOfficeHost application. The configuration is in the app.config file of the Host project, and shown in the following snippet. The predefined WSHttpBinding is used, which, by default, will offer Windows credentials to authenticate the caller. In this case, the intermediary service will be offering the Windows credentials of the user of its own client, who it will be impersonating.

    <client>
          <endpoint
                address="http://localhost:8020/Derivatives/Calculator"
                   binding="wsHttpBinding"
                contract="DerivativesCalculator.IDerivativesCalculator"
                name="BackOfficeDerivativesCalculator"/>
    </client>
    
  5. Look at the code of the derivatives calculator service hosted by the BackOfficeHost application. That code is in the DerivativesCalculatorServiceType.cs file of the BackOfficeHost project. The pertinent elements are in this next snippet. The CalculateDerivative() method that will be invoked by the intermediary service hosted by the Host application has a System.Security.Permissions.PrincipalPermission attribute that restricts access to one particular user.

    [PrincipalPermission(
          SecurityAction.Demand,
          Name = @"ws2k3r2082006DonHall")]
    [OperationBehavior(Impersonation=ImpersonationOption.Allowed)]
    decimal IDerivativesCalculator.CalculateDerivative(
          string[] symbols,
          decimal[] parameters,
          string[] functions)
    {
          [...]
          return new Calculator().CalculateDerivative(
                symbols, parameters, functions);
    }
    
  6. Modify the System.Security.Permissions.PrincipalPermission attribute so that the name specified for the sole authorized user is that of a valid user on the computer that has been granted the right to log on locally, but is not the user that is currently logged on.

  7. Choose Build, Build Solution from the Visual Studio 2005 menus.

  8. Choose Debug, Start Debugging from the Visual Studio 2005 menus to start the Host application and the BackOfficeHost application.

  9. Execute ImpersonationClientinClient.exe, and do so as the user that was selected as the sole user permitted to access the service hosted by the BackOfficeHost in step 6. Right-click on ImpersonationClientinClient.exe, choose Run As from the context menus, and select that user on the Run As dialog and enter that user’s credentials.

  10. When the output in the consoles of the Host and BackOfficeHost applications indicates that the services hosted by those applications are available, enter a keystroke in the console of the Client application. The Client application should request that the service hosted by the Host application calculate the value of a derivative. That service should delegate the work of doing the calculation to the service hosted by the BackOfficeHost application, and the Client application should get a response. Evidently, the intermediary service hosted by the Host application is impersonating the user of the Client application because no other user is authorized to use the service Hosted by the BackOfficeHost application.

  11. Close the consoles of all three applications.

Authorization

In addition to showing how to have the Windows Communication Foundation do impersonation, the foregoing exercise has also demonstrated the first option that the Windows Communication Foundation provides for authorization. That option is to add System.Security.Permissions.PrincipalPermission attributes to the methods by which the operations of a service are implemented. Those attributes can restrict access to individual users, or, as they are more commonly employed, to restrict access to users in particular roles.

By default, the roles referred to by System.Security.Permissions.PrincipalPermission attributes are, in fact, Windows groups, rather than application-specific roles. So, the management of authorization for an application gets tied to the assignment of Windows users to groups, which is awkward. The Windows Communication Foundation allows that problem to be circumvented using Role Providers.

Role Providers where introduced in Chapter 1, “Prerequisites.” Listing 7.11 shows the configuration of a Windows Communication Foundation service that has been configured to use a Role Provider to evaluate role membership requirements specified in System.Security.Permissions.PrincipalPermission attributes.

Example 7.11. Configuring a Service to Use a Role Provider

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service
name="DerivativesCalculator.DerivativesCalculatorServiceType"
        behaviorConfiguration="Authorization" >
        <endpoint
          address="Calculator"
          binding="wsHttpBinding"
          contract="DerivativesCalculator.IDerivativesCalculator"
         />
        <host>
          <baseAddresses>
            <add
            baseAddress="http://localhost:8000/Derivatives/" />
            <add
            baseAddress="net.tcp://localhost:8010/Derivatives/"/>
          </baseAddresses>
       </host>
       </service>
     </services>
     <behaviors>
       <serviceBehaviors>
         <behavior name="Authorization">
           <serviceAuthorization
principalPermissionMode="UseAspNetRoles"
roleProviderName="AuthorizationStoreRoleProvider" />
          </behavior>
        </serviceBehaviors>
      </behaviors>
    </system.serviceModel>
    <system.web>
    <roleManager
      defaultProvider="AuthorizationStoreRoleProvider"
      maxCachedResults="0"
      enabled="true"
      cacheRolesInCookie="false"
      cookieName=".ASPROLES"
      cookieTimeout="1"
      cookiePath="/"
      cookieRequireSSL="false"
      cookieSlidingExpiration="true"
      cookieProtection="All" >
    <providers>
      <clear />
      <add
        name="AuthorizationStoreRoleProvider"
        type="System.Web.Security.AuthorizationStoreRoleProvider"
        connectionStringName="AuthorizationServices"
        cacheRefreshInterval="1"
        applicationName="RoleProvider" />
     </providers>
    </roleManager>
   </system.web>
   <connectionStrings>
    <add
      name="AuthorizationServices"
      connectionString=
"msxml://C:WCFHandsOn[...]AuthorizationStore.xml" />
    </connectionStrings>
</configuration>

A set of behaviors with the arbitrary name Authorization is associated with the service. That set of behaviors includes a System.ServiceModel.Description.ServiceAuthorization behavior that is configured so that its PrincipalPermissionMode property is assigned the value System.ServiceModel.Description.PrincipalPermissionMode.UseAspNetRoles. Its RoleProviderName property is assigned the name of a Role Provider that is defined elsewhere in the configuration and in the way that Role Providers are usually defined. By virtue of this configuration, the service would use the specified Role Provider to evaluate the role membership requirements of System.Security.Permissions.PrincipalPermission attributes like the one applied to this operation:

[PrincipalPermission(SecurityAction.Demand, Role = "QuantitativeAnalyst")]
decimal IDerivativesCalculator.CalculateDerivative(
    string[] symbols,
    decimal[] parameters,
    string[] functions)
{
    return new Calculator().CalculateDerivative(
        symbols, parameters, functions);
}

The role identified by the attribute need not be a Windows group. It refers to a role that the Role Provider will look for in whatever store it uses as a repository for role information. Because the Role Provider that is identified by the configuration happens to be of the System.Web.Security.AuthorizationStoreRoleProvider class, that Role Provider will be looking for the role and the users assigned to it in an Authorization Manager authorization store. The particular Authorization Manager authorization store that will be queried is identified by the connection string that is also included in the configuration. Administrators could use the Authorization Manager Management Console snap-in to control which users are assigned to the role.

The option of using Role Providers to evaluate authorization demands expressed by System.Security.Permissions.PrincipalPermission attributes offers the flexibility of defining authorization requirements in terms of roles that may be defined in any repository of role information—not just in terms of membership in Windows groups. Still, any reliance on System.Security.Permissions.PrincipalPermission attributes for authorization has shortcomings. Because the System.Security.Permissions.PrincipalPermission attributes are in the code for the application, that code has to be modified to widen authorization to include users in additional roles or to restrict authorization to users in a smaller number of roles. In addition, System.Security.Permissions.PrincipalPermission attributes can only be used to evaluate the authorization of Windows accounts.

The Windows Communication Foundation offers a far better way of authorizing access than System.Security.Permissions.PrincipalPermission attributes can provide. To explore that option, follow these steps:

  1. Open the Visual Studio 2005 solution, Authorization.sln, in the folder WCFHandsOnSecurityBasicsAuthorization. The solution contains a .NET console application called Client that uses a derivatives calculator service hosted within another .NET console application called Host. The solution also contains a class library called CustomServiceAuthorizationManager.

  2. Notice that the definition of the service’s contract, which is in the IDerivativesCalculator.cs file of both the Host and Client projects, exercises the option of explicitly providing a value for the Action parameter of the sole System.ServiceModel.OperationContract attribute applied to any of its methods:

    [OperationContract(
        Action = "CalculateDerivative")]
    decimal CalculateDerivative(
        string[] symbols,
        decimal[] parameters,
        string[] functions);
    

    Whatever value is assigned to the Action parameter of a System.ServiceModel.OperationContract attribute must serve to uniquely identify the method to which the attribute is applied relative to the other methods of the service type. The reason is that the Windows Communication Foundation determines to which method of a service a message is to be directed by matching the Action header of the message to the value of the Action parameter of the method’s System.ServiceModel.OperationContract attribute.

  3. Look at how the client is configured by examining the app.config file of the Client project. The configuration is like the one shown in Listing 7.6, so the client will offer a username and password for the service to use for authentication.

  4. Study the app.config file of the Host project to see how the service is configured. It is reproduced in Listing 7.12. The service is configured with a set of behaviors that has the arbitrary name DerivativesCalculatorService. That set includes a System.ServiceModel.Description.ServiceCredentials behavior with its UserNameAuthentication property set to authenticate the credentials provided by the client using a custom validation routine rather than simply validating the credentials against Windows account information. Therefore, however authorization will be accomplished in this case, the mechanism must not be one that is restricted to use with Windows accounts.

    How authentication is to be accomplished is defined by another behavior in the set, the System.ServiceModel.Description.ServiceAuthorization behavior. That behavior is configured to ignore any System.Security.Permissions.PrincipalPermission attributes that exist in the code, by virtue of having the value System.ServiceModel.Description.PrincipalPermissionMode.None assigned to its PrincipalPermissionMode property. The behavior also has a type assigned to its ServiceAuthorizationManagerType property. Any type assigned as the value of System.ServiceModel.Description.ServiceAuthorization behavior’s ServiceAuthorizationManagerType property must derive from System.ServiceModel.ServiceAuthorizationManager. The type that is assigned in this case is the DerivativesCalculator.MyServiceAuthorizationManager type in the CustomServiceAuthorizationManager assembly.

    Example 7.12. Service Configuration

    <?xml version="1.0" encoding="utf-8" ?>
       <configuration>
         <system.serviceModel>
           <services>
             <service
    name="DerivativesCalculator.DerivativesCalculatorServiceType"
              behaviorConfiguration="DerivativesCalculatorService">
            <endpoint
              address="Calculator"
             binding="wsHttpBinding"
             bindingConfiguration="SecureMessage"
             contract="DerivativesCalculator.IDerivativesCalculator"/>
             <host>
               <baseAddresses>
                 <add
                   baseAddress="http://localhost:8000/Derivatives/" />
                 <add
                   baseAddress="net.tcp://localhost:8010/Derivatives/" />
               </baseAddresses>
             </host>
           </service>
         </services>
         <bindings>
           <wsHttpBinding>
             <binding name="SecureMessage">
               <security mode="Message">
                  <message clientCredentialType="UserName"/>
               </security>
             </binding>
           </wsHttpBinding>
          </bindings>
          <behaviors>
            <serviceBehaviors>
              <behavior name="DerivativesCalculatorService">
                <serviceCredentials>
                <userNameAuthentication
                  userNamePasswordValidationMode="Custom"
                  customUserNamePasswordValidatorType=
    "DerivativesCalculator.MyUserNamePasswordValidator,Host"/>
                <serviceCertificate
                  findValue="CN=FabrikamEnterprises"/>
                </serviceCredentials>
                <serviceAuthorization
                  principalPermissionMode="None"
                  serviceAuthorizationManagerType=
    "DerivativesCalculator.MyServiceAuthorizationManager,
    [ic:ccc] CustomServiceAuthorizationManager"/>
                <serviceMetadata
                  httpGetEnabled="true" />
            </behavior>
          </serviceBehaviors>
        </behaviors>
       </system.serviceModel>
    </configuration>
    
  5. Look at the assemblies referenced by the Host project in the Authorization solution. An assembly called CustomServiceAuthorizationManager is not among them.

  6. Look at the assemblies deployed in the same directory as the Host.exe assembly that is built from the Host project. That directory should be the WCFHandsOnSecurityBasicsAuthorizationHostin directory, and it contains an assembly called CustomServiceAuthorizationManager. The CustomServiceAuthorizationManager project in the solution is configured to copy the assembly that it builds into that directory. So, evidently, the reference in the configuration of the service to the DerivativesCalculator.MyServiceAuthorizationManager type in the CustomServiceAuthorizationManager assembly could be a reference to a type in any assembly that the .NET common language runtime loader can locate.

  7. Study the code of the class that is assigned as the value, in the configuration of the service, to the ServiceAuthorizationManagerType property of the System.ServiceModel.Description.ServiceAuthorization behavior. That code is in the MyServiceAuthorizationManager.cs file of the CustomServiceAuthorizationManager project. It is reproduced in Listing 7.13. The code defines a type that derives from System.ServiceModel.ServiceAuthorizationManager and overrides its virtual CheckAccess() method. Because the type has been assigned as the value of the ServiceAuthorizationManagerType property of the System.ServiceModel.Description.ServiceAuthorization behavior, its CheckAccess() override will be invoked whenever the service type with which the behavior is associated receives a request. The CheckAccess() method is passed a System.ServiceModel.OperationContext object that conveys information about the request. In particular, the code for the method can use the System.ServiceModel.OperationContext object to ascertain which operation will be executed in response to the request, and everything that is known about the user on whose behalf the request was sent. This expression yields the Action header of the message that identifies the operation to be executed:

    operationContext.IncomingMessageHeaders.Action
    

    This expression retrieves the information about the user:

    operationContext.ServiceSecurityContext.AuthorizationContext.ClaimSets
    

    That information is in the form of a collection of System.IdentityModel.Claim.ClaimSet objects, and each of the objects in that collection consists of an array of System.IdentityModel.Claim.Claim objects, each of which represents some claim made about the user. Based on the operation that is to be executed, and based on what is known about the user, the code for the CheckAccess() method decides whether the user is authorized to have the operation executed. If the user is authorized, the CheckAccess() method returns true, and otherwise it returns false.

    Example 7.13. ServiceAuthorizationManager Implementation

    public class MyServiceAuthorizationManager: ServiceAuthorizationManager
    {
        public override bool CheckAccess(OperationContext operationContext)
        {
            if (string.Compare(
                      operationContext.IncomingMessageHeaders.Action,
                      "CalculateDerivative",
                      true) == 0)
            {
    
                ReadOnlyCollection<ClaimSet> claimSets =
    operationContext.ServiceSecurityContext.AuthorizationContext.ClaimSets;
    
                ClaimSet claimSet = claimSets[0];
                foreach (Claim claim in claimSet)
                {
                     if(string.Compare(
                       claim.ClaimType,
                       ClaimTypes.Name,
                       true)==0)
                     {
                         if (string.Compare(
                       claim.Right,
    "http://schemas.xmlsoap.org/ws/2005/05/identity/right/identity",
                       true) == 0)
                         {
                             if (string.Compare(
                             (string)claim.Resource,
                             "don",
                             true) == 0)
                             {
                                  return true;
                             }
                         }
                     }
                }
            }
            return false;
        }
    }
    
  8. Choose Debug, Start Debugging from the Visual Studio 2005 menus.

  9. When the output in the console of the Host application confirms that the service is ready, enter a keystroke into the console of the Client application. The Client application should retrieve the value of a derivative from the service. It does so by offering a username and password to the service that the service authenticates using its custom validation routine. After authenticating the credentials proferred by the client, the service authorizes access to the derivatives calculation routine based on information from the authenticated credentials.

  10. Choose Debug, Stop Debugging from the Visual Studio 2005 menus to terminate the applications.

The authorization mechanism seen at work in the preceding steps is, in its simplicity and its power, a key innovation of the Windows Communication Foundation. It is the core of the Windows Communication Foundation’s Extensible Security Infrastructure (XSI).

XSI is conceptually very simple indeed. Whatever a client offers to a service to authenticate its user is considered to be credentials, and credentials consist of a number of claims made about the user of the client application by the issuer of the credentials. In the process of authentication, whatever form the credentials might take, the Windows Communication Foundation does two primary things: It decides whether it trusts the issuer of the credentials, and, if it does, it converts the credentials into a list of claims. Those claims can then be examined by a type that derives from System.ServiceModel.ServiceAuthorizationManager. That type can determine whether to authorize access by comparing the claims extracted from the credentials to the access requirements.

This simple solution for authorization is extremely powerful for several reasons. First, the same solution works regardless of the type of credentials used and irrespective of how those credentials are authenticated. In the case illustrated above, the user was authenticated from credentials consisting of a username and password by a custom routine that decided it trusted the issuer of those credentials—which was simply the user of the client application—because the password matched the username. The claim yielded from those credentials was a claim about the user’s username. If the authentication mechanism was reconfigured so that the client offered Kerberos credentials instead, the authentication process would involve confirming that those credentials were issued by a trusted domain controller. In that case, the claims yielded from the credentials would be claims about the user’s Windows security identifiers. Yet, whatever type of credentials are offered and however those credentials are authenticated, authenticated credentials are transformed into a list of claims that can be evaluated during the authorization process. The significance of this feat that XSI accomplishes becomes even more impressive when it is considered that the Windows Communication Foundation supports an unlimited variety of types of credentials. Among the types of credentials for which the Windows Communication Foundation provides inherent support are Kerberos credentials, NTLM credentials, username tokens, Security Assertion Markup Language (SAML) tokens, Windows CardSpace credentials, and X.509 certificates. However, the System.ServiceModel.Description.ClientCredentials class can be extended to accommodate additional types of credentials.

A second reason that XSI’s authorization system is so powerful is because the code that does the authorization for the service can be connected to the service through configuration. Whereas System.Security.Permissions.PrincipalPermission attributes get embedded in the code for the service so that widening or narrowing the access requirements might require changes to the service’s code and recompilation, the System.ServiceModel.ServiceAuthorizationManager type that a service is to use for authorization can be identified through configuration. Moreover, that type does not have to be in the service’s assembly or in any assembly referenced in the compilation of the service’s assembly. The type can be in any assembly that the .NET common language runtime loader can find on behalf of the Windows Communication Foundation at runtime. Therefore, changes can be made to the authorization process without the code for the service having to be modified or even recompiled.

A third reason that XSI’s authorization system is impressively powerful is that it does not restrict the definition of trusted issuers of credentials in any way. Whereas System.Security.Permissions.PrincipalPermission attributes are limited to evaluating access based on Kerberos or NTLM credentials, and the boundary of trusted issuers for those extends no further than the boundary of trust of the domain, XSI is not restricted to accepting credentials issued within the boundary of trust of the domain. It allows for more flexible definitions of trust. Therefore, it can provide the foundation for federated security, a prospect that will be explored further in the other chapters in this section.

Reversing the Changes to Windows

This chapter opened with some instructions for installing sample certificates, for configuring IIS and HTTP.SYS for SSL, and for configuring an identity for the server. Examples in some subsequent chapters will require those same steps to be executed, so one might choose not to reverse those steps right away. However, restoring Windows to its original security configuration after working through all of the examples in the book would be advisable.

Uninstalling the Certificates

Follow these steps to uninstall the certificates:

  1. Open the Microsoft Management Console by choosing Run from the Windows Start menus and entering

    mmc
    
  2. Choose File, Add/Remove Snap-In from the Microsoft Management Console menus.

  3. Click Add on the Add/Remove Snap-In dialog that opens.

  4. Choose Certificates from the list of available standalone snap-ins presented and click the Add button.

  5. Select Computer Account on the Certificates snap-in dialog and click the Next button.

  6. Accept the default on the Select Computer dialog and click the Finish button.

  7. Click the Close button on the Add Standalone Snap-In dialog.

  8. Click the OK button on the Add/Remove Snap-In dialog.

  9. Expand the Certificates node that now appears in the left panel of the Microsoft Management Console.

  10. Expand the Personal child-node of the Certificates node.

  11. Select the Certificates child-node of the Personal node.

  12. Select the FabrikamEnterprises certificate that should now have appeared in the right panel, and press the Delete key.

  13. If a confirmation dialog appears, click Yes.

  14. Select the Woodgrove certificate in the right panel, and press the Delete key.

  15. If a confirmation dialog appears, click Yes.

  16. In the left panel, Expand the Trusted Root Certification Authorities child node of the Certificates node.

  17. Select the Certificates child-node of the Trusted Root Certification Authorities node.

  18. Locate and select the Root Agency node in the right panel, and press the Delete key.

  19. If a configuration dialog appears, click Yes.

  20. Close the Microsoft Management Console.

Removing the SSL Configuration from IIS

To remove the SSL configuration from IIS do as follows:

  1. Choose Control Panel, Administrative Tools, Internet Information Services (IIS) Manager from the Windows Start menus.

  2. Expand the nodes of the tree control in the left pane until the node named Default Web Site becomes visible.

  3. Right-click on that node and choose Properties from the context menus that appear.

  4. Select the Directory Security tab.

  5. Click the Server Certificate button.

  6. Click Next on the first dialog of the Web Service Certificate Wizard.

  7. Select Remove the Current Certificate and click Next.

  8. Click Next on the Remove a Certificate dialog.

  9. Click Finish to complete the Wizard.

  10. Click OK on the Web Site Properties dialog.

  11. Close the IIS Manager.

Removing the SSL Configuration from HTTP.SYS

Follow these instructions to remove the SSL configuration from HTTP.SYS. The easiest tool to use to configure HTTP.SYS is Steve Johnson’s HTTP configuration utility, which has a graphical user interface. His utility is available at http://www.StevesTechSpot.com. Follow these instructions to use that tool to identify the certificate that HTTP.SYS is to use for SSL exchanges:

  1. Start the HTTP Configuration Utility available from http://www.StevesTechSpot.com.

  2. Choose the SSL Certs tab.

  3. Select the entry for IP address 127.0.0.1 and port 8020 and click the Remove button.

  4. Click OK on the main window of the HTTP Configuration Utility to close it.

Restoring the Identity of the Server

To restore the identity of the server, follow these steps:

  1. Use Notepad to open the hosts file in the System32driversetc subfolder of the system directory.

  2. Delete the line

    127.0.0.1 fabrikamenterprises
    
  3. Save the hosts file.

  4. Close the hosts file.

Summary

The basic tasks involved in securing communications are entity authentication, assuring the confidentiality, integrity and nonrepudiability of transmissions, potentially impersonating the source, and authorizing access. The Windows Communication Foundation can rely on SSL for entity authentication, confidentiality, integrity, and nonrepudiability—an option referred to as transport security. It can also accomplish those tasks using the mechanisms defined by the WS-Security specification. That option is referred to as message security. When the source of a transmission is authenticated as a Windows user, the Windows Communication Foundation can have a service impersonate that user, provided the client grants permission for the service to do so. For authorization, the Windows Communication Foundation supports the use of the System.Security.Permissions.PrincipalPermission attributes that were introduced in the very first version of the .NET Framework. However, the Windows Communication Foundation’s alternative XSI mechanism for authentication, although simple to use, is much more flexible.

References

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset