Created
September 26, 2021 06:31
-
-
Save jrichardsz/a91cd2500404e717753fdb23e9d6fd35 to your computer and use it in GitHub Desktop.
google oauth2 java client, googleoaauth2
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.jrichardsz.horus.third.google.client; | |
import java.util.Map; | |
import org.jrichardsz.horus.exceptions.BadGoogleResponseException; | |
import org.jrichardsz.horus.exceptions.GoogleOauthRestApiException; | |
public interface GoogleClient { | |
public String getAuthorizeUrl(String redirectUri, String scope, String clientId); | |
public Map<String, Object> getAccessToken(String authorizationCode, String clientId, | |
String clientSecret, String redirect) throws GoogleOauthRestApiException; | |
public String getDataUserFromPlusApi(String accessToken) | |
throws BadGoogleResponseException, GoogleOauthRestApiException; | |
public String getDataUserFromPeopleApi(String accessToken) | |
throws BadGoogleResponseException, GoogleOauthRestApiException; | |
} |
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.jrichardsz.horus.third.google.client.impl; | |
import java.io.BufferedReader; | |
import java.io.IOException; | |
import java.io.InputStreamReader; | |
import java.io.OutputStreamWriter; | |
import java.io.UnsupportedEncodingException; | |
import java.net.HttpURLConnection; | |
import java.net.URL; | |
import java.net.URLEncoder; | |
import java.nio.charset.StandardCharsets; | |
import java.util.Map; | |
import org.jrichardsz.horus.common.HorusCommon; | |
import org.jrichardsz.horus.exceptions.BadGoogleResponseException; | |
import org.jrichardsz.horus.exceptions.GoogleOauthRestApiException; | |
import org.jrichardsz.horus.third.google.client.GoogleClient; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import org.springframework.http.HttpEntity; | |
import org.springframework.http.HttpHeaders; | |
import org.springframework.http.HttpMethod; | |
import org.springframework.stereotype.Component; | |
import org.springframework.util.Assert; | |
import org.springframework.web.client.HttpClientErrorException; | |
import org.springframework.web.client.HttpServerErrorException; | |
import org.springframework.web.client.RestTemplate; | |
import org.springframework.web.util.UriComponentsBuilder; | |
import com.fasterxml.jackson.databind.ObjectMapper; | |
import com.jayway.jsonpath.JsonPath; | |
import com.jayway.jsonpath.ReadContext; | |
@Component | |
public class GoogleClientImpl implements GoogleClient { | |
private static final Logger logger = LoggerFactory.getLogger(GoogleClientImpl.class); | |
public final String googleAuthUrlTemplate = "https://accounts.google.com/o/oauth2/v2/auth?" | |
+ "response_type=code&redirect_uri=%s&scope=%s&client_id=%s"; | |
private final String googleTokenGeneratorUrl = "https://accounts.google.com/o/oauth2/token?"; | |
private final String googlePeopleApiUrl = "https://people.googleapis.com/v1/people/me"; | |
private final String googlePlusApiUrl = "https://www.googleapis.com/plus/v1/people/me"; | |
private final String codeGrantType = "authorization_code"; | |
private final String prefixAuthHeader = "Bearer"; | |
public String getAuthorizeUrl(String redirectUri, String scope, String clientId) { | |
// scope encode | |
scope = encodeValue(scope); | |
return String.format(googleAuthUrlTemplate, redirectUri, scope, clientId); | |
} | |
// Method to encode a string value using `UTF-8` encoding scheme | |
private String encodeValue(String value) { | |
try { | |
return URLEncoder.encode(value, StandardCharsets.UTF_8.toString()); | |
} catch (UnsupportedEncodingException ex) { | |
throw new RuntimeException(ex.getCause()); | |
} | |
} | |
@SuppressWarnings("unchecked") | |
public Map<String, Object> getAccessToken(String authorizationCode, String clientId, | |
String clientSecret, String redirect) throws GoogleOauthRestApiException { | |
HttpURLConnection conn = null; | |
try { | |
StringBuilder urlParameters = new StringBuilder(); | |
urlParameters.append("code=").append(authorizationCode).append("&client_id=").append(clientId) | |
.append("&client_secret=").append(clientSecret).append("&redirect_uri=").append(redirect) | |
.append("&grant_type=").append(codeGrantType); | |
URL url = new URL(googleTokenGeneratorUrl); | |
conn = (HttpURLConnection) url.openConnection(); | |
conn.setDoOutput(true); | |
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); | |
OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream()); | |
writer.write(urlParameters.toString()); | |
writer.flush(); | |
String tokenDataStr = ""; | |
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); | |
String line; | |
while ((line = reader.readLine()) != null) { | |
tokenDataStr = tokenDataStr + line; | |
} | |
writer.close(); | |
reader.close(); | |
ObjectMapper mapper = new ObjectMapper(); | |
Map<String, Object> tokenData = mapper.readValue(tokenDataStr, Map.class); | |
return tokenData; | |
} catch (IOException e) { | |
String errorResponse = HorusCommon.inputStreamToString(conn.getErrorStream()); | |
logger.info("google response:" + errorResponse); | |
throw new GoogleOauthRestApiException(String.format( | |
"Google platform returns a error [%s] when oauth code was exchanged for the token.", | |
e.getMessage()), e); | |
} catch (HttpClientErrorException e) { | |
String errorResponse = e.getResponseBodyAsString(); | |
logger.info("google response:" + errorResponse); | |
throw new GoogleOauthRestApiException(String.format( | |
"Google platform returns a error status code: %s when oauth code was exchanged for the token. Endpoint: %s", | |
e.getRawStatusCode(), googleTokenGeneratorUrl), e); | |
} catch (HttpServerErrorException e) { | |
String errorResponse = e.getResponseBodyAsString(); | |
logger.info("google response:" + errorResponse); | |
throw new GoogleOauthRestApiException(String.format( | |
"Google platform returns a error status code: %s when oauth code was exchanged for the token. Endpoint: %s", | |
e.getRawStatusCode(), googleTokenGeneratorUrl), e); | |
} catch (Exception e) { | |
String errorResponse = HorusCommon.inputStreamToString(conn.getErrorStream()); | |
logger.info("google response:" + errorResponse); | |
throw new GoogleOauthRestApiException(String.format( | |
"Unexpected error when oauth code was exchanged for the token in Google platform. Endpoint:%s", | |
googleTokenGeneratorUrl), e); | |
} | |
} | |
public String getDataUserFromPlusApi(String accessToken) | |
throws BadGoogleResponseException, GoogleOauthRestApiException { | |
HttpHeaders headers = new HttpHeaders(); | |
headers.set(HttpHeaders.AUTHORIZATION, prefixAuthHeader + " " + accessToken); | |
RestTemplate restTemplate = new RestTemplate(); | |
String plusApiResponse = null; | |
try { | |
plusApiResponse = restTemplate | |
.exchange(googlePlusApiUrl, HttpMethod.GET, new HttpEntity<>(headers), String.class) | |
.getBody(); | |
} catch (HttpClientErrorException e) { | |
String errorResponse = e.getResponseBodyAsString(); | |
logger.info("google response:" + errorResponse); | |
throw new GoogleOauthRestApiException(String.format( | |
"Google platform returns a error status code: %s when token was exchanged for the user information. Endpoint: %s", | |
e.getRawStatusCode(), googlePlusApiUrl), e); | |
} catch (HttpServerErrorException e) { | |
throw new GoogleOauthRestApiException(String.format( | |
"Google platform returns a error status code: %s when token was exchanged for the user information. Endpoint: %s", | |
e.getRawStatusCode(), googlePlusApiUrl), e); | |
} catch (Exception e) { | |
throw new GoogleOauthRestApiException(String.format( | |
"Unexpected error when oauth code was exchanged for the token in Google platform. Endpoint: %s", | |
googlePlusApiUrl), e); | |
} | |
String email = null; | |
try { | |
ReadContext ctx = JsonPath.parse(plusApiResponse); | |
email = ctx.read("$.emails[0].value"); | |
Assert.notNull(email, | |
"email from google plus api response must not be null: " + googlePlusApiUrl); | |
} catch (IllegalArgumentException e) { | |
throw new BadGoogleResponseException( | |
"Email cannot be extracted from google plus api response: " + plusApiResponse, | |
"Email cannot be extracted from google plus api response", e); | |
} catch (Exception e) { | |
throw new BadGoogleResponseException( | |
"Email cannot be extracted from google plus api response: " + plusApiResponse, | |
"Email cannot be extracted from google plus api response", e); | |
} | |
return email; | |
} | |
@Override | |
public String getDataUserFromPeopleApi(String accessToken) | |
throws BadGoogleResponseException, GoogleOauthRestApiException { | |
HttpHeaders headers = new HttpHeaders(); | |
headers.set(HttpHeaders.AUTHORIZATION, prefixAuthHeader + " " + accessToken); | |
RestTemplate restTemplate = new RestTemplate(); | |
String peopleApiResponse = null; | |
try { | |
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(googlePeopleApiUrl) | |
.queryParam("personFields", "emailAddresses"); | |
peopleApiResponse = restTemplate | |
.exchange(builder.toUriString(), HttpMethod.GET, new HttpEntity<>(headers), String.class) | |
.getBody(); | |
} catch (HttpClientErrorException e) { | |
String errorResponse = e.getResponseBodyAsString(); | |
logger.info("google response:" + errorResponse); | |
throw new GoogleOauthRestApiException(String.format( | |
"Google platform returns a error status code: %s when token was exchanged for the user information. Endpoint: %s", | |
e.getRawStatusCode(), googlePeopleApiUrl), e); | |
} catch (HttpServerErrorException e) { | |
throw new GoogleOauthRestApiException(String.format( | |
"Google platform returns a error status code: %s when token was exchanged for the user information. Endpoint: %s", | |
e.getRawStatusCode(), googlePeopleApiUrl), e); | |
} catch (Exception e) { | |
throw new GoogleOauthRestApiException(String.format( | |
"Unexpected error when oauth code was exchanged for the token in Google platform. Endpoint: %s", | |
googlePeopleApiUrl), e); | |
} | |
String email = null; | |
// expected response: | |
// https://gist.github.com/jrichardsz/585fba4ba7587dd41faea14fa32aa36b#file-personfields-emailaddresses | |
try { | |
ReadContext ctx = JsonPath.parse(peopleApiResponse); | |
email = ctx.read("$.emailAddresses[0].value"); | |
Assert.notNull(email, | |
"email from google people api response must not be null: " + googlePeopleApiUrl); | |
} catch (IllegalArgumentException e) { | |
throw new BadGoogleResponseException( | |
"Email cannot be extracted from google people api response: " + peopleApiResponse, | |
"Email cannot be extracted from google people api response", e); | |
} catch (Exception e) { | |
throw new BadGoogleResponseException( | |
"Email cannot be extracted from google people api response: " + peopleApiResponse, | |
"Email cannot be extracted from google people api response", e); | |
} | |
return email; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment