Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(jwt): implement JWT flow #9

Merged
merged 5 commits into from
Dec 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/main/java/io/cryostat/agent/ConfigModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,7 @@ public static String provideCryostatAgentRealm(
SmallRyeConfig config,
@Named(CRYOSTAT_AGENT_APP_NAME) String appName,
UUID instanceId) {
return config.getOptionalValue(CRYOSTAT_AGENT_REALM, String.class)
.orElseGet(() -> String.format("%s-%s", appName, instanceId));
return config.getOptionalValue(CRYOSTAT_AGENT_REALM, String.class).orElse(appName);
}

@Provides
Expand Down
23 changes: 9 additions & 14 deletions src/main/java/io/cryostat/agent/CryostatClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,9 @@ class CryostatClient implements Closeable {
private final Logger log = LoggerFactory.getLogger(getClass());

private WebClient http;
private final UUID instanceId;
private final URI baseUri;
private final URI callback;
private final String realm;
private final String authorization;
private final boolean trustAll;

CryostatClient(
Vertx vertx,
Expand All @@ -75,12 +72,9 @@ class CryostatClient implements Closeable {
String realm,
String authorization,
boolean trustAll) {
this.instanceId = instanceId;
this.baseUri = baseUri;
this.callback = callback;
this.realm = realm;
this.authorization = authorization;
this.trustAll = trustAll;

log.info("Using Cryostat baseuri {}", baseUri);

Expand All @@ -96,8 +90,9 @@ class CryostatClient implements Closeable {
this.http = WebClient.create(vertx, opts);
}

Future<PluginInfo> register() {
RegistrationInfo registrationInfo = new RegistrationInfo(realm, callback);
Future<PluginInfo> register(PluginInfo pluginInfo) {
RegistrationInfo registrationInfo =
new RegistrationInfo(pluginInfo.getId(), realm, callback, pluginInfo.getToken());
return http.post("/api/v2.2/discovery")
.putHeader(HttpHeaders.AUTHORIZATION.toString(), authorization)
.expect(ResponsePredicate.SC_SUCCESS)
Expand All @@ -109,19 +104,19 @@ Future<PluginInfo> register() {
.map(json -> json.mapTo(PluginInfo.class));
}

Future<Void> deregister(String id) {
return http.delete("/api/v2.2/discovery/" + id)
.putHeader(HttpHeaders.AUTHORIZATION.toString(), authorization)
Future<Void> deregister(PluginInfo pluginInfo) {
return http.delete("/api/v2.2/discovery/" + pluginInfo.getId())
.addQueryParam("token", pluginInfo.getToken())
.expect(ResponsePredicate.SC_SUCCESS)
.expect(ResponsePredicate.JSON)
.timeout(1_000L)
.send()
.map(t -> null);
}

Future<Void> update(String id, Set<DiscoveryNode> subtree) {
return http.post("/api/v2.2/discovery/" + id)
.putHeader(HttpHeaders.AUTHORIZATION.toString(), authorization)
Future<Void> update(PluginInfo pluginInfo, Set<DiscoveryNode> subtree) {
return http.post("/api/v2.2/discovery/" + pluginInfo.getId())
.addQueryParam("token", pluginInfo.getToken())
.expect(ResponsePredicate.SC_SUCCESS)
.expect(ResponsePredicate.JSON)
.timeout(1_000L)
Expand Down
48 changes: 30 additions & 18 deletions src/main/java/io/cryostat/agent/Registration.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@

import java.net.URI;
import java.net.UnknownHostException;
import java.time.Duration;
import java.time.Instant;
import java.util.Set;
import java.util.UUID;
Expand Down Expand Up @@ -70,7 +69,8 @@ class Registration extends AbstractVerticle {
private final int jmxPort;
private final int registrationRetryMs;

private PluginInfo pluginInfo;
private final PluginInfo pluginInfo = new PluginInfo();
private volatile String webServerId;
private MessageConsumer<Object> consumer;

Registration(
Expand Down Expand Up @@ -103,24 +103,33 @@ public void start() {
.consumer(
EVENT_BUS_ADDRESS,
msg -> {
log.info("Called back, attempting to update");
tryUpdate();
log.info("Called back, attempting to re-register");
vertx.setTimer(1, this::tryRegister);
});
}

private void tryRegister(Long id) {
cryostat.register()
cryostat.register(pluginInfo)
.onSuccess(
plugin -> {
this.pluginInfo = plugin;
getVertx()
.deployVerticle(webServer.get())
.onSuccess(unused -> tryUpdate(id));
this.pluginInfo.copyFrom(plugin);
log.info("Registered as {}", plugin.getId());
Future<String> serverId;
if (this.webServerId != null) {
serverId = Future.succeededFuture(this.webServerId);
} else {
serverId =
getVertx()
.deployVerticle(webServer.get())
.onSuccess(i -> this.webServerId = i);
}
serverId.onSuccess(unused -> tryUpdate(id));
})
.onFailure(
t -> {
log.error("Registration failure", t);
log.info("Registration retry period: {}(ms)", registrationRetryMs);
this.webServerId = null;
vertx.setTimer(registrationRetryMs, this::tryRegister);
});
}
Expand All @@ -130,7 +139,7 @@ void tryUpdate() {
}

private void tryUpdate(Long id) {
if (pluginInfo == null) {
if (!this.pluginInfo.isInitialized()) {
return;
}
DiscoveryNode selfNode;
Expand All @@ -141,7 +150,7 @@ private void tryUpdate(Long id) {
return;
}
log.info("publishing self as {}", selfNode.getTarget().getConnectUrl());
cryostat.update(pluginInfo.getId(), Set.of(selfNode))
cryostat.update(pluginInfo, Set.of(selfNode))
.onSuccess(
ar -> {
if (id != null) {
Expand All @@ -155,11 +164,8 @@ private void tryUpdate(Long id) {
.onComplete(
ar -> {
if (ar.failed()) {
Duration registrationRetryPeriod =
Duration.ofSeconds(5);
vertx.setTimer(
registrationRetryPeriod.toMillis(),
this::tryRegister);
registrationRetryMs, this::tryRegister);
return;
}
});
Expand Down Expand Up @@ -208,10 +214,16 @@ public void stop() {
}

Future<Void> deregister() {
if (this.pluginInfo == null) {
if (!this.pluginInfo.isInitialized()) {
return Future.succeededFuture();
}
return cryostat.deregister(pluginInfo.getId())
return cryostat.deregister(pluginInfo)
.onComplete(
ar -> {
if (this.webServerId != null) {
getVertx().undeploy(this.webServerId);
}
})
.onComplete(
ar -> {
if (ar.failed()) {
Expand All @@ -223,7 +235,7 @@ Future<Void> deregister() {
"Deregistered from Cryostat discovery plugin [{}]",
this.pluginInfo.getId());
}
this.pluginInfo = null;
this.pluginInfo.clear();
});
}
}
41 changes: 38 additions & 3 deletions src/main/java/io/cryostat/agent/model/PluginInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,33 @@
*/
package io.cryostat.agent.model;

import java.util.Objects;

public class PluginInfo {

private String id;
private String token;

PluginInfo() {}
public PluginInfo() {}

public PluginInfo(String id, String token) {
this.id = id;
this.token = token;
}

public void copyFrom(PluginInfo o) {
setId(o.getId());
setToken(o.getToken());
}

public void clear() {
copyFrom(new PluginInfo());
}

public boolean isInitialized() {
return id != null && token != null;
}

public String getId() {
return id;
}
Expand All @@ -57,11 +72,31 @@ public String getToken() {
return token;
}

void setId(String id) {
public void setId(String id) {
this.id = id;
}

void setToken(String token) {
public void setToken(String token) {
this.token = token;
}

@Override
public int hashCode() {
return Objects.hash(id, token);
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PluginInfo other = (PluginInfo) obj;
return Objects.equals(id, other.id) && Objects.equals(token, other.token);
}
}
22 changes: 21 additions & 1 deletion src/main/java/io/cryostat/agent/model/RegistrationInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,22 @@

public class RegistrationInfo {

private String id;
private String realm;
private URI callback;
private String token;

RegistrationInfo() {}

public RegistrationInfo(String realm, URI callback) {
public RegistrationInfo(String id, String realm, URI callback, String token) {
this.id = id;
this.realm = realm;
this.callback = callback;
this.token = token;
}

public String getId() {
return id;
}

public String getRealm() {
Expand All @@ -59,11 +67,23 @@ public URI getCallback() {
return callback;
}

public String getToken() {
return token;
}

void setId(String id) {
this.id = id;
}

void setRealm(String realm) {
this.realm = realm;
}

void setCallback(URI callback) {
this.callback = callback;
}

void setToken(String token) {
this.token = token;
}
}