package lv.ctco.cukes.oauth.internal; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import com.google.inject.Inject; import com.google.inject.Singleton; import lv.ctco.cukes.core.internal.context.GlobalWorldFacade; import lv.ctco.cukes.oauth.GrantType; import lv.ctco.cukes.oauth.OAuthCukesConstants; import org.apache.commons.codec.binary.Base64; import org.apache.commons.io.IOUtils; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.lang.reflect.Type; import java.net.HttpURLConnection; import java.net.URL; import java.util.Map; import java.util.Optional; @Singleton public class OAuthTokenRetriever { @Inject GlobalWorldFacade world; public Optional<String> getAuthorizationHeader() throws IOException { if (!world.getBoolean(OAuthCukesConstants.ENABLED, false)) { return Optional.empty(); } com.google.common.base.Optional<String> cachedToken = world.get(OAuthCukesConstants.CACHED_TOKEN); com.google.common.base.Optional<String> expiresOn = world.get(OAuthCukesConstants.TOKEN_EXPIRES_ON); if (!cachedToken.isPresent() || !cachedToken.isPresent()) { return retrieveAndCacheAccessToken(); } Long expiresOnAsSeconds = Long.parseLong(expiresOn.get()); // Threshold - 1 minute till token expires if (System.currentTimeMillis() / 1000 + 60 > expiresOnAsSeconds) { return retrieveAndCacheAccessToken(); } return Optional.of(cachedToken.get()); } public Optional<String> retrieveAndCacheAccessToken() throws IOException { Map<String, String> map = getOAuthResponse(); String accessToken = map.get("access_token"); String expires = map.get("expires_in"); world.put(OAuthCukesConstants.CACHED_TOKEN, accessToken); if (expires != null) { String expiresOn = String.valueOf(System.currentTimeMillis() / 1000 + Long.parseLong(expires)); world.put(OAuthCukesConstants.TOKEN_EXPIRES_ON, expiresOn); } return Optional.of(accessToken); } public Map<String, String> getOAuthResponse() throws IOException { String authServer = world.getOrThrow(OAuthCukesConstants.AUTH_SERVER); String clientId = world.getOrThrow(OAuthCukesConstants.CLIENT_ID); String clientSecret = world.getOrThrow(OAuthCukesConstants.CLIENT_SECRET); String grantType = world.getOrThrow(OAuthCukesConstants.GRANT_TYPE); URL url = new URL(authServer); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setDoInput(true); connection.setDoOutput(true); connection.addRequestProperty("Accept", "application/json"); connection.addRequestProperty("Authorization", "Basic " + Base64.encodeBase64String((clientId + ":" + clientSecret).getBytes())); connection.addRequestProperty("content-type", "application/x-www-form-urlencoded"); connection.setRequestMethod("POST"); OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream()); writer.write("a=b" + getRequestParameter(grantType)); writer.flush(); int responseCode = connection.getResponseCode(); if (responseCode >= 400) { throw new IllegalStateException("Cannot retrieve OAuth token: " + IOUtils.toString(connection.getErrorStream())); } String response = IOUtils.toString(connection.getInputStream()); Type type = new TypeToken<Map<String, String>>() { }.getType(); return new Gson().fromJson(response, type); } String getRequestParameter(String grantType) throws UnsupportedEncodingException { Map<String, String> params = GrantType.valueOf(grantType).getParameters(world); com.google.common.base.Optional<String> scope = world.get(OAuthCukesConstants.SCOPE); if (scope.isPresent()) { params.put("scope", scope.get()); } return params.entrySet(). stream(). map(e -> e.getKey() + "=" + e.getValue()). reduce("", (s, s2) -> s + "&" + s2); } }