Giter VIP home page Giter VIP logo

jersey-hmac-auth's Introduction

jersey-hmac-auth

Jersey-based HMAC authentication for the client and server.

This library makes it easy to add HMAC authentication to REST API's that are implemented using the Jersey library. Note that this also works for Jersey-based frameworks, like Dropwizard.

HMAC authentication provides a way for you to ensure the integrity and authenticity of API requests. You grant API access to permitted callers by giving each one an API key and a secret key that they use when generating requests. You can use this library to add support for HMAC authentication on the client and server.

On the client side, e.g. in an SDK library that interfaces with the API, the client must build requests following the authentication contract that jersey-hmac-auth implements. You can do this in any language. However, the jersey-hmac-auth library provides support in Java for client libraries that use the Jersey Client for making HTTP requests.

Getting Started

Server Side

Client Side

HMAC Versions

The HMAC version so far have only been used to distinguished between using POST/PUT data in signature or not.

The server may support any number of versions, however client must supply a version and appropriate include or not include data in signature.

  • Version 1 - Has mixed implementations for including content data in signature (deprecated)
  • Version 2 - Will not include content data in signature
  • Version 3 - Will include content data in signature

User Guide

See the User Guide for more details.

Contributing

To build and run tests locally:

$ git clone [email protected]:bazaarvoice/jersey-hmac-auth.git
$ cd jersey-hmac-auth
$ mvn clean install

To submit a new request or issue, please visit the Issues page.

Pull requests are always welcome.

Continuous Integration

Build Status

jersey-hmac-auth's People

Contributors

amykytchyn avatar bivasdas avatar bvbuild avatar dhruvitbv avatar jsurls avatar juddrogers avatar kalepusoujanya-bazaarvoice avatar l0s avatar matthewfitch23 avatar reason-bv avatar rfinn001 avatar robbytx avatar snyk-bot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jersey-hmac-auth's Issues

The authenticator should support caching the principal

The HmacAuthenticator class currently calls the getPrincipal method for each request. In some applications, this may result in a database or web service call to retrieve the principal for the supplied credentials. We should instead provide an option for this to be cached by the authenticator.

Updated Dropwizard example

dropwizard has changed significantly over time. Could someone provide an example with the most recent version of dropwizard?

RequestDecoder destroys the request body after reading it once

The RequestDecoder calls request.getEntity(String.class); to consume the request body if there is any content present. The problem is that it can only be read one time. After this, the request body gets cleared out. We need to be able to read the request body without the content being removed.

Support CORS preflight OPTIONS request

When making a request that requires CORS a preflight OPTIONS request must be sent to the server in order to get back available headers for the request. From what I can see these preflight requests receive a 204 No Content response without the Access-Control-Allow-Headers header populated.

Fail if the client is given a null/empty API or secret key

Passing a null API key when creating a HmacClientFilter can result in the following:

Caused by: java.lang.IllegalArgumentException: One or more of query value parameters are null
    at com.sun.jersey.api.uri.UriBuilderImpl.queryParam(UriBuilderImpl.java:471)
    at com.bazaarvoice.auth.hmac.client.RequestEncoder.addApiKey(RequestEncoder.java:36)
    at com.bazaarvoice.auth.hmac.client.RequestEncoder.encode(RequestEncoder.java:29)
    at com.bazaarvoice.auth.hmac.client.HmacClientFilter.handle(HmacClientFilter.java:53)
    at com.sun.jersey.api.client.Client.handle(Client.java:648)

We should ensure that the API and secret key values are valid upfront and fail with a more explicit and easy to understand exception.

Support rate limiting

The authenticator-related code in the server module may be a good place for some per-API-key rate limiting.

Signature comparison should not be performed using "String.equals"

Coda Hale has a nice writeup in this blog post about timing attacks. One thing that he demonstrates is that "String.equals" is not secure for comparing signatures, because it returns "false" upon the first byte that is not equal, and so signatures that begin with equal bytes may take slightly longer to process than those that do not. This type of attack requires a window of time in which to replay requests, and so the existing timestamp validation may make it difficult. However, we should replace the "equals" method in AbstractAuthenticator with something more secure (e.g. "MessageDigest.isEquals").

Support authorization for API keys

This is a request to support authorization in addition to the current support for authentication. We consider allowing some type of application-specific authorization level to be defined in a principal, and the have the library reject requests for unauthorized calls.

Support custom headers being included in the signature

Applications with custom HTTP headers may want to include them in the signature. It may make sense for requests to specify which headers are included in the signature and in which order so that the server can reconstruct the signature appropriately.

Tests with openjdk-8 failed

When I run "mvn clean install", The output is as follows(only copy the failed output):

