package net.dev123.commons.http.auth;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import net.dev123.commons.Constants;
import net.dev123.commons.ServiceProvider;
import net.dev123.commons.http.HttpMethod;
import net.dev123.commons.http.HttpRequestHelper;
import net.dev123.commons.http.HttpRequestMessage;
import net.dev123.commons.oauth.config.OAuthConfiguration;
import net.dev123.commons.oauth.config.OAuthConfigurationFactory;
import net.dev123.commons.oauth2.OAuth2;
import net.dev123.commons.oauth2.OAuth2.GrantType;
import net.dev123.commons.oauth2.OAuth2AccessToken;
import net.dev123.commons.util.ParseUtil;
import net.dev123.commons.util.StringUtil;
import net.dev123.commons.util.UrlUtil;
import net.dev123.exception.ExceptionCode;
import net.dev123.exception.LibException;
import net.dev123.exception.LibRuntimeException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.util.EntityUtils;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class OAuth2AuthorizeHelper {
private static Logger logger = LoggerFactory.getLogger(OAuth2AuthorizeHelper.class);
private ServiceProvider serviceProvider;
private OAuthConfiguration oAuthConfig;
private String consumerKey;
private String consumerSecret;
private String callbackUrl;
public OAuth2AuthorizeHelper(ServiceProvider serviceProvider) throws LibException {
if (serviceProvider == null) {
throw new LibException(ExceptionCode.PARAMETER_NULL);
}
this.serviceProvider = serviceProvider;
this.oAuthConfig =
OAuthConfigurationFactory.getOAuthConfiguration(serviceProvider);
this.consumerKey = oAuthConfig.getOAuthConsumerKey();
this.consumerSecret = oAuthConfig.getOAuthConsumerSecret();
this.callbackUrl = oAuthConfig.getOAuthCallbackURL();
}
public void setConsumer(String consumerKey, String consumerSecret) throws LibException {
if (StringUtil.isEmpty(consumerKey) || StringUtil.isEmpty(consumerSecret)) {
throw new LibException(ExceptionCode.PARAMETER_NULL);
}
this.consumerKey = consumerKey;
this.consumerSecret = consumerSecret;
}
public String getConsumerKey() {
return consumerKey;
}
public String getConsumerSecret() {
return consumerSecret;
}
public void setCallbackUrl(String callbackUrl) throws LibException {
if (StringUtil.isEmpty(callbackUrl)) {
throw new LibException(ExceptionCode.PARAMETER_NULL);
}
this.callbackUrl = callbackUrl;
}
public String getAuthorizationUrl(GrantType grantType, String state,
String... scope) {
Map<String, String> parameters = new HashMap<String, String>();
parameters.put(OAuth2.CLIENT_ID, consumerKey);
if (grantType == GrantType.IMPLICIT){
parameters.put(OAuth2.RESPONSE_TYPE, OAuth2.ResponseType.TOKEN.getTypeValue());
} if (grantType == GrantType.AUTHORIZATION_CODE) {
parameters.put(OAuth2.RESPONSE_TYPE, OAuth2.ResponseType.CODE.getTypeValue());
}
if (StringUtil.isNotEmpty(callbackUrl)) {
parameters.put(OAuth2.REDIRECT_URI, callbackUrl);
}
if (scope == null || scope.length == 0) {
scope = oAuthConfig.getOAuthScopes();
}
if (scope != null && scope.length > 0) {
parameters.put(OAuth2.SCOPE, StringUtil.join(scope, oAuthConfig.getOAuthScopeSeparator()));
}
if (StringUtil.isNotEmpty(state)) {
parameters.put(OAuth2.STATE, state);
}
String authorizationUrl = null;
try {
authorizationUrl = UrlUtil.appendQueryParameters(oAuthConfig.getOAuthAuthorizeURL(), parameters, "UTF-8");
} catch (UnsupportedEncodingException e) {
logger.error("生成授权地址出现异常", e);
}
return authorizationUrl;
}
public OAuth2AccessToken getAccessTokenByRefreshToken(String refreshToken,
String state, String... scope) throws LibException {
if (StringUtil.isEmpty(refreshToken)) {
throw new LibException(ExceptionCode.PARAMETER_NULL);
}
Authorization auth = new NullAuthorization(serviceProvider);
HttpRequestMessage httpRequestMessage =
new HttpRequestMessage(HttpMethod.POST, oAuthConfig.getOAuthAccessTokenURL(), auth);
httpRequestMessage.addParameter(OAuth2.GRANT_TYPE, GrantType.REFRESH_TOKEN.getTypeValue());
httpRequestMessage.addParameter(OAuth2.REFRESH_TOKEN, refreshToken);
httpRequestMessage.addParameter(OAuth2.CLIENT_ID, consumerKey);
httpRequestMessage.addParameter(OAuth2.CLIENT_SECRET, consumerSecret);
if (scope == null || scope.length == 0) {
scope = oAuthConfig.getOAuthScopes();
}
if (scope != null && scope.length > 0) {
httpRequestMessage.addParameter(OAuth2.SCOPE, StringUtil.join(scope, oAuthConfig.getOAuthScopeSeparator()));
}
if (StringUtil.isNotEmpty(state)) {
httpRequestMessage.addParameter(OAuth2.STATE, state);
}
OAuth2AccessToken accessToken = HttpRequestHelper.execute(httpRequestMessage,
new OAuth2AccessTokenResponseHandler());
return accessToken;
}
public OAuth2AccessToken getAccessTokenByAuthorizationCode(String authorizationCode,
String state, String... scope) throws LibException {
if (StringUtil.isEmpty(authorizationCode)) {
throw new LibException(ExceptionCode.PARAMETER_NULL);
}
Authorization auth = new NullAuthorization(serviceProvider);
HttpRequestMessage httpRequestMessage =
new HttpRequestMessage(HttpMethod.POST, oAuthConfig.getOAuthAccessTokenURL(), auth);
httpRequestMessage.addParameter(OAuth2.GRANT_TYPE, GrantType.AUTHORIZATION_CODE.getTypeValue());
httpRequestMessage.addParameter(OAuth2.CODE, authorizationCode);
httpRequestMessage.addParameter(OAuth2.CLIENT_ID, consumerKey);
httpRequestMessage.addParameter(OAuth2.CLIENT_SECRET, consumerSecret);
if (scope == null || scope.length == 0) {
scope = oAuthConfig.getOAuthScopes();
}
if (scope != null && scope.length > 0) {
httpRequestMessage.addParameter(OAuth2.SCOPE, StringUtil.join(scope, oAuthConfig.getOAuthScopeSeparator()));
}
if (StringUtil.isNotEmpty(state)) {
httpRequestMessage.addParameter(OAuth2.STATE, state);
}
if (StringUtil.isNotEmpty(callbackUrl)) {
httpRequestMessage.addParameter(OAuth2.REDIRECT_URI, callbackUrl);
}
OAuth2AccessToken accessToken = HttpRequestHelper.execute(httpRequestMessage,
new OAuth2AccessTokenResponseHandler());
return accessToken;
}
public static String retrieveAuthorizationCodeFromQueryString(String url) {
URI uri = URI.create(url);
Map<String, String> parameters = UrlUtil.extractQueryStringParameters(uri);
String code = null;
if (parameters != null) {
code = parameters.get(OAuth2.CODE);
}
return code;
}
public static OAuth2AccessToken retrieveAccessTokenFromFragment(String url) {
URI uri = URI.create(url);
Map<String, String> parameters = null;
final String fragment = uri.getFragment();
if (StringUtil.isNotEmpty(fragment)) {
parameters = new HashMap<String, String>();
Scanner scanner = new Scanner(fragment);
scanner.useDelimiter("&");
while (scanner.hasNext()) {
final String[] nameValue = scanner.next().split("=");
if (nameValue.length == 0 || nameValue.length > 2){
throw new IllegalArgumentException("Bad parameter");
}
final String name = nameValue[0];
String value = null;
if (nameValue.length == 2){
value = nameValue[1];
}
parameters.put(name, value);
}
}
OAuth2AccessToken token = null;
if (parameters != null) {
if (parameters.containsKey(OAuth2.ACCESS_TOKEN)) {
String accessToken = parameters.get(OAuth2.ACCESS_TOKEN);
Long expiresIn = Long.valueOf(parameters.get(OAuth2.EXPIRES_IN));
Date expiresDate = new Date(System.currentTimeMillis() + expiresIn * 1000);
token = new OAuth2AccessToken(accessToken, expiresDate);
token.setRefreshToken(parameters.get(OAuth2.REFRESH_TOKEN));
token.setScope(parameters.get(OAuth2.SCOPE));
token.setTokenType(parameters.get(OAuth2.TOKEN_TYPE));
}
}
return token;
}
private class OAuth2AccessTokenResponseHandler implements ResponseHandler<OAuth2AccessToken> {
private final Logger logger = LoggerFactory.getLogger(OAuth2AccessTokenResponseHandler.class.getSimpleName());
@Override
public OAuth2AccessToken handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
try {
StatusLine statusLine = response.getStatusLine();
HttpEntity entity = response.getEntity();
final String responseString = EntityUtils.toString(entity);
if (Constants.DEBUG) {
logger.debug("OAuth2AccessTokenResponseHandler : {}", responseString);
}
if (statusLine.getStatusCode() >= 300) {
JSONObject exceptionJson = new JSONObject(responseString);
String error = ParseUtil.getRawString(OAuth2.ERROR, exceptionJson);
if (exceptionJson.has(OAuth2.ERROR_DESCRIPTION)) {
error += (": " + ParseUtil.getRawString(OAuth2.ERROR_DESCRIPTION, exceptionJson));
}
String requestPath = ParseUtil.getRawString(OAuth2.ERROR_URI, exceptionJson);
throw new LibRuntimeException(ExceptionCode.OAUTH_EXCEPTION,
requestPath, error, serviceProvider);
}
JSONObject json = null;
try {
json = new JSONObject(responseString);
} catch (JSONException e) {
// 响应格式非JSON时,分析字符串
json = new JSONObject();
Scanner scanner = new Scanner(responseString);
scanner.useDelimiter("&");
while (scanner.hasNext()) {
final String[] nameValue = scanner.next().split("=");
if (nameValue.length == 0 || nameValue.length > 2){
throw new IllegalArgumentException("Bad parameter.");
}
json.put(nameValue[0], nameValue.length == 2 ? nameValue[1] : null);
}
if (!json.has(OAuth2.ACCESS_TOKEN)) {
if (Constants.DEBUG) {
logger.debug(e.getMessage(), e);
}
throw e;
}
}
String accessToken = ParseUtil.getRawString(OAuth2.ACCESS_TOKEN, json);
Long expiresIn = ParseUtil.getLong(OAuth2.EXPIRES_IN, json);
Date expiresDate = new Date(System.currentTimeMillis() + expiresIn * 1000);
OAuth2AccessToken token = new OAuth2AccessToken(accessToken, expiresDate);
token.setRefreshToken(ParseUtil.getRawString(OAuth2.REFRESH_TOKEN, json));
token.setTokenType(ParseUtil.getRawString(OAuth2.TOKEN_TYPE, json));
token.setScope(ParseUtil.getRawString(OAuth2.SCOPE, json));
return token;
} catch (JSONException e) {
throw new LibRuntimeException(ExceptionCode.JSON_PARSE_ERROR, e, serviceProvider);
}
}
}
}