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]

Reply via email to