You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by pp...@apache.org on 2023/05/15 15:09:08 UTC

[camel-quarkus] 06/06: Snmp: cover snmp v3 for POLL operation #4881

This is an automated email from the ASF dual-hosted git repository.

ppalaga pushed a commit to branch 2.13.x
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git

commit d61ff2a070b2e8f0ad4b04008c6ffafc284f7fa9
Author: JiriOndrusek <on...@gmail.com>
AuthorDate: Thu May 4 17:25:28 2023 +0200

    Snmp: cover snmp v3 for POLL operation #4881
---
 .../component/snmp/QuarkusSnmpOIDPoller.java       | 317 +++++++++++++++++++++
 .../camel/quarkus/component/snmp/SnmpRecorder.java |  18 ++
 .../quarkus/component/snmp/it/SnmpResource.java    |  38 +++
 .../camel/quarkus/component/snmp/it/SnmpRoute.java |  44 +--
 .../camel/quarkus/component/snmp/it/SnmpTest.java  |  82 +++---
 .../component/snmp/it/SnmpTestResource.java        |  51 +++-
 6 files changed, 445 insertions(+), 105 deletions(-)

diff --git a/extensions-jvm/snmp/runtime/src/main/java/org/apache/camel/quarkus/component/snmp/QuarkusSnmpOIDPoller.java b/extensions-jvm/snmp/runtime/src/main/java/org/apache/camel/quarkus/component/snmp/QuarkusSnmpOIDPoller.java
new file mode 100644
index 0000000000..ac94362abb
--- /dev/null
+++ b/extensions-jvm/snmp/runtime/src/main/java/org/apache/camel/quarkus/component/snmp/QuarkusSnmpOIDPoller.java
@@ -0,0 +1,317 @@
+/*
+ * 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.quarkus.component.snmp;
+
+import java.util.List;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.component.snmp.SnmpActionType;
+import org.apache.camel.component.snmp.SnmpEndpoint;
+import org.apache.camel.component.snmp.SnmpOIDPoller;
+import org.apache.camel.support.ScheduledPollConsumer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.snmp4j.CommunityTarget;
+import org.snmp4j.PDU;
+import org.snmp4j.ScopedPDU;
+import org.snmp4j.Snmp;
+import org.snmp4j.Target;
+import org.snmp4j.TransportMapping;
+import org.snmp4j.UserTarget;
+import org.snmp4j.event.ResponseEvent;
+import org.snmp4j.event.ResponseListener;
+import org.snmp4j.mp.MPv3;
+import org.snmp4j.mp.SnmpConstants;
+import org.snmp4j.security.AuthMD5;
+import org.snmp4j.security.AuthSHA;
+import org.snmp4j.security.Priv3DES;
+import org.snmp4j.security.PrivAES128;
+import org.snmp4j.security.PrivAES192;
+import org.snmp4j.security.PrivAES256;
+import org.snmp4j.security.PrivDES;
+import org.snmp4j.security.SecurityModels;
+import org.snmp4j.security.SecurityProtocols;
+import org.snmp4j.security.USM;
+import org.snmp4j.security.UsmUser;
+import org.snmp4j.smi.Address;
+import org.snmp4j.smi.GenericAddress;
+import org.snmp4j.smi.OID;
+import org.snmp4j.smi.OctetString;
+import org.snmp4j.smi.VariableBinding;
+import org.snmp4j.transport.DefaultTcpTransportMapping;
+import org.snmp4j.transport.DefaultUdpTransportMapping;
+import org.snmp4j.util.DefaultPDUFactory;
+import org.snmp4j.util.TreeEvent;
+import org.snmp4j.util.TreeUtils;
+
+/**
+ * A copy of SnmpOIDPoller fromm Camel
+ */
+public class QuarkusSnmpOIDPoller extends ScheduledPollConsumer implements ResponseListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SnmpOIDPoller.class);
+
+    private Address targetAddress;
+    private TransportMapping<? extends Address> transport;
+    private Snmp snmp;
+
+    private Target target;
+    private PDU pdu;
+    private SnmpEndpoint endpoint;
+
+    public QuarkusSnmpOIDPoller(SnmpEndpoint endpoint, Processor processor) {
+        super(endpoint, processor);
+        this.endpoint = endpoint;
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        super.doStart();
+
+        this.targetAddress = GenericAddress.parse(this.endpoint.getAddress());
+
+        // either tcp or udp
+        if ("tcp".equals(endpoint.getProtocol())) {
+            this.transport = new DefaultTcpTransportMapping();
+        } else if ("udp".equals(endpoint.getProtocol())) {
+            this.transport = new DefaultUdpTransportMapping();
+        } else {
+            throw new IllegalArgumentException("Unknown protocol: " + endpoint.getProtocol());
+        }
+
+        this.snmp = new Snmp(this.transport);
+
+        if (SnmpConstants.version3 == endpoint.getSnmpVersion()) {
+            UserTarget userTarget = new UserTarget();
+
+            userTarget.setSecurityLevel(endpoint.getSecurityLevel());
+            userTarget.setSecurityName(convertToOctetString(endpoint.getSecurityName()));
+            userTarget.setAddress(targetAddress);
+            userTarget.setRetries(endpoint.getRetries());
+            userTarget.setTimeout(endpoint.getTimeout());
+            userTarget.setVersion(endpoint.getSnmpVersion());
+
+            this.target = userTarget;
+
+            USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0);
+            SecurityModels.getInstance().addSecurityModel(usm);
+
+            OID authProtocol = convertAuthenticationProtocol(endpoint.getAuthenticationProtocol());
+
+            OctetString authPwd = convertToOctetString(endpoint.getAuthenticationPassphrase());
+
+            OID privProtocol = convertPrivacyProtocol(endpoint.getPrivacyProtocol());
+
+            OctetString privPwd = convertToOctetString(endpoint.getPrivacyPassphrase());
+
+            UsmUser user = new UsmUser(
+                    convertToOctetString(endpoint.getSecurityName()), authProtocol, authPwd, privProtocol, privPwd);
+
+            usm.addUser(convertToOctetString(endpoint.getSecurityName()), user);
+
+            ScopedPDU scopedPDU = new ScopedPDU();
+
+            if (endpoint.getSnmpContextEngineId() != null) {
+                scopedPDU.setContextEngineID(new OctetString(endpoint.getSnmpContextEngineId()));
+            }
+
+            if (endpoint.getSnmpContextName() != null) {
+                scopedPDU.setContextName(new OctetString(endpoint.getSnmpContextName()));
+            }
+
+            this.pdu = scopedPDU;
+        } else {
+            CommunityTarget communityTarget = new CommunityTarget();
+
+            communityTarget.setCommunity(convertToOctetString(endpoint.getSnmpCommunity()));
+            communityTarget.setAddress(targetAddress);
+            communityTarget.setRetries(endpoint.getRetries());
+            communityTarget.setTimeout(endpoint.getTimeout());
+            communityTarget.setVersion(endpoint.getSnmpVersion());
+
+            this.target = communityTarget;
+
+            this.pdu = new PDU();
+        }
+
+        // listen to the transport
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Starting OID poller on {} using {} protocol", endpoint.getAddress(), endpoint.getProtocol());
+        }
+        this.transport.listen();
+        if (LOG.isInfoEnabled()) {
+            LOG.info("Started OID poller on {} using {} protocol", endpoint.getAddress(), endpoint.getProtocol());
+        }
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        // stop listening to the transport
+        if (this.transport != null && this.transport.isListening()) {
+            LOG.info("Stopping OID poller on {}", targetAddress);
+            this.transport.close();
+            LOG.info("Stopped OID poller on {}", targetAddress);
+        }
+
+        super.doStop();
+    }
+
+    @Override
+    protected int poll() throws Exception {
+        this.pdu.clear();
+
+        int type = this.getPduType(this.endpoint.getType());
+
+        this.pdu.setType(type);
+
+        if (!endpoint.isTreeList()) {
+            // prepare the request items
+            for (OID oid : this.endpoint.getOids()) {
+                this.pdu.add(new VariableBinding(oid));
+            }
+        } else {
+            TreeUtils treeUtils = new TreeUtils(snmp, new DefaultPDUFactory());
+            for (OID oid : this.endpoint.getOids()) {
+                List events = treeUtils.getSubtree(target, new OID(oid));
+                for (Object eventObj : events) {
+                    TreeEvent event = (TreeEvent) eventObj;
+                    if (event == null) {
+                        LOG.warn("Event is null");
+                        continue;
+                    }
+                    if (event.isError()) {
+                        LOG.error("Error in event: {}", event.getErrorMessage());
+                        continue;
+                    }
+                    VariableBinding[] varBindings = event.getVariableBindings();
+                    if (varBindings == null || varBindings.length == 0) {
+                        continue;
+                    }
+                    for (VariableBinding varBinding : varBindings) {
+                        if (varBinding == null) {
+                            continue;
+                        }
+                        this.pdu.add(varBinding);
+                    }
+                }
+            }
+        }
+
+        // send the request
+        snmp.send(pdu, target, null, this);
+
+        return 1;
+    }
+
+    @Override
+    public void onResponse(ResponseEvent event) {
+        // Always cancel async request when response has been received
+        // otherwise a memory leak is created! Not canceling a request
+        // immediately can be useful when sending a request to a broadcast address.
+        ((Snmp) event.getSource()).cancel(event.getRequest(), this);
+
+        // check for valid response
+        if (event.getRequest() == null || event.getResponse() == null) {
+            // ignore null requests/responses
+            LOG.debug("Received invalid SNMP event. Request: {} / Response: {}", event.getRequest(), event.getResponse());
+            return;
+        }
+
+        PDU pdu = event.getResponse();
+        processPDU(pdu);
+    }
+
+    /**
+     * processes the pdu message
+     * 
+     * @param pdu the pdu
+     */
+    public void processPDU(PDU pdu) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Received response event for {} : {}", this.endpoint.getAddress(), pdu);
+        }
+        Exchange exchange = endpoint.createExchange(pdu);
+        try {
+            getProcessor().process(exchange);
+        } catch (Exception e) {
+            getExceptionHandler().handleException(e);
+        }
+    }
+
+    /**
+     * * @return Returns the target.
+     */
+    public Target getTarget() {
+        return this.target;
+    }
+
+    /**
+     * @param target The target to set.
+     */
+    public void setTarget(Target target) {
+        this.target = target;
+    }
+
+    private OctetString convertToOctetString(String value) {
+        if (value == null) {
+            return null;
+        }
+        return new OctetString(value);
+    }
+
+    private OID convertAuthenticationProtocol(String authenticationProtocol) {
+        if (authenticationProtocol == null) {
+            return null;
+        }
+        if ("MD5".equals(authenticationProtocol)) {
+            return AuthMD5.ID;
+        } else if ("SHA1".equals(authenticationProtocol)) {
+            return AuthSHA.ID;
+        } else {
+            throw new IllegalArgumentException("Unknown authentication protocol: " + authenticationProtocol);
+        }
+    }
+
+    private OID convertPrivacyProtocol(String privacyProtocol) {
+        if (privacyProtocol == null) {
+            return null;
+        }
+        if ("DES".equals(privacyProtocol)) {
+            return PrivDES.ID;
+        } else if ("TRIDES".equals(privacyProtocol)) {
+            return Priv3DES.ID;
+        } else if ("AES128".equals(privacyProtocol)) {
+            return PrivAES128.ID;
+        } else if ("AES192".equals(privacyProtocol)) {
+            return PrivAES192.ID;
+        } else if ("AES256".equals(privacyProtocol)) {
+            return PrivAES256.ID;
+        } else {
+            throw new IllegalArgumentException("Unknown privacy protocol: " + privacyProtocol);
+        }
+    }
+
+    private int getPduType(SnmpActionType type) {
+        if (SnmpActionType.GET_NEXT == type) {
+            return PDU.GETNEXT;
+        } else {
+            return PDU.GET;
+        }
+    }
+
+}
diff --git a/extensions-jvm/snmp/runtime/src/main/java/org/apache/camel/quarkus/component/snmp/SnmpRecorder.java b/extensions-jvm/snmp/runtime/src/main/java/org/apache/camel/quarkus/component/snmp/SnmpRecorder.java
index 8e357e5664..97f2f420c9 100644
--- a/extensions-jvm/snmp/runtime/src/main/java/org/apache/camel/quarkus/component/snmp/SnmpRecorder.java
+++ b/extensions-jvm/snmp/runtime/src/main/java/org/apache/camel/quarkus/component/snmp/SnmpRecorder.java
@@ -20,11 +20,14 @@ import java.util.Map;
 
 import io.quarkus.runtime.RuntimeValue;
 import io.quarkus.runtime.annotations.Recorder;
