diff --git a/components-starter/camel-debug-starter/src/main/doc/intro.adoc b/components-starter/camel-debug-starter/src/main/doc/intro.adoc index d3a0b3dc0efc..f688a925b0d8 100644 --- a/components-starter/camel-debug-starter/src/main/doc/intro.adoc +++ b/components-starter/camel-debug-starter/src/main/doc/intro.adoc @@ -1,3 +1,3 @@ Spring Boot auto-configuration for the Camel Debugger. -This starter enables the Camel Debugger in your Spring Boot application, allowing you to set breakpoints and step through Camel routes during development. The debugger integrates with IDEs and tooling through JMX. +This starter enables the Camel Debugger in your Spring Boot application, allowing you to set breakpoints and step through Camel routes during development. The debugger is controlled from Java, JMX or tooling, and can additionally expose a JMX RMI connector for remote tooling, which is disabled by default. diff --git a/components-starter/camel-debug-starter/src/main/doc/usage.adoc b/components-starter/camel-debug-starter/src/main/doc/usage.adoc new file mode 100644 index 000000000000..8ed5442eb463 --- /dev/null +++ b/components-starter/camel-debug-starter/src/main/doc/usage.adoc @@ -0,0 +1,20 @@ +Adding this starter to the classpath installs and enables the Camel Debugger. The debugger can be turned off with: + +[source,properties] +---- +camel.debug.enabled = false +---- + +=== JMX connector + +Tooling that attaches to the debugger from another process, such as the IntelliJ IDEA and VS Code Camel plugins, uses a JMX RMI connector. The connector is *disabled by default*, so having this starter on the classpath never opens a listening socket on its own. Enable it explicitly when remote tooling needs to attach: + +[source,properties] +---- +camel.debug.jmx-connector-enabled = true +camel.debug.jmx-connector-port = 1099 +---- + +WARNING: The JMX RMI connector is created without authentication or transport security. Anyone able to reach the port can control the debugger, suspend routes and read message payloads. Only enable it on a trusted network, and make sure the port is bound to a loopback interface or protected by a firewall. + +The `camel debug` command of Camel JBang does not need this connector: it drives a Spring Boot application through the local CLI connector provided by `camel-cli-connector-starter`. diff --git a/components-starter/camel-debug-starter/src/main/docs/debug.json b/components-starter/camel-debug-starter/src/main/docs/debug.json index d067ec9f2f22..e1583dfac17a 100644 --- a/components-starter/camel-debug-starter/src/main/docs/debug.json +++ b/components-starter/camel-debug-starter/src/main/docs/debug.json @@ -71,14 +71,14 @@ { "name": "camel.debug.jmx-connector-enabled", "type": "java.lang.Boolean", - "description": "Whether to create JMX connector that allows tooling to control the Camel debugger. This is what the IDEA and VSCode tooling is using.", + "description": "Whether to create JMX connector that allows tooling to control the Camel debugger. This is what the IDEA and VSCode tooling is using. The connector opens an RMI registry and a JMX RMI server on the configured port, without authentication or transport security, so it is disabled by default and must be turned on explicitly. Only enable it on a trusted network, and bind or firewall the port accordingly.", "sourceType": "org.apache.camel.spring.boot.debug.CamelDebugConfigurationProperties", - "defaultValue": true + "defaultValue": false }, { "name": "camel.debug.jmx-connector-port", "type": "java.lang.Integer", - "description": "Port number to expose a JMX RMI connector for tooling that needs to control the debugger.", + "description": "Port number to expose a JMX RMI connector for tooling that needs to control the debugger. Only in use when the JMX connector is enabled.", "sourceType": "org.apache.camel.spring.boot.debug.CamelDebugConfigurationProperties", "defaultValue": 1099 }, diff --git a/components-starter/camel-debug-starter/src/main/java/org/apache/camel/spring/boot/debug/CamelDebugConfigurationProperties.java b/components-starter/camel-debug-starter/src/main/java/org/apache/camel/spring/boot/debug/CamelDebugConfigurationProperties.java index d91c8b32ff87..89dedb370587 100644 --- a/components-starter/camel-debug-starter/src/main/java/org/apache/camel/spring/boot/debug/CamelDebugConfigurationProperties.java +++ b/components-starter/camel-debug-starter/src/main/java/org/apache/camel/spring/boot/debug/CamelDebugConfigurationProperties.java @@ -101,14 +101,17 @@ public class CamelDebugConfigurationProperties { private long fallbackTimeout = 300; /** - * Whether to create JMX connector that allows tooling to control the Camel debugger. - * This is what the IDEA and VSCode tooling is using. + * Whether to create JMX connector that allows tooling to control the Camel debugger. This is what the IDEA and + * VSCode tooling is using. The connector opens an RMI registry and a JMX RMI server on the configured port, without + * authentication or transport security, so it is disabled by default and must be turned on explicitly. Only enable + * it on a trusted network, and bind or firewall the port accordingly. */ - @Metadata(label = "advanced", defaultValue = "true") - private boolean jmxConnectorEnabled = true; + @Metadata(label = "advanced", defaultValue = "false") + private boolean jmxConnectorEnabled; /** - * Port number to expose a JMX RMI connector for tooling that needs to control the debugger. + * Port number to expose a JMX RMI connector for tooling that needs to control the debugger. Only in use when the + * JMX connector is enabled. */ @Metadata(label = "advanced", defaultValue = "1099") private int jmxConnectorPort = 1099; diff --git a/components-starter/camel-debug-starter/src/test/java/org/apache/camel/spring/boot/debug/CamelDebugAutoConfigurationDefaultTest.java b/components-starter/camel-debug-starter/src/test/java/org/apache/camel/spring/boot/debug/CamelDebugAutoConfigurationDefaultTest.java new file mode 100644 index 000000000000..84d69df15d05 --- /dev/null +++ b/components-starter/camel-debug-starter/src/test/java/org/apache/camel/spring/boot/debug/CamelDebugAutoConfigurationDefaultTest.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.spring.boot.debug; + +import org.apache.camel.CamelContext; +import org.apache.camel.impl.debugger.DebuggerJmxConnectorService; +import org.apache.camel.main.DebuggerConfigurationProperties; +import org.apache.camel.spi.BacklogDebugger; +import org.apache.camel.spring.boot.CamelAutoConfiguration; +import org.apache.camel.test.spring.junit6.CamelSpringBootTest; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.annotation.DirtiesContext; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * The debugger itself is installed when the starter is on the classpath, but the JMX RMI connector it can expose is + * opt-in, so no socket is opened by default. + */ +@DirtiesContext +@CamelSpringBootTest +@EnableAutoConfiguration +@SpringBootTest(classes = { + CamelDebugAutoConfigurationDefaultTest.TestConfiguration.class, + CamelDebugAutoConfiguration.class, + CamelAutoConfiguration.class +}) +class CamelDebugAutoConfigurationDefaultTest { + + @Autowired + CamelContext camelContext; + + @Autowired + CamelDebugConfigurationProperties configurationProperties; + + @Autowired + DebuggerConfigurationProperties debuggerConfigurationProperties; + + @Test + void shouldEnableTheDebuggerByDefault() { + assertThat(configurationProperties.isEnabled()).isTrue(); + assertThat(debuggerConfigurationProperties.isEnabled()).isTrue(); + assertThat(camelContext.hasService(BacklogDebugger.class)).isNotNull(); + } + + @Test + void shouldNotEnableTheJmxConnectorByDefault() { + assertThat(configurationProperties.isJmxConnectorEnabled()).isFalse(); + assertThat(debuggerConfigurationProperties.isJmxConnectorEnabled()).isFalse(); + } + + @Test + void shouldNotStartAnyJmxConnectorServiceByDefault() { + assertThat(camelContext.hasService(DebuggerJmxConnectorService.class)).isNull(); + } + + @Configuration + static class TestConfiguration { + } +} diff --git a/components-starter/camel-debug-starter/src/test/java/org/apache/camel/spring/boot/debug/CamelDebugAutoConfigurationJmxConnectorTest.java b/components-starter/camel-debug-starter/src/test/java/org/apache/camel/spring/boot/debug/CamelDebugAutoConfigurationJmxConnectorTest.java new file mode 100644 index 000000000000..d49a7bcac91e --- /dev/null +++ b/components-starter/camel-debug-starter/src/test/java/org/apache/camel/spring/boot/debug/CamelDebugAutoConfigurationJmxConnectorTest.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.spring.boot.debug; + +import java.net.InetSocketAddress; +import java.net.Socket; +import java.util.concurrent.TimeUnit; + +import org.apache.camel.CamelContext; +import org.apache.camel.impl.debugger.DebuggerJmxConnectorService; +import org.apache.camel.main.DebuggerConfigurationProperties; +import org.apache.camel.spring.boot.CamelAutoConfiguration; +import org.apache.camel.test.AvailablePortFinder; +import org.apache.camel.test.spring.junit6.CamelSpringBootTest; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +/** + * The JMX RMI connector is opened only when it is explicitly requested. + */ +@DirtiesContext +@CamelSpringBootTest +@EnableAutoConfiguration +@SpringBootTest(classes = { + CamelDebugAutoConfigurationJmxConnectorTest.TestConfiguration.class, + CamelDebugAutoConfiguration.class, + CamelAutoConfiguration.class +}) +class CamelDebugAutoConfigurationJmxConnectorTest { + + private static final int PORT = AvailablePortFinder.getNextAvailable(); + + @Autowired + CamelContext camelContext; + + @Autowired + DebuggerConfigurationProperties debuggerConfigurationProperties; + + @DynamicPropertySource + static void debugProperties(DynamicPropertyRegistry registry) { + registry.add("camel.debug.jmx-connector-enabled", () -> "true"); + registry.add("camel.debug.jmx-connector-port", () -> PORT); + } + + @Test + void shouldStartTheJmxConnectorWhenEnabled() { + assertThat(debuggerConfigurationProperties.isJmxConnectorEnabled()).isTrue(); + assertThat(debuggerConfigurationProperties.getJmxConnectorPort()).isEqualTo(PORT); + + DebuggerJmxConnectorService service = camelContext.hasService(DebuggerJmxConnectorService.class); + assertThat(service).isNotNull(); + assertThat(service.isStarted()).isTrue(); + } + + @Test + void shouldListenOnTheConfiguredPortWhenEnabled() { + await().atMost(20, TimeUnit.SECONDS).untilAsserted(() -> { + try (Socket socket = new Socket()) { + socket.connect(new InetSocketAddress("localhost", PORT), 1000); + assertThat(socket.isConnected()).isTrue(); + } + }); + } + + @Configuration + static class TestConfiguration { + } +} diff --git a/docs/spring-boot/modules/ROOT/pages/starters/debug.adoc b/docs/spring-boot/modules/ROOT/pages/starters/debug.adoc index 8914f523250f..d2400eabf7e1 100644 --- a/docs/spring-boot/modules/ROOT/pages/starters/debug.adoc +++ b/docs/spring-boot/modules/ROOT/pages/starters/debug.adoc @@ -5,7 +5,7 @@ Spring Boot auto-configuration for the Camel Debugger. -This starter enables the Camel Debugger in your Spring Boot application, allowing you to set breakpoints and step through Camel routes during development. The debugger integrates with IDEs and tooling through JMX. +This starter enables the Camel Debugger in your Spring Boot application, allowing you to set breakpoints and step through Camel routes during development. The debugger is controlled from Java, JMX or tooling, and can additionally expose a JMX RMI connector for remote tooling, which is disabled by default. == Maven coordinates @@ -17,6 +17,29 @@ This starter enables the Camel Debugger in your Spring Boot application, allowin ---- +== Usage + +Adding this starter to the classpath installs and enables the Camel Debugger. The debugger can be turned off with: + +[source,properties] +---- +camel.debug.enabled = false +---- + +=== JMX connector + +Tooling that attaches to the debugger from another process, such as the IntelliJ IDEA and VS Code Camel plugins, uses a JMX RMI connector. The connector is *disabled by default*, so having this starter on the classpath never opens a listening socket on its own. Enable it explicitly when remote tooling needs to attach: + +[source,properties] +---- +camel.debug.jmx-connector-enabled = true +camel.debug.jmx-connector-port = 1099 +---- + +WARNING: The JMX RMI connector is created without authentication or transport security. Anyone able to reach the port can control the debugger, suspend routes and read message payloads. Only enable it on a trusted network, and make sure the port is bound to a loopback interface or protected by a firewall. + +The `camel debug` command of Camel JBang does not need this connector: it drives a Spring Boot application through the local CLI connector provided by `camel-cli-connector-starter`. + == Spring Boot Auto-Configuration The starter supports 15 options, which are listed below. @@ -33,8 +56,8 @@ The starter supports 15 options, which are listed below. | camel.debug.include-exception | Trace messages to include exception if the message failed | true | Boolean | camel.debug.include-exchange-properties | Whether to include the exchange properties in the traced message | true | Boolean | camel.debug.include-exchange-variables | Whether to include the exchange variables in the traced message | true | Boolean -| camel.debug.jmx-connector-enabled | Whether to create JMX connector that allows tooling to control the Camel debugger. This is what the IDEA and VSCode tooling is using. | true | Boolean -| camel.debug.jmx-connector-port | Port number to expose a JMX RMI connector for tooling that needs to control the debugger. | 1099 | Integer +| camel.debug.jmx-connector-enabled | Whether to create JMX connector that allows tooling to control the Camel debugger. This is what the IDEA and VSCode tooling is using. The connector opens an RMI registry and a JMX RMI server on the configured port, without authentication or transport security, so it is disabled by default and must be turned on explicitly. Only enable it on a trusted network, and bind or firewall the port accordingly. | false | Boolean +| camel.debug.jmx-connector-port | Port number to expose a JMX RMI connector for tooling that needs to control the debugger. Only in use when the JMX connector is enabled. | 1099 | Integer | camel.debug.logging-level | The debugger logging level to use when logging activity. | info | LoggingLevel | camel.debug.single-step-include-start-end | In single step mode, then when the exchange is created and completed, then simulate a breakpoint at start and end, that allows to suspend and watch the incoming/complete exchange at the route (you can see message body as response, failed exception etc). | false | Boolean | camel.debug.standby | To set the debugger in standby mode, where the debugger will be installed by not automatic enabled. The debugger can then later be enabled explicit from Java, JMX or tooling. | false | Boolean