org.isuper.oauth.client.OAuthApacheHttpClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of isuper.oauth-client Show documentation
Show all versions of isuper.oauth-client Show documentation
OAuth Client Library includes Apache and Google based HTTP client implementation using OAuth v2.0
The newest version!
/**
*
*/
package org.isuper.oauth.client;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.isuper.common.utils.Preconditions;
import org.isuper.httpclient.AsyncHttpClient;
import org.isuper.oauth.OAuthClientConfig;
import org.isuper.oauth.OAuthCredential;
import org.isuper.oauth.client.exceptions.InvalidOAuthCredentialException;
import org.isuper.oauth.client.exceptions.RefreshTokenRevokedException;
import org.isuper.oauth.v20.GrantType;
import org.isuper.oauth.v20.OAuth20;
import org.isuper.oauth.v20.ParameterStyle;
import org.isuper.oauth.v20.ResponseType;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* @author Super Wang
*
*/
public class OAuthApacheHttpClient implements OAuthHttpClient {
private static final Logger LOG = LogManager.getLogger("org.isuper.oauth.client.apache");
public static final DateFormat DEFAULT_DATE_FORMAT = new SimpleDateFormat("E MMM dd HH:mm:ss Z yyyy", Locale.US);
private static final JsonFactory JSON_FACTORY = new JsonFactory();
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(JSON_FACTORY);
protected final OAuthClientConfig clientConfig;
protected final AsyncHttpClient httpclient;
private OAuthApacheHttpClient(final OAuthClientConfig clientConfig) {
this.clientConfig = clientConfig;
try {
this.httpclient = AsyncHttpClient.newInstance(this.clientConfig.proxyHostname == null || "".equals(this.clientConfig.proxyHostname.trim()) ? null : this.clientConfig.proxyHostname, this.clientConfig.proxyPort);
} catch (Throwable e) {
throw new RuntimeException("Failed to init " + OAuthApacheHttpClient.class.getSimpleName(), e);
}
}
/**
* @param clientConfigFile
* The OAuth client configuration JSON file
* @return
* OAuth HTTP client
*/
public static OAuthHttpClient newInstance(final String clientConfigFile) {
return newInstance(clientConfigFile, DEFAULT_DATE_FORMAT);
}
/**
* @param clientConfigFile
* The OAuth client configuration JSON file
* @param dateFormat
* The date format for JSON parser
* @return
* OAuth HTTP client
*/
public static OAuthHttpClient newInstance(final String clientConfigFile, final DateFormat dateFormat) {
OBJECT_MAPPER.setDateFormat(dateFormat);
OAuthClientConfig clientConfig;
try {
clientConfig = OAuthClientConfig.readFromClasspath(clientConfigFile);
return new OAuthApacheHttpClient(clientConfig);
} catch (Throwable e) {
throw new RuntimeException("Failed to init " + OAuthApacheHttpClient.class.getSimpleName(), e);
}
}
/* (non-Javadoc)
* @see org.isuper.oauth.client.OAuthHttpClient#getAuthorizeURL(org.isuper.oauth.v20.ResponseType, java.lang.String, java.lang.String, java.lang.String, java.util.Map)
*/
@Override
public String getAuthorizeURL(ResponseType responseType, String redirectURL, String state, String scope, Map props) {
if (responseType == null) {
responseType = ResponseType.CODE;
}
Preconditions.notEmptyString(redirectURL, "Can not get access token with null or empty redirect URL!");
try {
URIBuilder builder = new URIBuilder(this.clientConfig.authUri);
builder.addParameter(OAuth20.OAUTH_RESPONSE_TYPE, responseType.name().toLowerCase());
builder.addParameter(OAuth20.OAUTH_CLIENT_ID, this.clientConfig.clientId);
builder.addParameter(OAuth20.OAUTH_REDIRECT_URI, redirectURL);
if (!Preconditions.isEmptyString(state)) {
builder.addParameter(OAuth20.OAUTH_STATE, state);
}
if (!Preconditions.isEmptyString(scope)) {
builder.addParameter(OAuth20.OAUTH_SCOPE, scope);
}
if (props != null && !props.isEmpty()) {
for (Map.Entry entry : props.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
builder.addParameter(key, value == null ? "" : value);
}
}
return builder.build().toURL().toExternalForm();
} catch (URISyntaxException | MalformedURLException e) {
throw new RuntimeException(String.format("Invalid authorization URL: %s", this.clientConfig.authUri));
}
}
/* (non-Javadoc)
* @see org.isuper.oauth.client.OAuthHttpClient#retrieveAccessToken(org.isuper.oauth.v20.ParameterStyle, java.lang.String, org.isuper.oauth.v20.GrantType, java.lang.String)
*/
@Override
public OAuthCredential retrieveAccessToken(ParameterStyle style, String code, GrantType grantType, String redirectURL) throws IOException {
if (grantType == null) {
grantType = GrantType.AUTHORIZATION_CODE;
}
Preconditions.notEmptyString(code, "Can not get access token with null or empty OAuth authorization code!");
HttpRequestBase request;
switch (style) {
case QUERY_STRING:
try {
URIBuilder builder = new URIBuilder(this.clientConfig.authUri);
builder.addParameter(OAuth20.OAUTH_CODE, code);
builder.addParameter(OAuth20.OAUTH_CLIENT_ID, this.clientConfig.clientId);
builder.addParameter(OAuth20.OAUTH_CLIENT_SECRET, this.clientConfig.clientSecret);
builder.addParameter(OAuth20.OAUTH_REDIRECT_URI, redirectURL);
builder.addParameter(OAuth20.OAUTH_GRANT_TYPE, grantType.name().toLowerCase());
request = new HttpGet(builder.build());
} catch (URISyntaxException e) {
throw new RuntimeException(String.format("Invalid token URL: %s", this.clientConfig.tokenUri));
}
break;
default:
HttpPost post = new HttpPost(this.clientConfig.tokenUri);
List nameValuePairs = new ArrayList<>(5);
nameValuePairs.add(new BasicNameValuePair(OAuth20.OAUTH_CODE, code));
nameValuePairs.add(new BasicNameValuePair(OAuth20.OAUTH_CLIENT_ID, this.clientConfig.clientId));
nameValuePairs.add(new BasicNameValuePair(OAuth20.OAUTH_CLIENT_SECRET, this.clientConfig.clientSecret));
nameValuePairs.add(new BasicNameValuePair(OAuth20.OAUTH_REDIRECT_URI, redirectURL));
nameValuePairs.add(new BasicNameValuePair(OAuth20.OAUTH_GRANT_TYPE, grantType.name().toLowerCase()));
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
request = post;
break;
}
LOG.trace(request.getRequestLine());
try {
Future future = this.httpclient.execute(request, null);
HttpResponse resp = future.get();
StatusLine status = resp.getStatusLine();
HttpEntity entity = resp.getEntity();
String contentType = entity.getContentType().getValue();
String content = EntityUtils.toString(entity);
LOG.trace(resp.getStatusLine());
LOG.trace(contentType);
LOG.trace(content);
if (status.getStatusCode() != 200) {
throw new IOException("Failed response from server: " + status.toString());
}
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(content, OAuthCredential.class);
} catch (InterruptedException | ExecutionException e) {
LOG.error(e.getLocalizedMessage(), e);
}
return null;
}
/* (non-Javadoc)
* @see org.isuper.oauth.client.OAuthHttpClient#refreshToken(org.isuper.oauth.v20.ParameterStyle, java.lang.String, org.isuper.oauth.v20.GrantType)
*/
@Override
public OAuthCredential refreshToken(ParameterStyle style, String refreshToken, GrantType grantType) throws RefreshTokenRevokedException, IOException {
if (grantType == null) {
grantType = GrantType.REFRESH_TOKEN;
}
Preconditions.notEmptyString(refreshToken, "Can not get a new access token with null or empty OAuth refresh token!");
HttpRequestBase request;
switch (style) {
case QUERY_STRING:
try {
URIBuilder builder = new URIBuilder(this.clientConfig.tokenUri);
builder.addParameter(OAuth20.OAUTH_REFRESH_TOKEN, refreshToken);
builder.addParameter(OAuth20.OAUTH_CLIENT_ID, this.clientConfig.clientId);
builder.addParameter(OAuth20.OAUTH_CLIENT_SECRET, this.clientConfig.clientSecret);
builder.addParameter(OAuth20.OAUTH_GRANT_TYPE, grantType.name().toLowerCase());
request = new HttpGet(builder.build());
} catch (URISyntaxException e) {
throw new RuntimeException(String.format("Invalid token URL: %s", this.clientConfig.tokenUri));
}
break;
default:
HttpPost post = new HttpPost(this.clientConfig.tokenUri);
List nameValuePairs = new ArrayList<>(4);
nameValuePairs.add(new BasicNameValuePair(OAuth20.OAUTH_REFRESH_TOKEN, refreshToken));
nameValuePairs.add(new BasicNameValuePair(OAuth20.OAUTH_CLIENT_ID, this.clientConfig.clientId));
nameValuePairs.add(new BasicNameValuePair(OAuth20.OAUTH_CLIENT_SECRET, this.clientConfig.clientSecret));
nameValuePairs.add(new BasicNameValuePair(OAuth20.OAUTH_GRANT_TYPE, grantType.name().toLowerCase()));
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
request = post;
break;
}
LOG.trace(request.getRequestLine());
try {
Future future = this.httpclient.execute(request, null);
HttpResponse resp = future.get();
StatusLine status = resp.getStatusLine();
HttpEntity entity = resp.getEntity();
String contentType = entity.getContentType().getValue();
String content = EntityUtils.toString(entity);
LOG.trace(resp.getStatusLine());
LOG.trace(contentType);
LOG.trace(content);
if (status.getStatusCode() == 400) {
throw new RefreshTokenRevokedException(content);
} else if (status.getStatusCode() != 200) {
throw new IOException(status.toString() + ": " + content);
}
ObjectMapper objectMapper = new ObjectMapper();
OAuthCredential credential = objectMapper.readValue(content, OAuthCredential.class);
if (Preconditions.isEmptyString(credential.getRefreshToken())) {
credential.setRefreshToken(refreshToken);
}
return credential;
} catch (InterruptedException | ExecutionException e) {
LOG.error(e.getLocalizedMessage(), e);
}
return null;
}
/* (non-Javadoc)
* @see org.isuper.oauth.http.OAuthHttpClient#getJSONResources(java.lang.Class, org.isuper.oauth.OAuthCredential, java.lang.String, java.lang.String[])
*/
@Override
public T getResource(Class resultClass, OAuthCredential credential, String endpoint, String... params) throws InvalidOAuthCredentialException, IOException {
return OBJECT_MAPPER.treeToValue(getRawResource(credential, endpoint, params), resultClass);
}
/* (non-Javadoc)
* @see org.isuper.oauth.http.OAuthHttpClient#getResources(java.lang.Class, org.isuper.oauth.OAuthCredential, java.lang.String, java.lang.String[])
*/
@Override
public List getResources(Class resultClass, String treeKey, OAuthCredential credential, String endpoint, String... params) throws InvalidOAuthCredentialException, IOException {
JsonNode node = getRawResource(credential, endpoint, params);
if (Preconditions.isEmptyString(treeKey)) {
return OBJECT_MAPPER.readValue(node.traverse(), OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, resultClass));
}
node = node.get(treeKey);
return OBJECT_MAPPER.readValue(node.traverse(), OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, resultClass));
}
/* (non-Javadoc)
* @see org.isuper.oauth.client.OAuthHttpClient#getRawResource(org.isuper.oauth.OAuthCredential, java.lang.String, java.lang.String[])
*/
@Override
public JsonNode getRawResource(OAuthCredential credential, String endpoint, String... params) throws InvalidOAuthCredentialException, IOException {
if (Preconditions.isEmptyString(credential.accessToken)) {
throw new InvalidOAuthCredentialException("Missing access token in credential: " + credential);
}
HttpRequestBase request;
try {
URIBuilder builder = new URIBuilder(endpoint);
if (params != null && params.length > 0) {
String key, value;
for (int p = 0; p + 1 < params.length; p += 2) {
key = params[p];
if (Preconditions.isEmptyString(key)) {
continue;
}
value = params[p + 1];
builder.addParameter(key, value == null ? "" : value);
}
}
request = new HttpGet(builder.build());
} catch (URISyntaxException e) {
throw new RuntimeException(String.format("Invalid token URL: %s", this.clientConfig.tokenUri));
}
request.addHeader("Authorization", "Bearer " + credential.accessToken);
LOG.trace(request.getRequestLine());
try {
Future future = this.httpclient.execute(request, null);
HttpResponse resp = future.get();
StatusLine status = resp.getStatusLine();
HttpEntity entity = resp.getEntity();
String contentType = entity.getContentType().getValue();
String content = EntityUtils.toString(entity);
LOG.trace(resp.getStatusLine());
LOG.trace(contentType);
LOG.trace(content);
if (status.getStatusCode() == 401) {
throw new InvalidOAuthCredentialException("Invalid credential: " + credential);
} else if (status.getStatusCode() != 200) {
throw new IOException("Failed response from server: " + status.toString());
}
return OBJECT_MAPPER.readTree(content);
} catch (InterruptedException | ExecutionException e) {
LOG.error(e.getLocalizedMessage(), e);
}
return null;
}
/* (non-Javadoc)
* @see java.io.Closeable#close()
*/
@Override
public void close() throws IOException {
this.httpclient.close();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy