From a626ea51ffe9eeefc6f14b2de83f337c31b1dc58 Mon Sep 17 00:00:00 2001 From: Stefano Mazzocchi Date: Mon, 10 May 2010 23:24:58 +0000 Subject: [PATCH] if the user's computer's clock is not synchronized with Freebase's, the initial oauth handshake will fail because Freebase believe there is a replay attack going on. To avoid that we ask Acre to tell us what time it is in Freebase land and we sign the request with that instead. We default back to the user clock only if Acre is down or swamped. git-svn-id: http://google-refine.googlecode.com/svn/trunk@704 7d457c2a-affb-35e4-300a-418c747d4874 --- .../FreebaseTimeCommonsHttpOAuthConsumer.java | 69 +++++++++++++++++++ .../gridworks/oauth/OAuthUtilities.java | 3 +- 2 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/metaweb/gridworks/oauth/FreebaseTimeCommonsHttpOAuthConsumer.java diff --git a/src/main/java/com/metaweb/gridworks/oauth/FreebaseTimeCommonsHttpOAuthConsumer.java b/src/main/java/com/metaweb/gridworks/oauth/FreebaseTimeCommonsHttpOAuthConsumer.java new file mode 100644 index 000000000..c0d233a1c --- /dev/null +++ b/src/main/java/com/metaweb/gridworks/oauth/FreebaseTimeCommonsHttpOAuthConsumer.java @@ -0,0 +1,69 @@ +package com.metaweb.gridworks.oauth; + +import java.io.IOException; + +import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.HttpConnectionParams; +import org.apache.http.params.HttpParams; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FreebaseTimeCommonsHttpOAuthConsumer extends CommonsHttpOAuthConsumer { + + final static Logger logger = LoggerFactory.getLogger("oauth"); + + private static final long serialVersionUID = -4139931605235255279L; + + private static final int SOCKET_TIMEOUT = 3000; + private static final int CONNECTION_TIMEOUT = 3000; + + private static final String TIMER_URL = "http://gridworks-gadgets.freebaseapps.com/time"; + + public FreebaseTimeCommonsHttpOAuthConsumer(String consumerKey, String consumerSecret) { + super(consumerKey, consumerSecret); + } + + /** + * It might be that the user's computer's clock is not synchronized enough with the Freebase servers + * and this might result in Freebase thinking that it was under a replay attack. + * To avoid this problem we get the timestamp directly from acre that we know is synchronized. + * + * NOTE: this call is potentially vulnerable to a man-in-the-middle (MITM) attack, but the same + * could be said if we used an NTP client. + */ + protected String generateTimestamp() { + + long time = -1; + + try { + HttpParams httpParams = new BasicHttpParams(); + HttpConnectionParams.setSoTimeout(httpParams, SOCKET_TIMEOUT); + HttpConnectionParams.setConnectionTimeout(httpParams, CONNECTION_TIMEOUT); + HttpClient httpClient = new DefaultHttpClient(httpParams); + HttpGet httpget = new HttpGet(TIMER_URL); + HttpResponse response = httpClient.execute(httpget); + HttpEntity entity = response.getEntity(); + if (entity != null) { + time = Long.parseLong(EntityUtils.toString(entity),10); + logger.info("Got remote timestamp {}", time); + } + } catch (IOException e) { + logger.warn("Error obtaining the synchronized remote timestamp, defaulting to the local one",e); + } + + if (time == -1) { + time = System.currentTimeMillis(); + } + + return Long.toString(time / 1000L); + } + +} diff --git a/src/main/java/com/metaweb/gridworks/oauth/OAuthUtilities.java b/src/main/java/com/metaweb/gridworks/oauth/OAuthUtilities.java index 64cade03b..34c436ee2 100644 --- a/src/main/java/com/metaweb/gridworks/oauth/OAuthUtilities.java +++ b/src/main/java/com/metaweb/gridworks/oauth/OAuthUtilities.java @@ -7,7 +7,6 @@ import javax.servlet.http.HttpServletRequest; import oauth.signpost.OAuthConsumer; import oauth.signpost.OAuthProvider; -import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer; import oauth.signpost.commonshttp.CommonsHttpOAuthProvider; import oauth.signpost.http.HttpParameters; @@ -44,7 +43,7 @@ public class OAuthUtilities { if (provider == null) throw new RuntimeException("Provider can't be null"); String[] consumer_info = infos.get(provider.getHost()); if (consumer_info == null) throw new RuntimeException("Can't find secrets for provider '" + provider.getHost() + "'"); - OAuthConsumer oauthConsumer = new CommonsHttpOAuthConsumer(consumer_info[0],consumer_info[1]); + OAuthConsumer oauthConsumer = new FreebaseTimeCommonsHttpOAuthConsumer(consumer_info[0],consumer_info[1]); HttpParameters params = new HttpParameters(); params.put("realm", provider.getHost()); oauthConsumer.setAdditionalParameters(params);