1. Introduction

Security is an important aspect of web-services. Security can be ensured at several different application layers. The Oracle document here propounds different mechanisms of implementing security. In this article we are going to keep it simple and demonstrate how transport layer security could be introduced. So we are going to cook-up a simple jax-rs application that entertains some GET requests and implement security features in the tomcat container where it is deployed. Those needing a reference on Tomcat could check out the hyper-link. The example code is available for download at the end of the write-up.

2. Project Set-Up

We will create a Maven web-app project from Eclipse. Steps are as listed below.

Fire up Eclipse from a suitable workspace/folder

Click on New->File->Project…

Choose the creation of a Maven project and follow the wizard as shown in the screenshots below

Once the project is created, just add folder ‘src/main/java’ to it by clicking on Java Resources->New->Source Folder to have a final project structure as follows



3. Add Maven Dependencies

We will use Jersey implementation of jax-RS version 1.19 and Jersey-json so that the application serves out data in JSON format.

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.javacodegeeks.example</groupId> <artifactId>jaxRSSecurity</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>jaxRSSecurity Maven Webapp</name> <url>http://maven.apache.org</url> <properties> <jersey.version>1.19</jersey.version> <maven.plugin.version>2.2</maven.plugin.version> <jdk.version>1.6</jdk.version> </properties> <dependencies> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-servlet</artifactId> <version>${jersey.version}</version> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-json</artifactId> <version>${jersey.version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> <build> <finalName>jaxRSSecurity</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>${maven.plugin.version}</version> <configuration> <source>${jdk.version}</source> <target>${jdk.version}</target> </configuration> </plugin> </plugins> </build> </project>

4. Java Code

4.1 Create a resource class

In our case we will just create a POJO class with a few attributes

Student.java

package com.javacodegeeks.model; import org.codehaus.jackson.annotate.JsonIgnore; public class Student { String firstName, lastName; String school; int id; public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getSchool() { return school; } public void setSchool(String school) { this.school = school; } public int getId() { return id; } public void setId(int id) { this.id = id; } @Override public String toString(){ return firstName+" "+lastName+"is a student of "+school; } }

4.2 Service Class

The following class exposes two GET requests.

Services.java

package com.javacodegeeks.util; import java.util.ArrayList; import java.util.List; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import com.javacodegeeks.model.Student; @Path("/rest") public class Services { @GET @Path("/student/list") @Produces(MediaType.APPLICATION_JSON) public List studentList(){ List studentList = new ArrayList(); Student st1 = new Student(); st1.setFirstName("Emily"); st1.setLastName("Watson"); st1.setSchool("Edinburgh High School"); studentList.add(st1); Student st2 = new Student(); st2.setFirstName("Sarah"); st2.setLastName("Williams"); st2.setSchool("MountainView High School"); studentList.add(st2); return studentList; } @GET @Path("/student/{id}") @Produces(MediaType.APPLICATION_JSON) public Student studentById(@PathParam("id") int id){ Student student = new Student(); student.setFirstName("Andrew"); student.setLastName("Jones"); student.setSchool("St.Mary's"); student.setId(id); return student; } }

4.3 Add Security Features

Next, we will make changes to the web.xml to put some security restrictions in place. The goal is to employ Basic Authentication and seek a username and password when a request is made to access ../student/list data.

web.xml