+import org.apache.camel.Consumer;
 import org.apache.camel.Endpoint;
+import org.apache.camel.Processor;
 import org.apache.camel.Producer;
 import org.apache.camel.component.snmp.SnmpActionType;
 import org.apache.camel.component.snmp.SnmpComponent;
 import org.apache.camel.component.snmp.SnmpEndpoint;
+import org.apache.camel.component.snmp.SnmpTrapConsumer;
 
 @Recorder
 public class SnmpRecorder {
@@ -67,5 +70,20 @@ public class SnmpRecorder {
                 return new QuarkusSnmpProducer(this, getType());
             }
         }
+
+        @Override
+        public Consumer createConsumer(Processor processor) throws Exception {
+            if (getType() == SnmpActionType.TRAP) {
+                SnmpTrapConsumer answer = new SnmpTrapConsumer(this, processor);
+                // As the SnmpTrapConsumer is not a polling consumer we don't need to call the configureConsumer here.
+                return answer;
+            } else if (getType() == SnmpActionType.POLL) {
+                QuarkusSnmpOIDPoller answer = new QuarkusSnmpOIDPoller(this, processor);
+                configureConsumer(answer);
+                return answer;
+            } else {
+                throw new IllegalArgumentException("The type '" + getType() + "' is not valid!");
+            }
+        }
     }
 }
