From e3c584e96dcd2a2766a12c3aad6d18030221b220 Mon Sep 17 00:00:00 2001 From: Andreas Dinauer Date: Sat, 11 Apr 2026 12:08:52 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=A7=20Prefix=20changes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dev/dinauer/{ => oidcproxy}/JwtUtils.java | 2 +- .../java/dev/dinauer/oidcproxy/Resource.java | 111 +++++++++++++++++ .../oidcproxy/callback/CallbackService.java | 3 +- .../oidcproxy/proxy/ForwardService.java | 17 --- .../oidcproxy/proxy/ProxyResource.java | 113 ------------------ .../oidcproxy/{ => session}/AccessToken.java | 2 +- .../oidcproxy/session/SessionCache.java | 2 - .../oidcproxy/session/SessionService.java | 1 - .../oidcproxy/startup/RouteService.java | 4 +- src/main/resources/routes.yaml | 7 +- 10 files changed, 118 insertions(+), 144 deletions(-) rename src/main/java/dev/dinauer/{ => oidcproxy}/JwtUtils.java (94%) create mode 100644 src/main/java/dev/dinauer/oidcproxy/Resource.java delete mode 100644 src/main/java/dev/dinauer/oidcproxy/proxy/ProxyResource.java rename src/main/java/dev/dinauer/oidcproxy/{ => session}/AccessToken.java (72%) diff --git a/src/main/java/dev/dinauer/JwtUtils.java b/src/main/java/dev/dinauer/oidcproxy/JwtUtils.java similarity index 94% rename from src/main/java/dev/dinauer/JwtUtils.java rename to src/main/java/dev/dinauer/oidcproxy/JwtUtils.java index f453f41..5d553bf 100644 --- a/src/main/java/dev/dinauer/JwtUtils.java +++ b/src/main/java/dev/dinauer/oidcproxy/JwtUtils.java @@ -1,4 +1,4 @@ -package dev.dinauer; +package dev.dinauer.oidcproxy; import io.smallrye.jwt.auth.principal.DefaultJWTParser; import io.smallrye.jwt.auth.principal.ParseException; diff --git a/src/main/java/dev/dinauer/oidcproxy/Resource.java b/src/main/java/dev/dinauer/oidcproxy/Resource.java new file mode 100644 index 0000000..2649a35 --- /dev/null +++ b/src/main/java/dev/dinauer/oidcproxy/Resource.java @@ -0,0 +1,111 @@ +package dev.dinauer.oidcproxy; + +import dev.dinauer.oidcproxy.callback.CallbackService; +import dev.dinauer.oidcproxy.proxy.ForwardService; +import dev.dinauer.oidcproxy.proxy.ResponseHandler; +import dev.dinauer.oidcproxy.proxy.exception.ProxyHttpException; +import dev.dinauer.oidcproxy.proxy.exception.TokenNotFoundException; +import dev.dinauer.oidcproxy.startup.PathConverter; +import dev.dinauer.oidcproxy.startup.ProxyRoute; +import dev.dinauer.oidcproxy.startup.RouteService; +import io.quarkus.vertx.web.Route; +import io.smallrye.common.annotation.Blocking; +import io.vertx.core.http.HttpServerResponse; +import io.vertx.ext.web.RoutingContext; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import jakarta.ws.rs.core.Context; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.http.HttpResponse; +import java.util.*; + +@ApplicationScoped +public class Resource +{ + private static final Logger LOG = LoggerFactory.getLogger(Resource.class); + + @Inject + RouteService routeService; + + @Inject + ForwardService forwardService; + + @Inject + CallbackService callbackService; + + @Inject + LogoutService logoutService; + + @Route(path = "/auth/callback", order = 0) + @Blocking + public void callback(@Context RoutingContext context) + { + callbackService.get(context.response(), context.request()); + } + + @Route(path = "/auth/logout", order = 1) + @Blocking + public void logout(@Context HttpServerResponse response) + { + logoutService.logout(response); + } + + @Route(path = "/api/*", order = 2) + @Blocking + public void proxy(@Context RoutingContext context) + { + String path = dropPrefix(context.request().path(), "/api"); + Optional match = routeService.match(path); + if (match.isPresent()) + { + route(context, path, match.get()); + } + else + { + LOG.error("No route found for request path '{}'", context.request().path()); + ResponseHandler.notFound(context); + } + } + + private void route(RoutingContext context, String path, ProxyRoute route) + { + List requestSegments = PathConverter.toSegments(path); + LOG.info("Matched route with target '{}'", route.target()); + try + { + String targetURI = route.target() + PathConverter.toPath(requestSegments); + HttpResponse response = forwardService.send(context, targetURI, route.strategy()); + ResponseHandler.success(context, response); + } + catch (ProxyHttpException e) + { + LOG.error("Upstream returned error status {}.", e.getStatusCode(), e); + ResponseHandler.error(context, e.getStatusCode()); + } + catch (TokenNotFoundException e) + { + LOG.error("Token not found.", e); + ResponseHandler.error(context, 401); + } + catch (InterruptedException e) + { + LOG.error("Proxy request was interrupted, returning 503.", e); + Thread.currentThread().interrupt(); + ResponseHandler.error(context, 503); + } + catch (Exception e) + { + LOG.error("Error occurred on upstream.", e); + ResponseHandler.error(context, 502); + } + } + + private String dropPrefix(String pathRaw, String prefixRaw) + { + List path = PathConverter.toSegments(pathRaw); + List prefix = PathConverter.toSegments(prefixRaw); + return PathConverter.toPath(new LinkedList<>(path.subList(prefix.size(), path.size()))); + } +} diff --git a/src/main/java/dev/dinauer/oidcproxy/callback/CallbackService.java b/src/main/java/dev/dinauer/oidcproxy/callback/CallbackService.java index 7c236d4..415fb45 100644 --- a/src/main/java/dev/dinauer/oidcproxy/callback/CallbackService.java +++ b/src/main/java/dev/dinauer/oidcproxy/callback/CallbackService.java @@ -1,7 +1,6 @@ package dev.dinauer.oidcproxy.callback; -import dev.dinauer.JwtUtils; -import dev.dinauer.oidcproxy.AccessToken; +import dev.dinauer.oidcproxy.JwtUtils; import dev.dinauer.oidcproxy.callback.model.TokenResponse; import dev.dinauer.oidcproxy.session.SessionCache; import io.vertx.core.http.Cookie; diff --git a/src/main/java/dev/dinauer/oidcproxy/proxy/ForwardService.java b/src/main/java/dev/dinauer/oidcproxy/proxy/ForwardService.java index 86c2f85..cf4595c 100644 --- a/src/main/java/dev/dinauer/oidcproxy/proxy/ForwardService.java +++ b/src/main/java/dev/dinauer/oidcproxy/proxy/ForwardService.java @@ -18,12 +18,8 @@ import java.util.*; @ApplicationScoped public class ForwardService { - private static final String AUTH_HEADER = "Authorization"; private static final HttpClient CLIENT = HttpClient.newHttpClient(); - @Inject - SessionCache sessionCache; - @Inject HeaderFilter headerFilter; @@ -44,19 +40,6 @@ public class ForwardService throw new ProxyHttpException(response.statusCode()); } - private List> buildHeaders(List> request, Set cookies, String strategy) throws TokenNotFoundException - { - List headerNames = request.stream().map(Map.Entry::getKey).toList(); - if (!headerNames.contains(AUTH_HEADER) && "OIDC".equals(strategy) && cookies.size() == 1) - { - String session = cookies.iterator().next().getValue(); - List> headers = new LinkedList<>(request); - headers.add(Map.entry(AUTH_HEADER, sessionCache.get(session))); - return headers; - } - return request; - } - private byte[] extractBody(RoutingContext context) { if (context.body().buffer() != null) diff --git a/src/main/java/dev/dinauer/oidcproxy/proxy/ProxyResource.java b/src/main/java/dev/dinauer/oidcproxy/proxy/ProxyResource.java deleted file mode 100644 index e5f29d9..0000000 --- a/src/main/java/dev/dinauer/oidcproxy/proxy/ProxyResource.java +++ /dev/null @@ -1,113 +0,0 @@ -package dev.dinauer.oidcproxy.proxy; - -import dev.dinauer.oidcproxy.LogoutService; -import dev.dinauer.oidcproxy.callback.CallbackService; -import dev.dinauer.oidcproxy.proxy.exception.ProxyHttpException; -import dev.dinauer.oidcproxy.proxy.exception.TokenNotFoundException; -import dev.dinauer.oidcproxy.session.SessionCache; -import dev.dinauer.oidcproxy.startup.PathConverter; -import dev.dinauer.oidcproxy.startup.ProxyRoute; -import dev.dinauer.oidcproxy.startup.RouteService; -import io.quarkus.vertx.web.Route; -import io.smallrye.common.annotation.Blocking; -import io.vertx.core.http.Cookie; -import io.vertx.core.http.HttpServerRequest; -import io.vertx.core.http.HttpServerResponse; -import io.vertx.ext.web.RoutingContext; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import jakarta.ws.rs.core.Context; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.net.http.HttpResponse; -import java.util.*; - -@ApplicationScoped -public class ProxyResource -{ - private static final Logger LOG = LoggerFactory.getLogger(ProxyResource.class); - - @Inject - RouteService routeService; - - @Inject - ForwardService forwardService; - - @Inject - CallbackService callbackService; - - @Inject - LogoutService logoutService; - - @Route(path = "/auth/callback", order = 0) - @Blocking - public void callback(@Context RoutingContext context) - { - callbackService.get(context.response(), context.request()); - } - - @Route(path = "/auth/logout", order = 1) - @Blocking - public void logout(@Context HttpServerResponse response) - { - logoutService.logout(response); - } - - @Route(path = "/*", order = 2) - @Blocking - public void proxy(@Context RoutingContext context) - { - HttpServerRequest request = context.request(); - System.out.println(request.path()); - List requestSegments = PathConverter.toSegments(request.path()); - - Optional routeOptional = routeService.match(requestSegments); - if (routeOptional.isPresent()) - { - ProxyRoute route = routeOptional.get(); - LOG.info("Matched route with target '{}'", route.target()); - try - { - String targetURI = route.target() + PathConverter.toPath(requestSegments); - HttpResponse response = forwardService.send(context, targetURI, route.strategy()); - ResponseHandler.success(context, response); - } - catch (ProxyHttpException e) - { - LOG.error("Upstream returned error status {}.", e.getStatusCode(), e); - ResponseHandler.error(context, e.getStatusCode()); - } - catch (TokenNotFoundException e) - { - LOG.error("Token not found.", e); - ResponseHandler.error(context, 401); - } - catch (InterruptedException e) - { - LOG.error("Proxy request was interrupted, returning 503.", e); - Thread.currentThread().interrupt(); - ResponseHandler.error(context, 503); - } - catch (Exception e) - { - LOG.error("Error occurred on upstream.", e); - ResponseHandler.error(context, 502); - } - } - else - { - LOG.error("No route found for request path '{}'", context.request().path()); - ResponseHandler.notFound(context); - } - } - - private List dropPrefix(List route, List request) - { - for (int i = 0; i < route.size(); i++) - { - request.removeFirst(); - } - return request; - } -} diff --git a/src/main/java/dev/dinauer/oidcproxy/AccessToken.java b/src/main/java/dev/dinauer/oidcproxy/session/AccessToken.java similarity index 72% rename from src/main/java/dev/dinauer/oidcproxy/AccessToken.java rename to src/main/java/dev/dinauer/oidcproxy/session/AccessToken.java index a53c586..4f67c7d 100644 --- a/src/main/java/dev/dinauer/oidcproxy/AccessToken.java +++ b/src/main/java/dev/dinauer/oidcproxy/session/AccessToken.java @@ -1,4 +1,4 @@ -package dev.dinauer.oidcproxy; +package dev.dinauer.oidcproxy.session; import java.time.ZonedDateTime; diff --git a/src/main/java/dev/dinauer/oidcproxy/session/SessionCache.java b/src/main/java/dev/dinauer/oidcproxy/session/SessionCache.java index 222d6cf..1999c11 100644 --- a/src/main/java/dev/dinauer/oidcproxy/session/SessionCache.java +++ b/src/main/java/dev/dinauer/oidcproxy/session/SessionCache.java @@ -1,13 +1,11 @@ package dev.dinauer.oidcproxy.session; -import dev.dinauer.oidcproxy.AccessToken; import dev.dinauer.oidcproxy.proxy.exception.TokenNotFoundException; import io.quarkus.narayana.jta.QuarkusTransaction; import io.quarkus.runtime.Startup; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.control.ActivateRequestContext; import jakarta.inject.Inject; -import jakarta.transaction.Transactional; import org.jboss.logging.Logger; import java.security.MessageDigest; diff --git a/src/main/java/dev/dinauer/oidcproxy/session/SessionService.java b/src/main/java/dev/dinauer/oidcproxy/session/SessionService.java index 673053e..bbdb91b 100644 --- a/src/main/java/dev/dinauer/oidcproxy/session/SessionService.java +++ b/src/main/java/dev/dinauer/oidcproxy/session/SessionService.java @@ -1,6 +1,5 @@ package dev.dinauer.oidcproxy.session; -import dev.dinauer.oidcproxy.AccessToken; import io.smallrye.jwt.auth.principal.DefaultJWTParser; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; diff --git a/src/main/java/dev/dinauer/oidcproxy/startup/RouteService.java b/src/main/java/dev/dinauer/oidcproxy/startup/RouteService.java index 8f9d6c1..d8e8506 100644 --- a/src/main/java/dev/dinauer/oidcproxy/startup/RouteService.java +++ b/src/main/java/dev/dinauer/oidcproxy/startup/RouteService.java @@ -57,12 +57,12 @@ public class RouteService this.routes = result; } - public Optional match(List request) + public Optional match(String request) { Pair best = null; for (ProxyRoute proxyRoute : this.routes) { - Optional match = SegmentMatcher.match(proxyRoute.segments(), request); + Optional match = SegmentMatcher.match(proxyRoute.segments(), PathConverter.toSegments(request)); if (match.isPresent()) { int matchLength = match.get(); diff --git a/src/main/resources/routes.yaml b/src/main/resources/routes.yaml index 11de261..c7fb52b 100644 --- a/src/main/resources/routes.yaml +++ b/src/main/resources/routes.yaml @@ -1,7 +1,4 @@ routes: - - path: /api - target: http://localhost:8081 - strategy: OIDC - path: / - target: http://example.com - strategy: NONE \ No newline at end of file + target: http://localhost:8081 + strategy: OIDC \ No newline at end of file