You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by tp...@apache.org on 2022/07/04 14:44:19 UTC

[nifi] branch main updated: NIFI-9916: ListenTrapSNMP USM parsing refactor.

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

tpalfy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/main by this push:
     new 685088a59c NIFI-9916: ListenTrapSNMP USM parsing refactor.
685088a59c is described below

commit 685088a59c034d415c820d7724a2e16dfa4ac6a2
Author: Lehel <Le...@hotmail.com>
AuthorDate: Wed May 11 00:42:30 2022 +0200

    NIFI-9916: ListenTrapSNMP USM parsing refactor.
    
    This closes #6034.
    
    Signed-off-by: Tamas Palfy <tp...@apache.org>
---
 .../src/main/resources/META-INF/NOTICE             |  23 ++++
 .../nifi-snmp-bundle/nifi-snmp-processors/pom.xml  |   6 +
 .../snmp/configuration/V1TrapConfiguration.java    |  22 ++--
 .../java/org/apache/nifi/snmp/dto/UserDetails.java |  58 ---------
 .../snmp/operations/SNMPTrapReceiverHandler.java   |  40 +------
 .../nifi/snmp/processors/ListenTrapSNMP.java       | 129 +++++++++++++++++++--
 .../properties/V3SecurityProperties.java           |   6 +-
 .../apache/nifi/snmp/utils/JsonFileUsmReader.java  |  49 ++++++++
 .../org/apache/nifi/snmp/utils/JsonUsmReader.java  |  41 +++++++
 .../nifi/snmp/utils/SecurityNamesUsmReader.java    |  42 +++++++
 .../org/apache/nifi/snmp/utils/UsmJsonParser.java  |  47 ++++++++
 .../java/org/apache/nifi/snmp/utils/UsmReader.java |  26 +++++
 .../nifi/snmp/utils/UsmUserDeserializer.java       |  82 +++++++++++++
 .../additionalDetails.html                         |   5 +-
 .../configuration/V1TrapConfigurationTest.java     |  30 ++---
 .../testrunners/SNMPV3TestRunnerFactory.java       |   2 +-
 .../operations/SNMPTrapReceiverHandlerTest.java    |  68 +++--------
 .../nifi/snmp/utils/JsonFileUsmReaderTest.java     |  50 ++++++++
 .../apache/nifi/snmp/utils/JsonUsmReaderTest.java  |  63 ++++++++++
 .../nifi/snmp/utils/JsonUsmReaderTestBase.java     |  52 +++++++++
 .../snmp/utils/SecurityNamesUsmReaderTest.java     |  53 +++++++++
 .../resources/{users.json => invalid_users.json}   |   6 +-
 .../src/test/resources/users.json                  |   4 +-
 23 files changed, 710 insertions(+), 194 deletions(-)

diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-nar/src/main/resources/META-INF/NOTICE b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-nar/src/main/resources/META-INF/NOTICE
index 8dde122c7b..1ba904292a 100644
--- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-nar/src/main/resources/META-INF/NOTICE
+++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-nar/src/main/resources/META-INF/NOTICE
@@ -22,3 +22,26 @@ The following binary components are provided under the Apache Software License v
 
       This product includes software from the Spring Framework,
       under the Apache License 2.0 (see: StringUtils.containsWhitespace())
