davsclaus commented on code in PR #27435:
URL: https://github.com/apache/camel/pull/27435#discussion_r4194244618
##########
components/camel-undertow/src/main/java/org/apache/camel/component/undertow/handlers/CamelWebSocketHandler.java:
##########
@@ -142,37 +169,127 @@ private static void send(
*/
@Override
public void handleRequest(HttpServerExchange exchange) throws Exception {
- UndertowConsumer currentConsumer = getConsumer();
- if (currentConsumer != null &&
currentConsumer.getEndpoint().getOauthHttpSecurity() != null) {
- if (exchange.isInIoThread()) {
- exchange.dispatch(this);
- return;
+ entryHandler.handleRequest(exchange);
+ }
+
+ /**
+ * The handler that applies the security settings of the path to an
upgrade request and then performs the WebSocket
+ * handshake. A consumer can run its own handlers, such as its access log,
before it.
+ */
+ public HttpHandler getUpgradeHandler() {
+ return upgradeHandler;
+ }
+
+ /**
+ * Lets the given security provider wrap this handler, as it wraps the
handlers of HTTP endpoints. The handler stays
+ * registered as is, so that it remains shared by the consumer and the
producers of the path.
+ */
+ public void wrapWith(UndertowSecurityProvider securityProvider) throws
Exception {
+ HttpHandler wrapped =
securityProvider.wrapHttpHandler(consumerRequestHandler);
+ // a provider that returns no handler disables the path, as it does
for HTTP endpoints
+ this.entryHandler = wrapped != null ? wrapped :
ResponseCodeHandler.HANDLE_405;
+ }
+
+ private void handleConsumerRequest(HttpServerExchange exchange) throws
Exception {
+ consumerHandler.handleRequest(exchange);
+ }
+
+ private void upgrade(HttpServerExchange exchange) throws Exception {
+ List<UndertowEndpoint> endpoints = securityEndpoints();
+ if
(endpoints.stream().noneMatch(CamelWebSocketHandler::hasSecurityChecks)) {
+ this.delegate.handleRequest(exchange);
+ return;
+ }
+ if (exchange.isInIoThread()) {
+ exchange.dispatch(upgradeHandler);
+ return;
+ }
+ Set<String> authenticatedEndpoints = new HashSet<>();
+ Map<String, Object> headers = new HashMap<>();
+ for (UndertowEndpoint endpoint : endpoints) {
+ OAuthHttpSecuritySupport oauthHttpSecurity =
endpoint.getOauthHttpSecurity();
+ if (oauthHttpSecurity != null) {
+ Validation validation =
oauthHttpSecurity.validate(endpoint.getCamelContext(),
authorizationHeaders(exchange));
+ exchange.getRequestHeaders().remove(Headers.AUTHORIZATION);
+ if (!validation.isAuthenticated()) {
+ reject(exchange, validation);
+ return;
+ }
+
exchange.putAttachment(OAUTH_TOKEN_VALIDATION_RESULT_ATTACHMENT,
validation.getValidationResult());
}
- OAuthHttpSecuritySupport oauthHttpSecurity =
currentConsumer.getEndpoint().getOauthHttpSecurity();
- Validation validation =
oauthHttpSecurity.validate(currentConsumer.getEndpoint().getCamelContext(),
- authorizationHeaders(exchange));
- exchange.getRequestHeaders().remove(Headers.AUTHORIZATION);
- if (!validation.isAuthenticated()) {
- reject(exchange, validation);
- return;
+ if (endpoint.requiresAuthentication()) {
+ int statusCode = endpoint.authenticate(exchange);
+ if (statusCode != StatusCodes.OK) {
+ exchange.setStatusCode(statusCode);
+ exchange.endExchange();
+ return;
+ }
+ authenticatedEndpoints.add(endpoint.getEndpointUri());
+ if (endpoint.getSecurityProvider() != null) {
+ endpoint.getSecurityProvider().addHeader(headers::put,
exchange);
+ }
}
- exchange.putAttachment(OAUTH_TOKEN_VALIDATION_RESULT_ATTACHMENT,
validation.getValidationResult());
+ }
+ if (!authenticatedEndpoints.isEmpty()) {
+ exchange.putAttachment(SECURITY_PROVIDER_RESULT_ATTACHMENT,
+ new SecurityProviderResult(authenticatedEndpoints,
headers));
}
this.delegate.handleRequest(exchange);
}
- private UndertowConsumer getConsumer() {
+ /**
+ * The endpoints whose security settings apply to the path: the
consumer's, also while it is stopped, otherwise the
+ * producers'. All the Camel endpoints of a path share its WebSocket
connections.
+ */
+ private List<UndertowEndpoint> securityEndpoints() {
Review Comment:
Optional: once a consumer is on the path, the producers' own `allowedRoles`
/ `securityProvider` are not used, so a producer with `allowedRoles=admin` on a
path whose consumer has no security sends to every peer. It is documented, and
the producer options are new, but a one-time WARN when a producer's security
settings differ from the consumer's would avoid surprises.
##########
components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowComponent.java:
##########
@@ -372,7 +373,12 @@ public HttpHandler registerEndpoint(
handlers.add(registrationInfo);
HttpHandler handlerWrapped = handler;
- if (this.securityProvider != null) {
+ if (handler instanceof CamelWebSocketHandler webSocketHandler) {
+ // the WebSocket handler of a path is shared by its consumer and
producers, so it must stay registered as is
+ if (this.securityProvider != null) {
+ webSocketHandler.wrapWith(this.securityProvider);
Review Comment:
Nit: this also wraps the new `CamelWebSocketHandler` that is thrown away
when the path already has a shared handler. Harmless (the provider is
component-wide and the shared handler was wrapped at its first registration),
but wrapping only the instance that is returned would read clearer.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]