users@jersey.java.net

Re: [Jersey] oAuth HMAC_SHA1 implementation bug

From: DirkM <dirk_at_olx.com>
Date: Thu, 27 Aug 2009 14:48:27 -0500 (CDT)

Paul Sandoz wrote:
>
> You should be able to use a container request filter or a resource
>

I'm very impressed with the way every time I think of a new use-case Jersey
has a well thought-out way to handle it. I think it would be helpful to add
a link from the wiki page about OAuth to the container filter package
description you cited above.


Here's the class I wrote for simple OAuth authentication.

Notes:
1. AuthenticationFailedException is a class I wrote. I have an
ExceptionMapper to turn it into an HTTP 401. I need to do it this way
because of how our architecture is set up, but anyone copying this code
could simply throw a WebApplicationException.

2. Checking for the existence of each parameter is not really necessary, I
just did it to be able to give a nicer error message to the user.

3. In order to get this to work with Guice, I couldn't use an <init-param>
in the web.xml (as for some reason it doesn't get picked up). Instead I did
this:
                HashMap<String, String> params = new HashMap<String,
String>();
               
params.put("com.sun.jersey.spi.container.ContainerRequestFilters",
"com.olx.iphone.auth.AuthenticationFilter");
                serve("/*").with(GuiceContainer.class, params);

4. Please don't use my password to break into my bank account


public class AuthenticationFilter implements ContainerRequestFilter {
    private final static int TIMESTAMP_EXPIRY_SECONDS = 60;
    
    
    @Override
    public ContainerRequest filter(ContainerRequest containerRequest) {
        // Read the OAuth parameters from the request
        OAuthServerRequest request = new
OAuthServerRequest(containerRequest);
        OAuthParameters params = new OAuthParameters();
        params.readRequest(request);
        
        // Check the required OAuth parameters have been provided
        checkForParameter(OAuthParameters.SIGNATURE_METHOD,
params.getSignatureMethod());
        checkForParameter(OAuthParameters.SIGNATURE, params.getSignature());
        checkForParameter(OAuthParameters.TOKEN, params.getToken());
        checkForParameter(OAuthParameters.NONCE, params.getNonce());
        checkForParameter(OAuthParameters.TIMESTAMP, params.getTimestamp());
        checkForParameter(OAuthParameters.VERSION, params.getVersion());
        
        // Set the token secret, against which we will verify the request
        OAuthSecrets secrets = new OAuthSecrets();
        String tokenSecret = "tokensecret";
        secrets.setTokenSecret(tokenSecret);
        
        // Check that the timestamp has not expired
        String timestampStr = params.getTimestamp();
        try {
            long timestampSeconds = Long.valueOf(timestampStr);
            long timestampMillis = timestampSeconds * 1000;
            long currentTimeMillis = System.currentTimeMillis();
            long currentTimeSeconds = currentTimeMillis / 1000;
            if(timestampSeconds > currentTimeSeconds) {
                String msg = "Timestamp is in the future!\n" +
                             "Timestamp " + timestampStr + " (" + (new
Date(timestampMillis)) + ") " +
                             "is later than the current time (" + (new
Date(currentTimeMillis)) + ")";
                throwException(msg);
            }
            if(timestampSeconds < currentTimeSeconds -
TIMESTAMP_EXPIRY_SECONDS) {
                String msg = "Timestamp expired\n" +
                             "Timestamp " + timestampStr + " (" + (new
Date(timestampMillis)) + ") " +
                             "is more than " + TIMESTAMP_EXPIRY_SECONDS + "
" +
                             "seconds before the current time (" + (new
Date(currentTimeMillis)) + ")";
                throwException(msg);
            }
        } catch (NumberFormatException e) {
            throwException("Could not parse oAuth timestamp '" +
timestampStr + "'");
        }
        
        // Verify the signature
        try {
            if(!OAuthSignature.verify(request, params, secrets)) {
                throwException("Signature failed verification");
            }
        } catch (OAuthSignatureException e) {
            throw new AuthenticationFailedException(e);
        }
        
        return containerRequest;
    }

    private void checkForParameter(String paramName, String paramValue) {
        if(paramValue == null || paramValue.isEmpty()) {
            throwException("Missing or empty parameter '" + paramName +
"'");
        }
    }

    private void throwException(String msg) {
        String exceptionMsg = "OAuth authentication failure: " + msg;
        throw new AuthenticationFailedException(exceptionMsg);
    }
}

-- 
View this message in context: http://n2.nabble.com/oAuth-HMAC-SHA1-implementation-bug-tp3506009p3529549.html
Sent from the Jersey mailing list archive at Nabble.com.