+
+  (ASLv2) Jackson JSON processor
+      The following NOTICE information applies:
+        # Jackson JSON processor
+
+        Jackson is a high-performance, Free/Open Source JSON processing library.
+        It was originally written by Tatu Saloranta (tatu.saloranta@iki.fi), and has
+        been in development since 2007.
+        It is currently developed by a community of developers, as well as supported
+        commercially by FasterXML.com.
+
+        ## Licensing
+
+        Jackson core and extension components may licensed under different licenses.
+        To find the details that apply to this artifact see the accompanying LICENSE file.
+        For more information, including possible other licensing options, contact
+        FasterXML.com (http://fasterxml.com).
+
+        ## Credits
+
+        A list of contributors may be found from CREDITS file, which is included
+        in some artifacts (usually source distributions); but is always available
+        from the source code management (SCM) system project uses.
diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/pom.xml b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/pom.xml
index 81d95301e2..0cc6a3c0bc 100644
--- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/pom.xml
+++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/pom.xml
@@ -55,6 +55,12 @@ language governing permissions and limitations under the License. -->
             <groupId>com.fasterxml.jackson.core</groupId>
             <artifactId>jackson-databind</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-json-utils</artifactId>
+            <version>1.17.0-SNAPSHOT</version>
+            <scope>compile</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/V1TrapConfiguration.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/V1TrapConfiguration.java
index 896b0d9728..1e77fabdb0 100644
--- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/V1TrapConfiguration.java
+++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/V1TrapConfiguration.java
@@ -20,6 +20,14 @@ import org.apache.nifi.util.StringUtils;
 
 public class V1TrapConfiguration {
 
+    static final String ENTERPRISE_OID_MUST_BE_SPECIFIED = "Enterprise OID must be specified.";
+    static final String AGENT_ADDRESS_MUST_BE_SPECIFIED = "Agent address must be specified.";
+    public static final String GENERIC_TRAP_TYPE_MUST_BE_BETWEEN_0_AND_6 = "Generic Trap Type must be between 0 and 6.";
+    public static final String GENERIC_TRAP_TYPE_IS_NOT_A_NUMBER = "Generic Trap Type is not a number.";
+    public static final String SPECIFIC_TRAP_TYPE_MUST_BE_BETWEEN_0_AND_2147483647 = "Specific Trap Type must be between 0 and 2147483647.";
+    public static final String GENERIC_TRAP_TYPE_IS_6_ENTERPRISE_SPECIFIC_BUT_SPECIFIC_TRAP_TYPE_IS_NOT_PROVIDED = "Generic Trap Type is [6 - Enterprise Specific]" +
+            " but Specific Trap Type is not provided or not a number.";
+
     private final String enterpriseOid;
     private final String agentAddress;
     private final String genericTrapType;
@@ -83,33 +91,31 @@ public class V1TrapConfiguration {
 
         public V1TrapConfiguration build() {
             if (StringUtils.isEmpty(enterpriseOid)) {
-                throw new IllegalArgumentException("Enterprise OID must be specified.");
+                throw new IllegalArgumentException(ENTERPRISE_OID_MUST_BE_SPECIFIED);
             }
             if (StringUtils.isEmpty(agentAddress)) {
-                throw new IllegalArgumentException("Agent address must be specified.");
+                throw new IllegalArgumentException(AGENT_ADDRESS_MUST_BE_SPECIFIED);
             }
 
             final int parsedGenericTrapType;
             try {
                 parsedGenericTrapType = Integer.parseInt(genericTrapType);
                 if (parsedGenericTrapType < 0 || parsedGenericTrapType > 6) {
-                    throw new IllegalArgumentException("Generic Trap Type must be between 0 and 6.");
+                    throw new IllegalArgumentException(GENERIC_TRAP_TYPE_MUST_BE_BETWEEN_0_AND_6);
                 }
             } catch (NumberFormatException e) {
-                throw new IllegalArgumentException("Generic Trap Type is not a number.");
+                throw new IllegalArgumentException(GENERIC_TRAP_TYPE_IS_NOT_A_NUMBER);
             }
 
             if (parsedGenericTrapType == 6) {
                 try {
                     final int parsedSpecificTrapType = Integer.parseInt(specificTrapType);
                     if (parsedSpecificTrapType < 0) {
-                        throw new IllegalArgumentException("Specific Trap Type must be between 0 and 2147483647.");
+                        throw new IllegalArgumentException(SPECIFIC_TRAP_TYPE_MUST_BE_BETWEEN_0_AND_2147483647);
                     }
                 } catch (NumberFormatException e) {
-                    throw new IllegalArgumentException("Generic Trap Type is [6 - Enterprise Specific] but Specific Trap Type is not provided or not a number.");
+                    throw new IllegalArgumentException(GENERIC_TRAP_TYPE_IS_6_ENTERPRISE_SPECIFIC_BUT_SPECIFIC_TRAP_TYPE_IS_NOT_PROVIDED);
                 }
-            } else if (StringUtils.isNotEmpty(specificTrapType)) {
-                throw new IllegalArgumentException("Invalid argument: Generic Trap Type is not [6 - Enterprise Specific] but Specific Trap Type is provided.");
             }
             return new V1TrapConfiguration(this);
         }
diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/dto/UserDetails.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/dto/UserDetails.java
deleted file mode 100644
index 26cc9ff5b1..0000000000
--- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/dto/UserDetails.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.nifi.snmp.dto;
-
-public class UserDetails {
-
-    private String securityName;
-    private String authProtocol;
-    private String authPassphrase;
-    private String privProtocol;
-    private String privPassphrase;
-
-    public UserDetails() {
-    }
-
-    public UserDetails(final String securityName, final String authProtocol, final String authPassphrase,
-                       final String privProtocol, final String privPassphrase) {
-        this.securityName = securityName;
-        this.authProtocol = authProtocol;
-        this.authPassphrase = authPassphrase;
-        this.privProtocol = privProtocol;
-        this.privPassphrase = privPassphrase;
-    }
-
-    public String getSecurityName() {
-        return securityName;
-    }
-
-    public String getAuthProtocol() {
-        return authProtocol;
-    }
-
-    public String getAuthPassphrase() {
-        return authPassphrase;
-    }
-
-    public String getPrivProtocol() {
-        return privProtocol;
-    }
-
-    public String getPrivPassphrase() {
-        return privPassphrase;
-    }
-}
diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SNMPTrapReceiverHandler.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SNMPTrapReceiverHandler.java
index 53b1ff2eda..85cec04281 100644
--- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SNMPTrapReceiverHandler.java
+++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SNMPTrapReceiverHandler.java
@@ -16,16 +16,11 @@
  */
 package org.apache.nifi.snmp.operations;
 
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.nifi.logging.ComponentLog;
 import org.apache.nifi.processor.ProcessSessionFactory;
 import org.apache.nifi.processor.exception.ProcessException;
 import org.apache.nifi.snmp.configuration.SNMPConfiguration;
-import org.apache.nifi.snmp.dto.UserDetails;
 import org.apache.nifi.snmp.factory.core.SNMPManagerFactory;
-import org.apache.nifi.snmp.utils.SNMPUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.snmp4j.Snmp;
@@ -38,24 +33,21 @@ import org.snmp4j.security.UsmUser;
 import org.snmp4j.smi.Integer32;
 import org.snmp4j.smi.OctetString;
 
-import java.io.File;
-import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.List;
-import java.util.Scanner;
 
 public class SNMPTrapReceiverHandler {
 
     private static final Logger logger = LoggerFactory.getLogger(SNMPTrapReceiverHandler.class);
 
     private final SNMPConfiguration configuration;
-    private final String usmUsersFilePath;
+    private final List<UsmUser> usmUsers;
     private Snmp snmpManager;
     private boolean isStarted;
 
-    public SNMPTrapReceiverHandler(final SNMPConfiguration configuration, final String usmUsersFilePath) {
+    public SNMPTrapReceiverHandler(final SNMPConfiguration configuration, final List<UsmUser> usmUsers) {
         this.configuration = configuration;
-        this.usmUsersFilePath = usmUsersFilePath;
+        this.usmUsers = usmUsers;
         snmpManager = new SNMPManagerFactory().createSnmpManagerInstance(configuration);
     }
 
@@ -89,34 +81,10 @@ public class SNMPTrapReceiverHandler {
         if (configuration.getVersion() == SnmpConstants.version3) {
             USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0);
             SecurityModels.getInstance().addSecurityModel(usm);
-
-            try (Scanner scanner = new Scanner(new File(usmUsersFilePath))) {
-                final String content = scanner.useDelimiter("\\Z").next();
-                final ObjectMapper mapper = new ObjectMapper();
-                final List<UserDetails> userDetails = mapper.readValue(content, new TypeReference<List<UserDetails>>() {
-                });
-                userDetails.stream()
-                        .map(this::convertToUsmUser)
-                        .forEach(user -> snmpManager.getUSM().addUser(user));
-
-            } catch (FileNotFoundException e) {
-                throw new ProcessException("USM user file not found, please check the file path and file permissions.", e);
-            } catch (JsonProcessingException e) {
-                throw new ProcessException("Could not parse USM user file, please check the processor details for examples.", e);
-            }
+            usmUsers.forEach(user -> snmpManager.getUSM().addUser(user));
         }
     }
 
-    private UsmUser convertToUsmUser(final UserDetails user) {
-        return new UsmUser(
-                new OctetString(user.getSecurityName()),
-                SNMPUtils.getAuth(user.getAuthProtocol()),
-                new OctetString(user.getAuthPassphrase()),
-                SNMPUtils.getPriv(user.getPrivProtocol()),
-                new OctetString(user.getPrivPassphrase())
-        );
-    }
-
     // Visible for testing.
     void setSnmpManager(final Snmp snmpManager) {
         this.snmpManager = snmpManager;
diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/ListenTrapSNMP.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/ListenTrapSNMP.java
index b36ff7d226..26931bb458 100644
--- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/ListenTrapSNMP.java
+++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/ListenTrapSNMP.java
@@ -23,23 +23,37 @@ import org.apache.nifi.annotation.documentation.CapabilityDescription;
 import org.apache.nifi.annotation.documentation.Tags;
 import org.apache.nifi.annotation.lifecycle.OnScheduled;
 import org.apache.nifi.annotation.lifecycle.OnStopped;
+import org.apache.nifi.components.AllowableValue;
+import org.apache.nifi.components.ConfigVerificationResult;
 import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.components.resource.ResourceCardinality;
+import org.apache.nifi.components.resource.ResourceType;
 import org.apache.nifi.flowfile.FlowFile;
+import org.apache.nifi.logging.ComponentLog;
 import org.apache.nifi.processor.AbstractSessionFactoryProcessor;
 import org.apache.nifi.processor.ProcessContext;
 import org.apache.nifi.processor.ProcessSessionFactory;
 import org.apache.nifi.processor.Relationship;
+import org.apache.nifi.processor.VerifiableProcessor;
+import org.apache.nifi.processor.util.JsonValidator;
 import org.apache.nifi.processor.util.StandardValidators;
 import org.apache.nifi.snmp.configuration.SNMPConfiguration;
 import org.apache.nifi.snmp.operations.SNMPTrapReceiverHandler;
 import org.apache.nifi.snmp.processors.properties.BasicProperties;
 import org.apache.nifi.snmp.processors.properties.V3SecurityProperties;
+import org.apache.nifi.snmp.utils.JsonFileUsmReader;
+import org.apache.nifi.snmp.utils.JsonUsmReader;
 import org.apache.nifi.snmp.utils.SNMPUtils;
+import org.apache.nifi.snmp.utils.SecurityNamesUsmReader;
+import org.apache.nifi.snmp.utils.UsmReader;
+import org.snmp4j.security.UsmUser;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -54,25 +68,60 @@ import java.util.Set;
 @WritesAttribute(attribute = SNMPUtils.SNMP_PROP_PREFIX + "*", description = "Attributes retrieved from the SNMP response. It may include:"
         + " snmp$errorIndex, snmp$errorStatus, snmp$errorStatusText, snmp$nonRepeaters, snmp$requestID, snmp$type, snmp$variableBindings")
 @RequiresInstanceClassLoading
-public class ListenTrapSNMP extends AbstractSessionFactoryProcessor {
+public class ListenTrapSNMP extends AbstractSessionFactoryProcessor implements VerifiableProcessor {
+
+    public static final AllowableValue USM_JSON_FILE_PATH = new AllowableValue("usm-json-file-path", "Json File Path", "The path of the JSON file containing the USM users");
+    public static final AllowableValue USM_JSON_CONTENT = new AllowableValue("usm-json-content", "Json Content", "The JSON containing the USM users");
+    public static final AllowableValue USM_SECURITY_NAMES = new AllowableValue("usm-security-names", "Security Names", "In case of noAuthNoPriv security level" +
+            " - the list of security names separated by commas");
 
     public static final PropertyDescriptor SNMP_MANAGER_PORT = new PropertyDescriptor.Builder()
             .name("snmp-manager-port")
             .displayName("SNMP Manager Port")
             .description("The port where the SNMP Manager listens to the incoming traps.")
             .required(true)
-            .defaultValue("0")
             .addValidator(StandardValidators.PORT_VALIDATOR)
             .build();
 
-    public static final PropertyDescriptor SNMP_USM_USERS_FILE_PATH = new PropertyDescriptor.Builder()
+    public static final PropertyDescriptor SNMP_USM_USER_SOURCE = new PropertyDescriptor.Builder()
+            .name("snmp-usm-users-source")
+            .displayName("USM Users Source")
+            .description("The ways to provide USM User data")
+            .required(true)
+            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+            .allowableValues(USM_JSON_CONTENT, USM_JSON_FILE_PATH, USM_SECURITY_NAMES)
+            .dependsOn(BasicProperties.SNMP_VERSION, BasicProperties.SNMP_V3)
+            .build();
+
+    public static final PropertyDescriptor SNMP_USM_USERS_JSON_FILE_PATH = new PropertyDescriptor.Builder()
             .name("snmp-usm-users-file-path")
-            .displayName("SNMP Users File Path")
+            .displayName("USM Users JSON File Path")
             .description("The path of the json file containing the user credentials for SNMPv3. Check Usage for more details.")
-            .required(true)
-            .defaultValue("")
+            .required(false)
+            .identifiesExternalResource(ResourceCardinality.SINGLE, ResourceType.FILE)
             .dependsOn(BasicProperties.SNMP_VERSION, BasicProperties.SNMP_V3)
-            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+            .dependsOn(SNMP_USM_USER_SOURCE, USM_JSON_FILE_PATH)
+            .build();
+
+    public static final PropertyDescriptor SNMP_USM_USERS_JSON = new PropertyDescriptor.Builder()
+            .name("snmp-usm-users-json-content")
+            .displayName("USM Users JSON content")
+            .description("The JSON containing the user credentials for SNMPv3. Check Usage for more details.")
+            .required(false)
+            .dependsOn(BasicProperties.SNMP_VERSION, BasicProperties.SNMP_V3)
+            .dependsOn(SNMP_USM_USER_SOURCE, USM_JSON_CONTENT)
+            .addValidator(JsonValidator.INSTANCE)
+            .build();
+
+    public static final PropertyDescriptor SNMP_USM_SECURITY_NAMES = new PropertyDescriptor.Builder()
+            .name("snmp-usm-security-names")
+            .displayName("SNMP Users Security Names")
+            .description("Security names listed separated by commas in SNMPv3. Check Usage for more details.")
+            .required(false)
+            .dependsOn(BasicProperties.SNMP_VERSION, BasicProperties.SNMP_V3)
+            .dependsOn(V3SecurityProperties.SNMP_SECURITY_LEVEL, V3SecurityProperties.NO_AUTH_NO_PRIV)
+            .dependsOn(SNMP_USM_USER_SOURCE, USM_SECURITY_NAMES)
+            .addValidator(StandardValidators.NON_BLANK_VALIDATOR)
             .build();
 
     public static final Relationship REL_SUCCESS = new Relationship.Builder()
@@ -90,7 +139,10 @@ public class ListenTrapSNMP extends AbstractSessionFactoryProcessor {
             BasicProperties.SNMP_VERSION,
             BasicProperties.SNMP_COMMUNITY,
             V3SecurityProperties.SNMP_SECURITY_LEVEL,
-            SNMP_USM_USERS_FILE_PATH
+            SNMP_USM_USER_SOURCE,
+            SNMP_USM_USERS_JSON_FILE_PATH,
+            SNMP_USM_USERS_JSON,
+            SNMP_USM_SECURITY_NAMES
     ));
 
     private static final Set<Relationship> RELATIONSHIPS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
@@ -99,22 +151,59 @@ public class ListenTrapSNMP extends AbstractSessionFactoryProcessor {
     )));
 
     private volatile SNMPTrapReceiverHandler snmpTrapReceiverHandler;
+    private volatile List<UsmUser> usmUsers;
+
+
+    @Override
+    public List<ConfigVerificationResult> verify(ProcessContext context, ComponentLog verificationLogger, Map<String, String> attributes) {
+        final List<ConfigVerificationResult> results = new ArrayList<>();
+
+        final String usmUserSource = context.getProperty(SNMP_USM_USER_SOURCE).getValue();
+
+        if (usmUserSource != null) {
+            final UsmReader usmReader = getUsmReader(context, usmUserSource);
+
+            try {
+                if (usmReader != null) {
+                    usmReader.readUsm();
+                }
+            } catch (Exception e) {
+                results.add(new ConfigVerificationResult.Builder()
+                        .verificationStepName("USM User processing")
+                        .outcome(ConfigVerificationResult.Outcome.FAILED)
+                        .explanation(e.getMessage() + " " + e.getCause().getMessage())
+                        .build());
+            }
+        }
+        return results;
+    }
 
     @OnScheduled
     public void initSnmpManager(ProcessContext context) {
         final int version = SNMPUtils.getVersion(context.getProperty(BasicProperties.SNMP_VERSION).getValue());
         final int managerPort = context.getProperty(SNMP_MANAGER_PORT).asInteger();
-        final String usmUsersFilePath = context.getProperty(SNMP_USM_USERS_FILE_PATH).getValue();
+        final String securityLevel = context.getProperty(V3SecurityProperties.SNMP_SECURITY_LEVEL).getValue();
+
         SNMPConfiguration configuration;
 
         configuration = SNMPConfiguration.builder()
                 .setManagerPort(managerPort)
                 .setVersion(version)
-                .setSecurityLevel(context.getProperty(V3SecurityProperties.SNMP_SECURITY_LEVEL).getValue())
+                .setSecurityLevel(securityLevel)
                 .setCommunityString(context.getProperty(BasicProperties.SNMP_COMMUNITY).getValue())
                 .build();
 
-        snmpTrapReceiverHandler = new SNMPTrapReceiverHandler(configuration, usmUsersFilePath);
+        final String usmUserSource = context.getProperty(SNMP_USM_USER_SOURCE).getValue();
+
+        if (usmUserSource != null) {
+            final UsmReader usmReader = getUsmReader(context, usmUserSource);
+            if (usmReader != null) {
+                usmUsers = usmReader.readUsm();
+            }
+
+        }
+
+        snmpTrapReceiverHandler = new SNMPTrapReceiverHandler(configuration, usmUsers);
     }
 
     @Override
@@ -122,6 +211,7 @@ public class ListenTrapSNMP extends AbstractSessionFactoryProcessor {
         if (!snmpTrapReceiverHandler.isStarted()) {
             snmpTrapReceiverHandler.createTrapReceiver(processSessionFactory, getLogger());
         }
+        context.yield();
     }
 
     @OnStopped
@@ -140,4 +230,21 @@ public class ListenTrapSNMP extends AbstractSessionFactoryProcessor {
     protected List<PropertyDescriptor> getSupportedPropertyDescriptors() {
         return PROPERTY_DESCRIPTORS;
     }
+
+    private UsmReader getUsmReader(ProcessContext context, String usmUserSource) {
+        final String usmUsersJsonFilePath = context.getProperty(SNMP_USM_USERS_JSON_FILE_PATH).getValue();
+        final String usmUsersJson = context.getProperty(SNMP_USM_USERS_JSON).getValue();
+        final String usmSecurityNames = context.getProperty(SNMP_USM_SECURITY_NAMES).getValue();
+
+        UsmReader usmReader = null;
+
+        if (USM_JSON_FILE_PATH.getValue().equals(usmUserSource)) {
+            usmReader = new JsonFileUsmReader(usmUsersJsonFilePath);
+        } else if (USM_JSON_CONTENT.getValue().equals(usmUserSource)) {
+            usmReader = new JsonUsmReader(usmUsersJson);
+        } else if (USM_SECURITY_NAMES.getValue().equals(usmUserSource)) {
+            usmReader = new SecurityNamesUsmReader(usmSecurityNames);
+        }
+        return usmReader;
+    }
 }
diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/properties/V3SecurityProperties.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/properties/V3SecurityProperties.java
index 07688d7b15..412f75892a 100644
--- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/properties/V3SecurityProperties.java
+++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/properties/V3SecurityProperties.java
@@ -36,11 +36,11 @@ public class V3SecurityProperties {
 
     // SNMPv3 security levels
     public static final AllowableValue NO_AUTH_NO_PRIV = new AllowableValue(SecurityLevel.noAuthNoPriv.name(), SecurityLevel.noAuthNoPriv.name(),
-            "No authentication or encryption.");
+            "Communication without authentication and privacy.");
     public static final AllowableValue AUTH_NO_PRIV = new AllowableValue(SecurityLevel.authNoPriv.name(), SecurityLevel.authNoPriv.name(),
-            "Authentication without encryption.");
+            "Communication with authentication and without privacy.");
     public static final AllowableValue AUTH_PRIV = new AllowableValue(SecurityLevel.authPriv.name(), SecurityLevel.authPriv.name(),
-            "Authentication and encryption.");
+            "Communication with authentication and privacy.");
 
     // SNMPv3 authentication protocols
     public static final AllowableValue MD5 = new AllowableValue("MD5", "MD5",
diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/utils/JsonFileUsmReader.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/utils/JsonFileUsmReader.java
new file mode 100644
index 0000000000..b0705cf2b9
--- /dev/null
+++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/utils/JsonFileUsmReader.java
@@ -0,0 +1,49 @@
+/*
+ * 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.nifi.snmp.utils;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import org.apache.nifi.processor.exception.ProcessException;
+import org.snmp4j.security.UsmUser;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.List;
+import java.util.Scanner;
+
+public class JsonFileUsmReader implements UsmReader {
+
+    private final String usmUsersFilePath;
+
+    public JsonFileUsmReader(String usmUsersFilePath) {
+        this.usmUsersFilePath = usmUsersFilePath;
+    }
+
+    @Override
+    public List<UsmUser> readUsm() {
+        final List<UsmUser> userDetails;
+        try (Scanner scanner = new Scanner(new File(usmUsersFilePath))) {
+            final String content = scanner.useDelimiter("\\Z").next();
+            userDetails = UsmJsonParser.parse(content);
+        } catch (FileNotFoundException e) {
+            throw new ProcessException("USM user file not found, please check the file path and file permissions.", e);
+        } catch (JsonProcessingException e) {
+            throw new ProcessException("Could not parse USM user file, please check the processor details for examples.", e);
+        }
+        return userDetails;
+    }
+}
diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/utils/JsonUsmReader.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/utils/JsonUsmReader.java
new file mode 100644
index 0000000000..b23ccd99b9
--- /dev/null
+++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/utils/JsonUsmReader.java
@@ -0,0 +1,41 @@
+/*
+ * 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.nifi.snmp.utils;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import org.apache.nifi.processor.exception.ProcessException;
+import org.snmp4j.security.UsmUser;
+
+import java.util.List;
+
+public class JsonUsmReader implements UsmReader {
+
+    private final String usmUsersJson;
+
+    public JsonUsmReader(String usmUsersJson) {
+        this.usmUsersJson = usmUsersJson;
+    }
+
+    @Override
+    public List<UsmUser> readUsm() {
+        try {
+            return UsmJsonParser.parse(usmUsersJson);
+        } catch (JsonProcessingException e) {
+            throw new ProcessException("Could not parse USM user file, please check the processor details for examples.", e);
+        }
+    }
+}
diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/utils/SecurityNamesUsmReader.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/utils/SecurityNamesUsmReader.java
new file mode 100644
index 0000000000..f742f9abd4
--- /dev/null
+++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/utils/SecurityNamesUsmReader.java
@@ -0,0 +1,42 @@
+/*
+ * 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.nifi.snmp.utils;
+
+import org.snmp4j.security.UsmUser;
+import org.snmp4j.smi.OctetString;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class SecurityNamesUsmReader implements UsmReader {
+
+    private final String usmSecurityNames;
+
+    public SecurityNamesUsmReader(String usmSecurityNames) {
+        this.usmSecurityNames = usmSecurityNames;
+    }
+
+    @Override
+    public List<UsmUser> readUsm() {
+        return Arrays.stream(usmSecurityNames.trim().split(","))
+                .map(securityName -> new UsmUser(
+                        new OctetString(securityName), null, null, null, null)
+                )
+                .collect(Collectors.toList());
+    }
+}
diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/utils/UsmJsonParser.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/utils/UsmJsonParser.java
new file mode 100644
index 0000000000..3b6c98442c
--- /dev/null
+++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/utils/UsmJsonParser.java
@@ -0,0 +1,47 @@
+/*
+ * 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.nifi.snmp.utils;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import org.snmp4j.security.UsmUser;
+
+import java.util.List;
+
+public class UsmJsonParser {
+
+    private UsmJsonParser() {
+        // Utility class, not to instantiate.
+    }
+
+    private static final ObjectMapper MAPPER;
+    private static final SimpleModule MODULE;
+
+    static {
+        MAPPER = new ObjectMapper();
+        MODULE = new SimpleModule();
+        MODULE.addDeserializer(UsmUser.class, new UsmUserDeserializer());
+        MAPPER.registerModule(MODULE);
+    }
+
+    static List<UsmUser> parse(final String json) throws JsonProcessingException {
+        return MAPPER.readValue(json, new TypeReference<List<UsmUser>>() {
+        });
+    }
+}
diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/utils/UsmReader.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/utils/UsmReader.java
new file mode 100644
index 0000000000..02defebe15
--- /dev/null
+++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/utils/UsmReader.java
@@ -0,0 +1,26 @@
+/*
+ * 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.nifi.snmp.utils;
+
+import org.snmp4j.security.UsmUser;
+
+import java.util.List;
+
+public interface UsmReader {
+
+    List<UsmUser> readUsm();
+}
diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/utils/UsmUserDeserializer.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/utils/UsmUserDeserializer.java
new file mode 100644
index 0000000000..f07ccf78a7
--- /dev/null
+++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/utils/UsmUserDeserializer.java
@@ -0,0 +1,82 @@
+/*
+ * 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.nifi.snmp.utils;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import org.snmp4j.security.UsmUser;
+import org.snmp4j.smi.OID;
+import org.snmp4j.smi.OctetString;
+
+import java.io.IOException;
+
+class UsmUserDeserializer extends StdDeserializer<UsmUser> {
+
+    public UsmUserDeserializer() {
+        super((Class<?>) null);
+    }
+
+    @Override
+    public UsmUser deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
+        JsonNode node = jp.getCodec().readTree(jp);
+        String securityName = node.get("securityName").asText();
+
+        OID authProtocol = null;
+        final JsonNode authProtocolNode = node.get("authProtocol");
+        if (authProtocolNode != null) {
+            authProtocol = SNMPUtils.getAuth(authProtocolNode.asText());
+        }
+
+        OctetString authPassphrase = null;
+        final JsonNode authPassphraseNode = node.get("authPassphrase");
+        if (authPassphraseNode != null) {
+            authPassphrase = new OctetString(authPassphraseNode.asText());
+        }
+
+        if (authProtocol != null && authPassphrase == null) {
+            throw new IllegalArgumentException("Authentication passphrase must be set and at least 8 bytes long if" +
+                    "authentication protocol is specified.");
+        }
+
+        OID privProtocol = null;
+        final JsonNode privProtocolNode = node.get("privProtocol");
+        if (privProtocolNode != null) {
+            privProtocol = SNMPUtils.getPriv(privProtocolNode.asText());
+        }
+
+        OctetString privPassphrase = null;
+        final JsonNode privPassphraseNode = node.get("privPassphrase");
+        if (privPassphraseNode != null) {
+            privPassphrase = new OctetString(privPassphraseNode.asText());
+        }
+
+        if (privProtocol != null && privPassphrase == null) {
+            throw new IllegalArgumentException("Privacy passphrase must be set and at least 8 bytes long if" +
+                    "authentication protocol is specified.");
+        }
+
+        return new UsmUser(
+                new OctetString(securityName),
+                authProtocol,
+                authPassphrase,
+                privProtocol,
+                privPassphrase
+        );
+    }
+}
diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/resources/docs/org.apache.nifi.snmp.processors.ListenTrapSNMP/additionalDetails.html b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/resources/docs/org.apache.nifi.snmp.processors.ListenTrapSNMP/additionalDetails.html
index 37aaa668f7..9cffa38cbb 100644
--- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/resources/docs/org.apache.nifi.snmp.processors.ListenTrapSNMP/additionalDetails.html
+++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/resources/docs/org.apache.nifi.snmp.processors.ListenTrapSNMP/additionalDetails.html
@@ -24,10 +24,11 @@
 <h2>Summary</h2>
 <p>
     This processor listens to SNMP traps and creates a flowfile from the trap PDU.
-    The versions SNMPv1, SNMPv2c and SNMPv3 are supproted. The component is based on <a href="http://www.snmp4j.org/">SNMP4J</a>.
+    The versions SNMPv1, SNMPv2c and SNMPv3 are supported. The component is based on <a href="http://www.snmp4j.org/">SNMP4J</a>.
 </p>
 <p>
-    In case of SNMPv3, users can be specified in a json file. E.g.:
+    SNMPv3 has user-based security. The USM Users Source property allows users to choose between three different ways to provide the USM user database.
+    An example json file containing two users:
 <pre>
 <code>
 [
diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/configuration/V1TrapConfigurationTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/configuration/V1TrapConfigurationTest.java
index 1575113165..c7d4e26577 100644
--- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/configuration/V1TrapConfigurationTest.java
+++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/configuration/V1TrapConfigurationTest.java
@@ -20,6 +20,11 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 
+import static org.apache.nifi.snmp.configuration.V1TrapConfiguration.AGENT_ADDRESS_MUST_BE_SPECIFIED;
+import static org.apache.nifi.snmp.configuration.V1TrapConfiguration.ENTERPRISE_OID_MUST_BE_SPECIFIED;
+import static org.apache.nifi.snmp.configuration.V1TrapConfiguration.GENERIC_TRAP_TYPE_IS_6_ENTERPRISE_SPECIFIC_BUT_SPECIFIC_TRAP_TYPE_IS_NOT_PROVIDED;
+import static org.apache.nifi.snmp.configuration.V1TrapConfiguration.GENERIC_TRAP_TYPE_MUST_BE_BETWEEN_0_AND_6;
+import static org.apache.nifi.snmp.configuration.V1TrapConfiguration.SPECIFIC_TRAP_TYPE_MUST_BE_BETWEEN_0_AND_2147483647;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThrows;
 
@@ -51,7 +56,7 @@ public class V1TrapConfigurationTest {
     @Test
     public void testRequireNonNullEnterpriseOid() {
         exceptionRule.expect(IllegalArgumentException.class);
-        exceptionRule.expectMessage("Enterprise OID must be specified.");
+        exceptionRule.expectMessage(ENTERPRISE_OID_MUST_BE_SPECIFIED);
         V1TrapConfiguration.builder()
                 .agentAddress(AGENT_ADDRESS)
                 .genericTrapType(String.valueOf(GENERIC_TRAP_TYPE))
@@ -62,7 +67,7 @@ public class V1TrapConfigurationTest {
     @Test
     public void testRequireNonNullAgentAddress() {
         exceptionRule.expect(IllegalArgumentException.class);
-        exceptionRule.expectMessage("Agent address must be specified.");
+        exceptionRule.expectMessage(AGENT_ADDRESS_MUST_BE_SPECIFIED);
         V1TrapConfiguration.builder()
                 .enterpriseOid(ENTERPRISE_OID)
                 .genericTrapType(String.valueOf(GENERIC_TRAP_TYPE))
@@ -78,7 +83,7 @@ public class V1TrapConfigurationTest {
                 .genericTrapType("-1")
                 .build()
         );
-        assertEquals("Generic Trap Type must be between 0 and 6.", exception.getMessage());
+        assertEquals(GENERIC_TRAP_TYPE_MUST_BE_BETWEEN_0_AND_6, exception.getMessage());
     }
 
     @Test
@@ -89,7 +94,7 @@ public class V1TrapConfigurationTest {
                 .genericTrapType("7")
                 .build()
         );
-        assertEquals("Generic Trap Type must be between 0 and 6.", exception.getMessage());
+        assertEquals(GENERIC_TRAP_TYPE_MUST_BE_BETWEEN_0_AND_6, exception.getMessage());
     }
 
     @Test
@@ -112,7 +117,7 @@ public class V1TrapConfigurationTest {
                 .specificTrapType("-1")
                 .build()
         );
-        assertEquals("Specific Trap Type must be between 0 and 2147483647.", exception.getMessage());
+        assertEquals(SPECIFIC_TRAP_TYPE_MUST_BE_BETWEEN_0_AND_2147483647, exception.getMessage());
     }
 
     @Test
@@ -123,19 +128,6 @@ public class V1TrapConfigurationTest {
                 .genericTrapType(String.valueOf(GENERIC_TRAP_TYPE))
                 .build()
         );
-        assertEquals("Generic Trap Type is [6 - Enterprise Specific] but Specific Trap Type is not provided or not a number.", exception.getMessage());
+        assertEquals(GENERIC_TRAP_TYPE_IS_6_ENTERPRISE_SPECIFIC_BUT_SPECIFIC_TRAP_TYPE_IS_NOT_PROVIDED, exception.getMessage());
     }
-
-    @Test
-    public void testGenericTrapTypeIsNotEnterpriseSpecificButSpecificTrapTypeIsSet() {
-        final IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> V1TrapConfiguration.builder()
-                .agentAddress(AGENT_ADDRESS)
-                .enterpriseOid(ENTERPRISE_OID)
-                .genericTrapType("5")
-                .specificTrapType("123")
-                .build()
-        );
-        assertEquals("Invalid argument: Generic Trap Type is not [6 - Enterprise Specific] but Specific Trap Type is provided.", exception.getMessage());
-    }
-
 }
diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/testrunners/SNMPV3TestRunnerFactory.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/testrunners/SNMPV3TestRunnerFactory.java
index 998766e21f..4dfdd39252 100644
--- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/testrunners/SNMPV3TestRunnerFactory.java
+++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/testrunners/SNMPV3TestRunnerFactory.java
@@ -105,7 +105,7 @@ public class SNMPV3TestRunnerFactory implements SNMPTestRunnerFactory {
         final SNMPConfiguration snmpConfiguration = snmpV3ConfigurationFactory.createSnmpListenTrapConfig(managerPort);
         runner.setProperty(ListenTrapSNMP.SNMP_MANAGER_PORT, String.valueOf(snmpConfiguration.getManagerPort()));
         runner.setProperty(BasicProperties.SNMP_VERSION, getVersionName(snmpConfiguration.getVersion()));
-        runner.setProperty(ListenTrapSNMP.SNMP_USM_USERS_FILE_PATH, USM_USERS_FILE_PATH);
+        runner.setProperty(ListenTrapSNMP.SNMP_USM_USERS_JSON_FILE_PATH, USM_USERS_FILE_PATH);
 
         return runner;
     }
diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPTrapReceiverHandlerTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPTrapReceiverHandlerTest.java
index 25a20eaabd..3759df62b5 100644
--- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPTrapReceiverHandlerTest.java
+++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPTrapReceiverHandlerTest.java
@@ -16,35 +16,28 @@
  */
 package org.apache.nifi.snmp.operations;
 
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.nifi.processor.ProcessSessionFactory;
 import org.apache.nifi.remote.io.socket.NetworkUtils;
 import org.apache.nifi.snmp.configuration.SNMPConfiguration;
-import org.apache.nifi.snmp.dto.UserDetails;
-import org.apache.nifi.snmp.utils.SNMPUtils;
+import org.apache.nifi.snmp.utils.JsonFileUsmReader;
 import org.apache.nifi.util.MockComponentLog;
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
 import org.snmp4j.Snmp;
 import org.snmp4j.mp.SnmpConstants;
 import org.snmp4j.security.USM;
 import org.snmp4j.security.UsmUser;
 
-import java.io.File;
-import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Scanner;
-import java.util.Set;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Answers.RETURNS_DEEP_STUBS;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -95,52 +88,25 @@ public class SNMPTrapReceiverHandlerTest {
     }
 
     @Test
-    public void testAddUsmUsers() throws JsonProcessingException, FileNotFoundException {
-        final Set<String> expectedUserAttributes = new HashSet<>();
-        try (Scanner scanner = new Scanner(new File(USERS_JSON))) {
-            final String content = scanner.useDelimiter("\\Z").next();
-            final ObjectMapper mapper = new ObjectMapper();
-            final List<UserDetails> userDetails = mapper.readValue(content, new TypeReference<List<UserDetails>>() {
-            });
-            userDetails
-                    .forEach(user -> {
-                        expectedUserAttributes.add(user.getSecurityName());
-                        expectedUserAttributes.add(SNMPUtils.getAuth(user.getAuthProtocol()).toString());
-                        expectedUserAttributes.add(user.getAuthPassphrase());
-                        expectedUserAttributes.add(SNMPUtils.getPriv(user.getPrivProtocol()).toString());
-                        expectedUserAttributes.add(user.getPrivPassphrase());
-                    });
-        }
-        final Set<String> usmAttributes = new HashSet<>();
-        final SNMPConfiguration snmpConfiguration = mock(SNMPConfiguration.class);
-        final ProcessSessionFactory mockProcessSessionFactory = mock(ProcessSessionFactory.class);
-        final MockComponentLog mockComponentLog = new MockComponentLog("componentId", new Object());
-        final Snmp mockSnmpManager = mock(Snmp.class);
-        final USM mockUsm = mock(USM.class);
+    public void testAddUsmUsers() {
+        final List<UsmUser> usmUsers = new JsonFileUsmReader(USERS_JSON).readUsm();
 
-        when(snmpConfiguration.getManagerPort()).thenReturn(NetworkUtils.getAvailableUdpPort());
-        when(snmpConfiguration.getVersion()).thenReturn(SnmpConstants.version3);
-        doAnswer(invocation -> {
-            UsmUser usmUser = (UsmUser) invocation.getArgument(0);
-            usmAttributes.add(usmUser.getSecurityName().toString());
-            usmAttributes.add(usmUser.getAuthenticationProtocol().toString());
-            usmAttributes.add(usmUser.getAuthenticationPassphrase().toString());
-            usmAttributes.add(usmUser.getPrivacyProtocol().toString());
-            usmAttributes.add(usmUser.getPrivacyPassphrase().toString());
-            return null;
-        }).when(mockUsm).addUser(any(UsmUser.class));
-        when(mockSnmpManager.getUSM()).thenReturn(mockUsm);
+        final SNMPConfiguration snmpConfiguration = SNMPConfiguration.builder()
+                .setManagerPort(NetworkUtils.getAvailableUdpPort())
+                .setVersion(SnmpConstants.version3)
+                .build();
 
-        final SNMPTrapReceiverHandler trapReceiverHandler = new SNMPTrapReceiverHandler(snmpConfiguration, USERS_JSON);
-        trapReceiverHandler.setSnmpManager(mockSnmpManager);
-        trapReceiverHandler.createTrapReceiver(mockProcessSessionFactory, mockComponentLog);
+        final Snmp mockSnmpManager = mock(Snmp.class, RETURNS_DEEP_STUBS);
+        final ArgumentCaptor<UsmUser> usmUserCaptor = ArgumentCaptor.forClass(UsmUser.class);
 
+        final SNMPTrapReceiverHandler trapReceiverHandler = new SNMPTrapReceiverHandler(snmpConfiguration, usmUsers);
+        trapReceiverHandler.setSnmpManager(mockSnmpManager);
+        trapReceiverHandler.createTrapReceiver(null, null);
 
+        verify(mockSnmpManager.getUSM(), times(2)).addUser(usmUserCaptor.capture());
         verify(mockSnmpManager).addCommandResponder(any(SNMPTrapReceiver.class));
 
         assertTrue(trapReceiverHandler.isStarted());
-
-        assertEquals(expectedUserAttributes, usmAttributes);
+        assertEquals(usmUsers, usmUserCaptor.getAllValues());
     }
-
 }
diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/utils/JsonFileUsmReaderTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/utils/JsonFileUsmReaderTest.java
new file mode 100644
index 0000000000..098bcd334b
--- /dev/null
+++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/utils/JsonFileUsmReaderTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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.nifi.snmp.utils;
+
+import org.apache.nifi.processor.exception.ProcessException;
+import org.junit.jupiter.api.Test;
+import org.snmp4j.security.UsmUser;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class JsonFileUsmReaderTest extends JsonUsmReaderTestBase {
+
+    @Test
+    void testReadJsonFile() {
+        final UsmReader jsonFileUsmReader = new JsonFileUsmReader(USERS_JSON_PATH);
+        final List<UsmUser> usmUsers = jsonFileUsmReader.readUsm();
+
+        assertEquals(expectedUsmUsers, usmUsers);
+    }
+
+    @Test
+    void testReadJsonFileThrowsException() {
+        final UsmReader jsonFileUsmReader = new JsonFileUsmReader(NOT_FOUND_USERS_JSON_PATH);
+        assertThrows(ProcessException.class, jsonFileUsmReader::readUsm);
+    }
+
+    @Test
+    void testReadInvalidJsonThrowsException() {
+        final UsmReader jsonFileUsmReader = new JsonFileUsmReader(INVALID_USERS_JSON_PATH);
+        assertThrows(ProcessException.class, jsonFileUsmReader::readUsm);
+    }
+
+}
diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/utils/JsonUsmReaderTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/utils/JsonUsmReaderTest.java
new file mode 100644
index 0000000000..8e36a4bdda
--- /dev/null
+++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/utils/JsonUsmReaderTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.nifi.snmp.utils;
+
+import org.apache.nifi.processor.exception.ProcessException;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.snmp4j.security.UsmUser;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class JsonUsmReaderTest extends JsonUsmReaderTestBase {
+
+    private static String USERS_JSON;
+    private static String INVALID_USERS_JSON;
+
+    @BeforeAll
+    public static void setup() throws IOException {
+        USERS_JSON = readFile(USERS_JSON_PATH);
+        INVALID_USERS_JSON = readFile(INVALID_USERS_JSON_PATH);
+    }
+
+    @Test
+    void testReadJson() {
+        final UsmReader jsonUsmReader = new JsonUsmReader(USERS_JSON);
+        final List<UsmUser> usmUsers = jsonUsmReader.readUsm();
+
+        assertEquals(expectedUsmUsers, usmUsers);
+    }
+
+    @Test
+    void testReadInvalidJsonThrowsException() {
+        final UsmReader jsonUsmReader = new JsonUsmReader(INVALID_USERS_JSON);
+        assertThrows(ProcessException.class, jsonUsmReader::readUsm);
+    }
+
+    static String readFile(String path) throws IOException {
+        byte[] encoded = Files.readAllBytes(Paths.get(path));
+        return new String(encoded, StandardCharsets.UTF_8);
+    }
+
+}
diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/utils/JsonUsmReaderTestBase.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/utils/JsonUsmReaderTestBase.java
new file mode 100644
index 0000000000..82402d0503
--- /dev/null
+++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/utils/JsonUsmReaderTestBase.java
@@ -0,0 +1,52 @@
+/*
+ * 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.nifi.snmp.utils;
+
+import org.snmp4j.security.UsmUser;
+import org.snmp4j.smi.OID;
+import org.snmp4j.smi.OctetString;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class JsonUsmReaderTestBase {
+
+    static final String USERS_JSON_PATH = "src/test/resources/users.json";
+    static final String NOT_FOUND_USERS_JSON_PATH = "src/test/resources/not_found.json";
+    static final String INVALID_USERS_JSON_PATH = "src/test/resources/invalid_users.json";
+
+    static final List<UsmUser> expectedUsmUsers;
+
+    static {
+        expectedUsmUsers = new ArrayList<>();
+        expectedUsmUsers.add(new UsmUser(
+                new OctetString("user1"),
+                new OID("1.3.6.1.6.3.10.1.1.2"),
+                new OctetString("abc12345"),
+                new OID("1.3.6.1.6.3.10.1.2.2"),
+                new OctetString("abc12345")
+        ));
+        expectedUsmUsers.add(new UsmUser(
+                new OctetString("user2"),
+                new OID("1.3.6.1.6.3.10.1.1.3"),
+                new OctetString("abc12345"),
+                new OID("1.3.6.1.4.1.4976.2.2.1.1.2"),
+                new OctetString("abc12345")
+        ));
+    }
+
+}
diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/utils/SecurityNamesUsmReaderTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/utils/SecurityNamesUsmReaderTest.java
new file mode 100644
index 0000000000..1a1d590b0c
--- /dev/null
+++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/utils/SecurityNamesUsmReaderTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.nifi.snmp.utils;
+
+import org.junit.jupiter.api.Test;
+import org.snmp4j.security.UsmUser;
+import org.snmp4j.smi.OctetString;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class SecurityNamesUsmReaderTest {
+
+    @Test
+    void testReadJson() {
+        final List<UsmUser> expectedUsmUsers = new ArrayList<>();
+        expectedUsmUsers.add(new UsmUser(
+                new OctetString("user1"),
+                null,
+                null,
+                null,
+                null
+        ));
+        expectedUsmUsers.add(new UsmUser(
+                new OctetString("user2"),
+                null,
+                null,
+                null,
+                null
+        ));
+        final String securityNames = "user1,user2";
+        final UsmReader securityNamesUsmReader = new SecurityNamesUsmReader(securityNames);
+        final List<UsmUser> usmUsers = securityNamesUsmReader.readUsm();
+
+        assertEquals(expectedUsmUsers, usmUsers);
+    }
+}
diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/resources/users.json b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/resources/invalid_users.json
similarity index 69%
copy from nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/resources/users.json
copy to nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/resources/invalid_users.json
index b6ce71a154..806440382b 100644
--- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/resources/users.json
+++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/resources/invalid_users.json
@@ -1,14 +1,14 @@
 [
   {
     "securityName":"user1",
-    "authProtocol":"MD5",
+    "authProtocol":"INVALID",
     "authPassphrase":"abc12345",
     "privProtocol":"DES",
     "privPassphrase":"abc12345"
   },
   {
-    "securityName":"newUser2",
-    "authProtocol":"MD5",
+    "securityName":"user2",
+    "authProtocol":"SHA",
     "authPassphrase":"abc12345",
     "privProtocol":"AES256",
     "privPassphrase":"abc12345"
diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/resources/users.json b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/resources/users.json
index b6ce71a154..113586e9c8 100644
--- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/resources/users.json
+++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/resources/users.json
@@ -7,8 +7,8 @@
     "privPassphrase":"abc12345"
   },
   {
-    "securityName":"newUser2",
-    "authProtocol":"MD5",
+    "securityName":"user2",
+    "authProtocol":"SHA",
     "authPassphrase":"abc12345",
     "privProtocol":"AES256",
     "privPassphrase":"abc12345"