The web service examples used so far in this book have not attempted to provide any security measures to ensure that they can only be accessed by authorized users, or to provide some level of assurance to the client that the server to which it might be about to pass sensitive information is the one to which it thinks it is connected. At the time of this writing, security for web services is the subject of several in-progress JSRs, such as JSR 105 (XML Digital Signature APIs; see http://jcp.org/jsr/detail/105.jsp) and JSR 106 (XML Digital Encryption APIs; see http://jcp.org/jsr/detail/106.jsp). Until these JSRs are completed and their
HTTP basic authentication is a simple mechanism that requires the client to supply a username and password to gain access to a service. The authentication information is encoded and sent in an HTTP header to the server, which can then verify whether the
[13] Basic authentication is what is happening when you log onto a web site for which you preregister for access to member-only areas. The dialog box that pops up to get your username and password is the browser's way to get the information required for the authentication header in the HTTP request.
To
Define the role or roles that are allowed access to some or all of the web service and the set of users that belong to those roles.
Define the URLs within the web service that require protection, and specify which roles should be able to use them.
Configure the web service client to send the appropriate authentication information when accessing the service.
The first step involves setting up authentication information for the web container that
Defining a new role does not add any protection. To achieve this, it is necessary to include authorization information in the
web.xml
file for the web service. The authorization information defines which of the web service's URLs are to be protected and which role or roles are to be allowed to access those URLs. Allowing a role to access a URL has the effect of making it possible for all of the users in that role to access the URL, provided that they can authenticate
The book image web service can be accessed without requiring authentication at almost any URL that starts with
http://localhost:8000/BookImageService
. In order to
[14] The result of this configuration is rather unusual because the web service now has both protected and unprotected URLs, all of which provide access to the same service. In reality, you are most likely to protect all access to the web service by precisely defining which URLs it responds to and mapping them all to the appropriate roles. Here, both a protected and an
unprotected service are provided so that we can use it to illustrate the SAAJ APIs without having to first introduce basic authentication.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/j2ee/dtds/web-app_2_3.dtd">
<web-app>
<display-name>SAAJ Book Image Service</display-name>
<description>SAAJ Book Image Service</description>
<servlet>
<servlet-name>BookImageService</servlet-name>
<display-name>Servlet for the SAAJ book Image Service</display-name>
<servlet-class>ora.jwsnut.chapter3.bookimageservice.BookImageServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>BookImageService</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<security-constraint>
<web-resource-collection>
<web-resource-name>SAAJ Book Image Service</web-resource-name>
<url-pattern>/basicAuth/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>JWSGroup</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Book Image Service</realm-name>
</login-config>
</web-app>
The security-constraint element specifies which URLs are to be protected (using the url-pattern element) and the role or roles allowed access to them (in the auth-constraint element). It is also necessary to specify how the identity of the caller is to be determined. This is achieved by the login-config element, which requires the use of basic authentication.
You can verify that this constraint is active by attempting to access the service with your web browser. With the J2EE 1.4 server running, point your browser at the URL http://localhost:8000/BookImageService . You should see an error page resulting from the fact that the service does not support access using the HTTP GET method. If, however, you use the URL http://localhost:8000/BookImageService/basicAuth , you are instead prompted to enter a username and password. Only after you correctly enter these do you see the same error page. If you are using the JWSDP with the Tomcat web server, use port number 8080 instead of 8000 in these URLs.
When it is run using the Ant target run-client , the Java client for the book image service that we used earlier in this chapter uses the URL http://localhost:8000/BookImageService to access the web service; therefore, it does not need to supply a username and password. The client gets the URL from its command line, so it is possible to arrange for it to access the protected URL http://localhost:8000/BookImageService/basicAuth instead. If you do this, however, you get an exception, since the web server expects to receive a username and a password to validate access to this URL, and refuses access if it does not get them (or if they are incorrect). SAAJ uses a slightly different URL syntax to allow the username and password to be included with the URL, which looks like this:
In the case of the book image service, for a user called JWSUserName with the password JWSPassword , the appropriate URL is:
The Ant project file for this example includes a target that can be used to run the client with this URL. To try it out,
ant run-basicauth-client
Since
JWSUserName
has access to the role
JWSGroup
, the web container allows the client access to the service, based on the
auth-constraint
element in the
web.xml
file. To
If you need more security than basic authentication can provide (as you almost
In order to use HTTPS, you need to have the Java Secure Sockets Extension (JSSE) installed on both the client and server systems. If you are using Java 2 Version 1.4, JSSE is part of the
|
The means by which you enable HTTPS support in your web server is
In the following descriptions, we use the shorthand ${EXAMPLES_ROOT} to refer to the directory in which you installed the example source code for this book, and we use ${JAVA_HOME} for the installation directory of J2SE. The first step is to create the certificate that the web server sends to any client that connects to it over HTTPS. To create this certificate, open a command window on serverhost , make ${EXAMPLES_ROOT} your working directory, and type the following command (all on one line):
keytool -genkey -alias server -keyalg RSA -keypass changeit -storepass changeit -keystore server.keystore -dname "CN=serverhost"
The certificate is created in a new keystore whose name is given by the
-keystore
argument, which in this case is stored in the installation directory of the example source code for the sake of convenience. The
-storepass
argument
The -dname argument can be used to supply a set of attributes that identify the certificate and its owning organization. Here, we set only the CN attribute, which specifies the name of the host to which the certificate belongs. It is important that you use the correct hostname because the client may extract this attribute and check that it matches the name of the host to which it thinks it is connected. [15]
[15] Obviously, in a real-world environment, it is not a good idea to use CN=localhost , but this might be appropriate for testing purposes.
The
keytool
command creates a self-signed certificate, which is,
The second step required to activate HTTPS is to enable it in the Tomcat web server by editing the server.xml file, which you'll find in its conf directory. Open this file in an editor and add the lines shown in bold in the following code section, substituting the pathname of the example source code installation directory in the value of the keyStoreFile attribute:
<Service className="org.apache.catalina.core.StandardService" debug="0"
name="Java Web Services Developer Pack">
<Connector className="org.apache.coyote.tomcat4.CoyoteConnector"
acceptCount="10" ........>
<Factory className="org.apache.catalina.net.DefaultServerSocketFactory"
/>
</Connector>
<!-- Added for SSL -->
<Connector className="org.apache.catalina.connector.http.HttpConnector
"
port="8443" minProcessors="5" maxProcessors="75"
enableLookups="false
"
acceptCount="10" connectionTimeout="60000" debug="0
"
scheme="https" secure="true">
<Factory className="org.apache.catalina.net.SSLServerSocketFactory
"
keystoreFile="${EXAMPLES_ROOT}\server.keystore
"
keystorePass="changeit
"
clientAuth="false" protocol="TLS"/>
</Connector>
<!-- End of SSL section -->
Note the following:
SSL is enabled by adding a second Connector element to the Service element for "Java Web Services Developer Pack." There is also another Service element in this file for internal services ” make sure you modify the correct
Service
element.
The filename supplied using the keystoreFile attribute must be the name of the keystore in which the certificate was created (or imported) by keytool . Similarly, the correct keystore password must be supplied using the keystorePass attribute.
HTTPS is enabled on port 8443, rather than port 8080. This is one of the two port
Having completed these steps, you can check that all is well by restarting the Tomcat web server and pointing your browser at the URL
https://serverhost:8443
(note that the protocol is
https
instead of
http
and the port number is 8443). Your browser will probably ask you to confirm that you accept the server's certificate and will then display the web server's home page. If you have not obtained and installed a certificate from a certificate authority, you will probably be
Now let's move to the client system. In order to use the book image web service client with HTTPS, you have to give it the appropriate URL. If you want to use basic authentication together with HTTPS, use the following URL:
To use HTTPS on its own, use:
Port number 7000 is used because this is the port on which the J2EE reference implementations listen for HTTPS connections. If you are using the JWSDP with the Tomcat web server, then the port number is 8443 instead of 7000.
When you use either of these URLs, the client connects over HTTPS and expects to receive the server's certificate and validate it. How does the validation work? The complete process is complex and not of any great interest from a web service development viewpoint. However, one of the following two conditions must hold:
The server's certificate must be installed in a keystore on the client machine to which the client application has access.
The server's certificate must be issued by a trusted authority whose certificate is installed in the client machine's keystore. In this case, the certificate itself does not need to be in the client's keystore.
In the first case, the certificate for the issuing authority is almost certainly found in the certificate store that is supplied with the JRE, which can be found at ${JAVA_HOME}\jre\lib\security\cacerts ; therefore, there is not any further work to do on the client system. If you created your own self-signed certificate, then you need to import it into a keystore that is accessible to the client.
Although you could import certificates directly into the JRE keystore, we will instead create and use a private keystore in order to demonstrate how simple it is to do this. This also has the advantage that you can experiment with certificates without the possibility of
copy ${JAVA_HOME}\jre\lib\security\cacerts
${EXAMPLES_ROOT}\client.keystore
Next, if you are using a self-signed certificate, you need to get a copy of it and import it into the newly created keystore; you can skip this step if the server is using a certificate issued by a trusted authority. To get the certificate, go to the server machine and proceed as
If you are using the JWSDP Tomcat web server, go to the directory containing the keystore ( server.keystore ) created in the previous section and type the command:
keytool -export -alias server -storepass changeit -keystore server.
keystore -file server.cer
If you are using the J2EE reference implementation, go to the directory lib\security below the J2EE installation directory and type the command:
keytool -export -alias server -storepass changeit -keystore keystore.jks
-file server.cer
Copy the newly created file server.cer from the server machine to the ${EXAMPLES_ROOT} directory on the client machine and import it there using the following command:
keytool -import -v -trustcacerts -alias JWSNutshell -storepass changeit
-keystore client.keystore -file server.cer
Reply when asked if you want to trust this certificate. Note that you can use any valid name for the alias, as long as it does not
In order to run the client application with HTTPS, it is necessary to supply the correct URL and arrange for it to use the keystore that has just been created to look for certificates. To point the application at the correct keystore, the two system properties listed in Table 3-4 need to be set.
|
Property |
Description |
|---|---|
|
javax.net.ssl.trustStore |
The pathname of the keystore. In this case, this is ${EXAMPLES_ROOT}\client.keystore. |
|
javax.net.ssl.trustStorePassword |
The password needed to access the keystore. By default, this password is changeit . |
A target that runs the web service over HTTPS using basic authentication by setting the appropriate values for both of these properties has been included in the Ant buildfile for this example:
<target name="run-httpsserver-client" if="client.present"
depends="init">
<java classname="${CLIENT_CLASS_NAME}" fork="yes">
<sysproperty key="javax.net.ssl.trustStore
"
value="${EXAMPLES_ROOT}/client.keystore"/>
<sysproperty key="javax.net.ssl.trustStorePassword
"
value="changeit"/>
<arg line="${CLIENT_HTTPS_SERVER_AUTH_ARGS}"/>
<classpath refid="run.path"/>
</java>
</target>
The property CLIENT_HTTPS_SERVER_AUTH_ARGS is set using properties in the jwsnutExamples.properties file to the appropriate URL for the service, which in this case is:
(or port 7000 if you are using the J2EE reference implementation).
To use this target, open a command window, make chapter3\bookimageservice (relative to the installation directory of the book's example source code) your working directory, and then type the command:
ant run-httpsserver-client
You should see the application start up and run as usual, although there will probably be a
|
|