Skip to content

Commit

Permalink
refactor, use JWT subject claim to track plugin ID
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewazores committed Mar 21, 2024
1 parent a1c3f62 commit 50b3f4c
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 33 deletions.
15 changes: 4 additions & 11 deletions src/main/java/io/cryostat/discovery/Discovery.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.apache.commons.lang3.StringUtils;
Expand Down Expand Up @@ -199,9 +198,6 @@ public Response register(@Context RoutingContext ctx, JsonObject body)

// TODO apply URI range validation to the remote address
InetAddress remoteAddress = getRemoteAddress(ctx);
String authzHeader =
Optional.ofNullable(ctx.request().headers().get(HttpHeaders.AUTHORIZATION))
.orElse("None");

URI location;
DiscoveryPlugin plugin;
Expand All @@ -216,9 +212,8 @@ public Response register(@Context RoutingContext ctx, JsonObject body)
if (!Objects.equals(plugin.callback, callbackUri)) {
throw new BadRequestException();
}
location = jwtFactory.getPluginLocation(plugin.id.toString());
jwtFactory.parseDiscoveryPluginJwt(
priorToken, realmName, location, remoteAddress, false);
location = jwtFactory.getPluginLocation(plugin);
jwtFactory.parseDiscoveryPluginJwt(plugin, priorToken, location, remoteAddress, false);
} else {
// new plugin registration
plugin = new DiscoveryPlugin();
Expand All @@ -231,7 +226,7 @@ public Response register(@Context RoutingContext ctx, JsonObject body)

DiscoveryNode.getUniverse().children.add(plugin.realm);

location = jwtFactory.getPluginLocation(plugin.id.toString());
location = jwtFactory.getPluginLocation(plugin);

var dataMap = new JobDataMap();
dataMap.put(PLUGIN_ID_MAP_KEY, plugin.id);
Expand All @@ -254,9 +249,7 @@ public Response register(@Context RoutingContext ctx, JsonObject body)
scheduler.scheduleJob(jobDetail, trigger);
}

String token =
jwtFactory.createDiscoveryPluginJwt(
authzHeader, realmName, remoteAddress, location);
String token = jwtFactory.createDiscoveryPluginJwt(plugin, remoteAddress, location);

// TODO implement more generic env map passing by some platform detection strategy or
// generalized config properties
Expand Down
19 changes: 10 additions & 9 deletions src/main/java/io/cryostat/discovery/DiscoveryJwtFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public class DiscoveryJwtFactory {
String httpPath;

public String createDiscoveryPluginJwt(
String authzHeader, String realm, InetAddress requestAddr, URI resource)
DiscoveryPlugin plugin, InetAddress requestAddr, URI resource)
throws SocketException, UnknownHostException, URISyntaxException, JOSEException {
URI hostUri =
new URI(
Expand All @@ -95,9 +95,9 @@ public String createDiscoveryPluginJwt(
.issueTime(now)
.notBeforeTime(now)
.expirationTime(expiry)
.subject(authzHeader)
.subject(plugin.id.toString())
.claim(RESOURCE_CLAIM, resource.toASCIIString())
.claim(REALM_CLAIM, realm)
.claim(REALM_CLAIM, plugin.realm.name)
.build();

SignedJWT jwt = new SignedJWT(new JWSHeader.Builder(JWSAlgorithm.HS256).build(), claims);
Expand All @@ -114,19 +114,19 @@ public String createDiscoveryPluginJwt(
}

public JWT parseDiscoveryPluginJwt(
String rawToken, String realm, URI resource, InetAddress requestAddr)
DiscoveryPlugin plugin, String rawToken, URI resource, InetAddress requestAddr)
throws ParseException,
JOSEException,
BadJWTException,
SocketException,
UnknownHostException,
URISyntaxException {
return parseDiscoveryPluginJwt(rawToken, realm, resource, requestAddr, true);
return parseDiscoveryPluginJwt(plugin, rawToken, resource, requestAddr, true);
}

public JWT parseDiscoveryPluginJwt(
DiscoveryPlugin plugin,
String rawToken,
String realm,
URI resource,
InetAddress requestAddr,
boolean checkTimeClaims)
Expand Down Expand Up @@ -156,8 +156,9 @@ public JWT parseDiscoveryPluginJwt(
new JWTClaimsSet.Builder()
.issuer(issuer)
.audience(List.of(issuer, requestAddr.getHostAddress()))
.subject(plugin.id.toString())
.claim(RESOURCE_CLAIM, resource.toASCIIString())
.claim(REALM_CLAIM, realm)
.claim(REALM_CLAIM, plugin.realm.name)
.build();
Set<String> requiredClaimNames =
new HashSet<>(Set.of("iat", "iss", "aud", "sub", REALM_CLAIM));
Expand All @@ -176,7 +177,7 @@ public JWT parseDiscoveryPluginJwt(
}

// TODO refactor this
public URI getPluginLocation(String pluginId) throws URISyntaxException {
public URI getPluginLocation(DiscoveryPlugin plugin) throws URISyntaxException {
URI hostUri =
new URI(
String.format(
Expand All @@ -185,6 +186,6 @@ public URI getPluginLocation(String pluginId) throws URISyntaxException {
.resolve(httpPath)
.resolve(DISCOVERY_API_PATH)
.normalize();
return hostUri.resolve(pluginId).normalize();
return hostUri.resolve(plugin.id.toString()).normalize();
}
}
23 changes: 10 additions & 13 deletions src/main/java/io/cryostat/discovery/DiscoveryJwtValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public JWT validateJwt(
URISyntaxException,
MalformedURLException {
if (StringUtils.isBlank(token)) {
throw new UnauthorizedException();
throw new UnauthorizedException("Token cannot be blank");
}
InetAddress addr = null;
HttpServerRequest req = ctx.request();
Expand All @@ -88,13 +88,13 @@ public JWT validateJwt(
try {
parsed =
jwtFactory.parseDiscoveryPluginJwt(
plugin,
token,
plugin.realm.name,
jwtFactory.getPluginLocation(plugin.id.toString()),
jwtFactory.getPluginLocation(plugin),
addr,
validateTimeClaims);
} catch (BadJWTException e) {
throw new UnauthorizedException(e);
throw new UnauthorizedException("Provided JWT was invalid", e);
}

URI requestUri = new URI(req.absoluteURI());
Expand All @@ -109,7 +109,7 @@ public JWT validateJwt(
parsed.getJWTClaimsSet()
.getStringClaim(DiscoveryJwtFactory.RESOURCE_CLAIM));
} catch (URISyntaxException use) {
throw new UnauthorizedException(use);
throw new UnauthorizedException("JWT resource claim was invalid", use);
}
boolean matchesAbsoluteRequestUri =
resourceClaim.isAbsolute() && Objects.equals(fullRequestUri, resourceClaim);
Expand All @@ -119,14 +119,11 @@ public JWT validateJwt(
"Token resource claim does not match requested resource");
}

// try {
// String subject = parsed.getJWTClaimsSet().getSubject();
// if (!auth.validateHttpHeader(() -> subject, resourceActions()).get()) {
// throw new ApiException(401, "Token subject has insufficient permissions");
// }
// } catch (ExecutionException | InterruptedException e) {
// throw new ApiException(401, "Token subject permissions could not be determined");
// }
String subject = parsed.getJWTClaimsSet().getSubject();
if (!Objects.equals(subject, plugin.id.toString())) {
throw new UnauthorizedException(
"Token subject claim does not match the original subject");
}

return parsed;
}
Expand Down

0 comments on commit 50b3f4c

Please sign in to comment.