package divconq.oauth;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.scribe.builder.api.DefaultApi20;
import org.scribe.exceptions.OAuthException;
import org.scribe.extractors.AccessTokenExtractor;
import org.scribe.model.OAuthConfig;
import org.scribe.model.OAuthConstants;
import org.scribe.model.OAuthRequest;
import org.scribe.model.Response;
import org.scribe.model.Token;
import org.scribe.model.Verb;
import org.scribe.model.Verifier;
import org.scribe.oauth.OAuth20ServiceImpl;
import org.scribe.oauth.OAuthService;
import org.scribe.utils.OAuthEncoder;
import org.scribe.utils.Preconditions;
/**
* Google OAuth2.0
* Released under the same license as scribe (MIT License)
* @author yincrash
*
* find at https://gist.github.com/yincrash/2465453
*
* even better would be to grab from:
* https://github.com/codolutions/scribe-java
*
* above is best and most current I can find, but need to collect whole code from there
*
*/
public class Google2Api extends DefaultApi20 {
public static final String REFRESH_TOKEN = "refresh_token";
public static final String GRANT_TYPE = "grant_type";
public static final String GRANT_TYPE_AUTHORIZATION_CODE = "authorization_code";
public static final String GRANT_TYPE_REFRESH_TOKEN = "refresh_token";
public static final String ACCESS_TYPE = "access_type";
public static final String ACCESS_TYPE_OFFLINE = "offline";
public static final String APPROVAL_PROMPT = "approval_prompt";
public static final String APPROVAL_PROMPT_FORCE = "force";
private static final String AUTHORIZE_URL = "https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=%s&redirect_uri=%s";
private static final String SCOPED_AUTHORIZE_URL = AUTHORIZE_URL + "&scope=%s";
private static final String SUFFIX_OFFLINE = "&" + ACCESS_TYPE + "=" + ACCESS_TYPE_OFFLINE
+ "&" + APPROVAL_PROMPT + "=" + APPROVAL_PROMPT_FORCE;
@Override
public String getAccessTokenEndpoint() {
return "https://accounts.google.com/o/oauth2/token";
}
@Override
public AccessTokenExtractor getAccessTokenExtractor() {
return new AccessTokenExtractor() {
@Override
public Token extract(String response) {
Preconditions.checkEmptyString(response, "Response body is incorrect. Can't extract a token from an empty string");
Matcher matcher = Pattern.compile("\"access_token\" : \"([^&\"]+)\"").matcher(response);
if (matcher.find())
{
String token = OAuthEncoder.decode(matcher.group(1));
return new Token(token, "", response);
}
else
{
throw new OAuthException("Response body is incorrect. Can't extract a token from this: '" + response + "'", null);
}
}
};
}
@Override
public String getAuthorizationUrl(OAuthConfig config) {
// + SUFFIX_OFFLINE TODO not used unless in offline mode
// Append scope if present
if (config.hasScope()) {
return String.format(SCOPED_AUTHORIZE_URL + SUFFIX_OFFLINE, config.getApiKey(),
OAuthEncoder.encode(config.getCallback()),
OAuthEncoder.encode(config.getScope()));
} else {
return String.format(AUTHORIZE_URL + SUFFIX_OFFLINE, config.getApiKey(),
OAuthEncoder.encode(config.getCallback()));
}
}
@Override
public Verb getAccessTokenVerb() {
return Verb.POST;
}
@Override
public OAuthService createService(OAuthConfig config) {
return new GoogleOAuth2Service(config);
}
private class GoogleOAuth2Service extends OAuth20ServiceImpl {
private static final String GRANT_TYPE_AUTHORIZATION_CODE = "authorization_code";
private static final String GRANT_TYPE = "grant_type";
//private DefaultApi20 api;
private OAuthConfig config;
public GoogleOAuth2Service(OAuthConfig config) {
super(Google2Api.this, config);
//this.api = api;
this.config = config;
}
@Override
public Token getAccessToken(Token requestToken, Verifier verifier) {
OAuthRequest request = new OAuthRequest(Google2Api.this.getAccessTokenVerb(), Google2Api.this.getAccessTokenEndpoint());
switch (Google2Api.this.getAccessTokenVerb()) {
case POST:
request.addBodyParameter(OAuthConstants.CLIENT_ID, config.getApiKey());
if (config.getApiSecret() != null && config.getApiSecret().length() > 0)
request.addBodyParameter(OAuthConstants.CLIENT_SECRET, config.getApiSecret());
if (requestToken == null) {
request.addBodyParameter(OAuthConstants.CODE, verifier.getValue());
request.addBodyParameter(OAuthConstants.REDIRECT_URI, config.getCallback());
request.addBodyParameter(GRANT_TYPE, GRANT_TYPE_AUTHORIZATION_CODE);
} else {
request.addBodyParameter(REFRESH_TOKEN, requestToken.getSecret());
request.addBodyParameter(GRANT_TYPE, GRANT_TYPE_REFRESH_TOKEN);
}
//request.addBodyParameter(OAuthConstants.CODE, verifier.getValue());
//request.addBodyParameter(OAuthConstants.REDIRECT_URI, config.getCallback());
//request.addBodyParameter(GRANT_TYPE, GRANT_TYPE_AUTHORIZATION_CODE);
break;
case GET:
default:
request.addQuerystringParameter(OAuthConstants.CLIENT_ID, config.getApiKey());
if (config.getApiSecret() != null && config.getApiSecret().length() > 0)
request.addBodyParameter(OAuthConstants.CLIENT_SECRET, config.getApiSecret());
request.addQuerystringParameter(OAuthConstants.CODE, verifier.getValue());
request.addQuerystringParameter(OAuthConstants.REDIRECT_URI, config.getCallback());
if(config.hasScope()) request.addQuerystringParameter(OAuthConstants.SCOPE, config.getScope());
}
Response response = request.send();
return Google2Api.this.getAccessTokenExtractor().extract(response.getBody());
}
}
}