-
Notifications
You must be signed in to change notification settings - Fork 31
How to Use
This page shows how to use jersey-hmac-auth on the server to secure your API and also in client libraries that you build to interface with the API.
To implement jersey-hmac-auth on the server, add this dependency to your application:
<dependency>
<groupId>com.bazaarvoice.auth</groupId>
<artifactId>jersey-hmac-auth-server</artifactId>
<version>${version}</version>
</dependency>
You can secure your API endpoints by adding the @HmacAuth
annotation to their corresponding Jersey resource methods. For example:
@Path("/pizza")
@Produces(MediaType.TEXT_PLAIN)
public class PizzaResource {
@GET
public String get(@HmacAuth Principal principal) {
// This gets control only if the request is authenticated.
// The principal identifies the API caller (and can be of any type you want).
}
}
If a caller makes an HTTP GET
request to the /pizza
endpoint, then by default the resource method will get control only if the request is authenticated successfully. If authentication fails, then jersey-hmac-auth will automatically reject the request and return a "401 (Unauthorized)" HTTP status code before this method gets control.
You can control the default authentication behavior (e.g. to make authentication optional) by using a non-default request handler. There are more details about request handlers below.
Requests are authenticated on the server by an Authenticator class that you provide.
The authenticator is responsible for authenticating a request given the credentials on the request (e.g. the API key, the signature provided by the caller, and other such parameters). The authenticator also returns a "principal" object representing the authenticated API caller. The jersey-hmac-auth library will take the returned principal and inject it into the Jersey resource method that gets control to handle the request.
The following is an example authenticator:
public class MyAuthenticator extends AbstractCachingAuthenticator<Principal> {
// some code is intentionally missing
@Override
protected Principal loadPrincipal(Credentials credentials) {
// return the principal identified by the credentials from the API request
}
@Override
protected String getSecretKeyFromPrincipal(Principal principal) {
// return the secret key for the given principal
}
}
The jersey-hmac-auth library provides abstract authenticator classes that you can extend for your own use. If you need something more custom, then you are welcome to create your own authenticator that implements the Authenticator interface.
The AbstractAuthenticator
class provides the following features:
- Validates the API key to ensure that it specifies a non-null principal.
- Validates the signature by generating a new signature and comparing it to the one provided by the caller. This ensures that the caller had a valid secret key (they are a trusted source) and that the request has not been tampered with after being sent.
- Validates the request timestamp. This ensures that the timestamp does not fall outside of an allowed time range. This is used to reduce the window of time for which a replay attack can occur.
The AbstractCachingAuthenticator
class provides the same features as AbstractAuthenticator
, but also:
- Caches the principal so that your authenticator implementation does not have to retrieve it on every request made by the same caller. This is especially helpful if your authenticator retrieves the principal by querying another system (e.g. a database or some other service).
Todo...
Todo...
- Register the authentication provider with Jersey.
If using Dropwizard:
environment.addProvider(new HmacAuthProvider(new DefaultRequestHandler(new MyAuthenticator())));
If using straight Jersey, you basically do the same, but add the HmacAuthProvider
to your Jersey environment.
Both implementations require specifying (or implementing your own) RequestHandler
. There are three RequestHandler
s provided for use:
* [DefaultRequestHandler](server/src/main/java/com/bazaarvoice/auth/hmac/server/PassThroughRequestHandler.java) - for general use, requires all requests to include proper authentication
* [OptionalRequestHandler](server/src/main/java/com/bazaarvoice/auth/hmac/server/OptionalRequestHandler.java) - relaxed, does not require authentication, but will authenticate if credentials are provided
* [PassThroughRequestHandler](server/src/main/java/com/bazaarvoice/auth/hmac/server/PassThroughRequestHandler.java) - for testing, simply returns the Principal passed in
The following clients are available, but note that you can write your own in any language as long as it follows the appropriate contract.
To implement a Java client (using Jersey) that constructs requests encoded for HMAC authentication:
(1) Add this maven dependency:
<dependency>
<groupId>com.bazaarvoice.auth</groupId>
<artifactId>jersey-hmac-auth-client</artifactId>
<version>${version}</version>
</dependency>
(2) Add the HmacClientFilter
to your Jersey client:
Client client; // this is your Jersey client constructed someplace else
client.addFilter(new HmacClientFilter(apiKey, secretKey, client.getMessageBodyWorkers()));
To implement a Python client that constructs requests encoded for HMAC authentication, please refer to the python-hmac-auth library.