diff --git a/integration-tests-jvm/snmp/src/main/java/org/apache/camel/quarkus/component/snmp/it/SnmpResource.java b/integration-tests-jvm/snmp/src/main/java/org/apache/camel/quarkus/component/snmp/it/SnmpResource.java
index 3d35fe115d..99ec6d8bd0 100644
--- a/integration-tests-jvm/snmp/src/main/java/org/apache/camel/quarkus/component/snmp/it/SnmpResource.java
+++ b/integration-tests-jvm/snmp/src/main/java/org/apache/camel/quarkus/component/snmp/it/SnmpResource.java
@@ -28,9 +28,12 @@ import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
+import org.apache.camel.ConsumerTemplate;
+import org.apache.camel.Exchange;
 import org.apache.camel.ProducerTemplate;
 import org.apache.camel.component.snmp.SnmpMessage;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
@@ -60,6 +63,9 @@ public class SnmpResource {
     @Named("snmpTrapResults")
     Map<String, Deque<SnmpMessage>> snmpResults;
 
+    @Inject
+    ConsumerTemplate consumerTemplate;
+
     @Inject
     ProducerTemplate producerTemplate;
 
@@ -87,6 +93,9 @@ public class SnmpResource {
 
         String response = pdu.stream()
                 .flatMap(m -> m.getSnmpMessage().getVariableBindings().stream())
+                //snmp may add null oid to the result - because responder supports v3
+                // (see https://camel.apache.org/components/3.20.x/snmp-component.html#_the_result_of_a_poll)
+                .filter(vb -> !"Null".equals(vb.getVariable().toString()))
                 .map(vb -> vb.getVariable().toString())
                 .collect(Collectors.joining(","));
 
@@ -106,6 +115,35 @@ public class SnmpResource {
         return Response.ok().build();
     }
 
+    @Path("/poll/{version}")
+    @POST
+    @Produces(MediaType.TEXT_PLAIN)
+    public Response poll(@PathParam("version") int version,
+            @QueryParam("user") String user,
+            @QueryParam("securityLevel") String securityLevel,
+            String oid) {
+        String url = String.format("snmp:%s?protocol=udp&snmpVersion=%d&type=POLL&oids=%s", snmpListenAddress, version, oid);
+        if (user != null) {
+            url = url + "&securityName=" + user;
+        }
+        if (securityLevel != null) {
+            url = url + "&securityLevel=" + securityLevel;
+        }
+
+        //Even if routeBuilder is preferred instead of consumerTemplate, consumerTemplete can be used in a case, when the component uses polling consumers by default.
+        // In this case:
+        // - only polling consumer is used by the SNMP component
+        // - usage of the consumerTemplate reduces a lot of requests between SNMP providers significantly, thus making the tests more stable.
+        Exchange e = consumerTemplate.receive(url);
+
+        String result = e.getIn().getBody(SnmpMessage.class).getSnmpMessage().getVariableBindings().stream()
+                //snmp may add null oid to the result - because responder supports v3
+                // (see https://camel.apache.org/components/3.20.x/snmp-component.html#_the_result_of_a_poll)
+                .filter(vb -> !"Null".equals(vb.getVariable().toString()))
+                .map(v -> v.getVariable().toString()).collect(Collectors.joining(","));
+        return Response.ok(result).build();
+    }
+
     @Path("/results/{from}")
     @POST
     @Produces(MediaType.TEXT_PLAIN)
diff --git a/integration-tests-jvm/snmp/src/main/java/org/apache/camel/quarkus/component/snmp/it/SnmpRoute.java b/integration-tests-jvm/snmp/src/main/java/org/apache/camel/quarkus/component/snmp/it/SnmpRoute.java
index 3f906ab477..1862fe37ab 100644
--- a/integration-tests-jvm/snmp/src/main/java/org/apache/camel/quarkus/component/snmp/it/SnmpRoute.java
+++ b/integration-tests-jvm/snmp/src/main/java/org/apache/camel/quarkus/component/snmp/it/SnmpRoute.java
@@ -30,7 +30,6 @@ import javax.inject.Singleton;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.snmp.SnmpMessage;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
-import org.snmp4j.mp.SnmpConstants;
 
 @ApplicationScoped
 public class SnmpRoute extends RouteBuilder {
@@ -41,12 +40,9 @@ public class SnmpRoute extends RouteBuilder {
     @ConfigProperty(name = TRAP_V0_PORT)
     int trap0Port;
 
-    @ConfigProperty(name = "SnmpRoute_trap_v1")
+    @ConfigProperty(name = TRAP_V1_PORT)
     int trap1Port;
 
-    @ConfigProperty(name = "snmpListenAddress")
-    String snmpListenAddress;
-
     @Inject
     @Named("snmpTrapResults")
     Map<String, Deque<SnmpMessage>> snmpResults;
@@ -60,33 +56,6 @@ public class SnmpRoute extends RouteBuilder {
         //TRAP consumer snmpVersion=1
         from("snmp:0.0.0.0:" + trap1Port + "?protocol=udp&type=TRAP&snmpVersion=1")
                 .process(e -> snmpResults.get("v1_trap").add(e.getIn().getBody(SnmpMessage.class)));
-
-        //POLL consumer 2 oids, snmpVersion=0
-        from("snmp://" + snmpListenAddress + "?protocol=udp&snmpVersion=0&type=POLL&oids=" +
-                SnmpConstants.sysLocation + "," + SnmpConstants.sysContact)
-                        .process(e -> snmpResults.get("v0_poll2oids").add(e.getIn().getBody(SnmpMessage.class)));
-        //POLL consumer 2 oids, snmpVersion=1
-        from("snmp://" + snmpListenAddress + "?protocol=udp&snmpVersion=1&type=POLL&oids=" +
-                SnmpConstants.sysLocation + "," + SnmpConstants.sysContact)
-                        .process(e -> snmpResults.get("v1_poll2oids").add(e.getIn().getBody(SnmpMessage.class)));
-
-        // POLL consumer starting with dot snmpVersion=0
-        from("snmp://" + snmpListenAddress
-                + "?protocol=udp&snmpVersion=0&type=POLL&oids=.1.3.6.1.4.1.6527.3.1.2.21.2.1.50")
-                        .process(e -> snmpResults.get("v0_pollStartingDot").add(e.getIn().getBody(SnmpMessage.class)));
-        //POLL consumer startingWith dot snmpVersion=1
-        from("snmp://" + snmpListenAddress
-                + "?protocol=udp&snmpVersion=1&type=POLL&oids=.1.3.6.1.4.1.6527.3.1.2.21.2.1.50")
-                        .process(e -> snmpResults.get("v1_pollStartingDot").add(e.getIn().getBody(SnmpMessage.class)));
-
-        //POLL consumer snmpVersion=0
-        from("snmp://" + snmpListenAddress + "?protocol=udp&snmpVersion=0&type=POLL&oids="
-                + SnmpConstants.sysDescr)
-                        .process(e -> snmpResults.get("v0_poll").add(e.getIn().getBody(SnmpMessage.class)));
-        //POLL consumer snmpVersion=1
-        from("snmp://" + snmpListenAddress + "?protocol=udp&snmpVersion=1&type=POLL&oids="
-                + SnmpConstants.sysDescr)
-                        .process(e -> snmpResults.get("v1_poll").add(e.getIn().getBody(SnmpMessage.class)));
     }
 
     static class Producers {
@@ -95,15 +64,8 @@ public class SnmpRoute extends RouteBuilder {
         @Named("snmpTrapResults")
         Map<String, Deque<SnmpMessage>> snmpResults() {
             Map<String, Deque<SnmpMessage>> map = new ConcurrentHashMap<>();
-            map.put("v0_trap", new ConcurrentLinkedDeque<SnmpMessage>());
-            map.put("v1_trap", new ConcurrentLinkedDeque<SnmpMessage>());
-            map.put("v0_poll", new ConcurrentLinkedDeque<SnmpMessage>());
-            map.put("v1_poll", new ConcurrentLinkedDeque<SnmpMessage>());
-            map.put("v3_poll", new ConcurrentLinkedDeque<SnmpMessage>());
-            map.put("v0_pollStartingDot", new ConcurrentLinkedDeque<SnmpMessage>());
-            map.put("v1_pollStartingDot", new ConcurrentLinkedDeque<SnmpMessage>());
-            map.put("v0_poll2oids", new ConcurrentLinkedDeque<SnmpMessage>());
-            map.put("v1_poll2oids", new ConcurrentLinkedDeque<SnmpMessage>());
+            map.put("v0_trap", new ConcurrentLinkedDeque<>());
+            map.put("v1_trap", new ConcurrentLinkedDeque<>());
             return map;
         }
     }
diff --git a/integration-tests-jvm/snmp/src/test/java/org/apache/camel/quarkus/component/snmp/it/SnmpTest.java b/integration-tests-jvm/snmp/src/test/java/org/apache/camel/quarkus/component/snmp/it/SnmpTest.java
index fac78e768c..1220e8aa44 100644
--- a/integration-tests-jvm/snmp/src/test/java/org/apache/camel/quarkus/component/snmp/it/SnmpTest.java
+++ b/integration-tests-jvm/snmp/src/test/java/org/apache/camel/quarkus/component/snmp/it/SnmpTest.java
@@ -22,9 +22,11 @@ import java.util.stream.Stream;
 import io.quarkus.test.common.QuarkusTestResource;
 import io.quarkus.test.junit.QuarkusTest;
 import io.restassured.RestAssured;
+import io.restassured.specification.RequestSpecification;
 import org.hamcrest.Matchers;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.MethodSource;
+import org.junit.jupiter.params.provider.ValueSource;
 import org.snmp4j.mp.SnmpConstants;
 import org.snmp4j.smi.OID;
 
@@ -76,38 +78,44 @@ class SnmpTest {
     }
 
     @ParameterizedTest
-    @MethodSource("supportedVersions")
+    @ValueSource(ints = { 0, 1, 3 })
     public void testPoll(int version) throws Exception {
-        String resultsName = "v" + version + "_poll";
+        RequestSpecification rs = RestAssured.given()
+                .body(POLL_OID.toString());
 
-        await().atMost(20L, TimeUnit.SECONDS).pollDelay(100, TimeUnit.MILLISECONDS).until(() -> {
-            String result = RestAssured.given()
-                    .body(SnmpConstants.sysDescr.toString())
-                    .post("/snmp/results/" + resultsName)
-                    .then()
-                    .statusCode(200)
-                    .extract().body().asString();
+        if (version == 3) {
+            rs.queryParam("user", "test")
+                    .queryParam("securityLevel", 1);
+        }
 
-            return result
-                    .startsWith("My POLL Printer - response #1,My POLL Printer - response #2,My POLL Printer - response #3");
-        });
+        rs.post("/snmp/poll/" + version)
+                .then()
+                .statusCode(200)
+                .body(Matchers.equalTo("My POLL Printer - response #1"));
     }
 
     @ParameterizedTest
     @MethodSource("supportedVersions")
-    public void testPollStartingDot(int version) throws Exception {
-        String resultsName = "v" + version + "_pollStartingDot";
-
-        await().atMost(20L, TimeUnit.SECONDS).pollDelay(100, TimeUnit.MILLISECONDS).until(() -> {
-            String result = RestAssured.given()
-                    .body(DOT_OID.toString())
-                    .post("/snmp/results/" + resultsName)
-                    .then()
-                    .statusCode(200)
-                    .extract().body().asString();
+    public void testPollWith2OIDs(int version) throws Exception {
+        RestAssured.given()
+                .body(TWO_OIDS_A + "," + TWO_OIDS_B)
+                .post("/snmp/poll/" + version)
+                .then()
+                .statusCode(200)
+                .body(Matchers.anyOf(
+                        Matchers.equalTo("My 2 OIDs A Printer - response #1,My 2 OIDs B Printer - response #1"),
+                        Matchers.equalTo("My 2 OIDs B Printer - response #1,My 2 OIDs A Printer - response #1")));
+    }
 
-            return result.startsWith("My DOT Printer - response #1,My DOT Printer - response #2,My DOT Printer - response #3");
-        });
+    @ParameterizedTest
+    @MethodSource("supportedVersions")
+    public void testPollStartingDot(int version) throws Exception {
+        RestAssured.given()
+                .body("." + DOT_OID)
+                .post("/snmp/poll/" + version)
+                .then()
+                .statusCode(200)
+                .body(Matchers.equalTo("My DOT Printer - response #1"));
     }
 
     @ParameterizedTest
@@ -134,30 +142,4 @@ class SnmpTest {
                 .body(Matchers.endsWith("2,My GET_NEXT Printer - response #3"));
     }
 
-    @ParameterizedTest
-    @MethodSource("supportedVersions")
-    public void testPollWith2OIDs(int version) throws Exception {
-        String resultsName = "v" + version + "_poll2oids";
-
-        await().atMost(20L, TimeUnit.SECONDS).pollDelay(100, TimeUnit.MILLISECONDS).until(() -> {
-            String resultOid1 = RestAssured.given()
-                    .body(TWO_OIDS_A.toString())
-                    .post("/snmp/results/" + resultsName)
-                    .then()
-                    .statusCode(200)
-                    .extract().body().asString();
-            String resultOid2 = RestAssured.given()
-                    .body(TWO_OIDS_B.toString())
-                    .post("/snmp/results/" + resultsName)
-                    .then()
-                    .statusCode(200)
-                    .extract().body().asString();
-
-            return resultOid1.startsWith(
-                    "My 2 OIDs A Printer - response #1,My 2 OIDs A Printer - response #2,My 2 OIDs A Printer - response #3") &&
-                    resultOid2.startsWith(
-                            "My 2 OIDs B Printer - response #1,My 2 OIDs B Printer - response #2,My 2 OIDs B Printer - response #3");
-        });
-
-    }
 }
diff --git a/integration-tests-jvm/snmp/src/test/java/org/apache/camel/quarkus/component/snmp/it/SnmpTestResource.java b/integration-tests-jvm/snmp/src/test/java/org/apache/camel/quarkus/component/snmp/it/SnmpTestResource.java
index 769c7824b6..c487d4acdc 100644
--- a/integration-tests-jvm/snmp/src/test/java/org/apache/camel/quarkus/component/snmp/it/SnmpTestResource.java
+++ b/integration-tests-jvm/snmp/src/test/java/org/apache/camel/quarkus/component/snmp/it/SnmpTestResource.java
@@ -34,8 +34,16 @@ import org.snmp4j.PDU;
 import org.snmp4j.PDUv1;
 import org.snmp4j.ScopedPDU;
 import org.snmp4j.Snmp;
+import org.snmp4j.mp.CounterSupport;
+import org.snmp4j.mp.DefaultCounterListener;
+import org.snmp4j.mp.MPv3;
 import org.snmp4j.mp.SnmpConstants;
 import org.snmp4j.mp.StatusInformation;
+import org.snmp4j.security.AuthSHA;
+import org.snmp4j.security.SecurityModels;
+import org.snmp4j.security.SecurityProtocols;
+import org.snmp4j.security.USM;
+import org.snmp4j.security.UsmUser;
 import org.snmp4j.smi.OID;
 import org.snmp4j.smi.OctetString;
 import org.snmp4j.smi.UdpAddress;
@@ -51,6 +59,7 @@ public class SnmpTestResource implements QuarkusTestResourceLifecycleManager {
 
     @Override
     public Map<String, String> start() {
+        SecurityProtocols.getInstance().addDefaultProtocols();
         DefaultUdpTransportMapping udpTransportMapping;
         try {
             udpTransportMapping = new DefaultUdpTransportMapping(new UdpAddress(LOCAL_ADDRESS));
@@ -59,6 +68,20 @@ public class SnmpTestResource implements QuarkusTestResourceLifecycleManager {
             TestCommandResponder responder = new TestCommandResponder(snmpResponder);
             snmpResponder.addCommandResponder(responder);
 
+            SecurityModels respSecModels = new SecurityModels() {
+            };
+
+            CounterSupport.getInstance().addCounterListener(new DefaultCounterListener());
+            MPv3 mpv3CR = (MPv3) snmpResponder.getMessageDispatcher().getMessageProcessingModel(MPv3.ID);
+            mpv3CR.setLocalEngineID(MPv3.createLocalEngineID(new OctetString("responder")));
+            respSecModels.addSecurityModel(new USM(SecurityProtocols.getInstance(),
+                    new OctetString(mpv3CR.getLocalEngineID()), 0));
+            mpv3CR.setSecurityModels(respSecModels);
+
+            snmpResponder.getUSM().addUser(
+                    new UsmUser(new OctetString("test"), AuthSHA.ID, new OctetString("changeit"),
+                            AuthSHA.ID, new OctetString("changeit")));
+
             snmpResponder.listen();
         } catch (Exception e) {
             throw new RuntimeException(e);
@@ -75,6 +98,7 @@ public class SnmpTestResource implements QuarkusTestResourceLifecycleManager {
 
     @Override
     public void stop() {
+        SecurityProtocols.setSecurityProtocols(null);
         if (snmpResponder != null) {
             try {
                 snmpResponder.close();
@@ -115,7 +139,7 @@ public class SnmpTestResource implements QuarkusTestResourceLifecycleManager {
             int numberOfSent = counts.getOrDefault(key, 0);
 
             try {
-                PDU response = makeResponse(++numberOfSent, SnmpConstants.version1, vbs);
+                PDU response = makeResponse(pdu, ++numberOfSent, SnmpConstants.version1, vbs);
                 if (response != null) {
                     response.setRequestID(pdu.getRequestID());
                     commandResponder.getMessageDispatcher().returnResponsePdu(
@@ -130,18 +154,18 @@ public class SnmpTestResource implements QuarkusTestResourceLifecycleManager {
             counts.put(key, numberOfSent);
         }
 
-        private PDU makeResponse(int counter, int version, Vector<? extends VariableBinding> vbs) {
-            PDU responsePDU = new PDU();
+        private PDU makeResponse(PDU originalPDU, int counter, int version, Vector<? extends VariableBinding> vbs) {
+            PDU responsePDU = (PDU) originalPDU.clone();
             responsePDU.setType(PDU.RESPONSE);
             responsePDU.setErrorStatus(PDU.noError);
             responsePDU.setErrorIndex(0);
             if (vbs.isEmpty()) {
-                VariableBinding vb = generateResponseBinding(counter, SnmpTest.PRODUCE_PDU_OID);
+                VariableBinding vb = generateResponseBinding(counter, version, SnmpTest.PRODUCE_PDU_OID);
                 if (vb != null) {
                     responsePDU.add(vb);
                 }
             } else {
-                vbs.stream().forEach(vb -> responsePDU.add(generateResponseBinding(counter, vb.getOid())));
+                vbs.stream().forEach(vb -> responsePDU.add(generateResponseBinding(counter, version, vb.getOid())));
             }
             if (responsePDU.getVariableBindings().isEmpty()) {
                 return null;
@@ -149,7 +173,7 @@ public class SnmpTestResource implements QuarkusTestResourceLifecycleManager {
             return responsePDU;
         }
 
-        private VariableBinding generateResponseBinding(int counter, OID oid) {
+        private VariableBinding generateResponseBinding(int counter, int version, OID oid) {
             //get next test
             if (SnmpTest.GET_NEXT_OID.equals(oid)) {
                 //if counter < 2 return the same oid
@@ -166,11 +190,12 @@ public class SnmpTestResource implements QuarkusTestResourceLifecycleManager {
             }
 
             if (SnmpTest.POLL_OID.equals(oid)) {
-                if (counter < 4) {
-                    return new VariableBinding(SnmpTest.POLL_OID,
-                            new OctetString("My POLL Printer - response #" + counter));
+                if (counter > 1) {
+                    throw new RuntimeException(
+                            String.format("Not expected request #%d for poll of version %d.", counter, version));
                 }
-
+                return new VariableBinding(SnmpTest.POLL_OID,
+                        new OctetString("My POLL Printer - response #" + counter));
             }
 
             if (SnmpTest.PRODUCE_PDU_OID.equals(oid)) {
@@ -195,10 +220,8 @@ public class SnmpTestResource implements QuarkusTestResourceLifecycleManager {
             }
 
             if (SnmpTest.DOT_OID.equals(oid)) {
-                if (counter < 4) {
-                    return new VariableBinding(SnmpTest.DOT_OID,
-                            new OctetString("My DOT Printer - response #" + counter));
-                }
+                return new VariableBinding(SnmpTest.DOT_OID,
+                        new OctetString("My DOT Printer - response #" + counter));
             }
 
             return null;