Last active
August 29, 2015 14:20
-
-
Save gkhays/7d65bc62bf15121187b5 to your computer and use it in GitHub Desktop.
Working with Google APIs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
clientId=Enter Client ID |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.netiq; | |
import java.awt.Desktop; | |
import java.awt.Desktop.Action; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.io.UnsupportedEncodingException; | |
import java.net.URI; | |
import java.net.URLEncoder; | |
import java.util.Properties; | |
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver; | |
import com.sun.jersey.api.client.Client; | |
import com.sun.jersey.api.client.ClientResponse; | |
import com.sun.jersey.api.client.WebResource; | |
public class GoogleAuthCode { | |
public static final String APPLICATION_JSON = "application/json"; | |
public static final String AUTHORIZATION = "Authorization"; | |
public static final String CONTENT_TYPE = "Content-Type"; | |
public static final String ACCOUNT_CHOOSER_URL = "https://accounts.google.com/AccountChooser?service=lso&continue="; | |
public static final String REDIRECT_URI = "http://localhost/Callback"; | |
public static final String OAUTH_URL = "https://accounts.google.com/o/oauth2/auth?"; | |
public static final String SCOPE = "https://www.googleapis.com/auth/admin.directory.user"; | |
private static String _clientId = null; | |
/** | |
* <pre> | |
GET https://accounts.google.com/o/oauth2/auth? | |
scope=https://www.googleapis.com/auth/admin.directory.user& | |
redirect_uri=https://localhost/Callback& | |
response_type=code& | |
client_id=430723156037-c3149idj1vhnqaotri5o5qem9prmm1hd.apps.googleusercontent.com& | |
access_type=offline | |
* </pre> | |
* @param redirectUri | |
* @return | |
* @throws UnsupportedEncodingException | |
*/ | |
private static String getAuthUri(String redirectUri) | |
throws UnsupportedEncodingException { | |
String responseType = "code"; | |
String accessType = "offline"; | |
StringBuilder uriBuilder = new StringBuilder(OAUTH_URL); | |
uriBuilder.append("response_type=").append(responseType).append("&"); | |
uriBuilder.append("scope=").append(URLEncoder.encode(SCOPE, "UTF-8")) | |
.append("&"); | |
uriBuilder.append("redirect_uri=") | |
.append(URLEncoder.encode(redirectUri, "UTF-8")).append("&"); | |
uriBuilder.append("client_id=").append(_clientId).append("&"); | |
uriBuilder.append("accessType=").append(accessType); | |
return uriBuilder.toString(); | |
} | |
private static void getProperties() throws IOException { | |
Properties prop = loadPropertiesAsResource(); | |
_clientId = prop.getProperty("clientId"); | |
} | |
private static void invokeBrowser(String url) throws IOException { | |
if (Desktop.isDesktopSupported()) { | |
Desktop deskTop = Desktop.getDesktop(); | |
if (deskTop.isSupported(Action.BROWSE)) { | |
System.out.println("Attempting to browse to " + url + " ..."); | |
deskTop.browse(URI.create(url)); | |
} | |
} | |
} | |
/** | |
* @see <a | |
* href="http://stackoverflow.com/questions/333363/loading-a-properties-file-from-java-package">Loading | |
* a properties file from Java package</a> | |
* @return | |
* @throws IOException | |
*/ | |
private static Properties loadPropertiesAsResource() throws IOException { | |
Properties prop = new Properties(); | |
InputStream in = GoogleAuthCode.class | |
.getResourceAsStream("client.properties"); | |
prop.load(in); | |
in.close(); | |
return prop; | |
} | |
/** | |
* Authenticate to Google Apps using OAuth 2. | |
* | |
* @param args | |
* @throws IOException | |
*/ | |
public static void main(String[] args) throws IOException { | |
getProperties(); | |
// Google will call me back at the redirect URL. Set up a listener. | |
LocalServerReceiver receiver = new LocalServerReceiver(); | |
String redirectUri = receiver.getRedirectUri(); | |
System.out.println("Local receiver listening on port " | |
+ receiver.getPort()); | |
// Make sure to grant the token as an admin user. In my case, | |
// ghays@accessreview.net. | |
System.out.println("(1) Request authentication using OAuth 2."); | |
String authUri = getAuthUri(redirectUri); | |
System.out.println("Making request to authorization URI: " | |
+ authUri.toString()); | |
System.out.println("Redirect URI: " + redirectUri); | |
// (1) Authorize | |
Client client = Client.create(); | |
WebResource wr = client.resource(authUri); | |
ClientResponse response = wr.header(CONTENT_TYPE, APPLICATION_JSON) | |
.get(ClientResponse.class); | |
int status = response.getStatus(); | |
System.out.println("HTTP Response Status: " + status); | |
// Launch the Google Account Chooser. Of the form: | |
// https://accounts.google.com/AccountChooser?service=lso&continue=[authorizeurl] | |
// | |
// See http://stackoverflow.com/questions/14384354/force-google-account-chooser | |
String chooserUri = ACCOUNT_CHOOSER_URL + URLEncoder.encode(authUri, "UTF-8"); | |
invokeBrowser(chooserUri); | |
// Receive authorization code. | |
System.out.println("Waiting for the code..."); | |
String code = receiver.waitForCode(); | |
receiver.stop(); // TODO - Put this in a try/finally. | |
System.out.println("Google authorization code: " + code); | |
// TODO - Can we persist the authorization code? | |
} | |
/** | |
* <pre> | |
2015-04-30 16:57:08.322:INFO::Logging to STDERR via org.mortbay.log.StdErrLog | |
2015-04-30 16:57:08.323:INFO::jetty-6.1.26 | |
2015-04-30 16:57:08.346:INFO::Started SocketConnector@localhost:14975 | |
Local receiver listening on port 14975 | |
(1) Request authentication using OAuth 2. | |
Making request to authorization URI: https://accounts.google.com/o/oauth2/auth?response_type=code&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fadmin.directory.user&redirect_uri=http%3A%2F%2Flocalhost%3A14975%2FCallback&client_id=430723156037-c3149idj1vhnqaotri5o5qem9prmm1hd.apps.googleusercontent.com&accessType=offline | |
Redirect URI: http://localhost:14975/Callback | |
HTTP Response Status: 200 | |
Attempting to browse to https://accounts.google.com/AccountChooser?service=lso&continue=https%3A%2F%2Faccounts.google.com%2Fo%2Foauth2%2Fauth%3Fresponse_type%3Dcode%26scope%3Dhttps%253A%252F%252Fwww.googleapis.com%252Fauth%252Fadmin.directory.user%26redirect_uri%3Dhttp%253A%252F%252Flocalhost%253A14975%252FCallback%26client_id%3D430723156037-c3149idj1vhnqaotri5o5qem9prmm1hd.apps.googleusercontent.com%26accessType%3Doffline ... | |
Waiting for the code... | |
2015-04-30 16:57:15.034:INFO::Stopped SocketConnector@localhost:14975 | |
Google authorization code: 4/5BIHWBuGQWLoOjjcrSMR8L8GnySSea1q9QkNBHl0gUU.AkyzX7Xet3UaPm8kb2vw2M0D2qoYmgI | |
* </pre> | |
*/ | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.gkh.test; | |
import java.awt.Desktop; | |
import java.awt.Desktop.Action; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.io.UnsupportedEncodingException; | |
import java.net.URI; | |
import java.net.URLEncoder; | |
import java.util.Properties; | |
import org.codehaus.jettison.json.JSONException; | |
import org.codehaus.jettison.json.JSONObject; | |
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver; | |
import com.sun.jersey.api.client.Client; | |
import com.sun.jersey.api.client.ClientResponse; | |
import com.sun.jersey.api.client.WebResource; | |
public class GoogleToken { | |
public static final String APPLICATION_ENCODED = "application/x-www-form-urlencoded"; | |
public static final String APPLICATION_JSON = "application/json"; | |
public static final String AUTHORIZATION = "Authorization"; | |
public static final String CONTENT_TYPE = "Content-Type"; | |
public static final String ACCOUNT_CHOOSER_URL = "https://accounts.google.com/AccountChooser?service=lso&continue="; | |
public static final String REDIRECT_URI = "http://localhost/Callback"; | |
public static final String OAUTH_URL = "https://accounts.google.com/o/oauth2/auth?"; | |
public static final String SCOPE = "https://www.googleapis.com/auth/admin.directory.user"; | |
private static String _clientId = null; | |
private String _redirectUri = null; | |
private String _scope = null; | |
private LocalServerReceiver _receiver = null; | |
private Client _client = null; | |
private WebResource _webResource = null; | |
private ClientResponse _response = null; | |
// Discussions on whether or not to throw an exception in a constructor. The | |
// guidance is to not produce a partially constructed object that may be | |
// subclassed and abused. | |
// http://stackoverflow.com/questions/6086334/is-it-good-practice-to-make-the-constructor-throw-an-exception | |
// http://stackoverflow.com/questions/1371369/can-constructors-throw-exceptions-in-java/1373419#1373419 | |
// http://stackoverflow.com/questions/7532078/java-exception-in-constructors-problematic-or-not | |
// http://www.oracle.com/technetwork/java/seccodeguide-139067.html#7 | |
public GoogleToken(String scope, String propertyFileName) throws IOException { | |
_scope = scope; | |
init(propertyFileName); | |
} | |
public GoogleToken() throws IOException { | |
_scope = SCOPE; | |
init(null); | |
} | |
public String connect() throws IOException { | |
String authUri = getAuthUri(); | |
System.out.println("Making request to authorization URI: " | |
+ authUri.toString()); | |
System.out.println("Redirect URI: " + _redirectUri); | |
// (1) Authorize | |
_client = Client.create(); | |
_webResource = _client.resource(authUri); | |
_response = _webResource.header(CONTENT_TYPE, APPLICATION_JSON).get( | |
ClientResponse.class); | |
int status = _response.getStatus(); | |
System.out.println("HTTP Response Status: " + status); | |
String code = null; | |
if (status == 200) { | |
// Launch the Google Account Chooser. Of the form: | |
// https://accounts.google.com/AccountChooser?service=lso&continue=[authorizeurl] | |
// See http://stackoverflow.com/questions/14384354/force-google-account-chooser | |
String chooserUri = ACCOUNT_CHOOSER_URL | |
+ URLEncoder.encode(authUri, "UTF-8"); | |
invokeBrowser(chooserUri); | |
// Receive authorization code. | |
System.out.println("Waiting for the code..."); | |
code = _receiver.waitForCode(); | |
_receiver.stop(); // TODO - Put this in a try/finally. | |
System.out.println("Google authorization code: " + code); | |
} | |
// TODO - Can we persist the authorization code? | |
return code; | |
} | |
public JSONObject exchangeCodeForToken(String code) throws JSONException, | |
UnsupportedEncodingException { | |
String OAUTH_TOKEN_URL = "www.googleapis.com/oauth2/v3/token"; | |
String clientSecret = "WA5hqvXVh8pnvjrbCbkHmCIC"; | |
String tokenUrl = "https://" + OAUTH_TOKEN_URL; | |
StringBuilder payloadBuilder = new StringBuilder("code=").append(code); | |
payloadBuilder.append("&client_id=").append(_clientId); | |
payloadBuilder.append("&client_secret=").append(clientSecret); | |
payloadBuilder.append("&redirect_uri=").append( | |
URLEncoder.encode(_redirectUri, "UTF-8")); | |
payloadBuilder.append("&grant_type=").append("authorization_code"); | |
payloadBuilder.append("&access_type=").append("offline"); | |
System.out.println("(2) Exchange authorization code for a token."); | |
System.out.println("Making request to " + tokenUrl); | |
_webResource = _client.resource(tokenUrl); | |
_response = _webResource.header(CONTENT_TYPE, APPLICATION_ENCODED) | |
.entity(payloadBuilder.toString()).post(ClientResponse.class); | |
int status = _response.getStatus(); | |
JSONObject jsonResponse = null; | |
if (status == 200) { | |
jsonResponse = _response.getEntity(JSONObject.class); | |
System.out.println("Response Status: " + status); | |
System.out.println("Token:\n" + jsonResponse.toString(2)); | |
} | |
return jsonResponse; | |
} | |
/** | |
* <pre> | |
GET https://accounts.google.com/o/oauth2/auth? | |
scope=https://www.googleapis.com/auth/admin.directory.user& | |
redirect_uri=https://localhost/Callback& | |
response_type=code& | |
client_id=430723156037-c3149idj1vhnqaotri5o5qem9prmm1hd.apps.googleusercontent.com& | |
access_type=offline | |
* </pre> | |
* @return | |
* @throws UnsupportedEncodingException | |
*/ | |
private String getAuthUri() | |
throws UnsupportedEncodingException { | |
String responseType = "code"; | |
String accessType = "offline"; | |
StringBuilder uriBuilder = new StringBuilder(OAUTH_URL); | |
uriBuilder.append("response_type=").append(responseType).append("&"); | |
uriBuilder.append("scope=").append(URLEncoder.encode(SCOPE, "UTF-8")) | |
.append("&"); | |
uriBuilder.append("redirect_uri=") | |
.append(URLEncoder.encode(_redirectUri, "UTF-8")).append("&"); | |
uriBuilder.append("client_id=").append(_clientId).append("&"); | |
uriBuilder.append("accessType=").append(accessType); | |
return uriBuilder.toString(); | |
} | |
private void getProperties(String fileName) throws IOException { | |
Properties prop = null; | |
if (fileName == null) { | |
prop = loadPropertiesAsResource(); | |
} else { | |
prop = loadPropertiesAsResource(fileName); | |
} | |
_clientId = prop.getProperty("clientId"); | |
} | |
private void init(String pfn) throws IOException { | |
if (pfn != null) { | |
getProperties(pfn); | |
} else { | |
getProperties(null); | |
} | |
// Google will call me back at the redirect URL. Set up a listener. | |
_receiver = new LocalServerReceiver(); | |
_redirectUri = _receiver.getRedirectUri(); | |
System.out.println("Local receiver listening on port " | |
+ _receiver.getPort()); | |
// Make sure to grant the token as an admin user. In my case, | |
// ghays@accessreview.net. | |
System.out.println("(1) Request authentication using OAuth 2."); | |
} | |
private void invokeBrowser(String url) throws IOException { | |
if (Desktop.isDesktopSupported()) { | |
Desktop deskTop = Desktop.getDesktop(); | |
if (deskTop.isSupported(Action.BROWSE)) { | |
System.out.println("Attempting to browse to " + url + " ..."); | |
deskTop.browse(URI.create(url)); | |
} | |
} | |
} | |
/** | |
* @see <a | |
* href="http://stackoverflow.com/questions/333363/loading-a-properties-file-from-java-package">Loading | |
* a properties file from Java package</a> | |
* @return | |
* @throws IOException | |
*/ | |
private Properties loadPropertiesAsResource() throws IOException { | |
Properties prop = new Properties(); | |
InputStream in = GoogleToken.class | |
.getResourceAsStream("client.properties"); | |
prop.load(in); | |
in.close(); | |
return prop; | |
} | |
private Properties loadPropertiesAsResource(String name) throws IOException { | |
Properties prop = new Properties(); | |
InputStream in = GoogleToken.class | |
.getResourceAsStream(name); | |
prop.load(in); | |
in.close(); | |
return prop; | |
} | |
/** | |
* Authenticate to Google Apps using OAuth 2. | |
* | |
* @param args | |
* @throws IOException | |
*/ | |
public static void main(String[] args) throws IOException { | |
GoogleToken authCode = new GoogleToken(); | |
authCode.connect(); | |
} | |
/** | |
* This is what the Google account chooser URI looks like. | |
* | |
* <pre> | |
https://accounts.google.com/AccountChooser?service=lso&continue=https%3A%2F%2Faccounts.google.com%2Fo | |
%2Foauth2%2Fauth%3Fresponse_type%3Dcode%26scope%3Dhttps%3A%2F%2Fwww.googleapis.com%2Fauth | |
%2Fadmin.directory.user%26redirect_uri%3Dhttp%3A%2F%2Flocalhost%3A14539%2FCallback%26client_id | |
%3D430723156037-c3149idj1vhnqaotri5o5qem9prmm1hd.apps.googleusercontent.com%26accessType%3Doffline%26hl | |
%3Den%26from_login%3D1%26as%3D-c695002fd5825cf&btmpl=authsub&hl=en | |
* </pre> | |
*/ | |
/** | |
* <pre> | |
2015-04-30 16:57:08.322:INFO::Logging to STDERR via org.mortbay.log.StdErrLog | |
2015-04-30 16:57:08.323:INFO::jetty-6.1.26 | |
2015-04-30 16:57:08.346:INFO::Started SocketConnector@localhost:14975 | |
Local receiver listening on port 14975 | |
(1) Request authentication using OAuth 2. | |
Making request to authorization URI: https://accounts.google.com/o/oauth2/auth?response_type=code&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fadmin.directory.user&redirect_uri=http%3A%2F%2Flocalhost%3A14975%2FCallback&client_id=430723156037-c3149idj1vhnqaotri5o5qem9prmm1hd.apps.googleusercontent.com&accessType=offline | |
Redirect URI: http://localhost:14975/Callback | |
HTTP Response Status: 200 | |
Attempting to browse to https://accounts.google.com/AccountChooser?service=lso&continue=https%3A%2F%2Faccounts.google.com%2Fo%2Foauth2%2Fauth%3Fresponse_type%3Dcode%26scope%3Dhttps%253A%252F%252Fwww.googleapis.com%252Fauth%252Fadmin.directory.user%26redirect_uri%3Dhttp%253A%252F%252Flocalhost%253A14975%252FCallback%26client_id%3D430723156037-c3149idj1vhnqaotri5o5qem9prmm1hd.apps.googleusercontent.com%26accessType%3Doffline ... | |
Waiting for the code... | |
2015-04-30 16:57:15.034:INFO::Stopped SocketConnector@localhost:14975 | |
Google authorization code: 4/5BIHWBuGQWLoOjjcrSMR8L8GnySSea1q9QkNBHl0gUU.AkyzX7Xet3UaPm8kb2vw2M0D2qoYmgI | |
* </pre> | |
*/ | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment