package de.pzzz.vertx.oauth; import java.util.logging.Logger; import io.vertx.core.Future; import io.vertx.core.MultiMap; import io.vertx.core.Promise; import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; import io.vertx.core.http.HttpMethod; import io.vertx.ext.web.client.HttpRequest; import io.vertx.ext.web.client.WebClient; import io.vertx.ext.web.client.WebClientOptions; import io.vertx.ext.web.codec.BodyCodec; public class OAuthWebClient { private static final Logger LOG = Logger.getLogger(OAuthWebClient.class.getName()); private final WebClient webClient; private final OAuthConfig config; private OAuthToken token; public OAuthWebClient(final Vertx vertx, final OAuthConfig config) { this.webClient = WebClient.create(vertx, new WebClientOptions() .setLogActivity(true).setSsl(true).setTrustAll(config.isTrustAllCertificates()).setVerifyHost(false)); this.config = config; } public Future> prepareAuthenticatedPut(final String requestPath) { return prepareAuthenticatedRequest(HttpMethod.PUT, requestPath); } public Future> prepareAuthenticatedGet(final String requestPath) { return prepareAuthenticatedRequest(HttpMethod.GET, requestPath); } public Future> prepareAuthenticatedPost(final String requestPath) { return prepareAuthenticatedRequest(HttpMethod.POST, requestPath); } public Future> prepareAuthenticatedDelete(final String requestPath) { return prepareAuthenticatedRequest(HttpMethod.DELETE, requestPath); } public Future> prepareAuthenticatedRequest(final HttpMethod method, final String requestPath) { Promise> promise = Promise.promise(); ensureIsAuthenticated().andThen(v -> promise.complete(webClient.requestAbs(method, config.getBaseUrl() + requestPath) .bearerTokenAuthentication(token.getToken())) ).onFailure(promise::fail); return promise.future(); } private Future ensureIsAuthenticated() { if (null != token && token.isValid()) { LOG.finest("keeping token..."); return Future.succeededFuture(); } LOG.finest("Requesting new token..."); return getToken(); } private Future getToken() { String baseErrorMessage = "Failed to login! "; Promise promise = Promise.promise(); MultiMap form = MultiMap.caseInsensitiveMultiMap(); form.set("grant_type", "client_credentials"); LOG.fine("Requesting new token..."); webClient.postAbs(config.getOauthTokenUrl()) .basicAuthentication(config.getOauthClientId(), config.getOauthClientSecret()) .as(BodyCodec.json(OAuthToken.class)) .sendForm(form) .onSuccess(response -> { if (response.statusCode() == 200) { token = response.body(); LOG.finest("Got new token..."); promise.complete(); } else { String errorMessage = baseErrorMessage + response.statusCode() + " - " + response.statusMessage(); handleTokenError(errorMessage, promise); } }) .onFailure(error -> { String errorMessage = baseErrorMessage + error.getMessage(); handleTokenError(errorMessage, promise); }); return promise.future(); } private void handleTokenError(final String errorMessage, final Promise promise) { LOG.severe(errorMessage); token = null; promise.fail(errorMessage); } }