diff --git a/src/main/java/io/cryostat/discovery/Discovery.java b/src/main/java/io/cryostat/discovery/Discovery.java index 4031959bd..c236ef2a9 100644 --- a/src/main/java/io/cryostat/discovery/Discovery.java +++ b/src/main/java/io/cryostat/discovery/Discovery.java @@ -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; @@ -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; @@ -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(); @@ -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); @@ -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 diff --git a/src/main/java/io/cryostat/discovery/DiscoveryJwtFactory.java b/src/main/java/io/cryostat/discovery/DiscoveryJwtFactory.java index 3a8b59349..97f9451a5 100644 --- a/src/main/java/io/cryostat/discovery/DiscoveryJwtFactory.java +++ b/src/main/java/io/cryostat/discovery/DiscoveryJwtFactory.java @@ -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( @@ -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); @@ -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) @@ -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 requiredClaimNames = new HashSet<>(Set.of("iat", "iss", "aud", "sub", REALM_CLAIM)); @@ -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( @@ -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(); } } diff --git a/src/main/java/io/cryostat/discovery/DiscoveryJwtValidator.java b/src/main/java/io/cryostat/discovery/DiscoveryJwtValidator.java index 7a2b66571..df0c7f5ae 100644 --- a/src/main/java/io/cryostat/discovery/DiscoveryJwtValidator.java +++ b/src/main/java/io/cryostat/discovery/DiscoveryJwtValidator.java @@ -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(); @@ -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()); @@ -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); @@ -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; }