Skip to main content

Authentication in Jersey

Posted by mhadley on March 7, 2008 at 1:14 PM PST

I'm working on an internal project building some RESTful services using a combination of Jersey, JPA, Glassfish and Derby. Actions on some resources require authentication and I need access to the name of the authenticated user in the resource method. This entry describes the steps to set this up - kudos to my colleague Hubert for working out much of the below.

Obviously you're going to need all the ingredients listed above. I'm using NetBeans which came bundled with Glassfish and Derby so all I had to do was install the RESTful Web Services plug-in, YMMV.

Next you need a database to store username, password and group information. Here's the table definitions I used:

CREATE TABLE users (
    id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    username VARCHAR(64) UNIQUE NOT NULL,
    password VARCHAR(64) NOT NULL,
);
CREATE INDEX username ON users(username);

CREATE TABLE groups (
    id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    username VARCHAR(64) NOT NULL REFERENCES users(username) ON DELETE CASCADE,
    groupname VARCHAR(64)
);

Depending on your needs you could lose the integer fields, the important thing is to have a column in the group table with the same name as the column in the users table that holds the username. Those two columns are used to join the users table to the groups table. The Glassfish security realm is going to execute a query like this to retrieve the groups (which map to security roles) that a particular user is a member of:

SELECT groupname FROM groups g, users u where g.username = u.username and u.username = ?

Add some users and groups for testing purposes, note that the password should be an md5 hash, not plaintext - there are several web sites that offer online MD5 generators that you can use. I used groups named USERS and ADMINISTRATORS, you'll see where these come in later.

Next you need to define a JDBC data source, connection pool and security realm in Glassfish. The first two are pretty straightforward and will likely be taken care of already if you have deployed a web application using the database. Setting up the security realm is also straightforward once you have a suitable database structure as described above. You do this via the admin console as shown below (there are a couple of additional fields on the form, you can leave those blank):

realm.png

Its now possible to require authentication for access to a JAX-RS resource via web.xml. Say I have a resource that only authenticated users can use, e.g.:

@Path("dropbox")
public class DropBox {
    @Context
    SecurityContext security;
   
    @POST
    public Response drop(InputStream data) {
        String username = security.getUserPrincipal().getName();
        ...
    }
}

Note the use of dependency injection to get an instance of SecurityContext and how that interface provides access to the username. In order for this to work we have to tell the container that authentication is required for access to the /dropbox URI. Add the following lines to your web.xml to restrict use of this resource to members of the USERS group:

<security-constraint>
    <display-name>DropBox</display-name>
    <web-resource-collection>
        <web-resource-name>DropBox</web-resource-name>
        <description></description>
        <url-pattern>/dropbox</url-pattern>
        <http-method>GET</http-method>
        <http-method>POST</http-method>
        <http-method>HEAD</http-method>
        <http-method>PUT</http-method>
        <http-method>OPTIONS</http-method>
        <http-method>TRACE</http-method>
        <http-method>DELETE</http-method>
    </web-resource-collection>
    <auth-constraint>
        <description>Have to be a USER</description>
        <role-name>USERS</role-name>
    </auth-constraint>
</security-constraint>
<login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>userauthn</realm-name>
</login-config>
<security-role>
    <description/>
    <role-name>USERS</role-name>
</security-role>

That about it, after you redeploy the application, the next time you try to access /dropbox you'll get a 401 Unauthorized response unless you include a suitable Authorization header in the request.

Related Topics >>

Comments

Hi marc - Thanks for the post, it was very helpful. In order to get it to work on glassfish, I needed to add security-role-mapping to my sun-web.xml file. I tried posting it here, but it isn't previewing appropriately. Thanks again.

Hi marc,good article. But I run my jersey app in tomcat and want to use Spring Security 2.0.0 to do the authentication and the authorization jobs :) Please give me some ideas how to implement it! Thanks.

Suggest you post a question to the Jersey users group, there are several people there who are using Spring: users [at] jersey.dev.java.net.