Running com.bazaarvoice.auth.hmac.client.HmacClientFilterTest
java.lang.Exception: Invalid signature
at com.bazaarvoice.auth.hmac.client.SignatureValidatingHttpServer.validate(SignatureValidatingHttpServer.java:28)
at com.bazaarvoice.auth.hmac.client.ValidatingHttpServer.handle(ValidatingHttpServer.java:50)
at org.simpleframework.http.core.Dispatcher.dispatch(Dispatcher.java:121)
at org.simpleframework.http.core.Dispatcher.run(Dispatcher.java:103)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
java.lang.Exception: Invalid signature
at com.bazaarvoice.auth.hmac.client.SignatureValidatingHttpServer.validate(SignatureValidatingHttpServer.java:28)
at com.bazaarvoice.auth.hmac.client.ValidatingHttpServer.handle(ValidatingHttpServer.java:50)
at org.simpleframework.http.core.Dispatcher.dispatch(Dispatcher.java:121)
at org.simpleframework.http.core.Dispatcher.run(Dispatcher.java:103)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
java.lang.Exception: Invalid signature
at com.bazaarvoice.auth.hmac.client.SignatureValidatingHttpServer.validate(SignatureValidatingHttpServer.java:28)
at com.bazaarvoice.auth.hmac.client.ValidatingHttpServer.handle(ValidatingHttpServer.java:50)
at org.simpleframework.http.core.Dispatcher.dispatch(Dispatcher.java:121)
at org.simpleframework.http.core.Dispatcher.run(Dispatcher.java:103)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Tests run: 5, Failures: 0, Errors: 3, Skipped: 0, Time elapsed: 4.623 sec <<< FAILURE! - in com.bazaarvoice.auth.hmac.client.HmacClientFilterTest
validateSignatureWhenThereIsNoContent(com.bazaarvoice.auth.hmac.client.HmacClientFilterTest) Time elapsed: 2.808 sec <<< ERROR!

com.sun.jersey.api.client.UniformInterfaceException: GET http://localhost:1112?apiKey=someApiKey returned a response status of 500 Internal Server Error
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:686)
at com.sun.jersey.api.client.WebResource.get(WebResource.java:191)
at com.bazaarvoice.auth.hmac.client.HmacClientFilterTest.validateSignatureWhenThereIsNoContent(HmacClientFilterTest.java:127)

validateSignatureWhenContentIsPojo(com.bazaarvoice.auth.hmac.client.HmacClientFilterTest) Time elapsed: 0.765 sec <<< ERROR!
com.sun.jersey.api.client.UniformInterfaceException: PUT http://localhost:1113?passkey=someApiKey returned a response status of 500 Internal Server Error
at com.sun.jersey.api.client.WebResource.voidHandle(WebResource.java:707)
at com.sun.jersey.api.client.WebResource.access$400(WebResource.java:74)
at com.sun.jersey.api.client.WebResource$Builder.put(WebResource.java:522)
at com.bazaarvoice.auth.hmac.client.HmacClientFilterTest.validateSignatureWhenContentIsPojo(HmacClientFilterTest.java:160)

validateSignatureWhenContentIsBinary(com.bazaarvoice.auth.hmac.client.HmacClientFilterTest) Time elapsed: 0.278 sec <<< ERROR!
com.sun.jersey.api.client.UniformInterfaceException: PUT http://localhost:1114?passkey=someApiKey returned a response status of 500 Internal Server Error
at com.sun.jersey.api.client.WebResource.voidHandle(WebResource.java:707)
at com.sun.jersey.api.client.WebResource.access$400(WebResource.java:74)
at com.sun.jersey.api.client.WebResource$Builder.put(WebResource.java:522)
at com.bazaarvoice.auth.hmac.client.HmacClientFilterTest.validateSignatureWhenContentIsBinary(HmacClientFilterTest.java:194)

Results :

Tests in error:
HmacClientFilterTest.validateSignatureWhenThereIsNoContent:127 » UniformInterface
HmacClientFilterTest.validateSignatureWhenContentIsPojo:160 » UniformInterface
HmacClientFilterTest.validateSignatureWhenContentIsBinary:194 » UniformInterface

It seems an exception in com.sun.jersey.api.client.UniformInterfaceException caused this error.
Can you tell me how to solve this issue? Thanks.

Jersey 2 Compatibility

It looks like this project is only compatible with Jersey 1. Even adding it to my POM for Jersey 2.19 without adding any other classes causes an error, even when I exclude Jersey 1:

javax.servlet.ServletException: Servlet.init() for servlet com.test.api.Application threw exception
    org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
    org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
    org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
    java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    java.lang.Thread.run(Thread.java:744)
root cause

java.lang.IllegalStateException: The resource configuration is not modifiable in this context.
    org.glassfish.jersey.server.ResourceConfig$ImmutableState.register(ResourceConfig.java:273)
    org.glassfish.jersey.server.ResourceConfig$ImmutableState.register(ResourceConfig.java:220)
    org.glassfish.jersey.server.ResourceConfig.register(ResourceConfig.java:452)
    org.glassfish.jersey.servlet.WebComponent.<init>(WebComponent.java:334)
    org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:170)
    org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:362)
    javax.servlet.GenericServlet.init(GenericServlet.java:160)
    org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
    org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
    org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
    java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    java.lang.Thread.run(Thread.java:744)

I can see in the source it's referencing the old com.sun packages.

Any plans to support Jersey 2? It will probably be late for me (HMAC integration due tomorrow) but might be nice for progeny.

validateTimestamp in AbstractAuthenticator throws exception on invalid timestamp format

Instead of handling the invalid timestamp format correctly, an exception is propigated up.

Fix needs to be in this function to catch the exception on TimeUtils.parse()

private boolean validateTimestamp(String timestamp) {
        DateTime requestTime = TimeUtils.parse(timestamp);
        long difference = Math.abs((new Duration(requestTime, TimeUtils.nowInUTC())).getMillis());
        return difference <= this.allowedTimestampRange;
    }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.