[wip] minor additions

This commit is contained in:
Peter Schuller 2021-12-17 07:56:58 +01:00
parent b950c9ebdb
commit ca0bd8d67a
3 changed files with 208 additions and 0 deletions

View file

@ -0,0 +1,53 @@
package de.pzzz.vertx.oauth;
import java.io.Serializable;
public class OAuthConfig implements Serializable {
private static final long serialVersionUID = -2962157804887273549L;
private String oauthClientId;
private String oauthClientSecret;
private String oauthTokenUrl;
private String baseUrl;
private boolean trustAllCertificates;
public String getOauthClientId() {
return oauthClientId;
}
public void setOauthClientId(final String oauthClientId) {
this.oauthClientId = oauthClientId;
}
public String getOauthClientSecret() {
return oauthClientSecret;
}
public void setOauthClientSecret(final String oauthClientSecret) {
this.oauthClientSecret = oauthClientSecret;
}
public String getOauthTokenUrl() {
return oauthTokenUrl;
}
public void setOauthTokenUrl(final String oauthTokenUrl) {
this.oauthTokenUrl = oauthTokenUrl;
}
public String getBaseUrl() {
return baseUrl;
}
public void setBaseUrl(final String baseUrl) {
this.baseUrl = baseUrl;
}
public boolean isTrustAllCertificates() {
return trustAllCertificates;
}
public void setTrustAllCertificates(final boolean trustAllCertificates) {
this.trustAllCertificates = trustAllCertificates;
}
}

View file

@ -0,0 +1,59 @@
package de.pzzz.vertx.oauth;
import java.io.Serializable;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Represents an OAuth2 Token as received from IAM via client credentials flow.
*/
public class OAuthToken implements Serializable {
private static final long serialVersionUID = -1712414758315937247L;
private static final Integer EXPIRATION_OFFSET = 30;
@JsonProperty("access_token")
private String token;
@JsonProperty("token_type")
private String type;
@JsonProperty("expires_in")
private Integer expiresIn;
@JsonIgnore
private final Date issued;
public OAuthToken() {
issued = new Date();
}
public boolean isValid() {
int diffSeconds = (int) Math.ceil((new Date().getTime() - issued.getTime())/1000f);
return diffSeconds < (expiresIn - EXPIRATION_OFFSET);
}
public String getToken() {
return token;
}
public void setToken(final String token) {
this.token = token;
}
public String getType() {
return type;
}
public void setType(final String type) {
this.type = type;
}
public Integer getExpiresIn() {
return expiresIn;
}
public void setExpiresIn(final Integer expiresIn) {
this.expiresIn = expiresIn;
}
}

View file

@ -0,0 +1,96 @@
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<HttpRequest<Buffer>> prepareAuthenticatedPut(final String requestPath) {
return prepareAuthenticatedRequest(HttpMethod.PUT, requestPath);
}
public Future<HttpRequest<Buffer>> prepareAuthenticatedGet(final String requestPath) {
return prepareAuthenticatedRequest(HttpMethod.GET, requestPath);
}
public Future<HttpRequest<Buffer>> prepareAuthenticatedPost(final String requestPath) {
return prepareAuthenticatedRequest(HttpMethod.POST, requestPath);
}
public Future<HttpRequest<Buffer>> prepareAuthenticatedDelete(final String requestPath) {
return prepareAuthenticatedRequest(HttpMethod.DELETE, requestPath);
}
public Future<HttpRequest<Buffer>> prepareAuthenticatedRequest(final HttpMethod method, final String requestPath) {
Promise<HttpRequest<Buffer>> promise = Promise.promise();
ensureIsAuthenticated().onComplete(v ->
promise.complete(webClient.requestAbs(method, config.getBaseUrl() + requestPath)
.bearerTokenAuthentication(token.getToken()))
).onFailure(promise::fail);
return promise.future();
}
private Future<Void> ensureIsAuthenticated() {
if (null != token && token.isValid()) {
LOG.finest("keeping token...");
return Future.succeededFuture();
}
LOG.finest("Requesting new token...");
return getToken();
}
private Future<Void> getToken() {
String baseErrorMessage = "Failed to login! ";
Promise<Void> 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<Void> promise) {
LOG.severe(errorMessage);
token = null;
promise.fail(errorMessage);
}
}