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
This commit is contained in:
Stefano Mazzocchi 2010-05-10 23:24:58 +00:00
parent 60ef31012a
commit a626ea51ff
2 changed files with 70 additions and 2 deletions

View File

@ -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);
}
}

View File

@ -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);