Migrate to OAuth2
- implement OAuth2 for both Spreadsheets & Fusion Tables - switch cookie name from authsub_token to oauth2_token so there's no confusion - implementation is otherwise unchanged - in particular still uses old Fusion Tables SQL API
This commit is contained in:
parent
d7081415d4
commit
bf2f775c0b
@ -31,6 +31,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Controller for GData extension.
|
||||
*
|
||||
* This is run in the Butterfly (ie Refine) server context using the Rhino
|
||||
* Javascript interpreter.
|
||||
*/
|
||||
|
||||
var html = "text/html";
|
||||
var encoding = "UTF-8";
|
||||
var version = "0.2";
|
||||
@ -101,21 +108,13 @@ function process(path, request, response) {
|
||||
} else if (path == "authorized") {
|
||||
var context = {};
|
||||
context.winname = request.getParameter("winname");
|
||||
context.callback = request.getParameter("callback");
|
||||
context.callback = request.getParameter("cb");
|
||||
|
||||
(function() {
|
||||
var queryString = request.getQueryString();
|
||||
if (queryString != null) {
|
||||
var AuthSubUtil = Packages.com.google.gdata.client.http.AuthSubUtil;
|
||||
|
||||
// FIXME(SM): can we safely assume UTF-8 encoding here?
|
||||
var onetimeUseToken = AuthSubUtil.getTokenFromReply(
|
||||
Packages.java.net.URLDecoder.decode(queryString, "UTF-8"));
|
||||
if (onetimeUseToken) {
|
||||
var sessionToken = AuthSubUtil.exchangeForSessionToken(onetimeUseToken, null);
|
||||
Packages.com.google.refine.extension.gdata.TokenCookie.setToken(request, response, sessionToken);
|
||||
return;
|
||||
}
|
||||
var token = Packages.com.google.refine.extension.gdata.GDataExtension.getTokenFromCode(module,request);
|
||||
if (token) {
|
||||
Packages.com.google.refine.extension.gdata.TokenCookie.setToken(request, response, token);
|
||||
return;
|
||||
}
|
||||
Packages.com.google.refine.extension.gdata.TokenCookie.deleteToken(request, response);
|
||||
})();
|
||||
|
@ -34,7 +34,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
var GdataExtension = {};
|
||||
|
||||
GdataExtension.isAuthorized = function() {
|
||||
return $.cookie('authsub_token') !== null;
|
||||
return $.cookie('oauth2_token') !== null;
|
||||
};
|
||||
|
||||
GdataExtension.showAuthorizationDialog = function(onAuthorized, onNotAuthorized) {
|
||||
@ -57,6 +57,6 @@ GdataExtension.showAuthorizationDialog = function(onAuthorized, onNotAuthorized)
|
||||
};
|
||||
window[callbackName] = callback;
|
||||
|
||||
var url = ModuleWirings['gdata'] + "authorize?winname=" + escape(windowName) + "&callback=" + escape(callbackName);
|
||||
var url = ModuleWirings['gdata'] + "authorize?winname=" + escape(windowName) + "&cb=" + escape(callbackName);
|
||||
var win = window.open(url, "openrefinegdataauth", "resizable=1,width=800,height=600");
|
||||
};
|
||||
|
@ -34,12 +34,18 @@ import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.google.gdata.client.http.AuthSubUtil;
|
||||
import com.google.api.client.http.GenericUrl;
|
||||
import com.google.api.client.http.HttpRequest;
|
||||
import com.google.api.client.http.HttpRequestFactory;
|
||||
import com.google.api.client.http.HttpResponse;
|
||||
import com.google.api.client.http.HttpTransport;
|
||||
import com.google.api.client.http.javanet.NetHttpTransport;
|
||||
|
||||
import com.google.refine.commands.Command;
|
||||
|
||||
public class DeAuthorizeCommand extends Command {
|
||||
|
||||
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
|
||||
@Override
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
@ -50,7 +56,16 @@ public class DeAuthorizeCommand extends Command {
|
||||
|
||||
String sessionToken = TokenCookie.getToken(request);
|
||||
if (sessionToken != null) {
|
||||
AuthSubUtil.revokeToken(sessionToken, null);
|
||||
|
||||
// No method to do this in Google's client lib, so roll our own
|
||||
HttpRequestFactory factory = HTTP_TRANSPORT.createRequestFactory();
|
||||
GenericUrl url = new GenericUrl("https://accounts.google.com/o/oauth2/revoke?token="+sessionToken);
|
||||
HttpRequest rqst = factory.buildGetRequest(url);
|
||||
HttpResponse resp = rqst.execute();
|
||||
if (resp.getStatusCode() != 200) {
|
||||
respond(response, String.valueOf(resp.getStatusCode()), resp.getStatusMessage());
|
||||
}
|
||||
|
||||
TokenCookie.deleteToken(request, response);
|
||||
}
|
||||
respond(response, "200 OK", "");
|
||||
|
@ -30,7 +30,6 @@ package com.google.refine.extension.gdata;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
@ -39,19 +38,12 @@ import java.util.Scanner;
|
||||
import java.util.regex.MatchResult;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.google.gdata.client.GoogleService;
|
||||
import com.google.gdata.client.Service.GDataRequest;
|
||||
import com.google.gdata.client.Service.GDataRequest.RequestType;
|
||||
import com.google.gdata.client.http.AuthSubUtil;
|
||||
import com.google.gdata.util.ContentType;
|
||||
import com.google.gdata.util.ServiceException;
|
||||
|
||||
import com.google.refine.util.ParsingUtilities;
|
||||
|
||||
import edu.mit.simile.butterfly.ButterflyModule;
|
||||
|
||||
/**
|
||||
* @author Tom Morris <tfmorris@gmail.com>
|
||||
* @copyright 2010,2013 Thomas F. Morris
|
||||
@ -61,41 +53,22 @@ public class FusionTableHandler {
|
||||
|
||||
final static private String FUSION_TABLES_SERVICE_URL =
|
||||
"https://www.google.com/fusiontables/api/query";
|
||||
// "https://www.googleapis.com/fusiontables/v1/query";
|
||||
|
||||
final static private Pattern CSV_VALUE_PATTERN =
|
||||
Pattern.compile("([^,\\r\\n\"]*|\"(([^\"]*\"\")*[^\"]*)\")(,|\\r?\\n)");
|
||||
|
||||
static public String getAuthorizationUrl(ButterflyModule module, HttpServletRequest request)
|
||||
throws MalformedURLException {
|
||||
char[] mountPointChars = module.getMountPoint().getMountPoint().toCharArray();
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(mountPointChars, 0, mountPointChars.length);
|
||||
sb.append("authorized?winname=");
|
||||
sb.append(ParsingUtilities.encode(request.getParameter("winname")));
|
||||
sb.append("&callback=");
|
||||
sb.append(ParsingUtilities.encode(request.getParameter("callback")));
|
||||
|
||||
URL thisUrl = new URL(request.getRequestURL().toString());
|
||||
URL authorizedUrl = new URL(thisUrl, sb.toString());
|
||||
|
||||
return AuthSubUtil.getRequestUrl(
|
||||
authorizedUrl.toExternalForm(), // execution continues at authorized on redirect
|
||||
"https://www.google.com/fusiontables/api/query",
|
||||
false,
|
||||
true);
|
||||
}
|
||||
|
||||
static public GDataRequest createFusionTablesPostRequest(
|
||||
GoogleService service, RequestType requestType, String query)
|
||||
throws IOException, ServiceException {
|
||||
|
||||
URL url = new URL(FUSION_TABLES_SERVICE_URL);
|
||||
GDataRequest request = service.getRequestFactory().getRequest(
|
||||
requestType, url, new ContentType("application/x-www-form-urlencoded"));
|
||||
|
||||
OutputStreamWriter writer =
|
||||
new OutputStreamWriter(request.getRequestStream());
|
||||
writer.append("sql=" + URLEncoder.encode(query, "UTF-8"));
|
||||
writer.append("sql=" + URLEncoder.encode(query, "UTF-8") + "&alt=csv");
|
||||
writer.flush();
|
||||
writer.close();
|
||||
|
||||
@ -106,7 +79,7 @@ public class FusionTableHandler {
|
||||
GoogleService service, RequestType requestType, String query)
|
||||
throws IOException, ServiceException {
|
||||
URL url = new URL(FUSION_TABLES_SERVICE_URL + "?sql=" +
|
||||
URLEncoder.encode(query, "UTF-8"));
|
||||
URLEncoder.encode(query, "UTF-8")+"&alt=csv");
|
||||
return service.getRequestFactory().getRequest(
|
||||
requestType, url, ContentType.TEXT_PLAIN);
|
||||
}
|
||||
|
@ -28,13 +28,22 @@
|
||||
*/
|
||||
package com.google.refine.extension.gdata;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.google.api.client.auth.oauth2.AuthorizationCodeResponseUrl;
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeRequestUrl;
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeTokenRequest;
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
|
||||
import com.google.api.client.http.HttpTransport;
|
||||
import com.google.api.client.http.javanet.NetHttpTransport;
|
||||
import com.google.api.client.json.JsonFactory;
|
||||
import com.google.api.client.json.jackson.JacksonFactory;
|
||||
import com.google.gdata.client.docs.DocsService;
|
||||
import com.google.gdata.client.http.AuthSubUtil;
|
||||
import com.google.gdata.client.spreadsheet.SpreadsheetService;
|
||||
|
||||
import com.google.refine.util.ParsingUtilities;
|
||||
@ -48,28 +57,72 @@ import edu.mit.simile.butterfly.ButterflyModule;
|
||||
*/
|
||||
abstract public class GDataExtension {
|
||||
static final String SERVICE_APP_NAME = "OpenRefine-GData-Extension";
|
||||
static final String CLIENT_ID = "647865400439.apps.googleusercontent.com";
|
||||
static final String CLIENT_SECRET = "0mW9OJji1yrgJk5AjJc5Pn6I"; // not really that secret, but the protocol accounts for that
|
||||
|
||||
/** Global instance of the HTTP transport. */
|
||||
static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
|
||||
|
||||
/** Global instance of the JSON factory. */
|
||||
static final JsonFactory JSON_FACTORY = new JacksonFactory();
|
||||
|
||||
static public String getAuthorizationUrl(ButterflyModule module, HttpServletRequest request)
|
||||
throws MalformedURLException {
|
||||
char[] mountPointChars = module.getMountPoint().getMountPoint().toCharArray();
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(mountPointChars, 0, mountPointChars.length);
|
||||
String authorizedUrl = makeRedirectUrl(module, request);
|
||||
|
||||
// New Oauth2
|
||||
GoogleAuthorizationCodeRequestUrl url = new GoogleAuthorizationCodeRequestUrl(
|
||||
CLIENT_ID,
|
||||
authorizedUrl, // execution continues at authorized on redirect
|
||||
Arrays.asList("https://www.googleapis.com/auth/fusiontables",
|
||||
"https://docs.google.com/feeds", // create new spreadsheets
|
||||
"https://spreadsheets.google.com/feeds"));
|
||||
|
||||
return url.toString();
|
||||
|
||||
}
|
||||
|
||||
private static String makeRedirectUrl(ButterflyModule module, HttpServletRequest request)
|
||||
throws MalformedURLException {
|
||||
StringBuffer sb = new StringBuffer(module.getMountPoint().getMountPoint());
|
||||
sb.append("authorized?winname=");
|
||||
sb.append(ParsingUtilities.encode(request.getParameter("winname")));
|
||||
sb.append("&callback=");
|
||||
sb.append(ParsingUtilities.encode(request.getParameter("callback")));
|
||||
sb.append("&cb=");
|
||||
sb.append(ParsingUtilities.encode(request.getParameter("cb")));
|
||||
|
||||
URL thisUrl = new URL(request.getRequestURL().toString());
|
||||
URL authorizedUrl = new URL(thisUrl, sb.toString());
|
||||
|
||||
return AuthSubUtil.getRequestUrl(
|
||||
authorizedUrl.toExternalForm(), // execution continues at authorized on redirect
|
||||
"https://docs.google.com/feeds https://spreadsheets.google.com/feeds https://www.google.com/fusiontables/api/query",
|
||||
false,
|
||||
true);
|
||||
return authorizedUrl.toExternalForm();
|
||||
}
|
||||
|
||||
static public String getTokenFromCode(ButterflyModule module, HttpServletRequest request)
|
||||
throws MalformedURLException {
|
||||
String redirectUrl = makeRedirectUrl(module, request);
|
||||
StringBuffer fullUrlBuf = request.getRequestURL();
|
||||
if (request.getQueryString() != null) {
|
||||
fullUrlBuf.append('?').append(request.getQueryString());
|
||||
}
|
||||
AuthorizationCodeResponseUrl authResponse =
|
||||
new AuthorizationCodeResponseUrl(fullUrlBuf.toString());
|
||||
// check for user-denied error
|
||||
if (authResponse.getError() != null) {
|
||||
// authorization denied...
|
||||
} else {
|
||||
// request access token using authResponse.getCode()...
|
||||
String code = authResponse.getCode();
|
||||
try {
|
||||
GoogleTokenResponse response = new GoogleAuthorizationCodeTokenRequest(HTTP_TRANSPORT,
|
||||
JSON_FACTORY, CLIENT_ID, CLIENT_SECRET, code, redirectUrl).execute();
|
||||
String token = response.getAccessToken();
|
||||
return token;
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
static public DocsService getDocsService(String token) {
|
||||
DocsService service = new DocsService(SERVICE_APP_NAME);
|
||||
|
@ -8,7 +8,7 @@ import com.google.refine.util.CookiesUtilities;
|
||||
|
||||
public class TokenCookie {
|
||||
|
||||
private static final String COOKIE_NAME = "authsub_token";
|
||||
private static final String COOKIE_NAME = "oauth2_token";
|
||||
private static int MAX_AGE = 30 * 24 * 60 * 60; // 30 days
|
||||
|
||||
public static String getToken(HttpServletRequest request) {
|
||||
|
Loading…
Reference in New Issue
Block a user