Documente Academic
Documente Profesional
Documente Cultură
Table of contents
If you're viewing this document online, you can click any of the topics below to link directly to that section.
1. Introduction.......................................................................................... 2 2. Create the Java Web service .............................................................. 5 3. Configure the Web service for XML encryption ................................... 9 4. Create the .NET client ....................................................................... 14 5. Wrap-up............................................................................................. 27
Page 1 of 29
ibm.com/developerWorks
Page 2 of 29
ibm.com/developerWorks
The development tools I used to create and run the Web service used in this tutorial were: IBM WebSphere Studio Application Developer 5.1.0 Microsoft Visual Studio .NET 2003 with Web Services Enhancements 1.0 SP1.
Microsoft Windows 2000 and Windows XP operating systems were used to complete the work for this tutorial. You should have a basic knowledge of security certificates and how encryption works. An overview of how encryption works can be found in Encryption: A brief introduction on page 4. You should also be familiar with IBM WebSphere Application Server -- for instance, you should know how to turn its security on and off. If you would like to read the tutorial but feel unsure about any of these subjects, Resources on page 28 has links to appropriate documentation.
Sample code
Before you begin working your way through the tutorial, unzip the source code archive, ws-encryptcode.zip, that is provided. There are two subdirectories in the source code folder, each containing two files. The Enc_wsdl_and_Java_implementation_file directory contains: bookstoreEnc.wsdl -- This is the WSDL file you will use to create the skeleton of the Web service at the start of the tutorial, in Examine the WSDL on page 5. It defines the credit card purchase service your Web service will provide. CreditCardBindingImpl.java -- A Java source code file that you will use to fully implement the credit card purchase service in Create the Web service on page6 . The Enc_cert_and_keystore directory contains: interops-enc-receiver.jceks interops-enc.cer The interops-enc-receiver.jceks keystore holds the private key that your Web service will need to decrypt incoming messages. You will configure the Java Web service to use it in Security certificates on page 9. interops-enc.cer is an X.509 certificate that contains the public key that the .NET client will use to encrypt its messages. You will configure the client to use it in Installing the public key security certificate on page 14.
ibm.com/developerWorks
Hedley Proctor is a software engineer at IBM Hursley, England. He has worked on versions 5 and 5.1 of the WebSphere SDK for Web Services, specializing in the Eclipse plugins, samples, and interoperability. He took an undergraduate degree in Physics at Oxford University and a Postgraduate Diploma in Philosophy at Durham University, before joining IBM in September 2002.
Page 4 of 29
ibm.com/developerWorks
Page 5 of 29
ibm.com/developerWorks
3. On the Service Deployment Configuration page, set the Service Web Project to be the dynamic Web project you created on the previous panel. You also need to choose a server. I used WebSphere Application Server 5.0.2 Test server, but you might wish to use a non-test one. 4. On the Web Service Selection page, browse to bookstoreEnc.wsdl and select it. Then click Next. 5. On the Web Service Skeleton Java Bean Configuration page, two example security configurations are available -- XML Digital Signature and XML Encryption. However, you will get a better idea of how the process works if you start with a blank configuration and configure things manually, so accept the default of no security and click Next. 6. On the Web Service Publication page, leave both of the publication options unchecked. Click Finish.
Page 6 of 29
ibm.com/developerWorks
If you expand the JavaSource directory of your Web service, you will see that a number of Java files have been created automatically by WebSphere Studio Application Developer. The WSDL document is simply a definition of a Web service. WebSphere Studio Application Developer has created the code that allows messages to be passed into and out of this Web service. However, what it can't do is write the business logic for you -- only you know how you actually want to process messages. The file in the JavaSource directory that contains the business logic of the Web service is called CreditCardBindingImpl.java, which is short for credit card binding implementation. This is the same name as the implementation file from our sample code, though it's not the same file. If you open it, you will see that it contains a method definition that is empty -- it is what is often called a skeleton implementation file. You will need to replace it with the real implementation file -- that is, with the file from our sample code archive with the same name. Move the CreditCardBindingImpl.java file that you extracted from ws-encryptcode.zip, into the JavaSource directory, so that it overwrites the skeleton file. This will produce an error in the console window. You need to make sure that this change is mirrored on the server. However, you have many more changes to make that will also need to be mirrored on the server, so wait until the end of webservices.xml settings on page 9 to make the server pick up the new files.
Page 7 of 29
ibm.com/developerWorks
4. When the server appears in the server pane, right-click on it and select Start.
Page 8 of 29
ibm.com/developerWorks
Security certificates
The only security certificates we actually need are the public and private keys, since the session key will be generated by the client. Remember, encryption keys should never be stored in a JKS keystore, as this format is not secure enough. There is no point in using good encryption if an attacker can just steal your keys! The private key that the server uses to decrypt the message should be in JCEKS format. I have supplied the public and private key certificates in ws-encryptcode.zip: interops-enc.cer is an X.509 public key certificate for the client. interops-enc-receiver.jceks is a JCEKS keystore public and private key pair for the server.
These are 1024-bit RSA keys. When attempting to create an interoperable, encrypted Web service, there is one important point to bear in mind. When an encrypted SOAP message is sent, the message includes a <KeyIdentifier> tag. This tag tells the recipient of the message, which of the recipient's private keys that the recipient will use to decrypt it since he or she might well have more than one. The default algorithm for generating the <KeyIdentifier> uses the Subject Key Identifier extension of the X.509 public key certificate. However, if you generate certificates using the Java keytool, they will be X.509 V1 certificates and will not have extensions which were only introduced in the X.509 V3 standard. When the Subject Key Identifier extension does not exist, the method for generating the <KeyIdentifier> is not well defined by current Web services standards, and you might find that different vendors have implemented different algorithms. For this reason, it is better to always use X.509 V3 public key certificates, which can be imported but not generated by the Java keytool. Most Certification Authorities (CAs) will issue X.509 V3 certificates. Store the interops-enc-receiver.jceks keystore in a location of your choosing. We will tell the server where to find it in the next section.
webservices.xml settings
Secure Web services: Encryption Page 9 of 29
ibm.com/developerWorks
All the security settings are configured using the webservices.xml file: 1. Expand the bookstoreEnc > WebContent > WEB-INF folder and open the webservices.xml file. This produces a number of pages, identified by tabs at the bottom. Select the Security Extensions tab. 2. On the right of this page, we can see two sets of configuration settings: Request Receiver Service Configuration Details and Response Sender Service Configuration Details. The request receiver settings determine how the server treats incoming messages, while the response sender settings govern the format of the messages it sends back. 3. We want the server to demand that incoming messages be encrypted. Expand Request Receiver Service Configuration Details > Required Confidentiality and click the Add button. You can see that we have two options for the parts of the message that must be encrypted: the body or the username token. Select bodycontent and click OK.
4. It is worth examining one of the other settings on this page. On the left-hand side of the page, expand the Server Service Configuration. You should see that it has one parameter, ActorURI, and that this parameter has no value assigned to it. If a value were present, it would indicate that messages to and from the Web service were being routed via an intermediary. In fact, if we had used the Web services wizard to create a secure Web service, an actor intermediary would have been used. However, .NET services by
Page 10 of 29 Secure Web services: Encryption
ibm.com/developerWorks
default do not use such an actor. So, whenever you are creating a Web service that you want to interoperate with .NET, make sure that you have set the ActorURI value to null. 5. Select the Binding Configurations tab of the webservices.xml file. 6. On the right-hand side of the page there are two sections: Request Receiver Binding Configuration Details and Response Sender Binding Configuration Details. Expand Request Receiver Binding Configuration Details > Encryption Information and click Add. 7. When a Web service receives a message that is encrypted, it reads the header information in the message, which tells it what algorithms have been used to encrypt the message. You need to use this dialog box to tell the service where to find the keys for each combination of algorithms that it might encounter. We would like to use triple DES for the symmetric encryption of our data and RSA for the asymmetric encryption of the session key, so enter the following information: Encryption name: InteropsEnc Data encryption method algorithm: http://www.w3.org/2001/04/xmlenc#tripledes-cbc Key encryption method algorithm: http://www.w3.org/2001/04/xmlenc#rsa-1_5 Encryption key name: Leave blank Encryption key locator: InteropsEncKeyLocator Then click OK.
8. Now we need to define the key locator. Scroll down to the Key Locators section and click Add. In the dialog box, enter the following information: Key locator name: InteropsEncKeyLocator
Secure Web services: Encryption Page 11 of 29
ibm.com/developerWorks
Key locator class: com.ibm.wsspi.wssecurity.config.KeyStoreKeyLocator (default) Key store storepass: interops Key store path: c:\keystores\interops-enc-receiver.jceks Key store type: JCEKS
9. Still in the key locator dialog box, click the key Add button and enter the following information: Alias: interops-private-key Key pass: interops Key name: CN=Interops Encryption Click OK to close the dialog box.
Page 12 of 29
ibm.com/developerWorks
It is worth taking note of the two sections between Encryption Information and Key Locators -- the Trust Anchor and Collection Certificate Store. Ordinarily, the private key that is being used for decryption will be part of a certificate chain that ends in a trusted, root CA. In order for the server to trust the private key, you must put the locations of the intermediate certificates in the Collection Certificate Store list and the location of the root CA certificate in the Trust Anchor list. However, the dummy certificate I have supplied with this article is not part of a chain, so we don't need to use either of these sections. At this point, save the webservices.xml file. You now have the correct settings for XML encryption, so you can restart the project on the server. Remember that we are using security, so I am assuming that security is enabled at the server. If it isn't, double-click on the server and change the settings in the Security tab. Right-click on the server and select Restart project > DefaultEAR.
Page 13 of 29
ibm.com/developerWorks
Page 14 of 29
ibm.com/developerWorks
4. Click Add and select Certificates from the list. 5. Accept the default of managing certificates for your user account and click Finish. 6. Close the Add Standalone snap-in dialog box and click OK in the Add/Remove Snap-in... dialog. 7. Expand the Certificates -- Current User list. You can see the various certificate stores and the certificates they contain.
Page 15 of 29
ibm.com/developerWorks
8. You should add the public key certificate to both the Personal and Trusted Root Certification Authorities stores. Usually public key certificates would only be stored in the Personal store, but as this one is self-certified, it needs to be installed in the Trusted Root Certification Authorities store in order for .NET to trust it. Double-click on the interops-enc.cer file.
Page 16 of 29
ibm.com/developerWorks
9. Click Install Certificate.... This should bring up the Certificate Import Wizard. Click Next. 10.Select Place all certificates in the following store and click Browse. 11.Select the Personal store and click OK. 12.The wizard will show that you have selected the Personal store. Click Next and then click Finish. 13.Repeat these steps to add the certificate to the Trusted Root Certificate Authorities store. You can add a certificate to as many stores as you wish.
ibm.com/developerWorks
Now that the appropriate security certificate has been installed, you can start writing the client. 1. Start Visual Studio .NET. 2. Create a new Visual Basic .NET project. Select the Windows Application type and call it the project, SecureInteropsEnc. This brings up a blank Windows form.
3. Expand the project and right-click on References. Select Add Reference. 4. Scroll down the list of .NET references and highlight Microsoft.Web.Services.dll. Click Select and then OK. You should see the reference added to your project.
Page 18 of 29
ibm.com/developerWorks
5. Right-click on References again and select Add Web Reference. 6. Assuming that your Web service is running on the same machine as your client, the location of the WSDL file will be http://localhost:9080/bookstoreEnc/wsdl/com/ onlinebookstore/www/bookstoreEnc.wsdl, since bookstoreEnc was the name of the dynamic Web project you created and www.onlinebookstore.com was the namespace of the WSDL. If your Web service is running on a remote machine, you need to replace localhost with the correct machine name or IP address. Type the appropriate URL into the box and press Return.
Page 19 of 29
ibm.com/developerWorks
You can see in the figure that my Web service was running on a machine called hproctor. 7. Once you have entered the URL, you should get a description of the CreditCardPurchaseService as having one method, creditCardPurchase(). Change the name of the reference to bookstoreEnc and click Add Reference. This generates a number of code stubs in your project, which can be seen using the class view. Expand the class view until you see the CreditCardPurchaseService class and double-click on it to open it in the editor. 8. We need to change this class to use the Web Services Enhancements code, rather than the older Web services code. The class inherits from Microsoft.Web.Services.WebServicesClientProtocol rather than inheriting from System.Web.Services.Protocols.SoapHttpClientProtocol. 9. We also want to look at the client messages using the TCP monitor, so change the port number in the address from 9080 to 9081. Then close the CreditCardPurchaseService code window.
ibm.com/developerWorks
button to invoke the Web service, and a text box for the response. It will also be useful to have a button to clear the two text boxes so that we can try a different input, so we'll add two text boxes and two buttons to the form. 1. Change the name of the first text box to Input and set its text property so that it is empty. 2. Change the name of the first button to InvokeWebService and set its text to Invoke Web Service. 3. Change the name of the second text box to WebServiceResponse and set its text property so that it is empty. 4. Change the name of the second button to ClearTextBox and set its text to Clear Text Boxes. Your form should now look like this:
ibm.com/developerWorks
Next, you need to add the code that will run when someone clicks the button to invoke the Web service. Use the two drop-down boxes at the top of the code window to select InvokeWebService as the object and Click as the method, respectively. The first thing you will need to do when someone clicks the button is to create an object that represents the Web service, so add the following line:
Dim WebService As New bookstoreEnc.CreditCardPurchaseService
Before the message is sent, you want it to be encrypted. But before it can be encrypted, you need to have the correct public key. You have stored the public key in the Personal certificate store, so you need to open that certificate store and search through it until you find the right key. The X.509 name of the certificate is Interops Encryption, so you can search through the certificates until you find a match. Add the following code:
Dim encryptionCertificate As X509Certificate Dim store As X509CertificateStore store = X509CertificateStore.CurrentUserStore(X509CertificateStore.MyStore) store.OpenRead() For Each cert As X509Certificate In store.Certificates If (cert.GetName.IndexOf("Interops Encryption") > -1) Then encryptionCertificate = cert End If Next cert
You now have the correct public key certificate. How can you use that to encrypt the message? Under .NET, in order to control how incoming or outgoing SOAP messages are processed, you first need to create objects that encapsulate a particular way of handling data. Then, you add those objects to particular sections of your SOAP message, or, as .NET refers to it, the SOAP context for a particular Web service. In this way, .NET understands how each section of the SOAP message should be handled. For this example, you first need to make an X509SecurityToken from the security certificate. The X509SecurityToken could be added to the SOAP message, and it would represent the public key of the certificate. This is what would be done with a message that was being digitally signed. However, in this scenario, you do not want to add the X509SecurityToken to the message. Rather, you need to use it to encrypt the data:
Dim encryptionSecurityToken As New X509SecurityToken(encryptionCertificate) Dim encryptedData As New EncryptedData(encryptionSecurityToken)
Now you have the encryptedData object. Which section of the SOAP context does it need to be added to? Well, for starters, you are only encrypting the outgoing message; the message you receive back from the server will not be encrypted. Hence, you need to use the RequestSoapContext() method on
Page 22 of 29 Secure Web services: Encryption
ibm.com/developerWorks
the object representing your Web service to signify that you are interested in the request message and not the response. Also, because it pertains to security, the encryptedData object must be added to the Security section of the SOAP context:
WebService.RequestSoapContext.Security.Elements.Add(encryptedData)
At this stage, your outgoing SOAP message is correctly encrypted. However, there is one more change you need to make. By default, .NET forces SOAP path headers to be processed. This example makes no use of the path header, so you can change the header so that processing it becomes optional:
WebService.RequestSoapContext.Path.MustUnderstand = False
At last you can add the code to invoke the Web service. You want the data the user has typed into the Input text box to be sent to it, and the response message to be displayed in the WebServiceResponse text box:
WebServiceResponse.Text = WebService.creditCardPurchase(Input.Text)
Finally, you need to implement the Click method of the ClearTextBox object to clear both boxes:
Input.Clear() WebServiceResponse.Clear()
Page 23 of 29
ibm.com/developerWorks
In WebSphere Studio Application Developer, select the TCP/IP Monitor tab on the lower pane and then double-click on the title bar of the window to maximize it. The SOAP request should look similar to the following code (I have edited it a bit so as to be readable):
<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Header> <wsrp:path soap:actor="http://schemas.xmlsoap.org/soap/actor/next" xmlns:wsrp="http://schemas.xmlsoap.org/rp"> <wsrp:action></wsrp:action> <wsrp:to> http://localhost:9081/bookstoreEnc/services/CreditCardPurchase </wsrp:to> <wsrp:id> uuid:0b4706aa-604f-490e-9a19-828c21981288 </wsrp:id> </wsrp:path> <wsu:Timestamp xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility"> <wsu:Created>2004-02-26T23:55:53Z</wsu:Created> <wsu:Expires>2004-02-27T00:00:53Z</wsu:Expires> </wsu:Timestamp> <wsse:Security soap:mustUnderstand="1" xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/07/secext"> <xenc:EncryptedKey Type="http://www.w3.org/2001/04/xmlenc#EncryptedKey" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"> <xenc:EncryptionMethod
Page 24 of 29
ibm.com/developerWorks
Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" /> <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> <wsse:SecurityTokenReference> <wsse:KeyIdentifier ValueType="wsse:X509v3"> X/cJNXQ2PMsP5YC3CjTZAak1534= </wsse:KeyIdentifier> </wsse:SecurityTokenReference> </KeyInfo> <xenc:CipherData> <xenc:CipherValue> VGtI79mcqGFgXjIOoW3jUpolIrmL/gi0iSbvZh3fMkoipLLVrYLBoBTxO0T6hW Gsq+TOJRfU8eHkBDheDxVdDVAq1h/jnP2I/mfKfu+H8l/MZ9v+LX6PpvprMU63 DwNZO0YGsajTCHhzrkXrokOjwjID1D6PcYpn67YDa4rRF+M= </xenc:CipherValue> </xenc:CipherData> <xenc:ReferenceList> <xenc:DataReference URI="#EncryptedContent-1946a169-b13d-4b83-b1ed-a72262a487b7" /> </xenc:ReferenceList> </xenc:EncryptedKey> </wsse:Security> </soap:Header> <soap:Body xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility" wsu:Id="Id-d1bee847-92e5-43d4-a3af-d985112c1487"> <xenc:EncryptedData Id="EncryptedContent-1946a169-b13d-4b83-b1ed-a72262a487b7" Type="http://www.w3.org/2001/04/xmlenc#Content" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"> <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" /> <xenc:CipherData> <xenc:CipherValue> K0WDlESZe2fxHtdllzaDWDZyu5rD/zUBNms76BQOPUsVmE5DKfwmdK6A/cKBG9ECg1j lqqhVBVntFqdfisl/o72ospN+DT5ClkMIDz17CFNASvDpgGytVJ0PM1+PSW+y </xenc:CipherValue> </xenc:CipherData> </xenc:EncryptedData> </soap:Body> </soap:Envelope>
You can also verify that the Web service produces an error message when you input invalid data:
Page 25 of 29
ibm.com/developerWorks
Page 26 of 29
ibm.com/developerWorks
If you are having problems with an interoperability trial, make sure you use a tool such as TCP/IP Monitor to visually inspect the SOAP messages. The XML tags might show you that there is a difference in the way that two vendors have implemented a standard. Also, be very careful with your security certificates. Since Java keystores are a different certificate format than PKCS, you need to ensure that the certificate the client uses correctly corresponds to the one that the server uses, and that no errors have been introduced by converting the certificate from one format to another. This tutorial has shown you how to bring your .NET clients into the open standards world of Web services. It also shows how Web services makes all platforms interoperable using common interaction protocols. This same scenario can be performed in permutations with services running on other platforms and programming languages, but that is a subject for another tutorial.
Secure Web services: Encryption Page 27 of 29
ibm.com/developerWorks
Resources
Download all the source files in ws-encryptcode.zip. "Secure Web Services: Interoperability," by Hedley Proctor (developerWorks, February 2004), covers interoperability using basic authentication and digital signature. "Developing a .NET client to interact with a WebSphere Web Service," by Andy Clarke and Mike Edwards (developerWorks, October 2003), does not cover security, but does give an explanation of how to construct a basic interoperability demo. If you are fairly new to interoperability and have found this tutorial difficult, Andy and Mike's is an excellent primer. "Secure, reliable, transacted Web services," by Donald F. Ferguson, Tony Storey, Brad Lovering, and John Shewchuk (developerWorks, October 2003), was written jointly by Web services architects from IBM and Microsoft. This article describes how the standards for secure Web services interoperability are being developed. The WebSphere Application Server Web services security documentation explains in detail what all the webservices.xml settings mean and how they are configured. It covers authentication, digital signatures, and encryption as they apply to both Java Web services and their clients. For more information on WS-Security using Microsoft .NET, try "Encrypting SOAP messages using Web Services Enhancements," by Jeannine Hall Gailey (MSDN, March 2003). The WS-Security 1.0 is a formal specification for Web services authentication, digital signature, and encryption, written by IBM, Microsoft, and Verisign. The Web Services Interoperabilty Organization (http://www.ws-i.org) (WS-I.org) address many issues of interoperability between different implementations of Web services through profiles that define how specifications like WS-Security should be implemented. The WebSphere Application Server InfoCenter explains the difference between WebSphere Application Server security and security, as defined by the Java 2 Platform. The Java keytool documentation explains how to use the Java keytool to generate self-signed certificates or import and export certificates from JKS or JCEKS keystores. The OpenSSL project (http://www.openssl.org) is an open source initiative that supplies a toolkit that implements Secure Socket Layer (SSL) and Transport Layer Security (TLS). It also provides a cryptography library. The toolkit can be used to generate self-signed certificates in a multitude of formats.
Secure Web services: Encryption
Page 28 of 29
ibm.com/developerWorks
"Introduction to the PKCS Standards" is an overview of the widely used PKCS cryptography standards. It is written by Mohan Atreya, an employee of RSA, the company that developed PKCS. (Document is in PDF format.)
Feedback
Please send us your feedback on this tutorial. We look forward to hearing from you!
Colophon
This tutorial was written entirely in XML, using the developerWorks Toot-O-Matic tutorial generator. The open source Toot-O-Matic tool is an XSLT stylesheet and several XSLT extension functions that convert an XML file into a number of HTML pages, a zip file, JPEG heading graphics, and two PDF files. Our ability to generate multiple text and binary formats from a single source file illustrates the power and flexibility of XML. (It also saves our production team a great deal of time and effort.) For more information about the Toot-O-Matic, visit www-106.ibm.com/developerworks/xml/library/x-toot/ .
Page 29 of 29