Developer Product Briefs
Write Secure Web Services
Use WSE 3.0 to secure your Web services and send binary data.
Write Secure Web Services
Use Web Services Enhancements (WSE) 3.0 to secure your Web services and send binary data.
by Vijay P. Mehta
July 27, 2005
Technology Toolbox: C#, SQL Server 2000, Visual Studio 2005 beta 2, Web Services Enhancements 3.0 (CTP)
Web services and binary attachments have proved a difficult pair to make work well together when it's time to implement security. But new functionality in Web Services Enhancement 3.0 (WSE3) should simplify working with binary attachments and Web services tremendously, giving you the ability to implement binary attachments with Web services out of the box.
The computing industry has debated the format of binary attachments in Web services for years; SOAP with Attachments (SwA), Direct Internet Message Encapsulation (DIME), and Message Transmission Optimization Mechanism (MTOM) all vied for supremacy. The first two, SwA and DIME, were fundamentally flawed because they lacked the means to apply WS-Security (the standard specification for applying security to Web services) to the message. MTOM, a younger specification, has overcome this flaw, and the W3C group recently moved MTOM into "Recommended" status.
Microsoft has long straddled the fence in this debate, but its recent move of supporting MTOM in the new release of WSE signals a more proactive approach by the company. In addition to the MTOM enhancements, WSE3 offers several new security features, including turnkey security solutions for enhancing your Web services, as well as a set of robust extensions to the policy model that make it simple to change security at run time.
I'll show you how to use some of these new security features in a real-world example that manipulates binary attachments with a Web service using the MTOM functionality inside WSE 3.0. The sample requires that you install Visual Studio 2005 and WSE3. As I write this article, WSE3 is a "Community Technical Preview" (CTP), which means it's an early beta release. Writing about a CTP technology might seem a little bleeding edge, but the current production version of WSE (2.0 SP3) is not supported with .NET 2.0, and we didn't want to write about something that has the potential to be obsolete in the relatively near term. Note that features are subject to change, as is the case when working with any beta software, but the fundamental concepts explained in this article should remain unchanged, even if their implementation changes slightly. You will also need to have a SQL Server database installed to work with the example. I used SQL Server 2000, but the sample should work as designed with MSDE or SQL Server 2005 (download the database scripts and the sample code here).
The inspiration for this sample came from a project I worked on that required designing and creating a Web service to send and receive PDF files. Specifically, the client wanted a way to digitally sign and encrypt the sending\receiving of PDF files to and from a relational database using a Web service. The only way to accomplish the task at the time was to write large amounts of custom code and ignore pieces of the WS* specifications on binary attachments (see the sidebar, "Creating the WS* Standards"). Binary attachment specifications simply didn't give developers an effective way to apply WS-Security to the message of the Web service. Fortunately, much has changed since I worked on that project, and WS* now provides MTOM, which allows you to secure the binary attachment (technically a MIME attachment with MTOM) with your Web services. Another key advantage of using MTOM is that the protocol allows for the byte array to be sent as is, not Base-64encoded (like its predecessors), which means that the message size is much smaller than DIME or SwA.
Drill Down on New Features
Let's take a closer look at some of the new features in WSE3 before I show you how to create the sample itself. First, Microsoft has provided a set of turnkey security models to enable you to use pattern-based methodologies to secure your Web services. These security models (assertions) are based on the WS* specifications, and they let you use standard industry best practices, saving you a lot of development time. WSE3 provides five turnkey security solutions: AnonymousOverCertificate, Kerberos, MutualCertificate, UsernameOverTransport, and UsernameOverCertificate (see Table 1). Choosing between them is as easy as changing a configuration file. (This article uses the MutualCertificate solution.)
WSE3 also includes several policy framework improvements. For example, WSE3 creates synergy between the imperative and the declarative programming models; what you do in code to the policy framework correlates directly to the changes you make in the policy configuration files. This gives you true extensibility for customized policy. WSE3 also includes an improved attributing system. For example, you can now decorate the service and the client with a policy attribute [Policy("MyPolicyRocks")], and WSE3 ships with a cool wizard that simplifies creating these policy files. Other improvements include MTOM support, WS-SecureConversation alignment (improved session management), 64-bit support, .NET 2.0 support, and a number of other improvements. You can find the complete list of features on the MSDN site (see Additional Resources).
Once you install WSE3, Visual Studio 2005, and SQL Server, open SQL Server Enterprise Manager and create a new database called WSE_Sample, then add a new table called PDF_Files. Include two columns in the table: Filename (nvarchar 50) and PDF (image 16), and set the Filename column as the primary key.
The sample includes a simple table structure that enables you to examine the inner workings of WSE3. Most real-world apps would include other column requirements, as well as a more complex table structure. Once you set up the database, open Visual Studio 2005 and create a new Web service by selecting File | New | Web Site | Web Service. Call the new Web service project "MTOM_WSE" and select HTTP as the location.
After the project loads, rename the ASMX file and the code-behind file to SecureMTOM.asmx and SecureMTOM.cs, respectively. In the code-behind file, rename the class and the default constructor from "Service" to "SecureMTOMService." You need to create a new method in the SecureMTOMService class called "GetPDF" to enable the new service to send and receive data, then define the return type as a Byte[], and give it a string parameter called "filename." Next, create a method called "InsertPDF," define the return type as void, and give it two parameters: a string called "fileName" and a Byte[] called "file." The implementation logic for these methods is straightforward:
//First method signature for retrieving PDFs
[WebMethod]
public Byte[] GetPDF(string fileName){}
//Second method signature used for inserting PDFs
[WebMethod]
public void InsertPDF(string fileName,
Byte[] pdfFile){}
Both methods use a SqlConnection for connecting to the database and a SqlCommand object for executing queries. The InsertPDF method requires that you add a pair of parameters to the Command object called FileName and PDF. The FileName parameter uses the type SqlDbType.NVarChar, and the PDF parameter uses type SqlDbType.Image. Set the value of these Command parameters to the value of the method parameters (the String fileName and the Byte[] pdfFile, respectively), and call the ExecuteNonQuery() function. The GetPDF method uses an inline SQL statement instead of a Command parameter. It also uses a SQLDataReader to execute the SELECT statement. After the SqlDataReader loads, call the GetBytes function to populate a Byte array, then return that array to the caller (see Listing 1).
Set Up the Security Features
You've implemented the guts of the service; the next step is to set up the security and the MTOM features. Before diving into the WSE console (which is integrated into Visual Studio 2005), you need to install some certificates on your local machine. You could generate your own certificates, but Microsoft was kind enough to provide some test certificates (created using Makecert.exe) and include them in the QuickStart examples with the WSE 3.0 install (the default path is: C:\Program Files\Microsoft WSE\v3.0\Samples\Sample Test Certificates). I won't walk you through the install step-by-step because you can find instructions to do this in the WSE 3.0 readme file. A note of caution, however: Install the Server Cert.cer in the "other people" certificate store and make sure that you give the ASP.NET user account appropriate permissions (for more information on installing the sample certificates, go to http://pluralsight.com/blogs/aaron/archive/2004/07/13/1623.aspx).
You're ready to start using WSE 3.0 after you install the certificates. Right-click on your Visual Studio 2005 solution, then select "WSE Settings 3.0." This brings up a new window with seven tabs: General, Security, Routing, Policy, TokenIssuing, Diagnostics, and Messaging. You enable a Web service for use with WSE3 with the WseProtocolFactory. You can do this in the General tab by checking "Enable this project for Web Services Enhancements" and by checking "Enable Microsoft Web Services Enhancement Soap Protocol Factory." Checking these two boxes (and clicking on OK) generates the WseProtocolFactory class in the background and updates the web.config file with the appropriate metadata (see Figure 1).
The WseProtocolFactory class intercepts SOAP messages and processes any WS* specifications you specify in the SOAP header. After you WSE3-enable the Web service, click on the Messaging tab and look at the MTOM Settings options. You have a couple options when configuring MTOM. First, you can configure the server to Always, Optional, or Never; second, you can specify whether the client is On or Off. Setting the server to Always means you are requiring all sends and receives to be MTOM-encoded. Setting to Optional means the service will accept MTOM, but will also accept other transmissions. Finally, configuring the server to Never means the service never accepts MTOM. The On/Off setting specifies whether future auto-generated client proxies will require MTOM.
Set the client to On and the server to Always. Clicking on OK updates the web.config file with the metadata, sets the service to accept only MTOM, and requires that the client send only MTOM messages. Next, you want to configure the security and policy. Navigate to the Policy tab in the WSE Settings 3.0 window, then click on the Add button and type in "ServerPolicy" as the name. After clicking on OK, the new WSE Security Setting Wizard pops up to walk you through the setup. The wizard is intuitive and makes it easy to set up any type of turnkey security solution. The first window you see asks you what you want to secure (a client or a service), while the next asks which type of security you want to use (Anonymous, Username, Certificate, or Windows); select Certificate. The final few steps require you to select who can authenticate and to specify where the certificates are located. The wizard then creates a new policy file called wse3policyCache.config, which it adds to your solution. This file contains all the configuration information that you selected in the wizard in XML form.
Enable MTOM and the turnkey Security in your Web service by decorating the SecureMTOMService class with [Policy("ServerPolicy")]. This tells your class to use the policy file you created in the wizard.
Build Your Client App
So far, you've created a Web service that uses MTOM and WS-Security. You still need to create a client application to test out the new functionality. Start by adding a new Windows Form project to your solution called WSE_Client. Rename the default form to something meaningful, such as MTOMTest, and add three buttons called btnGetPDF, btnSelcetFile, and btnInsert. Next, add a textbox called txtFile and drop a WebBrowser control and an OpenFileDialog control on the form (see Figure 2).
That's it for the UI controls. Next, add a new Web reference to the SecureMTOM Web service. I prefer choosing the Web reference from the "local machine" as opposed to the "current solution" when working with these pre-release bits. Previously, you created a ServerPolicy; now you need to go through the same process for the client. Navigate to the WSE Settings 3.0 tool and enable the project for WSE 3.0. Note that you cannot enable the Soap Protocol Factory because this isn't an ASP.NET Web service.
Continue with the same steps you did for the server until you get to the Policy tab. On that tab, click on Add type "ClientPolicy" rather than "ServerPolicy." Select "Secure a client" and "Certificate" for the authentication mode when the WSE security wizard comes up. The next steps ask you to select the locations of the Client certificate and the Server certificate. This prompts the wizard to update the app.config file, as well as generate a policy file like the server setup. You need to create a proxy to the SecureMTOM Web service when adding the implementation code for the btnGetPDF and btnInsert. If you set up the Web service correctly, you see a new creatable object hanging off the localhost Web reference, called SecureMTOMServiceWSE. Use this object to instantiate the reference. After the proxy has been instantiated, set the SoapVersion to default, call SetPolicy, and set RequireMtom to True:
localhost.SecureMTOMServiceWse
myService = new WSE_Client.localhost.
SecureMTOMServiceWse();
myService.SoapVersion =
SoapProtocolVersion.Default;
myService.SetPolicy("ClientPolicy");
myService.RequireMtom = true;
Complete the btnGetPDF by creating a Byte array and calling the GetPDF Web service to retrieve a file from the database. Next, use the FileStream object to write the file to disk and use the WebBrowser control to display the PDF in your client application. You can complete the btnInsert by creating a FileStream object to open a file, then use a BinaryReader to read the file into a Byte[]. Finally, call the InsertPDF Web method. You can make this example a little more useable by using the txtFile control as the source for the GetPDF and the InsertPDF calls, and using the btnSelect control with the OpenFileDialog control to browse for files (to insert), populating the txtFile control with the file path.
That's it for the sample. It's basic, but it should point the way forward for taking advantage of the security functionality in WSE 3.0. Some ideas for extending the example include using secure sessions, streaming the binary data, creating more robust policy files, using Kerberos and other security models, and modifying the data model so it's closer to what you would see in a real-world Web services application.
About the Author
Vijay P. Mehta works in enterprise architecture for a Fortune 500 company in Indiana, where he uses VS.NET to design, develop, and architect enterprise solutions. Reach him at [email protected].