Skip to content

Commit

Permalink
Make LCD reconfigure V3 users when auth data changes.
Browse files Browse the repository at this point in the history
`CommandGeneratorLcdConfigurator` configures auth data and caches based
on `(username, security engine id)`. If the authentication data is
changed, such as via `usmUserAuthKeyChange`, the cache is not updated
because neither the username nor engine ID changed. Despite new data
being passed in, this results in the old data being used and a "Wrong
SNMP PDU digest" error indication being returned.

Change the LCD to detect a changed authKey, authProtocol, privKey, or
privProtocol and reconfigure the V3 user as appropriate.
  • Loading branch information
topnotcher authored and lextm committed Aug 10, 2024
1 parent 71b7439 commit 8df333e
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 0 deletions.
21 changes: 21 additions & 0 deletions pysnmp/hlapi/asyncio/lcd.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,16 @@ def configure(
elif isinstance(authData, UsmUserData):
authDataKey = authData.userName, authData.securityEngineId
if authDataKey not in cache["auth"]:
add_user = True

elif self._usm_auth_changed(cache["auth"][authDataKey], authData):
config.delV3User(snmpEngine, authData.userName, authData.securityEngineId)
add_user = True

else:
add_user = False

if add_user:
config.addV3User(
snmpEngine,
authData.userName,
Expand Down Expand Up @@ -199,6 +209,17 @@ def unconfigure(self, snmpEngine, authData=None, contextName=null, **options):

return addrNames, paramsNames

@staticmethod
def _usm_auth_changed(cachedAuthData, newAuthData):
changed = False

changed |= (cachedAuthData.authKey != newAuthData.authKey)
changed |= (cachedAuthData.authProtocol != newAuthData.authProtocol)
changed |= (cachedAuthData.privKey != newAuthData.privKey)
changed |= (cachedAuthData.privProtocol != newAuthData.privProtocol)

return changed


class NotificationOriginatorLcdConfigurator(AbstractLcdConfigurator):
cacheKeys = ["auth", "name"]
Expand Down
78 changes: 78 additions & 0 deletions tests/hlapi/asyncio/manager/cmdgen/test_lcd_configurator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
from unittest import mock

from pysnmp import hlapi
from pysnmp.hlapi.asyncio.cmdgen import CommandGeneratorLcdConfigurator


@mock.patch('pysnmp.entity.config.addV3User')
@mock.patch('pysnmp.entity.config.delV3User')
def test_usm_auth_cache_cleared(delV3User, addV3User):
"""
Ensure auth cache is cleared when auth data is changed.
"""
snmpEngine = hlapi.SnmpEngine()
transportTarget = hlapi.UdpTransportTarget('198.51.100.1')

authDataValues = {
'userName': 'username',
'authKey': 'authkey1',
'authProtocol': hlapi.usmHMACMD5AuthProtocol,
'privKey': 'privkey1',
'privProtocol': hlapi.usmAesCfb128Protocol,
}

lcd = CommandGeneratorLcdConfigurator()
initialAuthData = hlapi.UsmUserData(**authDataValues)
lcd.configure(snmpEngine, initialAuthData, transportTarget)
addV3User.assert_called_with(
snmpEngine,
initialAuthData.userName,
initialAuthData.authProtocol,
initialAuthData.authKey,
initialAuthData.privProtocol,
initialAuthData.privKey,
securityEngineId=initialAuthData.securityEngineId,
securityName=initialAuthData.securityName,
authKeyType=initialAuthData.authKeyType,
privKeyType=initialAuthData.privKeyType,
)

# Ensure we do not add/delete if nothing changes
addV3User.reset_mock()
lcd.configure(snmpEngine, initialAuthData, transportTarget)
addV3User.assert_not_called()
delV3User.assert_not_called()

changeAuthValues = {
'authKey': 'authKey2',
'privProtocol': hlapi.usmDESPrivProtocol,
'authProtocol': hlapi.usmHMACSHAAuthProtocol,
'privKey': 'privKey2',
}

for field, value in changeAuthValues.items():
addV3User.reset_mock()
delV3User.reset_mock()

authDataValues[field] = value
authData = hlapi.UsmUserData(**authDataValues)
lcd.configure(snmpEngine, authData, transportTarget)

delV3User.assert_called_with(
snmpEngine,
authData.userName,
authData.securityEngineId,
)

addV3User.assert_called_with(
snmpEngine,
authData.userName,
authData.authProtocol,
authData.authKey,
authData.privProtocol,
authData.privKey,
securityEngineId=authData.securityEngineId,
securityName=authData.securityName,
authKeyType=authData.authKeyType,
privKeyType=authData.privKeyType,
)

0 comments on commit 8df333e

Please sign in to comment.