<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>JAX-RS Web Application</display-name> <servlet> <servlet-name>jersey-json-example-serlvet</servlet-name> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> <init-param> <param-name>com.sun.jersey.config.property.packages</param-name> <param-value>com.javacodegeeks.util</param-value> </init-param> <!-- This is to pass the resource data as JSON to the client--> <init-param> <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name> <param-value>true</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>jersey-json-example-serlvet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> <!-- This is where security features are being enabled --> <security-constraint> <display-name>Restricted GET Request</display-name> <web-resource-collection> <web-resource-name>Restricted GET request to student data</web-resource-name> <!-- Restricting access only to this URL for the GET method --> <url-pattern>/rest/student/list</url-pattern> <http-method>GET</http-method> </web-resource-collection> <auth-constraint> <role-name>client</role-name> </auth-constraint> <user-data-constraint> <!-- In production environment it is advised to set the guarantee as CONFIDENTIAL --> <transport-guarantee>NONE</transport-guarantee> </user-data-constraint> </security-constraint> <!-- Using Basic authentication --> <login-config> <auth-method>BASIC</auth-method> </login-config> <security-role> <description>Normal operator user</description> <role-name>client</role-name> </security-role> </web-app>

5. Changes to Tomcat

As stated above we are using Tomcat 7. Now for the user to be authenticated we will specify the role ‘client’ (which is the role chosen in our web.xml above) and some username and password in our container. This username and password will have to be supplied to access the restricted resource.

5.1 Enable authentication

In most Tomcat installations, the authentication feature comes enabled. Make sure that we have the following configuration enabled in the server.xml file under the Tomcat installation directory->conf

<!-- Use the LockOutRealm to prevent attempts to guess user passwords via a brute-force attack --> <Realm className="org.apache.catalina.realm.LockOutRealm"> <!-- This Realm uses the UserDatabase configured in the global JNDI resources under the key "UserDatabase". Any edits that are performed against this UserDatabase are immediately available for use by the Realm. --> <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/> </Realm>

5.2 Setting up Roles and Users

Now the ‘UserDatabase’ referred in the realm refers to the tomcat-users.xml file under the Tomcat installation directory->conf. So we are going to set up a role ‘client’ with a certain username and password as shown below. Also note that in Tomcat 7 to view the deployment status, ‘manager-status’, ‘manager-gui’ etc. are some of the predefined roles but they are not assigned by default. Hence, we will change our tomcat-users.xml as shown below. This will enable access to the ‘Manager Status’ by supplying the username and password as ‘tomcat’.

tomcat-users.xml

<tomcat-users> <role rolename="tomcat"/> <role rolename="role1"/> <role rolename="client"/> <user username="tomcat" password="tomcat" roles="tomcat,manager-gui,manager-status"/> <user username="both" password="tomcat" roles="tomcat,role1"/> <user username="role1" password="tomcat" roles="role1"/> <user username="user1" password="password" roles="client" /> </tomcat-users>

6. Build the Project, Deploy and Run

Now we will build our Maven project with the following command mvn clean install -e

Deploy the project on Tomcat, that is, simply pick the war file created by the above command in the ‘target’ folder of the project say jaxRSSecurity.war and place it under the ‘webapps’ folder of the Tomcat. Just note that if there are any other war files in the folder just remove it.

file created by the above command in the ‘target’ folder of the project say and place it under the ‘webapps’ folder of the Tomcat. Just note that if there are any other files in the folder just remove it. Next just start-up Tomcat. In Windows, go to the bin->startup.bat

Once the war is deployed successfully, open a browser and go to the URL where tomcat is running say, http://localhost:8008/jaxRSSecurity/rest/student/list

A dialogue box will prompt the username and password, just supply the values configured in tomcat-users.xml and it should display the output as shown in the screenshots below

and it should display the output as shown in the screenshots below Output: [{"firstName":"Emily","lastName":"Watson","school":"Edinburgh High School","id":0},{"firstName":"Sarah","lastName":"Williams","school":"MountainView High School","id":0}]

Notice that on hitting the other GET request at http://localhost:8008/jaxRSSecurity/rest/student/123 there is no prompt for authentication as this URL was not restricted in our web.xml file.

request at there is no prompt for authentication as this URL was not restricted in our file. Output {"firstName":"Andrew","lastName":"Jones","school":"St.Mary's","id":123}

7. Conclusion

This brings us to the end of the article.

Download the Eclipse project of this tutorial: