JAX-RS Security using API-KEY for Authorization Example

JAX-RS Security using API-KEY for Authorization Example

In this tutorial we will discuss how to secure JAX-RS RESTful web services using API-KEY or Service Key for Authorization. This form of security is used to ensure that certain RESTful endpoints are protected against unauthorized use.

What is an API-KEY

An API key assigns a unique 128-bit value to a user of the RESTful service. This API key is associated to a user and maintained in a datastore, in my case, MongoDB. The RESTful service then references this datastore together with the service id and API-KEY which each incoming request. Once the incoming requests are validated, access is either granted or denied to the specified end-point.

Advantages of using API-KEY for Authorization

Advantages

  • User passwords are never transmitted during authorization between client and server
  • API-KEYs are faster than Digest Authentication as only one call is needed as opposed to 2 calls for every request
  • API-KEYs works well with TLS/SSL and should be included in the header for added protection and to prevent the values from being captured in the logs.

API-KEY / Service ID Required in Header

For security reason we recommend that the API-KEY and Service ID be included in the HTTP Headers instead of HTTP Parameters via (@QueryParam). This is especially important when using TLS/SSL as it will guarantee that request data is encrypted end to end and prevent man in the middle attacks.

API-KEY Danger

Never put the API-KEY and Service ID in the HTTP Query Parameters or Matrix Parameters in RESTful API calls as these can be captured in the server logs and will allow to gain access to you client’s authorization credentials making your application less secure.

Getting Started

In order to run this tutorial yourself, you will need the following:

  • Java JDK 1.6 or greater
  • Favorite IDE Spring Tool Suite (STS), Eclipse IDE or NetBeans (I happen to be using STS because it comes with a Tomcat server built-in)
  • Tomcat 7 or greater or other popular container (Weblogic, Websphere, Glassfish, JBoss, VMWare vFabric, etc). For this tutorial I am using VMware vFabric tc Server Developer Edition which is essentially an enhanced Tomcat instance integrated with Spring STS
  • Jersey JAX-RS
  • log4J (for logging purposes)

Required Libraries

Copy all of the following jars to WebContent->WEB-INF->lib folder.

 asm-3.1.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
 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
 log4j-1.2.17.jar
 mongo-java-driver-3.0.2.jar
 persistence-api-1.0.2.jar

Complete Project Overview

I have added the project overview to give you a full view of the structure and show you all files contained in this sample project.

jax-rs_apikey_security_proj

RESTful Web Service End Points

Restricted URIs will be shown with LOCK icon in the table below.

#URIMethodDescription
1/rest/security/statusGETDisplays the current status of the API being used. Non-restricted REST end-point
2/rest/security/generateKeyInsecureGETGenerates an API-KEY for the given ID, provided the serviceid and apikey credentials are authorized and the serviceid account has a role of admin. **Restricted REST end-point
3/rest/security/generateKeySecureGETGenerates an API-KEY for the given ID, provided the serviceid and apikey credentials are authorized and the serviceid account has a role of admin. **Restricted REST end-point
4/rest/security/finditembyidGETSearches for an item by its ID returning the item as a JSON object. **Restricted REST end-point
5/rest/security/showallitemsGETRetrieves all items in our MongoDB datastore return the entire collection as a JSON array. **Restricted REST end-point

API-KEY Authentication Communication Flow

apikey_auth_flow

1 – Initial Request for Protected Resource

