Get a Handle on SOAP Headers
Use SOAP headers to authenticate Web Service clients.
October 30, 2009
TheSimple Object Access Protocol (SOAP) is an XML-based protocol that allows datato be sent in a structured manner between Web Service providers and consumers.SOAP is one of the key elements that allows the exchange of distributed databetween different languages and operating systems. I'll provide you with ageneral overview of SOAP, but if you want to read the complete specification,it's available at theW3C Web site. For more information on SOAP, see "Get a Handle on SOAP Headers" and "Web Services Interoperability and SOAP."
Insteadof covering several different aspects of SOAP, I'll focus specifically on howyou can customize SOAP messages in the .NET platform through the use of SOAPheaders to simplify Web Service access. You'll see that .NET provides nativeSOAP header classes, which can simplify Web Service application development andmake using headers a snap.
The SOAPbody portion of a message contains the majority of the details and data in aSOAP request or response, but the SOAP header portion also can play animportant role in Web Services. You normally use headers when data needs to besent to a Web Service in a SOAP message but the data is not related directly toa particular Web method's functionality. You could use headers with customauthentication schemes, Web method call tracking and logging, and sessionmanagement, or you could use them in situations where additional data needs tobe returned from a Web Service and the data needs to be separate from any datacontained within the SOAP body.
To helpyou understand when to use SOAP headers, I'll demonstrate how to create acustom authentication scheme in a Web Service that exposes customer accountdata. Each time a request is made for a user's account information, theconsumer of the service must prove it has access to the Web methodfunctionality the Web Service exposes. The user's credentials (username,password, etc.) should not be passed to every Web method called because thiscauses the user's authentication to be tied to the parameters of the Webmethod. If the authentication scheme changed, you would need to update each Webmethod, which could result in a large maintenance headache. Instead, you canuse SOAP headers to pass the proper user credentials within each SOAP message.By doing this, the credentials are separate from the actual data containedwithin the SOAP body.
Build a Custom SOAP Header Class
Workingwith SOAP headers in the .NET platform is relatively straightforward because ofthe platform's robust support for SOAP. The first step when working withheaders is to create a custom header class that derives from the SoapHeaderclass located within the System.Web.Services.Protocols namespace. Thisclass contains four different properties related to headers. Figure 1 providesa basic description of each property.
Property | Description |
---|---|
Actor | Used to get or set the recipient of the SOAP header. |
DidUnderstand | Used to get or set whether the Web method understood the SOAP header properly. |
EncodedMustUnderstand | Used to get or set the MustUnderstand property of the SoapHeader class. When EncodedMustUnderstand is set to a value of 1, the MustUnderstand class will be set to a value of True. |
MustUnderstand | Used to get or set a Boolean value (True or False), which represents whether the Web Service must process and understand a given SOAP header |
Figure1. You use theSoapHeader class creating your own custom headers in the .NET platform.SoapHeader contains four properties that help identify whether the header washandled properly. You don't have to use these properties to leverage SOAPheaders in .NET.
AuthenticationHeader is the custom SOAP header classthat derives from SoapHeader. It provides basic authenticationcapabilities. AuthenticationHeader resides at the Web Service and isused to extract header information from SOAP messages. The authentication data(also referred to as an authentication token) passed to this customheader class is generated initially by a Web method named Login and sentback to the consumer after he or she first logs in to the Web Service with aproper username and password. See Figure 2 for this login process.
[WebMethod]public string Login(string userName, string password) { User user = new User(); //Validate user. Complete code for the User class is //available with this article's code download. int userID = user.Validate(userName,password,null); if (userID != 0) { //If a user is found, generate auth token (GUID) //and insert it into the database. Return the //authentication token to the consumer. return user.InsertAuthToken(userID).ToString(); } else { //If user is not found, return empty string return String.Empty; }}
Figure2. The Login Webmethod validates the username and password against users in a database. If avalid user is found, a unique authentication token is generated and returned tothe Web Service consumer.
Afterlogging in, each subsequent SOAP message the consumer sends to the Web Serviceincludes the newly obtained authentication token as a SOAP header. By followingthis pattern, the actual username and password are sent to the Web Service onlyonce.
Note: Adiscussion of .NET encryption techniques is beyond the scope of this article,but you probably want to encrypt the username and password passed during thelogin process so prying eyes can't see them. You can find an in-depth sample ofusing encryption with Web Services at the XML for ASP.NET Developers website.
Figure 3shows the complete code for the AuthenticationHeader class. You can seethe code contains a property named AuthenticationToken. You can use thisproperty to get or set the value of the authentication token sent back to theWeb Service from the logged-in consumer. You also can use the property toensure any received tokens match a valid user in the database. Invalid tokenscause a SOAP Fault to be thrown.
using System;using System.Web.Services.Protocols; namespace CodeBank.WebServices.SOAPHeaders { //Derive from the SoapHeader class public class AuthenticationHeader : SoapHeader { private string _AuthenticationToken = String.Empty; //This property allows the Web Service to set //and get the SOAP Header authentication token public string AuthenticationToken { get { return _AuthenticationToken; } set { //Ensure we have something other than //an empty Auth Token if (value == String.Empty) { throw new SoapException("No Authentication Token " + "Received",null); //We have a token. Ensure it matches up //with a valid user. } else { User user = new User(); int userID = user.Validate(null,null,value); if (userID == 0) { //Throw SOAP Exception so we don't hit Web Method throw new SoapException("Invalid Authentication " + "Token",null); } } //If no problems are found, set the property value _AuthenticationToken = value; } } }}
Figure3. TheAuthenticationHeader class derives from SoapHeader. As a result, a Web Serviceconsumer can send a SOAP header containing the authentication token, and theWeb Service can use this class to read and validate the value.
Put the SoapHeaderAttribute Class to Work
Now thatyou've created the AuthenticationHeader class, you can apply it to anyWeb method within the Web Service, so header information sent to the WebService can be extracted and used. To accomplish this task, you need to add areference to the custom header class to the Web Service class:
//Web Service Class - SoapHeaderDemopublic class SoapHeaderDemo : System.Web.Services.WebService { public AuthenticationHeader AuthHeader; //....More code would follow}
Once youadd a reference to AuthenticationHeader, you can use the SoapHeaderAttributeclass (located within the System.Web.Services.Protocols namespace) toapply AuthenticationHeader to any Web method, such as the GetAccountDetailsmethod (see Figure 4).
//SOAP header ensures authentication token is//associated with a user[WebMethod]//Header only used as input to a Web Method[SoapHeader("AuthHeader", Direction=SoapHeaderDirection.In, Required=true)]public Account GetAccountDetails(int accountID) { //Pass Auth Token within header into Account constructor //so we can look up UserID Account ad = new Account(accountID,AuthHeader.AuthenticationToken); //Return filled Account object if UserID and //AccountID match up return ad;}
Figure4. You use theSoapHeaderAttribute class to associate a SOAP header class with a Web method.This example specifies that the AuthHeader object is used to grab the SOAPheader request value sent to the Web method and that the header is required.
As theWeb Service receives the SOAP request for GetAccountDetails, the code inFigure 3 is invoked, causing the authentication token to be extracted from theSOAP header. Then, this token value is validated against users in the database.Assuming the token matches a user, the Web method is called and theauthentication token value (now held in the AuthenticationHeader class'sAuthenticationToken property) can be accessed to retrieve the user'saccount details. You do this by calling the AuthHeader object's AuthenticationTokenproperty:
//Create a new Account object based upon an AccountID//and an authentication token value held in the SOAP//header class.Account ad = new Account(accountID,AuthHeader.AuthenticationToken);
Add SOAP Headers
Now thatI've described the Web Service side of things, I'll show you how to take theauthentication token received during the login process and add it to the SOAPrequest made by the Web Service consumer (on the client side). Fortunately,sending the authentication token value to the Web Service as a SOAP header isfairly straightforward because the header details are added automatically tothe Web Service proxy the consumer uses. You can generate the proxy by usingeither VS .NET or the WSDL.exe command-line utility to read the service's WSDLdocument. This code shows the portion of the proxy class that references the AuthenticationHeaderclass the Web Service exposes:
//The following public field/property is added//into the proxy class automaticallypublic AuthenticationHeader AuthenticationHeaderValue; //The following class shell is added into the//generated proxy codepublic class AuthenticationHeader : SoapHeader { public string AuthenticationToken;}
Once theauthentication token is received from the Web Service after logging in, theconsumer simply needs to reference the AuthenticationHeaderValueproperty within the proxy and assign a new instance of the AuthenticationHeaderclass to it. Once this is done, you can assign the token value to pass as aSOAP header by calling the AuthenticationToken property (see Figure 5).
//Create an instance of the proxy object.//Proxy is in//the SoapHeaderDemoService.WebServiceProxy namespaceSoapHeaderDemoService.WebServiceProxy.SoapHeaderDemo demo = new SoapHeaderDemoService.WebServiceProxy.SoapHeaderDemo(); //Assign new instance of SOAP header class to the proxy's//AuthenticationHeaderValue propertydemo.AuthenticationHeaderValue = new SoapHeaderDemoService.WebServiceProxy.AuthenticationHeader(); //Now assign the authentication token value by calling the//AuthenticationHeaderValue object's//AuthenticationToken propertydemo.AuthenticationHeaderValue.AuthenticationToken = _authToken;
Figure5. You assign thetoken value to pass as a SOAP header by calling the AuthenticationTokenproperty.
The codein Figure 5 adds an Authentication header section into the SOAP messagethat is sent to the Web Service automatically, as you can see in Figure 6.
a49d0f16-8880-45f3-99dd- 434eb640ecfa 123456789 Figure6. By using theproxy object's AuthenticationHeaderValue property, the .NET Framework adds theheader section to the SOAP request sent to the Web Service automatically. You cansee that the Web Service proxy (SoapHeaderDemo in this example) handlesnearly every detail involved in adding one or more headers to a SOAP message.This abstraction allows you to focus on developing the application rather thanworrying about the different XML technologies involved in creating a properlyformatted SOAP message. SOAPheaders can play an important role in SOAP messages. Using headers is as easyas creating a custom class that derives from the SoapHeader class,referencing the custom class in the Web Service, and adding the header to a Webmethod by using the SoapHeaderAttribute class. On the consumer or clientside, little code is required to add a SOAP header into a request. The proxyobject does the majority of the work to add header details into SOAP messages.By using headers, you can separate data used by the Web Service but not relateddirectly to functionality exposed by a given Web method. To see alive demo of the sample application used in this article, visit http://www.xmlforasp.net/codeSection.aspx?csID=73. The files referenced in thisarticle are available for download. Get to Know SOAP SOAP issimply a wire protocol, a way to transfer data between distributed systemsusing XML technologies and protocols such as HTTP. (For more details, see theW3C SOAP working group's definition at http://www.w3.org/TR/2002/WD-soap12-part1-20020626/.)Each SOAP message is either a request to receive data from a Web Service or aresponse to the consumer of a Web Service. SOAPmessages generally contain three main parts: an envelope, an optional header,and a body. Figure A shows an example of a SOAP message that contains thesethree parts. Header Details go here 123456789 Figure A. SOAP messagescan contain three different sections. The Body element contains the specificsof the Web Service request or response. The SOAPEnvelope element acts as a wrapper for the data contained within theSOAP message. Envelope normally defines several XML namespacesreferenced throughout the message as shown in Figure B. Next, the SOAP Headerelement allows data not directly associated with a Web method request orresponse (but needed in the messaging process) to be passed to or from a WebService. Finally, the SOAP Body element contains the actual data in theSOAP request or response. This data can include the operation or task (called aWeb method in .NET) involved in the messaging process, as well as any necessaryparameter data passed to or returned by the operation.
About the Author
You May Also Like