When I introduced this column last month I also provided an introduction to WCF as the new Web services technology to succeed ASP.NET Web services (ASMX) and Web Services Enhancements (WSE) now that .NET 3.0 has been released. In this column I ll help you make sense of the various HTTP bindings that WCF provides to support interoperable Web services. (For a backgrounder on how to create your first WCF Web service see ASP.NET and WCF: Meet Your New Web Service in the February 2007 issue of asp.netPRO.)
Adoption of Web Services Standards
The term Web service has been around since SOAP protocol was introduced in the late 1990s. With SOAP, a standard messaging format was born for exchanging messages between applications exposed to the Internet. An accompanying standard, Web Service Description Language (WSDL), made it possible to describe a list of operations exposed by a particular Web service, and associate an XML schema for operation messages. SOAP and WSDL were the first widely adopted standards geared toward interoperability between operating and technology platforms. Very soon after their introduction a slew of extended standards began to surface all with the goal of enhancing distributed and interoperable communications.
Early implementations of Web services were primarily concerned with interoperability on a basic level. One of the biggest concerns was getting technology platforms to properly agree on how to interpret message schema described by WSDL. Although some complex schema may still unveil incompatibilities, the great majority of Web service stacks interoperate well on this level. In the past several years additional Web services standards have been ratified by the W3C (http://www.w3c.org) and by OASIS (http://www.oasis-open.org) to support message addressing and routing semantics, security, and for the optimized transfer of binary data. Interoperability on many of these standards has begun to stabilize across platforms, as we saw happen with SOAP and WSDL. Beyond these standards, even more standards for advanced security scenarios (reliable messaging and transactions, to name a few) have gained wide industry support and are on the verge of ratification. Despite pending ratification, popular Web services technology platforms have already begun to support these standards for the business value they offer.
Not only have these standards made interoperable communication possible, they have also enabled more reliable and secure distributed communication scenarios over any protocol. Message-based communications can be based on these standards, regardless if they are exposed as interoperable Web services over HTTP or as non-interoperable, proprietary services over named pipes (IPC), TCP, MSMQ, or other transport protocols. This makes it possible to achieve end-to-end reliability and security over any protocol.
WCF was built from the ground-up with this in mind. It supports both ratified and emerging standards, while providing developers with the flexibility to choose which to apply, and over what transport protocol. With WCF, you expose service endpoints by creating a contract, exposing the contract at a particular address, and selecting a set of protocols supported by the endpoint using a binding configuration. Not all WCF services are Web services but they can be configured this way. In this article I ll discuss options for exposing interoperable Web service endpoints with WCF.
Web Services Bindings
In the traditional sense of interoperable Web services exposed over HTTP, WCF provides three standard bindings: BasicHttpBinding, WSHttpBinding, and WSFederationHttpBinding. Collectively, these bindings support a wide range of ratified and emerging Web services standards, including the following: SOAP 1.1 and 1.2; WSDL; WS-Addressing; MTOM; WS-Security; WS-Trust; WS-SecureConversation; SAML 1.0 and 1.1; WS-ReliableMessaging; WS-AtomicTransaction; and WS-Policy, WS-SecurityPolicy, and WS-MetadataExchange. Your choice of WCF binding is a function of the desired protocols for your Web service endpoints.
Another HTTP binding, WSDualHttpBinding, supports duplex communication between client and service. With this binding, two Web service endpoints using WSHttpBinding are exposed one at the service and another at the client to facilitate callbacks or non-durable out-of-band calls from a service. In theory, the messaging for each endpoint is interoperable, but the interaction to initiate duplex communication over HTTP is not part of a standard. Thus, WSDualHttpBinding is not considered an interoperable Web services binding.
In the following sections I ll cover BasicHttpBinding and WSHttpBinding, their support for ratified and emerging standards, and some typical implementation scenarios and configurations.
BasicHttpBinding is primarily useful for exposing WCF service endpoints that are compatible with earlier Web service stacks supporting Basic Profile 1.1, Basic Security Profile 1.0, and MTOM; for example, ASMX and Web Services Enhancements (WSE). Basic Profile is a specification produced by WS-I (http://www.ws-i.org) that provides guidance on how a basic set of Web service specifications such as SOAP 1.1, WSDL 1.0, and related bindings such as HTTP should be applied. Its goal is to constrain the use of these core specifications to agree on a set of messaging scenarios. Basic Security Profile is another set of guidance by WS-I that constrains core messaging scenarios for OASIS Web Service Security (WSS) specifically the SOAP Message Security specification and related token profiles for passing username and password or X.509-based credentials. MTOM is the formally ratified specification for optimizing how opaque data is transmitted with a SOAP message.
You can use BasicHttpBinding to migrate existing ASMX or WSE Web services leveraging these standards. Endpoints exposed over this binding can also be called by other legacy client technologies that don t understand SOAP 1.2 or WS-Addressing headers. Some typical scenarios for BasicHttpBinding include:
- Supporting SOAP 1.1
- UserName token support over SSL
- Mutual certificate authentication
- Sending large messages with MTOM
Supporting SOAP 1.1
BasicHttpBinding always serializes messages in SOAP 1.1 format, so this binding is a natural choice for any communications that should be based on that protocol. To expose a simple service over SOAP 1.1 without any security enabled, use the defaults for BasicHttpBinding, as follows:
<service name="WCFWebServices.NonSecureService"> <endpoint address="Soap11NoSecurity" contract= "WCFWebServices.IWebService"binding="basicHttpBinding"/> </service>
When clients call the service they don t pass any credentials, and messages aren t signed or encrypted which is the same result you get with a vanilla ASP.NET Web service.
UserName Token over SSL
Many Web services today require a username and password for authentication, and SSL for service authentication and message protection. Because BasicHttpBinding is not secure by default, you must customize the binding to achieve this. Set the security mode to TransportWithMessageCredential and change the client credential type to UserName. Most frequently, the service also wants to authenticate and authorize the username and password against a custom database and not the Windows domain. With WCF you associate a set of authentication and authorization behaviors setting userNamePasswordValidationMode and principalPermissionMode to MembershipProvider and UseAspNetRoles, respectively. This tells WCF to use the configured ASP.NET membership and role providers. The complete configuration for this scenario is shown in Figure 1.
<system.serviceModel> <services> <service name="WCFWebServices.UserNameService" behaviorConfiguration="usernameBehavior"> <endpoint address="Soap11UsernameTokenSSL" contract="WCFWebServices.IWebService" binding="basicHttpBinding" bindingConfiguration= "Soap11UsernameTokenSSL"/> </service> </services> <bindings> <basicHttpBinding> <binding name="Soap11UsernameTokenSSL"> <security mode="TransportWithMessageCredential"> <message clientCredentialType="UserName"/> </security> </binding> </basicHttpBinding> </bindings> <behaviors> <serviceBehaviors> <behavior name="usernameBehavior"> <serviceAuthorization principalPermissionMode= "UseAspNetRoles" /> <serviceCredentials> <userNameAuthentication userNamePasswordValidationMode= "MembershipProvider" /> </serviceCredentials> </behavior> </serviceBehaviors> </behaviors> </behaviors> </system.serviceModel>
Figure 1: Service configuration for username over SSL with ASP.NET authentication and authorization.
The IIS Web site hosting this service must have an SSL certificate installed to support this scenario. Clients use an HTTPS endpoint to reach the service, as is reflected in the client endpoint configuration:
<client> <endpoint address="https://localhost/WebServiceHost/ UserNameService.svc/Soap11UsernameTokenSSL" binding="basicHttpBinding" bindingConfiguration= "BasicHttpBinding_WebServiceContract1" contract="WinClient.localhost.WebServiceContract" name="Soap11UsernameTokenSSL"/> </client>
In addition, clients must provide a username and password to the ClientCredentials property of the proxy:
WebServiceContractClient proxy = new WebServiceContractClient("Soap11UsernameTokenSSL"); proxy.ClientCredentials.UserName.UserName = "username"; proxy.ClientCredentials.UserName.Password = "password";
These credentials are serialized in a secure and interoperable fashion according to the UserName Token Profile of OASIS WSS.
With SSL, messages are only protected from point-to-point, with no guarantees of protection all the way through to the application destination if a proxy or intermediary service is present. Using message security to secure transfer protects messages across multiple hops end-to-end but this scenario is not supported by BasicHttpProfile for UserName credentials. To achieve this, you can use WSHttpBinding (which I ll cover shortly).
Mutual Certificate Authentication
Business partners may be required to authenticate using an X.509 certificate, which means enabling mutual certificate authentication between client and service. Clients use a private key to sign outgoing messages and decrypt responses from the service, and they authenticate the service based on their service certificate using their public key to encrypt messages to the service and to authenticate the signature of responses.
OASIS WSS describes how to sign and encrypt messages using security tokens so that the exchange is interoperable and end-to-end. Message security must be enabled to support this scenario, and the service must provide a certificate and require clients to authenticate with certificates. To configure BasicHttpBinding for this, specify Message security mode in the binding configuration, supply a service certificate in the service behavior section, and require Certificate credentials instead of UserName (see Figure 2).
<system.serviceModel> <services> <service name="WCFWebServices.CertificateService" behaviorConfiguration="certificateBehavior"> <endpoint address="Soap11MutualCertificate" contract="WCFWebServices.IWebService" binding="basicHttpBinding" bindingConfiguration= "Soap11MutualCertificate"/> </service> </services> <bindings> <basicHttpBinding> <binding name="Soap11MutualCertificate"> <security mode="Message"> <message clientCredentialType="Certificate"/> </security> </binding> </basicHttpBinding> </bindings> <behaviors> <serviceBehaviors> <behavior name="certificateBehavior"> <serviceAuthorization principalPermissionMode="None"/> <serviceCredentials> <clientCertificate> <authentication certificateValidationMode= "PeerTrust" includeWindowsGroups="false" revocationMode="Online" trustedStoreLocation ="LocalMachine" mapClientCertificateToWindowsAccount ="false"/> </clientCertificate> <serviceCertificate findValue="RPKey" x509FindType="FindBySubjectName" storeLocation ="LocalMachine" storeName="My"/> </serviceCredentials> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel>
Figure 2: Mutual certificate authentication using message security.
To configure the service certificate you add it to the service behavior. Instead of using ASP.NET authentication, client certificates are authenticated according to settings in the <clientCertificate> section. Based on the configuration in Figure 2, PeerTrust is used, which means that the corresponding public key for each trusted client certificate must be installed in the TrustedPeople store in the LocalMachine certificate store.
The client requires access to the service public key, which means either installing it to the client machine certificate store or including a base64-encoded copy of the certificate in the client endpoint configuration. When you generate a proxy for a BasicHttpBinding endpoint, you must manually add information about the service certificate. If you install the public key certificate to the client machine, you can provide a certificate reference in the <identity> section:
<endpoint address="http://localhost/WebServiceHost/ CertificateService.svc/Soap11MutualCertificate" binding="basicHttpBinding" bindingConfiguration= "BasicHttpBinding_WebServiceContract2" contract= "WinClient.localhost.WebServiceContract" name="Soap11MutualCertificate" > <identity> <certificateReference findValue="RPKey" storeLocation="CurrentUser" storeName="My" x509FindType="FindBySubjectName"/> </identity> </endpoint>
An alternate approach is to provide it with the endpoint behavior, along with the client s private key certificate (see Figure 3).
<system.serviceModel> <behaviors> <endpointBehaviors> <behavior name="clientCertificate"> <clientCredentials> <clientCertificate findValue="SubjectKey" storeLocation="CurrentUser" storeName="My" x509FindType="FindBySubjectName"/> <serviceCertificate> <defaultCertificate findValue="RPKey" storeLocation="CurrentUser" storeName="My" x509FindType="FindBySubjectName"/> </serviceCertificate> </clientCredentials> </behavior> </endpointBehaviors> </behaviors> <client> <endpoint address="http://localhost/WebServiceHost/ CertificateService.svc/Soap11MutualCertificate" binding="basicHttpBinding" bindingConfiguration= "BasicHttpBinding_WebServiceContract2" contract= "WinClient.localhost.WebServiceContract" name= "Soap11MutualCertificate" > <identity> <certificateReference findValue="RPKey" storeLocation="CurrentUser" storeName="My" x509FindType="FindBySubjectName"/> </identity> </endpoint> </client> </system.serviceModel>
Figure 3: Configuring certificates for the client endpoint.
Fortunately, when you add a service reference in WCF, a base64-encoded copy of the service certificate is placed in the client configuration file as part of the <identity> section of the endpoint:
<endpoint address="http://localhost/WebServiceHost/ CertificateService.svc/Soap12MutualCertificateNego" binding="wsHttpBinding" bindingConfiguration= "WSHttpBinding_WebServiceContract12" contract= "WinClient.localhost.WebServiceContract" name= "Soap12MutualCertificateNego" behaviorConfiguration= "clientCertificate" > <identity> <certificate encodedValue="..." /> </identity> </endpoint>
Clients can also specify certificates in code:
proxy.ClientCredentials.ClientCertificate.SetCertificate( StoreLocation.CurrentUser, StoreName.My,X509FindType. FindBySubjectName, "SubjectKey"); proxy.ClientCredentials.ServiceCertificate. SetDefaultCertificate(StoreLocation.CurrentUser, StoreName.My, X509FindType.FindBySubjectName, "SubjectKey");
Mutual certificate authentication results in end-to-end message security according to OASIS WSS.
In any of these BasicHttpBinding security scenarios you can also optimize support for large messages using MTOM an interoperable encoding format for SOAP messages that reduces message size and parsing overhead when dealing with binary data in a SOAP message. I won t get into the details of the format here, but you can configure the binding to use MTOM instead of Text encoding (the default) with the message encoding setting:
<basicHttpBinding> <binding name="Soap11UserNameMTOM" messageEncoding="Mtom"/> </basicHttpBinding>
MTOM encoding is orthogonal to security settings, so this can be used in conjunction with any of the other binding and behavioral settings for the service. WSHttpBinding and WSFederationHttpBinding also support MTOM encoding. For this to work, the client must also be configured for MTOM. Because MTOM is included in the WSDL for the service, the generated client configuration will automatically include the correct setting.
WSHttpBinding allows you to expose WCF service endpoints compatible with more recent Web service stacks that support SOAP 1.2 and WS-Addressing in addition to other standards such as MTOM, Kerberos, and SAML token profiles for WSS, WS-SecureConversation, WS-ReliableMessaging, and WS-AtomicTransaction. You can use WSHttpBinding to migrate services based on ASMX with WSE that use these standards, while also supporting newer client technology stacks that implement the most recent versions of each specification. Some typical scenarios for WSHttpBinding deployments include the following:
- Supporting SOAP 1.2 and WS-Addressing
- UserName, Kerberos, Certificate, or SAML token authentication with end-to-end message security
- Secure sessions with WS-SecureConversation
- Reliable sessions with WS-ReliableMessaging
- Distributed transactions with WS-AtomicTransaction
- Sending large messages with MTOM
Supporting SOAP 1.2 and WS-Addressing
By default, WSHttpBinding serializes all messages using the SOAP 1.2 format with WS-Addressing headers included. To support these protocols on a simple anonymous service endpoint, you can customize WSHttpBinding and disable security:
<wsHttpBinding> <binding name="Soap12NoSecurity"> <security mode="None" /> </binding> </wsHttpBinding>
If you want a SOAP 1.2 endpoint without addressing headers, you must resort to a custom binding, and explicitly set the message version:
<customBinding> <binding name="wsHttpNoAddressing"> <textMessageEncoding messageVersion="Soap12" /> <httpTransport /> </binding> </customBinding>
Credential Support and Message Security
With WSHttpBinding you can send UserName credentials over SSL or use Certificate credentials for mutual authentication in the same way discussed for BasicHttpBinding. What s different is that messages will be serialized using SOAP 1.2 and include addressing headers. Another difference is that WSHttpBinding has full support for OASIS token profiles, which means sending any credentials, including UserName, Certificate, Windows/Kerberos, and SAML, with end-to-end message security.
With SSL, message protection is only applied point-to-point, with no guarantees that the message will be encrypted all the way through to its final destination. Message security, on the other hand, protects messages across multiple hops.
OASIS WSS describes how to sign and encrypt messaging using security tokens so that this end-to-end secure exchange is fully interoperable.
WSHttpBinding uses message security mode by default. Message security for non-Windows credentials requires that a service certificate be provided to authenticate the service and to facilitate message transfer protection. The behavior configuration for the service certificate is the same as I discussed for BasicHttpBinding. One of the key differences with WSHttpBinding is that service credentials can be negotiated and by default negotiation is enabled for the binding:
<wsHttpBinding> <binding name="Soap12UsernameTokenNego"> <security mode="Message" > <message clientCredentialType="UserName" negotiateServiceCredential="true" /> </security> </binding> </wsHttpBinding>
When negotiation is enabled the session key used for message protection is negotiated through a series of calls to the service tunneled through a protocol named WS-Trust. This exchange is built in to the WCF plumbing. It essentially saves the client from having access to the service certificate a priori for non-Windows credentials. For Windows credentials, no certificate is required. The problem with negotiation is that although WS-Trust is interoperable, the negotiation protocols used are not. So, to provide an interoperable endpoint today you would have to disable negotiation by setting negotiateServiceCredentials to false. For non-Windows credentials, this means that one-shot message security according to OASIS WSS is used, and the client must know the service certificate. For Windows credentials, this requires the presence of a Kerberos domain.
You can configure WSHttpBinding to use NTLM or Kerberos by setting the credential type to Windows:
<wsHttpBinding> <binding name="Soap12NoSecurity"> <security mode="Message" > <message clientCredentialType="Windows" /> </security> </binding> </wsHttpBinding>
If a Kerberos domain is present, the token is serialized as Kerberos; otherwise, NTLM is used. When the client proxy is constructed, it uses the Windows token for the client application by default usually the logged-in user. To specify an alternate credential, you can construct a NetworkCredential and assign it to the ClientCredentials reference before the channel is constructed on the first call:
NetworkCredential credential = new NetworkCredential( "username", "password", "domain"); proxy.ClientCredentials.Windows.ClientCredential = credential;
WSHttpBinding also supports IssuedToken credentials such as SAML tokens, but you should use WSFederationHttpBinding for this type of credential as it has more configuration options. This type of token also involves custom authorization.
Regardless of the credentials used to perform mutual authentication, secure sessions can be enabled so that a session key is generated for multiple communications between client and service. This can reduce the overhead of each message, along with authentication overhead at the service. By default, WSHttpBinding has secure sessions enabled. To disable it, use this configuration:
<wsHttpBinding> <binding name="Soap12UserNameNoSecureSession"> <security mode="Message" > <message clientCredentialType="UserName" negotiateServiceCredential="false" establishSecurityContext="false" /> </security> </binding> </wsHttpBinding>
Secure sessions are implemented with WS-SecureConversation protocol, which is interoperable with any technology stack that also implements the standard, including ASMX services using WSE. The standard is not yet ratified, though it is under the OASIS WS-SX committee (along with WS-Trust). A good number of platforms already support both of these standards so that interoperability can be achieved but you may also need to provide service endpoints that disable this, to reach a wider client base.
Reliable Sessions with WS-ReliableMessaging
Reliable sessions make it possible for messages to survive transient network failure and thus provide some level of delivery assurance. By default, this protocol is disabled in WSHttpBinding; however, it can be enabled with the following configuration:
<wsHttpBinding> <binding name="Soap12UserNameReliableSession"> <security mode="Message" > <message clientCredentialType="UserName" negotiateServiceCredential="false" establishSecurityContext="true" /> </security> <reliableSession enabled="true" ordered="false" inactivityTimeout="00:10:00"/> </binding> </wsHttpBinding>
You can also configure support for ordered messages and session activity timeout (which defaults to 10 minutes). When reliable sessions are enabled, secure sessions must also be enabled. Thus, platforms that support WS-ReliableMessaging are likely to support WS-SecureConversation. WS-ReliableMessaging is not yet ratified, but it is under review with the OASIS WS-RM committee, and has been implemented in several leading platforms in its current state. Like with WS-SecureConversation, you may need to provide endpoints without reliable sessions to reach a wider client base.
Transactions with WS-AtomicTransaction
Distributed transactions over HTTP are also supported with WSHttpBinding. Transactions warrant a longer discussion that I won t embark on here. Suffice it to say that the WS-AtomicTransaction specification, under review with the OASIS WS-TX committee, makes it possible for disparate systems to participate in distributed transactions over HTTP. This is another protocol that is not yet ratified or widely implemented, but you can expect to expose endpoints that support it for those clients that can leverage it.
Deploying WCF Web services for your ASP.NET applications can be as simple as your typical ASMX service, using BasicHttpBinding defaults. You can also support commonly implemented security standards by choosing BasicHttpBinding or WSHttpBinding with UserName, Windows, or Certificate credentials without negotiation, secure sessions, reliable messaging, or transactions. For services distributed over HTTP behind the firewall, or for WCF to WCF scenarios, or to support platforms that have implemented emerging standards for security and reliability, you can leverage WSHttpBinding and enable these features. I ll discuss these features in greater detail in future column entries.
The sample code accompanying this article is available for download.
Michele Leroux Bustamante is Chief Architect at IDesign Inc., Microsoft Regional Director for San Diego, Microsoft MVP for Connected Systems, and a BEA Technical Director. At IDesign Michele provides training, mentoring, and high-end architecture consulting services, specializing in scalable and secure .NET architecture design, globalization, Web services, and interoperability with Java platforms. She is a board member for the International Association of Software Architects (IASA), a frequent conference presenter, conference chair of SD s Web Services and Web Development tracks, and a frequently published author. Michele recently completed the book Learning WCF, published by O Reilly (book blog: http://www.thatindigogirl.com). Reach her at http://www.idesign.net or http://www.dasblonde.net.
WCF Home: http://wcf.netfx3.com
Michele s blog: http://www.dasblonde.net
Michele s WCF book: http://www.thatindigogirl.com