* About to connect() to localhost port 8888 (#0)
*   Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 8888 (#0)
> GET /RestfulApiKeySecurityExample/rest/security/generateKeySecure?id=ibm HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
> Host: localhost:8888
> Accept: */*
> Content-Type: application/json
> serviceid: avaldes
> apikey: 7e473a60-4bdf-4353-b966-9447314737be
>

2 – Server Responds with Success Code and Payload (on Success)

< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Content-Type: application/json
< Transfer-Encoding: chunked
< Date: Fri, 11 Dec 2015 20:09:17 GMT
<
* Connection #0 to host localhost left intact
* Closing connection #0
{"_id":"ibm","role":"client","api-key":"37798dc6-a9c2-4443-9188-95586be389e6"}

The Item Model (Item.java)

This will be used to as the object which we store and retrieve in order to test out our application. I added it because I wanted my web service to store and retrieve some Java object.

package com.avaldes.model;

import javax.persistence.Id;

import org.codehaus.jackson.annotate.JsonProperty;

public class Item {
  @Id
  private String _id;
  private String itemId;
  private String itemName;
  private double itemPrice;
  private int itemQuantity;
  
  public Item() {}
  
  public Item(String _id, String itemId, String itemName, 
      double itemPrice, int itemQuantity) {
    
    super();
    this._id = _id;
    this.itemId = itemId;
    this.itemName = itemName;
    this.itemPrice = itemPrice;
    this.itemQuantity = itemQuantity;
  }

  public String get_id() {
    return _id;
  }
  
  public void set_id(String _id) {
    this._id = _id;
  }
  
  @JsonProperty(value = "item-id")
  public String getItemId() {
    return itemId;
  }
  
  public void setItemId(String itemId) {
    this.itemId = itemId;
  }
  
  @JsonProperty(value = "item-name")
  public String getItemName() {
    return itemName;
  }
  
  public void setItemName(String itemName) {
    this.itemName = itemName;
  }
  
  @JsonProperty(value = "price")
  public double getItemPrice() {
    return itemPrice;
  }
  
  public void setItemPrice(double itemPrice) {
    this.itemPrice = itemPrice;
  }
  
  @JsonProperty(value = "quantity")
  public int getItemQuantity() {
    return itemQuantity;
  }
  
  public void setItemQuantity(int itemQuantity) {
    this.itemQuantity = itemQuantity;
  }

  @Override
  public String toString() {
    return "Item [_id=" + _id + ", itemId=" + itemId + ", itemName="
        + itemName + ", itemPrice=" + itemPrice + ", itemQuantity="
        + itemQuantity + "]";
  }
}

The User Model (User.java)

This will be used to as the object which we store and retrieve in order to test out our application. I added it because I wanted my web service to store and retrieve some Java object.

package com.avaldes.model;

import javax.persistence.Id;

import org.codehaus.jackson.annotate.JsonProperty;

public class User {
  @Id
  private String _id;
  private String apiKey;
  private String role;
  
  public User() {}
  
  public User(String _id, String apiKey, String role) {
    super();
    this._id = _id;
    this.apiKey = apiKey;
    this.role = role;
  }

  public String get_id() {
    return _id; 
  }

  public void set_id(String _id) {
    this._id = _id;
  }

  @JsonProperty(value = "api-key")
  public String getApiKey() {
    return apiKey;
  }
  
  public void setApiKey(String apiKey) {
    this.apiKey = apiKey;
  }
  
  @JsonProperty(value = "role")
  public String getRole() {
    return role;
  }
  
  public void setRole(String role) {
    this.role = role;
  }

  @Override
  public String toString() {
    return "User [_id=" + _id + ", apiKey=" + apiKey + ", role=" + role
        + "]";
  }
}

The Singleton Class for Mongo Database (MongoDBSingleton.java)

package com.avaldes.util;

import java.io.IOException;
import java.util.Properties;

import org.apache.log4j.Logger;

import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;
import com.mongodb.client.MongoDatabase;

public class MongoDBSingleton {
  static Logger logger = Logger.getLogger(MongoDBSingleton.class);
  private static final String properties_filename = "mongodb.properties";
  
  private static MongoClient mongo            = null;
  private static MongoDatabase mongoDatabase  = null;
  private static String hostname              = null;
  private static int port                     = 0;
  private static String username              = null;
  private static String password              = null;
  private static String database              = null;
  
  private static class Holder {
    private static final MongoDBSingleton instance = new MongoDBSingleton();
  }
  
  private MongoDBSingleton() {
    logger.info("Inside MongoDBSingleton...");
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    Properties properties = new Properties();
    try {
      logger.info("Reading mongo.properties...");
      properties.load(classLoader.getResourceAsStream(properties_filename));
      hostname = properties.getProperty("mongodb.hostname");
      logger.info("mongodb.hostname....: " + hostname);
      String portStr = properties.getProperty("mongodb.port");
      port = Integer.parseInt(portStr);
      logger.info("mongodb.port........: " + port);
      username = properties.getProperty("mongodb.username");
      logger.info("mongodb.username....: " + username);
      password = properties.getProperty("mongodb.password");
      logger.info("mongodb.password....: " + password);
      database = properties.getProperty("mongodb.database");
      logger.info("mongodb.database....: " + database);
      
    } catch (IOException e) {
      e.printStackTrace();
    }
  };
  
  public static MongoDBSingleton getInstance() {
    return Holder.instance;
  }
  
  public MongoClient getMongoClient() {
    String URI = String.format("mongodb://%s:%s@%s:%d/?authSource=%s", 
		      username, password, hostname, port, database); 
    MongoClientURI mongoClientURI = new MongoClientURI(URI);
    mongo = new MongoClient(mongoClientURI);
    return mongo;
  }
  
  public MongoDatabase getDatabase() {
    if (mongoDatabase == null) {
      mongo = getMongoClient();
    }
    return mongo.getDatabase(database);
  }
}

Complete Program (RestfulApiKeySecurityExample.java)

package com.avaldes.service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.apache.log4j.Logger;
import org.bson.Document;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;

import com.avaldes.model.Item;
import com.avaldes.model.StatusMessage;
import com.avaldes.model.User;
import com.avaldes.util.MongoDBSingleton;
import com.mongodb.BasicDBObject;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.util.JSON;
import com.sun.jersey.api.client.ClientResponse.Status;

@Path("/security")
public class RestfulApiKeySecurityExample {
  static Logger logger=Logger.getLogger(RestfulApiKeySecurityExample.class);

  @Path("/status")
  @GET
  @Produces(MediaType.TEXT_HTML)
  public String returnVersion() {
    return "RestfulApiKeySecurityExample Status is OK...";
  }

  @Path("/generateKeyInsecure")
  @GET
  @Produces(MediaType.APPLICATION_JSON)
  public Response generateApiKey(@QueryParam("id") String id,
    @QueryParam("serviceid") String service_id,
    @QueryParam("apikey") String api_key) throws JsonGenerationException,
    JsonMappingException, IOException {

    User user = null;
    logger.info("Getting all generateKeyInsecure...");

    if (id == null) {
      StatusMessage statusMessage = new StatusMessage();
      statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
      statusMessage.setMessage("CustomerId value is missing!!!");
      return Response.status(Status.PRECONDITION_FAILED.getStatusCode())
          .entity(statusMessage).build();
    }

    if (service_id == null) {
      StatusMessage statusMessage = new StatusMessage();
      statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
      statusMessage.setMessage("serviceid value is missing!!!");
      return Response.status(Status.PRECONDITION_FAILED.getStatusCode())
          .entity(statusMessage).build();
    }

    if (api_key == null) {
      StatusMessage statusMessage = new StatusMessage();
      statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
      statusMessage.setMessage("apikey value is missing!!!");
      return Response.status(Status.PRECONDITION_FAILED.getStatusCode())
          .entity(statusMessage).build();
    }

    if (!validUser(service_id, api_key, true)) {
      StatusMessage statusMessage = new StatusMessage();
      statusMessage.setStatus(Status.FORBIDDEN.getStatusCode());
      statusMessage.setMessage("Access Denied for this functionality !!!");
      return Response.status(Status.FORBIDDEN.getStatusCode())
          .entity(statusMessage).build();
    }

    MongoDBSingleton mongoDB = MongoDBSingleton.getInstance();
    MongoDatabase db = mongoDB.getDatabase();
    MongoCollection<BasicDBObject> collection = db.getCollection("users",
        BasicDBObject.class);

    BasicDBObject query = new BasicDBObject();
    query.put("_id", id);
    List<Document> results = db.getCollection("users").find(query)
        .into(new ArrayList<Document>());
    int size = results.size();

    if (size > 0) {
      StatusMessage statusMessage = new StatusMessage();
      statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
      statusMessage.setMessage("CustomerId already exists !!!");
      return Response.status(Status.PRECONDITION_FAILED.getStatusCode())
          .entity(statusMessage).build();
    }

    // Generate the API-KEY using Java's UUID class
    UUID apikey = UUID.randomUUID();
    user = new User(id, apikey.toString(), "client");
    logger.info("Creating new User: " + user);

    // Map Java POJO Object to JSON String
    ObjectMapper mapper = new ObjectMapper();
    String json = mapper.writeValueAsString(user);

    // Parse JSON string to BasicDBObject to insert into MongoDB collection
    BasicDBObject dbObject = (BasicDBObject) JSON.parse(json);
    collection.insertOne(dbObject);

    return Response.status(200).entity(user).build();
  }

  @Path("/generateKeySecure")
  @GET
  @Produces(MediaType.APPLICATION_JSON)
  public Response generateApiKeySecure(@QueryParam("id") String id,
      @HeaderParam("serviceid") String service_id,
      @HeaderParam("apikey") String api_key) throws JsonGenerationException,
    JsonMappingException, IOException {

    User user = null;
    logger.info("Getting all generateKeySecure...");

    if (id == null) {
      StatusMessage statusMessage = new StatusMessage();
      statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
      statusMessage.setMessage("CustomerId value is missing!!!");
      return Response.status(Status.PRECONDITION_FAILED.getStatusCode())
          .entity(statusMessage).build();
    }
    
    if (service_id == null) {
      StatusMessage statusMessage = new StatusMessage();
      statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
      statusMessage.setMessage("serviceid value is missing!!!");
      return Response.status(Status.PRECONDITION_FAILED.getStatusCode())
          .entity(statusMessage).build();
    }

    if (api_key == null) {
      StatusMessage statusMessage = new StatusMessage();
      statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
      statusMessage.setMessage("apikey value is missing!!!");
      return Response.status(Status.PRECONDITION_FAILED.getStatusCode())
          .entity(statusMessage).build();
    }

    if (!validUser(service_id, api_key, true)) {
      StatusMessage statusMessage = new StatusMessage();
      statusMessage.setStatus(Status.FORBIDDEN.getStatusCode());
      statusMessage.setMessage("Access Denied for this functionality !!!");
      return Response.status(Status.FORBIDDEN.getStatusCode())
          .entity(statusMessage).build();
    }

    MongoDBSingleton mongoDB = MongoDBSingleton.getInstance();
    MongoDatabase db = mongoDB.getDatabase();
    MongoCollection<BasicDBObject> collection = db.getCollection("users",
        BasicDBObject.class);

    BasicDBObject query = new BasicDBObject();
    query.put("_id", id);
    List<Document> results = db.getCollection("users").find(query)
        .into(new ArrayList<Document>());
    int size = results.size();

    if (size > 0) {
      StatusMessage statusMessage = new StatusMessage();
      statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
      statusMessage.setMessage("CustomerId already exists !!!");
      return Response.status(Status.PRECONDITION_FAILED.getStatusCode())
          .entity(statusMessage).build();
    }

    // Generate the API-KEY using Java's UUID class
    UUID apikey = UUID.randomUUID();
    user = new User(id, apikey.toString(), "client");
    logger.info("Creating new User: " + user);

    // Map Java POJO Object to JSON String
    ObjectMapper mapper = new ObjectMapper();
    String json = mapper.writeValueAsString(user);

    // Parse JSON string to BasicDBObject to insert into MongoDB collection
    BasicDBObject dbObject = (BasicDBObject) JSON.parse(json);
    collection.insertOne(dbObject);

    return Response.status(200).entity(user).build();
  }
  
  // --- Protected resource using service-id and api-key ---
  @Path("/finditembyid")
  @GET
  @Produces(MediaType.APPLICATION_JSON)
  public Response findItemById(@QueryParam("itemid") String item_id,
    @HeaderParam("serviceid") String service_id,
    @HeaderParam("apikey") String api_key) throws JsonGenerationException,
    JsonMappingException, IOException {

    Item item = null;

    logger.info("Inside findOrderById...");

    if (item_id == null) {
      StatusMessage statusMessage = new StatusMessage();
      statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
      statusMessage.setMessage("itemid value is missing!!!");
      return Response.status(Status.PRECONDITION_FAILED.getStatusCode())
          .entity(statusMessage).build();
    }

    if (service_id == null) {
      StatusMessage statusMessage = new StatusMessage();
      statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
      statusMessage.setMessage("serviceid value is missing!!!");
      return Response.status(Status.PRECONDITION_FAILED.getStatusCode())
          .entity(statusMessage).build();
    }

    if (api_key == null) {
      StatusMessage statusMessage = new StatusMessage();
      statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
      statusMessage.setMessage("apikey value is missing!!!");
      return Response.status(Status.PRECONDITION_FAILED.getStatusCode())
          .entity(statusMessage).build();
    }

    if (!validUser(service_id, api_key, false)) {
      StatusMessage statusMessage = new StatusMessage();
      statusMessage.setStatus(Status.FORBIDDEN.getStatusCode());
      statusMessage.setMessage("Access Denied for this functionality !!!");
      return Response.status(Status.FORBIDDEN.getStatusCode())
          .entity(statusMessage).build();
    }

    MongoDBSingleton mongoDB = MongoDBSingleton.getInstance();
    MongoDatabase db = mongoDB.getDatabase();

    BasicDBObject query = new BasicDBObject();
    query.put("_id", item_id);
    List<Document> results = db.getCollection("items").find(query)
        .into(new ArrayList<Document>());
    int size = results.size();

    if (size == 0) {
      StatusMessage statusMessage = new StatusMessage();
      statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
      statusMessage.setMessage("Unable to find that item !!!");
      return Response.status(Status.PRECONDITION_FAILED.getStatusCode())
          .entity(statusMessage).build();
    }

    for (Document current : results) {
      ObjectMapper mapper = new ObjectMapper();
      try {
        logger.info(current.toJson());
        item = mapper.readValue(current.toJson(), Item.class);
      } catch (JsonParseException e) {
        e.printStackTrace();
      } catch (JsonMappingException e) {
        e.printStackTrace();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }

    return Response.status(200).entity(item).build();
  }

  // --- Protected resource using service-id and api-key ---
  @Path("/showallitems")
  @GET
  @Produces(MediaType.APPLICATION_JSON)
  public Response showAllItems(@@HeaderParam("serviceid") String service_id,
    @@HeaderParam("apikey") String api_key) throws JsonGenerationException,
    JsonMappingException, IOException {

    Item item = null;

    logger.info("Inside showAllItems...");

    if (service_id == null) {
      StatusMessage statusMessage = new StatusMessage();
      statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
      statusMessage.setMessage("serviceid value is missing!!!");
      return Response.status(Status.PRECONDITION_FAILED.getStatusCode())
          .entity(statusMessage).build();
    }

    if (api_key == null) {
      StatusMessage statusMessage = new StatusMessage();
      statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
      statusMessage.setMessage("apikey value is missing!!!");
      return Response.status(Status.PRECONDITION_FAILED.getStatusCode())
          .entity(statusMessage).build();
    }

    if (!validUser(service_id, api_key, false)) {
      StatusMessage statusMessage = new StatusMessage();
      statusMessage.setStatus(Status.FORBIDDEN.getStatusCode());
      statusMessage.setMessage("Access Denied for this functionality !!!");
      return Response.status(Status.FORBIDDEN.getStatusCode())
          .entity(statusMessage).build();
    }

    MongoDBSingleton mongoDB = MongoDBSingleton.getInstance();
    MongoDatabase db = mongoDB.getDatabase();

    List<Document> results = db.getCollection("items").find()
        .into(new ArrayList<Document>());
    int size = results.size();

    if (size == 0) {
      StatusMessage statusMessage = new StatusMessage();
      statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
      statusMessage.setMessage("There are no Items to display !!!");
      return Response.status(Status.PRECONDITION_FAILED.getStatusCode())
          .entity(statusMessage).build();
    }

    List<Item> allItems = new ArrayList<Item>();
    for (Document current : results) {
      ObjectMapper mapper = new ObjectMapper();
      try {
        logger.info(current.toJson());
        item = mapper.readValue(current.toJson(), Item.class);
        allItems.add(item);
      } catch (JsonParseException e) {
        e.printStackTrace();
      } catch (JsonMappingException e) {
        e.printStackTrace();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }

    return Response.status(200).entity(allItems).build();
  }

  private boolean validUser(String serviceid, String apikey, 
	                                            boolean isAdmin) {
																							
    MongoDBSingleton mongoDB = MongoDBSingleton.getInstance();
    MongoDatabase db = mongoDB.getDatabase();
    List<Document> results = null;

    if (isAdmin) {
      results = db.getCollection("users")
          .find(new Document("_id", serviceid).append("role", "admin"))
          .limit(1).into(new ArrayList<Document>());
    } else {
      results = db.getCollection("users")
											.find(new Document("_id", serviceid))
											.limit(1).into(new ArrayList<Document>());
    }
    int size = results.size();

    if (size == 1) {
      for (Document current : results) {
        ObjectMapper mapper = new ObjectMapper();
        User user = null;
        try {
          // logger.info(current.toJson());
          user = mapper.readValue(current.toJson(), User.class);
        } catch (JsonParseException e) {
          e.printStackTrace();
        } catch (JsonMappingException e) {
          e.printStackTrace();
        } catch (IOException e) {
          e.printStackTrace();
        }
        if (user != null && serviceid.equalsIgnoreCase(user.get_id())
            && apikey.equals(user.getApiKey())) {
          return true;
        } else {
          return false;
        }
      }
      return false;
    } else {
      return false;
    }
  }
}

LOG4J Configuration File (log4j.xml)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "
          -//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

  <!-- Appenders -->
  <appender name="console" class="org.apache.log4j.ConsoleAppender">
  <param name="Target" value="System.out" />
    <layout class="org.apache.log4j.PatternLayout">
    <param name="ConversionPattern" value="%-5p: %c - %m%n" />
    </layout>
  </appender>
  
  <!-- Application Loggers -->
  <logger name="com.avaldes">
    <level value="info" />
  </logger>

  <!-- Root Logger -->
  <root>
    <priority value="warn" />
    <appender-ref ref="console" />
  </root>
</log4j:configuration>

Web Deployment Descriptor (web.xml)

This is a pretty straight forward deployment descriptor file – only thing you need to add is the location of you java package in the Jersey ServletContainer entry as init-param. Please ensure you add it to the web.xml file as shown below.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>JAX-RS API-KEY Secured Web Application</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  
  <servlet>
    <servlet-name>Jersey REST Service</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.avaldes</param-value>
    </init-param>
    <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 REST Service</servlet-name>
    <url-pattern>/rest/*</url-pattern>
  </servlet-mapping>
</web-app>

Testing out the Web Services

To test out the application I used both CURL and Postman which is a Google Chrome Application. Using this tool I validated each of the REST API calls. Please review the screen shots below:

Using CURL to Test out the API-KEY Access Authentication

curl -H 'Content-Type: application/json' -H 'serviceid: avaldes' 
-H 'apikey: 7e473a60-4bdf-4353-b966-9447314737be' -v -X GET 
http://localhost:8888/RestfulApiKeySecurityExample/rest/security/generateKeySecure?id=ibm

* About to connect() to localhost port 8888 (#0)
*   Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 8888 (#0)
> GET /RestfulApiKeySecurityExample/rest/security/generateKeySecure?id=ibm HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
> Host: localhost:8888
> Accept: */*
> Content-Type: application/json
> serviceid: avaldes
> apikey: 7e473a60-4bdf-4353-b966-9447314737be
>

< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Content-Type: application/json
< Transfer-Encoding: chunked
< Date: Fri, 11 Dec 2015 20:09:17 GMT
<
* Connection #0 to host localhost left intact
* Closing connection #0

{"_id":"ibm","role":"client","api-key":"37798dc6-a9c2-4443-9188-95586be389e6"}

Download the Complete Source Code

That’s It!

I hope you enjoyed this tutorial. It was certainly a lot of fun putting it together and testing it out. Please continue to share the love and like us so that we can continue bringing you quality tutorials. Happy Coding!!!

java_jaxrs_apikey

Related JAX-RS Tutorial Posts

  • RESTful Web Services with AngularJS, Bootstrap and Java using JAX-RS and Jersey
    In this tutorial we will develop a full blown CRUD application using JAX-RS API and Jersey to implement RESTful web services. JAX-RS stands for Java API for RESTful Web Services and by using this powerful API developers can easily build REST services. Jersey RESTful Web Services is an open source framework for developing RESTful Web Services in Java that provides support for JAX-RS APIs.
  • JAX-RS Security using JSON Web Encryption(JWE) with AngularJS, Bootstrap, Grid-UI and MongoDB Example
    In this tutorial we will discuss how to use AngularJS, Bootstrap and Grid-UI to connect to secure JAX-RS RESTful web services using JWE/JWT/JWS for Authentication and Authorization. In our example implementation, we will be using Symmetric Encryption where the receiver and sender share a common key.
  • JAX-RS Security using JSON Web Encryption (JWE) with JWS/JWT for Authentication and Authorization
    In this tutorial we will discuss how to secure JAX-RS RESTful web services using JSON Web Encryption(JWE), JSON Web Key (JWK), JSON Web Signature(JWS), and JSON Web Tokens(JWT) for Authentication and Authorization. JSON Web Encryption (JWE) encrypted content using Javascript Object Notation (JSON) based structures.
  • JAX-RS Security using JSON Web Tokens (JWT) for Authentication and Authorization
    In this tutorial we will discuss how to secure JAX-RS RESTful web services using JSON Web Tokens Authentication and Authorization. This form of security is used for authenticating a client using a signed token which can be verified by application servers. This token-based form of security is a ideal candidate for Cross-domain (CORS) access and when server-side scalability is a prime motivation factor.
  • JAX-RS Security using API-KEY for Authorization
    In this tutorial we will discuss how to secure JAX-RS RESTful web services using API-KEY or Service Key for Authorization. This form of security is used to ensure that certain RESTful endpoints are protected against unauthorized use.
  • JAX-RS Security using Digest Authentication and Authorization
    In this JAX-RS Digest Authentication and Authorization tutorial we will discuss how to set up digest security for our RESTful web service. This form of access authentication is slightly more complex than the previously discussed JAX-RS Basic Authentication Tutorial.
  • JAX-RS Security using Basic Authentication and Authorization
    In this JAX-RS basic authentication and authorization tutorial we will discuss how to set up security for our RESTful web service. We will need to ensure that some of the URIs are protected and only clients that have been authenticated and authorized are able to gain access and make use of them.
  • Upload and Download Multiple Binary Files using MongoDB
    In this tutorial we are going to develop multiple file upload and file download capability using RESTful web service using JAX-RS and Jersey storing the contents of files into MongoDB Database using a powerful feature in MongoDB for managing large files called GridFS.
  • Inserting and Retrieving Binary Data with MongoDB using JAX-RS RESTful Web Service
    In this tutorial we are going to develop file upload and file download capability using RESTful web service using JAX-RS and Jersey storing the contents of files into MongoDB Database using a powerful feature in MongoDB for managing large files called GridFS. The bulk of the framework for this tutorial came from my previous tutorial so you find many similarities between the two posts.
  • Inserting and Retrieving Binary Data with SQL Server Database using JAX-RS RESTful Web Service
    In this tutorial we are going to develop file upload and file download capability using RESTful web service using JAX-RS and Jersey storing the contents of the file into SQL Server Database using BLOB. Our example will be able to store PDF files, Excel files, Word Document files, Powerpoint files, Image files, or any other type of file available us provided we have ample amount of storage space.
  • File Download Example Using RESTful Web Service with JAX-RS and Jersey
    In this example we are going to develop file download capability using RESTful web service using JAX-RS and Jersey. As you will see, downloading a File using Jersey is very easy as it uses the HTTP GET for the file operations. In our web service, we will be allowing you to download the file via two mechanisms. You will be able to download by HTTP query parameters via @QueryParam and also by using the path parameters via @PathParam.
  • JAX-RS Restful Web Services with JNDI Datasource for MySQL in Tomcat
    In this tutorial we will discuss how to set up JAX-RS RESTful web services and configure a JNDI Datasource with Connection Pooling in Tomcat and connect to MYSQL Database. JNDI (Java Naming and Directory Interface) provides and interface to multiple naming and directory services.
  • File Upload Example Using RESTful Web Service with JAX-RS and Jersey
    In this example we are going to develop file upload capability using RESTful web service using JAX-RS and Jersey. As you will see, uploading a File using Jersey is pretty straight forward as it uses HTTP POST with the encoding type of multipart/form-data for the file operations.
  • RESTful Web Services @FormParam Example using JAX-RS and Jersey
    In this example we are going to develop a simple RESTful web service using JAX-RS and Jersey to extract form parameters submitted by a form using @FormParam annotation.
  • RESTful Web Services @MatrixParam Example using JAX-RS and Jersey
    In this example we are going to develop a simple RESTful web service using JAX-RS and Jersey to extract matrix parameters from the request URL using the @MatrixParam annotations.
  • RESTful Web Services @QueryParam Example using JAX-RS and Jersey
    In this example we are going to develop a simple RESTful web service using JAX-RS and Jersey to extract query parameters from the request URL using the @QueryParam annotation.
  • RESTful Web Services @PathParam Example using JAX-RS and Jersey
    In this example we are going to develop a simple RESTful web service using JAX-RS and Jersey to extract path parameters from the request URL using the @PathParam annotation.

Please Share Us on Social Media

Facebooktwittergoogle_plusredditpinterestlinkedinmail

Leave a Reply

Your email address will not be published. Required fields are marked *