🚧 Prefix changes
This commit is contained in:
parent
7a19f9f2dc
commit
e3c584e96d
@ -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;
|
||||
111
src/main/java/dev/dinauer/oidcproxy/Resource.java
Normal file
111
src/main/java/dev/dinauer/oidcproxy/Resource.java
Normal file
@ -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<ProxyRoute> 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<String> requestSegments = PathConverter.toSegments(path);
|
||||
LOG.info("Matched route with target '{}'", route.target());
|
||||
try
|
||||
{
|
||||
String targetURI = route.target() + PathConverter.toPath(requestSegments);
|
||||
HttpResponse<byte[]> 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<String> path = PathConverter.toSegments(pathRaw);
|
||||
List<String> prefix = PathConverter.toSegments(prefixRaw);
|
||||
return PathConverter.toPath(new LinkedList<>(path.subList(prefix.size(), path.size())));
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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<Map.Entry<String, String>> buildHeaders(List<Map.Entry<String, String>> request, Set<Cookie> cookies, String strategy) throws TokenNotFoundException
|
||||
{
|
||||
List<String> 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<Map.Entry<String, String>> 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)
|
||||
|
||||
@ -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<String> requestSegments = PathConverter.toSegments(request.path());
|
||||
|
||||
Optional<ProxyRoute> 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<byte[]> 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<String> dropPrefix(List<String> route, List<String> request)
|
||||
{
|
||||
for (int i = 0; i < route.size(); i++)
|
||||
{
|
||||
request.removeFirst();
|
||||
}
|
||||
return request;
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package dev.dinauer.oidcproxy;
|
||||
package dev.dinauer.oidcproxy.session;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -57,12 +57,12 @@ public class RouteService
|
||||
this.routes = result;
|
||||
}
|
||||
|
||||
public Optional<ProxyRoute> match(List<String> request)
|
||||
public Optional<ProxyRoute> match(String request)
|
||||
{
|
||||
Pair<Integer, ProxyRoute> best = null;
|
||||
for (ProxyRoute proxyRoute : this.routes)
|
||||
{
|
||||
Optional<Integer> match = SegmentMatcher.match(proxyRoute.segments(), request);
|
||||
Optional<Integer> match = SegmentMatcher.match(proxyRoute.segments(), PathConverter.toSegments(request));
|
||||
if (match.isPresent())
|
||||
{
|
||||
int matchLength = match.get();
|
||||
|
||||
@ -1,7 +1,4 @@
|
||||
routes:
|
||||
- path: /api
|
||||
target: http://localhost:8081
|
||||
strategy: OIDC
|
||||
- path: /
|
||||
target: http://example.com
|
||||
strategy: NONE
|
||||
target: http://localhost:8081
|
||||
strategy: OIDC
|
||||
Loading…
x
Reference in New Issue
Block a user