One of the highlights of the Java programming language is that the open-source community can provide excellent applications at a low cost or even free of charge. One example is Apache. Tomcat, which provides a robust web server for development using Servlet or JSP technology. Currently, Web Service technologies are becoming increasingly mature. Therefore, some applications may use the front-end thin clients with rich swing features to combine the data verification and business logic developed by the web or EJB layer. Such applications can run normally only when protected. However, security does not necessarily mean high costs. The purpose of this article is to demonstrate how the Web service client uses a self-Signed security certificate through secure HTTPS protocol. Problems with using self-signed certificatesHTTPS can be used seamlessly with insecure HTTP without interrupting the user experience. This is because SSL is designed to be verified and signed by a trusted third party. Verisign is a popular certification organization. If your web application requires secure communication, you can pay VeriSign to sign your SSL certificate. After Verisign signature, users on your web site can switch between HTTP and HTTPS without interruption, because all mainstream Web browsers trust the Verisign signature certificate. However, Verisign is not the only option to obtain the signature certificate. You can also sign your own certificate to save operation costs or for personal convenience. However, the self-signed certificate will interrupt the user experience of the web site. A dialog box is usually displayed in a web browser asking if you want to trust a self-signed certificate. This is a good feature of Web browsers, because they still have the opportunity to process a certificate signed by an unknown authority. This is not so easy when developing a web service client for communication over HTTPS. When running Java code, there is no dialog box asking whether to trust an untrusted Certification Authority. JRE throws an exception, indicating that it tries to connect to a web site with an untrusted certificate through https: Caused By:Sun. Security. validator. validatorexception:No trusted Certificate found Unable to catch this exception and continue. To enable the Web service to use a self-signed certificate, JRE must trust you as a certification authority in some way. Solution OverviewTo demonstrate the solution to this problem, I will perform the following steps:
- Generate and self-signed my own certificate;
- Configure SSL for Tomcat to use the certificate;
- Create a sample Web service to be called over HTTPS;
- Generate Web service client code from WSDL;
- Use a custom keystore solution to demonstrate the client;
Generate a self-signed certificateJDK comes with a tool, keytool.exe, used to manage the SSL Public Key/private key. The key is added and deleted in a binary file of the file system. The default keystore file is java_home/JRE/lib/security/cacerts. This file contains a list of certification bodies trusted by JRE. A list of well-known trusted companies (such as Verisign) already exists in the keystore. To view the list, run the following code with the password changeit: D:/> keytool-list-RFC-keystore Java_home/JRE/lib/security/cacerts The keytool application can be used to edit this file. However, to prevent errors, it is best to create a new file. If you do not tell keytool which file to use, it will create home/. keystore by default. To generate your self-signed certificate, run: D:/> keytool.exe-genkey-alias Tomcat -Keyalg RSA-storepass bigsecret-keypass bigsecret-dname "Cn = localhost" After the command is executed, A. keystore file is generated in the home directory. The meanings of various switching commands are as follows:
- Genkey:Notify the keytool application to generate a new public/private key pair.
- Alias:The name used to reference the key. Remember, the. keystore file can contain multiple keys.
- Keyalg:Use the RSA algorithm to generate a public/private key pair.
- Storepass:Password required to access the. keystore file.
- Keypass:The password required to manage the key.
- Dname:This value is very important .. I use localhost because this example is designed to run locally. This value must be www.myserver.com if a web application is registered as a http://www.myserver.com. If the name does not match, the certificate is automatically rejected.
Once the keytool application creates a new public/private key pair, it automatically signs the key. We just generated our self-signed certificate, which can be used for HTTPS communication. You only need to extract the self-Signed public key. I will show you how to do this later. Configure SSL for TomcatYou must configure tomcat to use a self-signed certificate. I am using tomcat. 5.0.30. Edit the tomcat/CONF/server. xml file. Search for "8443" in the file and unbind the <connector.../> comment to the port. You must add the following attributes to <connector.../>: Keystorepass = "bigsecret" When JRE is started, it will automatically find the home/. keystore file, and Tomcat will try to access it with the "bigsecret" password. When Tomcat is started, the console should have the following output: Feb 4, 3:11:23, 2006 Org. Apache. Coyote. http11.http11protocol start Info: Starting coyote HTTP/1.1 on Http-8443 This means that <connector.../> has successfully read The. keystore file and can now use port 8443 for secure HTTPS connections. Open a Web browser and enter https: // localhost: 8443/in the address bar /. Because the certificate is self-signed, the Web browser displays a dialog box asking if you trust the connection. If accepted, all communications will be conducted over https, making it secure. Create a Web ServiceI will use Apache The Axis project creates a very simple web service. The Web Service simulates the check of new email messages. The Web service client passes a unique token to identify a user. The Web service returns a list of new email messages (see list 1 ). Listing 1 import java.util.*;public class Email { public List getNewMessages(String id) { List l = new ArrayList(3); l.add("1"); l.add("2"); l.add("3"); return l; }} To obtain the deployed Web Service, perform the following steps:
- Cut and paste the code from List 1 to the email. JWS file under the webapp root directory.
- Edit the Web. xml file and add the axis Servlet and a *. JWS ing (List 2 ).
- Set axis
Jar files are placed in WEB-INF/lib. See the reference section at the end of the article to obtain the axis project URL.
Listing 2 <servlet> <servlet-name> AxisServlet </servlet-name> <display-name> Apache-Axis Servlet </display-name> <servlet-class> org.apache.axis.transport.http.AxisServlet </servlet-class></servlet><servlet-mapping> <servlet-name> AxisServlet </servlet-name> <url-pattern> *.jws </url-pattern></servlet-mapping> After deploying the war file included in this article (and configuring SSL for Tomcat), the Web can be securely accessed through HTTPS using the following URL: Https: // localhost: 8443/jdjarticlewebservice/email. JWS Use wsdl2javaThe Axis project provides a tool named wsdl2java that obtains a Web Service WSDL and automatically creates the Java source code required to use the web service. See generating email. JWS in listing 3. Web Service Code command line. Listing 3java -classpath .;axis.jar;log4j-1.2.8.jar ;commons-logging-1.0.4.jar ;commons-discovery-0.2.jar ;jaxrpc.jar;saaj.jar ;wsdl4j-1.5.1.jar org.apache.axis.wsdl.WSDL2Java -p jdj.wsclient.sharedhttp://localhost:8080/JDJArticle/Email.jws?wsdl Note the URL used to access the WSDL in listing 3. It uses insecure HTTP protocol on port 8080. Why not use HTTPS on port 8443? This is because of the self-signed certificate. The wsdl2java tool will encounter the same issue as the certificate problem solved in this article. Therefore, insecure protocols must be used. This means that the generated code must be slightly changed. Use "HTTPS" and "8443" to replace "HTTP" and "8080" references. The client ZIP file included in this article contains the changed code. Clients with custom keystoreThe default keystore of JRE is java_home/JRE/lib/security/cacerts. If a self-signed certificate appears, the Java application throws an exception because the certificate is not in the keystore. Therefore, there are two options for developing the client. The first option is to put the self-signed certificate into the default keystore of the JRE. Although this method works, it is not a good solution because it needs to be customized on each client machine. The second option is to generate a custom keystore, put the self-signed certificate into it, and distribute the custom keystore as part of the application (usually in a jar file ). To create a custom keystore for the client, follow these steps:
- Export the self-signed Public Key from home/. keystore.
- Import the self-signed Public Key to the new keystore created for the client.
To export the self-signed Public Key from home/. keystore, run the following code: D:/> keytool.exe-genkey-alias Tomcat -Keyalg RSA-storepass bigsecret-keypass bigsecret-dname "Cn = localhost" Now, you can create a custom keystore for the client by importing tomcat. CER: D:> keytool.exe-import-noprompt -Trustcacerts-alias tomcat-file tomcat. cer-keystore customkeystore-storepass Littlesecret Use "-keystore" Customkeystore "will create a new keystore file named customkeystore in the current working directory. You can find the customkeystore file in the/classpath/resources/keystore directory of the client ZIP file in this article. Replace the file with the generated file. Now there is only one client that uses this custom keystore .. I will demonstrate two implementation methods. The first method is to use the java system attributes javax.net. SSL. truststore and javax.net. SSL. truststorepassword to point to the customkeystore file and provide a password to access the file. This method is used by the sample Web service client in the jdj. wsclient. truststore package (see Listing 4 ). Listing 4public static void main(String[] args) throws Exception{ System.setProperty( "javax.net.ssl.trustStore", "classpath/resources/keystore/CustomKeystore"); System.setProperty( "javax.net.ssl.trustStorePassword", "littlesecret"); EmailServiceLocator wsl = new EmailServiceLocator(); Email_PortType ews = wsl.getEmail(); Object [] objects = ews.getNewMessages("12345"); out("Msg Count: " + objects.length);} Set system properties in the main () method, and then create an object that uses the web service. When the JRE needs to access the keystore, it searches for the classpath/resources/keystore/customkeystore file in the file system. Although this is only a simple solution, it still has problems because the keystore file must be stored in the file system, and the client code must know where to find it. The second solution has better portability. It stores resources in jar files, thus avoiding file system problems. The client code reads the customkeystore file and uses it to create a secure connection to the server in some way. The sample Web service client in the jdj. wsclient. socketfactory package uses this method (see listing 5 ). Listing 5public MySocketFactory(Hashtable table)throws Exception{ out("Created!"); KeyStore ks = KeyStore.getInstance( KeyStore.getDefaultType() ); char [] password = "littlesecret".toCharArray(); String keystore = "/resources/keystore/CustomKeystore"; Class tclass = this.getClass(); InputStream is = tclass.getResourceAsStream( keystore ); ks.load(is, password); KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks,password); TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); tmf.init(ks); SSLContext context = SSLContext.getInstance("SSL"); context.init( kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom() ); factory = context.getSocketFactory();} Listing 5 shows how to read the customkeystore file as a resource and use it to create javax.net. SSL. sslsocketfactory. Configure the axis pluggable architecture, and then use the mysocketfactory class to create a secure socket object from the factory. ConclusionThis article begins with a simple question: I want to use a self-signed certificate to protect web service communication over HTTPS. By default, JRE rejects the application's self-signed certificate because it is not from a trusted authority. To make secure communications run, the Web service client JRE must trust the self-signed certificate. To this end, I use the keytool application to generate a new public/private key pair, extract the self-Signed public key, create a new keystore, and import the self-signed certificate. Then I create a completely self-contained web service client that does not require any client configuration. |