oscerd commented on code in PR #27725:
URL: https://github.com/apache/camel/pull/27725#discussion_r4250269101


##########
components/camel-lra/src/main/java/org/apache/camel/service/lra/LRASagaService.java:
##########
@@ -84,17 +89,86 @@ public boolean isLongRunningActionHeaderSupported() {
         return true;
     }
 
+    /**
+     * Returns the coordinator of an LRA, which is joined, completed or 
compensated by calling its URL. Only an LRA
+     * hosted by the configured coordinator, or by one of the allowed 
coordinator URLs, is accepted.
+     */
     @Override
     public CompletableFuture<CamelSagaCoordinator> getSaga(String id) {
         CompletableFuture<CamelSagaCoordinator> coordinator;
         try {
-            coordinator = CompletableFuture.completedFuture(new 
LRASagaCoordinator(this, URI.create(id).toURL()));
+            URI lra = URI.create(id);
+            if (!isHostedByAllowedCoordinator(lra)) {
+                throw new IllegalArgumentException(
+                        "The Long-Running-Action " + id + " is not hosted by 
the LRA coordinator configured on the LRA"
+                                                   + " saga service. If it is 
a trusted coordinator, add its URL to"
+                                                   + " 
allowedCoordinatorUrls.");
+            }
+            coordinator = CompletableFuture.completedFuture(new 
LRASagaCoordinator(this, lra.toURL()));
         } catch (Exception ex) {
             coordinator = CompletableFuture.failedFuture(ex);
         }
         return coordinator;
     }
 
+    private boolean isHostedByAllowedCoordinator(URI lra) {
+        for (URI coordinator : allowedCoordinators()) {
+            if (isHostedBy(lra, coordinator)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * The URLs of the coordinators whose LRAs are accepted: the configured 
coordinator, and the allowed coordinator
+     * URLs.
+     */
+    private List<URI> allowedCoordinators() {
+        List<URI> coordinators = new ArrayList<>();
+        coordinators.add(URI.create(new 
LRAUrlBuilder().host(coordinatorUrl).path(coordinatorContextPath).build()));
+        coordinators.addAll(additionalCoordinators());
+        return coordinators;
+    }
+
+    private List<URI> additionalCoordinators() {
+        List<URI> coordinators = new ArrayList<>();
+        if (ObjectHelper.isNotEmpty(allowedCoordinatorUrls)) {
+            for (String url : allowedCoordinatorUrls.split(",")) {
+                if (!url.isBlank()) {
+                    coordinators.add(URI.create(url.trim()));
+                }
+            }
+        }
+        return coordinators;
+    }
+
+    /**
+     * Whether the LRA URL is under the coordinator URL: same scheme, host and 
port, no user info, and a path under the
+     * path of the coordinator.
+     */
+    private static boolean isHostedBy(URI lra, URI coordinator) {
+        if (lra.getScheme() == null || lra.getHost() == null || 
lra.getRawUserInfo() != null) {
+            return false;
+        }
+        String lraPath = lra.normalize().getRawPath();

Review Comment:
   Confirmed: `normalize()` leaves `%2e%2e`, `..;` and `..%2f` in place, so 
they passed the prefix check. The check now rejects a raw path that holds `;`, 
`%2e`, `%2f` or `%5c`, in any case, before comparing the normalized path. 
`rejectsEncodedOrParameterDotSegments` covers `%2e%2e`, `%2E%2E`, `..;`, 
`..%2f` and `..%5C`, next to the `..` case.
   
   _Claude Code on behalf of oscerd_
   



##########
components/camel-lra/src/main/java/org/apache/camel/service/lra/LRASagaService.java:
##########
@@ -84,17 +89,86 @@ public boolean isLongRunningActionHeaderSupported() {
         return true;
     }
 
+    /**
+     * Returns the coordinator of an LRA, which is joined, completed or 
compensated by calling its URL. Only an LRA
+     * hosted by the configured coordinator, or by one of the allowed 
coordinator URLs, is accepted.
+     */
     @Override
     public CompletableFuture<CamelSagaCoordinator> getSaga(String id) {
         CompletableFuture<CamelSagaCoordinator> coordinator;
         try {
-            coordinator = CompletableFuture.completedFuture(new 
LRASagaCoordinator(this, URI.create(id).toURL()));
+            URI lra = URI.create(id);
+            if (!isHostedByAllowedCoordinator(lra)) {
+                throw new IllegalArgumentException(
+                        "The Long-Running-Action " + id + " is not hosted by 
the LRA coordinator configured on the LRA"
+                                                   + " saga service. If it is 
a trusted coordinator, add its URL to"
+                                                   + " 
allowedCoordinatorUrls.");
+            }
+            coordinator = CompletableFuture.completedFuture(new 
LRASagaCoordinator(this, lra.toURL()));
         } catch (Exception ex) {
             coordinator = CompletableFuture.failedFuture(ex);
         }
         return coordinator;
     }
 
+    private boolean isHostedByAllowedCoordinator(URI lra) {
+        for (URI coordinator : allowedCoordinators()) {
+            if (isHostedBy(lra, coordinator)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * The URLs of the coordinators whose LRAs are accepted: the configured 
coordinator, and the allowed coordinator
+     * URLs.
+     */
+    private List<URI> allowedCoordinators() {
+        List<URI> coordinators = new ArrayList<>();
+        coordinators.add(URI.create(new 
LRAUrlBuilder().host(coordinatorUrl).path(coordinatorContextPath).build()));
+        coordinators.addAll(additionalCoordinators());
+        return coordinators;
+    }
+
+    private List<URI> additionalCoordinators() {
+        List<URI> coordinators = new ArrayList<>();
+        if (ObjectHelper.isNotEmpty(allowedCoordinatorUrls)) {
+            for (String url : allowedCoordinatorUrls.split(",")) {
+                if (!url.isBlank()) {
+                    coordinators.add(URI.create(url.trim()));
+                }
+            }
+        }
+        return coordinators;
+    }
+
+    /**
+     * Whether the LRA URL is under the coordinator URL: same scheme, host and 
port, no user info, and a path under the
+     * path of the coordinator.
+     */
+    private static boolean isHostedBy(URI lra, URI coordinator) {
+        if (lra.getScheme() == null || lra.getHost() == null || 
lra.getRawUserInfo() != null) {

Review Comment:
   Confirmed: for `http://lra_coordinator:8080/...`, `URI.getHost()` is null. 
Scheme, host, port and user info are now read through `URI.toURL()`, which 
accepts such names, and the path still comes from the `URI`. 
`acceptsAnLraOfACoordinatorWithAnUnderscoreInItsHostName` covers the configured 
coordinator, so also the LRAs the service starts itself, and 
`acceptsAnLraOfAnAllowedCoordinatorUrl` now has an allowed URL with an 
underscore.
   
   _Claude Code on behalf of oscerd_
   



##########
components/camel-lra/src/main/java/org/apache/camel/service/lra/LRASagaService.java:
##########
@@ -139,6 +213,12 @@ protected void doStart() throws Exception {
         if (localParticipantUrl == null) {
             throw new IllegalStateException("localParticipantUrl must be 
configured on the LRA saga service");
         }
+        for (URI coordinator : additionalCoordinators()) {
+            if (!coordinator.isAbsolute() || coordinator.getHost() == null) {

Review Comment:
   With the URL-based parsing, an entry with an underscore in its host is 
accepted here as well. The check now requires an `http` or `https` URL with a 
host, and the message says that no such URL could be read from the entry. 
`failsToStartWithAnAllowedCoordinatorUrlThatIsNotHttp` covers a non-http entry, 
next to the relative one.
   
   _Claude Code on behalf of oscerd_
   



-- 
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