package com.github.scribejava.core.oauth;
import com.github.scribejava.core.services.Base64Encoder;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.concurrent.Future;
import com.github.scribejava.core.builder.api.DefaultApi20;
import com.github.scribejava.core.model.OAuth2AccessToken;
import com.github.scribejava.core.model.OAuth2Authorization;
import com.github.scribejava.core.model.OAuthAsyncRequestCallback;
import com.github.scribejava.core.model.OAuthConfig;
import com.github.scribejava.core.model.OAuthConstants;
import com.github.scribejava.core.model.OAuthRequest;
import com.github.scribejava.core.model.Response;
import java.util.Map;
import java.util.concurrent.ExecutionException;
public class OAuth20Service extends OAuthService<OAuth2AccessToken> {
private static final String VERSION = "2.0";
private final DefaultApi20 api;
/**
* Default constructor
*
* @param api OAuth2.0 api information
* @param config OAuth 2.0 configuration param object
*/
public OAuth20Service(DefaultApi20 api, OAuthConfig config) {
super(config);
this.api = api;
}
//protected to facilitate mocking
protected OAuth2AccessToken sendAccessTokenRequestSync(OAuthRequest request)
throws IOException, InterruptedException, ExecutionException {
return api.getAccessTokenExtractor().extract(execute(request));
}
//protected to facilitate mocking
protected Future<OAuth2AccessToken> sendAccessTokenRequestAsync(OAuthRequest request) {
return sendAccessTokenRequestAsync(request, null);
}
//protected to facilitate mocking
protected Future<OAuth2AccessToken> sendAccessTokenRequestAsync(OAuthRequest request,
OAuthAsyncRequestCallback<OAuth2AccessToken> callback) {
return execute(request, callback, new OAuthRequest.ResponseConverter<OAuth2AccessToken>() {
@Override
public OAuth2AccessToken convert(Response response) throws IOException {
return getApi().getAccessTokenExtractor().extract(response);
}
});
}
public final Future<OAuth2AccessToken> getAccessTokenAsync(String code) {
return getAccessToken(code, null);
}
public final OAuth2AccessToken getAccessToken(String code)
throws IOException, InterruptedException, ExecutionException {
final OAuthRequest request = createAccessTokenRequest(code);
return sendAccessTokenRequestSync(request);
}
/**
* Start the request to retrieve the access token. The optionally provided callback will be called with the Token
* when it is available.
*
* @param code code
* @param callback optional callback
* @return Future
*/
public final Future<OAuth2AccessToken> getAccessToken(String code,
OAuthAsyncRequestCallback<OAuth2AccessToken> callback) {
final OAuthRequest request = createAccessTokenRequest(code);
return sendAccessTokenRequestAsync(request, callback);
}
protected OAuthRequest createAccessTokenRequest(String code) {
final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint());
final OAuthConfig config = getConfig();
request.addParameter(OAuthConstants.CLIENT_ID, config.getApiKey());
final String apiSecret = config.getApiSecret();
if (apiSecret != null) {
request.addParameter(OAuthConstants.CLIENT_SECRET, apiSecret);
}
request.addParameter(OAuthConstants.CODE, code);
request.addParameter(OAuthConstants.REDIRECT_URI, config.getCallback());
final String scope = config.getScope();
if (scope != null) {
request.addParameter(OAuthConstants.SCOPE, scope);
}
request.addParameter(OAuthConstants.GRANT_TYPE, OAuthConstants.AUTHORIZATION_CODE);
return request;
}
public final Future<OAuth2AccessToken> refreshAccessTokenAsync(String refreshToken) {
return refreshAccessToken(refreshToken, null);
}
public final OAuth2AccessToken refreshAccessToken(String refreshToken)
throws IOException, InterruptedException, ExecutionException {
final OAuthRequest request = createRefreshTokenRequest(refreshToken);
return sendAccessTokenRequestSync(request);
}
public final Future<OAuth2AccessToken> refreshAccessToken(String refreshToken,
OAuthAsyncRequestCallback<OAuth2AccessToken> callback) {
final OAuthRequest request = createRefreshTokenRequest(refreshToken);
return sendAccessTokenRequestAsync(request, callback);
}
protected OAuthRequest createRefreshTokenRequest(String refreshToken) {
if (refreshToken == null || refreshToken.isEmpty()) {
throw new IllegalArgumentException("The refreshToken cannot be null or empty");
}
final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getRefreshTokenEndpoint());
final OAuthConfig config = getConfig();
request.addParameter(OAuthConstants.CLIENT_ID, config.getApiKey());
request.addParameter(OAuthConstants.CLIENT_SECRET, config.getApiSecret());
request.addParameter(OAuthConstants.REFRESH_TOKEN, refreshToken);
request.addParameter(OAuthConstants.GRANT_TYPE, OAuthConstants.REFRESH_TOKEN);
return request;
}
public final OAuth2AccessToken getAccessTokenPasswordGrant(String uname, String password)
throws IOException, InterruptedException, ExecutionException {
final OAuthRequest request = createAccessTokenPasswordGrantRequest(uname, password);
return sendAccessTokenRequestSync(request);
}
public final Future<OAuth2AccessToken> getAccessTokenPasswordGrantAsync(String uname, String password) {
return getAccessTokenPasswordGrantAsync(uname, password, null);
}
/**
* Request Access Token Password Grant async version
*
* @param uname User name
* @param password User password
* @param callback Optional callback
* @return Future
*/
public final Future<OAuth2AccessToken> getAccessTokenPasswordGrantAsync(String uname, String password,
OAuthAsyncRequestCallback<OAuth2AccessToken> callback) {
final OAuthRequest request = createAccessTokenPasswordGrantRequest(uname, password);
return sendAccessTokenRequestAsync(request, callback);
}
protected OAuthRequest createAccessTokenPasswordGrantRequest(String username, String password) {
final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint());
final OAuthConfig config = getConfig();
request.addParameter(OAuthConstants.USERNAME, username);
request.addParameter(OAuthConstants.PASSWORD, password);
final String scope = config.getScope();
if (scope != null) {
request.addParameter(OAuthConstants.SCOPE, scope);
}
request.addParameter(OAuthConstants.GRANT_TYPE, OAuthConstants.PASSWORD);
final String apiKey = config.getApiKey();
final String apiSecret = config.getApiSecret();
if (apiKey != null && apiSecret != null) {
request.addHeader(OAuthConstants.HEADER,
OAuthConstants.BASIC + ' '
+ Base64Encoder.getInstance()
.encode(String.format("%s:%s", apiKey, apiSecret).getBytes(Charset.forName("UTF-8"))));
}
return request;
}
/**
* {@inheritDoc}
*/
@Override
public String getVersion() {
return VERSION;
}
@Override
public void signRequest(OAuth2AccessToken accessToken, OAuthRequest request) {
api.getSignatureType().signRequest(accessToken, request);
}
/**
* Returns the URL where you should redirect your users to authenticate your application.
*
* @return the URL where you should redirect your users
*/
public final String getAuthorizationUrl() {
return getAuthorizationUrl(null);
}
/**
* Returns the URL where you should redirect your users to authenticate your application.
*
* @param additionalParams any additional GET params to add to the URL
* @return the URL where you should redirect your users
*/
public String getAuthorizationUrl(Map<String, String> additionalParams) {
return api.getAuthorizationUrl(getConfig(), additionalParams);
}
public DefaultApi20 getApi() {
return api;
}
public OAuth2Authorization extractAuthorization(String redirectLocation) {
final OAuth2Authorization authorization = new OAuth2Authorization();
int end = redirectLocation.indexOf('#');
if (end == -1) {
end = redirectLocation.length();
}
for (String param : redirectLocation.substring(redirectLocation.indexOf('?') + 1, end).split("&")) {
final String[] keyValue = param.split("=");
if (keyValue.length == 2) {
switch (keyValue[0]) {
case "code":
authorization.setCode(keyValue[1]);
break;
case "state":
authorization.setState(keyValue[1]);
break;
default: //just ignore any other param;
}
}
}
return authorization;
}
}