Java, JavaFX, Groovy, Grails …
Jersey
Jersey JAX-RS, Tomcat, Basic Auth and Security Annotations
May 21st
While doing some research on securing JAX-RS Restful services, I came across this question on stackoverflow which asks how best to wire up a simple security mechanism for:
- Jersey JAX-RS.
- Tomcat.
- Basic Authentication.
- JSR 250 Annotations such as @RolesAllowed.
So in a nutshell….this can be accomplished quite easily by configuring the following:
- tomcat-users.xml (found in the conf dir of your tomcat install).
- the applications web.xml.
- and lastly annotating the restful service.
By adjusting the tomcat-users.xml you will create a tomcat memory realm of usernames and passwords.
To do this…simpy add the following to the tomcat-users.xml file:
<role rolename="admin" /> <user username="admin" password="adminadmin" roles="manager,admin,user" /> <role rolename="user" /> <user username="user" password="useruser" roles="user" />
Next you will want to adjust your web.xml to include both jersey resources and also the applications security configuration:
<servlet> <servlet-name>ServletAdaptor</servlet-name> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> <load-on-startup>1</load-on-startup> <init-param> <param-name>com.sun.jersey.spi.container.ResourceFilters</param-name> <param-value>com.sun.jersey.api.container.filter.RolesAllowedResourceFilterFactory</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>ServletAdaptor</servlet-name> <url-pattern>/resources/*</url-pattern> </servlet-mapping> <session-config> <session-timeout> 30 </session-timeout> </session-config> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <security-constraint> <web-resource-collection> <web-resource-name>Secure</web-resource-name> <url-pattern>/resources/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>admin</role-name> <role-name>user</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>BASIC</auth-method> <realm-name>Test</realm-name> </login-config> <security-role> <role-name>admin</role-name> </security-role> <security-role> <role-name>user</role-name> </security-role>
and lastly a rest service that utilizes the JSR-250 security annotations:
import com.sun.jersey.core.util.Base64;
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
@Path("/Test")
@RolesAllowed("admin")
public class Test {
@GET
@Produces("text/plain")
@RolesAllowed("user")
public String getNumber(@Context HttpHeaders headers){
System.out.println( getCredentials(headers));
return "1 Secured with User";
}
@GET
@Path("/Secure")
@RolesAllowed("admin")
@Produces("text/plain")
public String getSecureNumber(@Context HttpHeaders headers){
System.out.println( getCredentials(headers));
return "2 Secured with Admin";
}
private String getCredentials(HttpHeaders headers) {
String auth = headers.getRequestHeader("authorization").get(0);
auth = auth.substring("Basic ".length());
String[] values = new String(Base64.base64Decode(auth)).split(":");
String username = values[0];
String password = values[1];
String return_val = "Username = " + username + " Password = "+ password;
return return_val;
}
}If you deploy to localhost with the above configuration the urls are as follows
- an “admin” person has access to http://localhost:8080/MyService2/resources/Test/Secure
- a “user” person has access to = http://localhost:8080/MyService2/resources/Test/
Because this is “BASIC” security…a pop up will appear to log the person in when a request is made to the secured resource.
You can find a zipped copy of my Netbeans project here