Java Libraries
Use JAR files which are listed below:
asm-3.1.jar
commons-codec-1.10.jar
jackson-core-asl-1.9.2.jar
jackson-jaxrs-1.9.2.jar
jackson-mapper-asl-1.9.2.jar
jackson-xc-1.9.2.jar
javassist-3.19.0-GA.jar
jersey-client-1.18.jar
jersey-core-1.18.jar
jersey-json-1.18.jar
jersey-server-1.18.jar
jersey-servlet-1.18.jar
jettison-1.1.jar
jsr311-api-1.1.1.jar
resteasy-jaxb-provider-2.3.3.Final.jar
resteasy-jaxrs-2.3.1.GA.jar
scannotation-1.0.2.jar
Create Server Project
Create Dynamic Web Project in Eclipse. Copy all jar files above to the lib directory in the project
Create web.xml
This file is used to register a URL pattern in Jersey to intercept HTTP calls to the service.
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<context-param>
<param-name>resteasy.scan</param-name>
<param-value>true</param-value>
</context-param>
<servlet>
<servlet-name>resteasy-servlet</servlet-name>
<servlet-class>
org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>resteasy-servlet</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
</web-app>
Entity Class
Create entities package in server project. Create a entity class: Account.java as below
Account.java
package entities;
public class Account {
private String username;
private String password;
private String[] roles;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String[] getRoles() {
return roles;
}
public void setRoles(String[] roles) {
this.roles = roles;
}
public Account(String username, String password, String[] roles) {
this.username = username;
this.password = password;
this.roles = roles;
}
public Account() {
}
}
Models Class
Create model package in server project. Create a model class: AccountModel.java as below
AccountModel.java
package model;
import java.util.ArrayList;
import java.util.List;
import entities.Account;
public class AccountModel {
private List<Account> accounts;
public AccountModel() {
this.accounts = new ArrayList<Account>();
this.accounts.add(new Account("acc1", "123", new String[] { "superadmin", "admin", "employee" }));
this.accounts.add(new Account("acc2", "123", new String[] { "admin", "employee" }));
this.accounts.add(new Account("acc3", "123", new String[] { "employee" }));
}
public Account login(String username, String password) {
for (Account account : this.accounts) {
if (account.getUsername().equalsIgnoreCase(username) && account.getPassword().equalsIgnoreCase(password)) {
return account;
}
}
return null;
}
}
Interceptor Class
Create security package in server project. Create a interceptor class: SecurityInterceptor.java as below
SecurityInterceptor.java
package security;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import javax.annotation.security.DenyAll;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.ext.Provider;
import org.jboss.resteasy.annotations.interception.ServerInterceptor;
import org.jboss.resteasy.core.Headers;
import org.jboss.resteasy.core.ResourceMethod;
import org.jboss.resteasy.core.ServerResponse;
import org.jboss.resteasy.spi.Failure;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.interception.PreProcessInterceptor;
import org.jboss.resteasy.util.Base64;
import entities.Account;
import model.AccountModel;
@Provider
@ServerInterceptor
public class SecurityInterceptor implements PreProcessInterceptor {
private static final String AUTHORIZATION_PROPERTY = "Authorization";
private static final String AUTHENTICATION_SCHEME = "Basic";
private static final ServerResponse ACCESS_DENIED = new ServerResponse("Access denied for this resource", 401,
new Headers<Object>());
private static final ServerResponse ACCESS_FORBIDDEN = new ServerResponse("Nobody can access this resource", 403,
new Headers<Object>());
private static final ServerResponse SERVER_ERROR = new ServerResponse("INTERNAL SERVER ERROR", 500,
new Headers<Object>());
@Override
public ServerResponse preProcess(HttpRequest request, ResourceMethod methodInvoked)
throws Failure, WebApplicationException {
Method method = methodInvoked.getMethod();
// Access allowed for all
if (method.isAnnotationPresent(PermitAll.class)) {
return null;
}
// Access denied for all
if (method.isAnnotationPresent(DenyAll.class)) {
return ACCESS_FORBIDDEN;
}
// Get request headers
final HttpHeaders headers = request.getHttpHeaders();
// Fetch authorization header
final List<String> authorization = headers.getRequestHeader(AUTHORIZATION_PROPERTY);
// If no authorization information present; block access
if (authorization == null || authorization.isEmpty()) {
return ACCESS_DENIED;
}
// Get encoded username and password
final String encodedUserPassword = authorization.get(0).replaceFirst(AUTHENTICATION_SCHEME + " ", "");
// Decode username and password
String usernameAndPassword;
try {
usernameAndPassword = new String(Base64.decode(encodedUserPassword));
} catch (IOException e) {
return SERVER_ERROR;
}
// Split username and password tokens
final StringTokenizer tokenizer = new StringTokenizer(usernameAndPassword, ":");
final String username = tokenizer.nextToken();
final String password = tokenizer.nextToken();
// Verify user access
if (method.isAnnotationPresent(RolesAllowed.class)) {
RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class);
Set<String> rolesSet = new HashSet<String>(Arrays.asList(rolesAnnotation.value()));
// Is user valid?
if (!isUserAllowed(username, password, rolesSet)) {
return ACCESS_DENIED;
}
}
// Return null to continue request processing
return null;
}
private boolean isUserAllowed(final String username, final String password, final Set<String> rolesSet) {
AccountModel accountModel = new AccountModel();
Account account = accountModel.login(username, password);
if (account == null) {
return false;
} else {
for (String role : rolesSet) {
for (String r : account.getRoles()) {
if (role.equalsIgnoreCase(r)) {
return true;
}
}
}
return false;
}
}
}
Create Restful Web Services
Create Restful Web Services provides text/plain data for the client
package ws;
import javax.annotation.security.PermitAll;
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.MediaType;
import javax.ws.rs.core.Response;
@Path("api/demo")
public class DemoRestController {
@GET
@Path("work1")
@Produces({ MediaType.TEXT_PLAIN })
@PermitAll
public Response work1() {
try {
return Response.ok("Work 1").build();
} catch (Exception e) {
return Response.status(Response.Status.BAD_REQUEST).build();
}
}
@GET
@Path("work2")
@Produces({ MediaType.TEXT_PLAIN })
@RolesAllowed({ "superadmin" })
public Response work2() {
try {
return Response.ok("Work 2").build();
} catch (Exception e) {
return Response.status(Response.Status.BAD_REQUEST).build();
}
}
@GET
@Path("work3")
@Produces({ MediaType.TEXT_PLAIN })
@RolesAllowed({ "superadmin", "admin" })
public Response work3() {
try {
return Response.ok("Work 3").build();
} catch (Exception e) {
return Response.status(Response.Status.BAD_REQUEST).build();
}
}
@GET
@Path("work4")
@Produces({ MediaType.TEXT_PLAIN })
@RolesAllowed({ "superadmin", "admin", "employee" })
public Response work4() {
try {
return Response.ok("Work 4").build();
} catch (Exception e) {
return Response.status(Response.Status.BAD_REQUEST).build();
}
}
}
Testing Restful Web Services
Access restful web services use the following url: http://localhost:8080/SecurityJavaRestful_Server/api/demo/work1
Output
Work 1
Access restful web services use the following url: http://localhost:8080/SecurityJavaRestful_Server/api/demo/work2
Output
Access denied for this resource
Access restful web services use the following url: http://localhost:8080/SecurityJavaRestful_Server/api/demo/work3
Output
Access denied for this resource
Access restful web services use the following url: http://localhost:8080/SecurityJavaRestful_Server/api/demo/work4
Output
Access denied for this resource
Consume Restful Web Services from Java Application
Create Java Project in Eclipse. Add all jar files above to the project
Create DemoRestClientModel
DemoRestClientModel class contain methods call restful web services
package models;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import javax.ws.rs.core.MediaType;
import org.apache.commons.codec.binary.Base64;
public class DemoRestClientModel {
private String username = "acc2";
private String password = "123";
private Client client;
private WebResource webResource;
private String BASE_URL = "http://localhost:8080/SecurityJavaRestful_Server/api/";
public DemoRestClientModel() {
this.client = Client.create(new DefaultClientConfig());
this.webResource = this.client.resource(BASE_URL).path("demo");
}
public ClientResponse work1() {
ClientResponse response = null;
try {
WebResource resource = this.webResource;
response = resource.path("work1")
.type(MediaType.TEXT_PLAIN)
.get(ClientResponse.class);
} catch (Exception e) {
response = null;
}
return response;
}
public ClientResponse work2() {
ClientResponse response = null;
try {
String authStringAccount = new Base64().encodeToString((this.username + ":" + this.password).getBytes());
WebResource resource = this.webResource;
response = resource.path("work2")
.header("Authorization", "Basic " + authStringAccount)
.type(MediaType.TEXT_PLAIN)
.get(ClientResponse.class);
} catch (Exception e) {
response = null;
}
return response;
}
public ClientResponse work3() {
ClientResponse response = null;
try {
String authStringAccount = new Base64().encodeToString((this.username + ":" + this.password).getBytes());
WebResource resource = this.webResource;
response = resource.path("work3")
.header("Authorization", "Basic " + authStringAccount)
.type(MediaType.TEXT_PLAIN)
.get(ClientResponse.class);
} catch (Exception e) {
response = null;
}
return response;
}
public ClientResponse work4() {
ClientResponse response = null;
try {
String authStringAccount = new Base64().encodeToString((this.username + ":" + this.password).getBytes());
WebResource resource = this.webResource;
response = resource.path("work4")
.header("Authorization", "Basic " + authStringAccount)
.type(MediaType.TEXT_PLAIN)
.get(ClientResponse.class);
} catch (Exception e) {
response = null;
}
return response;
}
}
Run It
package main;
import com.sun.jersey.api.client.ClientResponse;
import models.DemoRestClientModel;
public class Main {
public static void main(String[] args) {
DemoRestClientModel demoRestClientModel = new DemoRestClientModel();
System.out.println("Test with work1 web method");
ClientResponse response1 = demoRestClientModel.work1();
int statusCode1 = response1.getStatus();
System.out.println("\tStatus Code: " + statusCode1);
String result1 = response1.getEntity(String.class);
System.out.println("\tResult: " + result1);
System.out.println("Test with work2 web method without account");
ClientResponse response2 = demoRestClientModel.work2();
int statusCode2 = response2.getStatus();
System.out.println("\tStatus Code: " + statusCode2);
String result2 = response2.getEntity(String.class);
System.out.println("\tResult: " + result2);
System.out.println("Test with acc2 have roles: admin and employee access work2 web method");
ClientResponse response3 = demoRestClientModel.work2();
int statusCode3 = response3.getStatus();
System.out.println("\tStatus Code: " + statusCode3);
String result3 = response3.getEntity(String.class);
System.out.println("\tResult: " + result3);
System.out.println("Test with acc2 have roles: admin and employee access work3 web method");
ClientResponse response4 = demoRestClientModel.work3();
int statusCode4 = response4.getStatus();
System.out.println("\tStatus Code: " + statusCode4);
String result4 = response4.getEntity(String.class);
System.out.println("\tResult: " + result4);
System.out.println("Test with acc2 have roles: admin and employee access work4 web method");
ClientResponse response5 = demoRestClientModel.work4();
int statusCode5 = response5.getStatus();
System.out.println("\tStatus Code: " + statusCode5);
String result5 = response5.getEntity(String.class);
System.out.println("\tResult: " + result5);
}
}
Output
Test with work1 web method
Status Code: 200
Result: Work 1
Test with work2 web method without account
Status Code: 401
Result: Access denied for this resource
Test with acc2 have roles: admin and employee access work2 web method
Status Code: 401
Result: Access denied for this resource
Test with acc2 have roles: admin and employee access work3 web method
Status Code: 200
Result: Work 3
Test with acc2 have roles: admin and employee access work4 web method
Status Code: 200
Result: Work 4