FreeRADIUS 3.0.26 / rlm_perl_privacyidea: Persistent "wrong otp pin" after successful token resync (AD password ends in symbols)

Hello FreeRADIUS and PrivacyIDEA communities,

I am setting up PrivacyIDEA (v3.11.1) with FreeRADIUS (v3.0.26, Ubuntu 22.04.5 TLS) to provide AD + TOTP authentication for a SonicWall SSL VPN. I am using the native Perl-based rlm_privacyidea module installed via the privacyidea-radius package (v3.4.3).

I have encountered a persistent issue where all authentication attempts fail with the error “RADIUS Authentication Failed” on the SonicWall, and the FreeRADIUS debug logs consistently show Reply-Message = "wrong otp pin" received from the PrivacyIDEA API. The token’s fail counter in the PrivacyIDEA web UI also increases.

Here’s a summary of my setup and debugging steps:

  • Setup:
    • FreeRADIUS is configured to use the native Perl module (rlm_privacyidea via rlm_perl) instantiated as privacyidea in the authorize section of a virtual server (configured in sites-enabled/privacyidea).
    • The Perl module config (/etc/freeradius/3.0/mods-available/privacyidea) uses privacyidea_server = "https://localhost", privacyidea_auth_mode = "totp", and SSL verification is effectively disabled (confirmed in logs: rlm_perl: Not verifying SSL certificate: false).
    • PrivacyIDEA is running on the same server (192.168.1.50) with an AD resolver and TOTP tokens assigned to users.
    • The SonicWall is configured as a RADIUS client sending Access-Request to the FreeRADIUS server (192.168.1.50:1812) using the ADPassword + OTP combined password format and SAMAccountName username format.
  • Debugging Performed (and results):
    • Confirmed network connectivity from SonicWall to FreeRADIUS and from FreeRADIUS to PrivacyIDEA API (https://localhost/validate/check) using curl (API is reachable and responds).
    • Confirmed FreeRADIUS loads the native Perl module correctly (no .so errors after installing privacyidea-radius package).
    • Confirmed PrivacyIDEA API communication is happening during authentication attempts (logs show rlm_perl: url: https://localhost/validate/check, user sent to privacyidea: ..., pass sent to privacyidea: ..., elapsed time: ..., privacyIDEA Result status is true!).
    • Confirmed FreeRADIUS sends the correct username (SAMAccountName) and the complete combined password string to the PrivacyIDEA API via the Perl module.
    • Crucially: Confirmed server time is accurate (NTP synchronized).
    • Crucially: Successfully performed the token resync test in the PrivacyIDEA web UI for the user’s token (entering current and next OTPs).
    • Verified user and token status in PrivacyIDEA (enabled, not locked).
    • Verified the PrivacyIDEA token/policy setting “Prepend the PIN in front of the OTP value” is checked, matching the ADPassword + OTP input format.
  • Specific Observation (Combined Password Format): The AD passwords for the users I’m testing end in symbols immediately followed by digits (e.g., ADPasswordEndingIn!) or ADPasswordEndingIn//). The combined password sent is ADPasswordEndingIn!)OTP or ADPasswordEndingIn//OTP. The logs show the full string being sent to the API.
  • Problem Diagnosis: Given that the PrivacyIDEA API is reached, the combined password string is sent, time is correct, token resync is successful, and the “Prepend” setting is correct, but PrivacyIDEA still returns “wrong otp pin”, I suspect there might be an edge case or a bug in PrivacyIDEA’s combined password splitting (splitToken) or subsequent OTP validation logic when the AD password part ends in symbols (like !, /, etc.) immediately followed by numeric OTP digits. This might cause PrivacyIDEA to incorrectly parse the string or fail the OTP check for that specific password structure.
  • Request for Assistance: Has anyone encountered a similar issue where “wrong otp pin” persists after successful resync, particularly when the AD password ends in symbols just before the OTP? Is this a known limitation or bug in PrivacyIDEA or the rlm_privacyidea module (Perl version)? Are there any further diagnostics I can perform on the PrivacyIDEA side or within the Perl module to pinpoint why the OTP validation is failing for this specific password structure?

I can provide the relevant FreeRADIUS configuration files (/etc/freeradius/3.0/mods-available/privacyidea, /etc/freeradius/3.0/sites-enabled/privacyidea) and full sudo freeradius -X debug logs upon request.

Thank you for your time and any insights you can provide.

Running freeradius in debug mode (freeradius -X) will also output the UserPasswort field.
Check, to which value this is decrypted by FreeRADIUS. In the past there have been issues with the encoding of special characters in the freeradius privacyidea module.

Okay, here is the reply in English to the community member, including the crucial information about the OTP-only success.


Thank you for your suggestion.

We have indeed run freeradius -X and checked the User-Password field in the debug output for attempts using the combined ADPassword + OTP.

The logs confirm that FreeRADIUS successfully decrypts the password from the SonicWall, and the User-Password field in the debug output shows the full, correct combined password string, including the symbols at the end of the AD password (e.g., User-Password = "test1234$$//095085"). ← ad password: test1234$$//
This suggests the basic RADIUS decryption from the SonicWall is working as expected.

However, we’ve discovered a critical, paradoxical behavior:

  • When we perform the RADIUS test from the SonicWall using the combined ADPassword + currentOTP, it fails with “wrong otp pin” in the PrivacyIDEA response (as noted in my initial post).
  • But, when we perform the RADIUS test from the SonicWall using ONLY the 6-digit currentOTP in the password field, the authentication unexpectedly succeeds. The FreeRADIUS logs show only the OTP being sent as User-Password, and PrivacyIDEA returns ACCESS GRANTED. We have also confirmed this behavior in a real NetExtender VPN login attempt – authenticating with only the OTP succeeds, while the combined password fails.

This behavior (succeeding with OTP-only) is not the intended function for an AD+OTP combined password setup where both factors should be required.

Given that FreeRADIUS is receiving the correct combined password string, and authentication succeeds when only the OTP is sent, this strongly suggests the issue lies within the rlm_privacyidea Perl module’s processing of the combined string, or more likely, PrivacyIDEA’s handling of the pass parameter in the /validate/check API when it contains a combined password (especially one where the AD password part ends in symbols), causing it to fail, while processing just the OTP works differently.

We can provide the FreeRADIUS debug logs showing both the failed combined login attempts (with the full decrypted password visible) and the successful OTP-only login attempts if that would be helpful.

Thank you for your time and further assistance.

Following up on my previous posts regarding the “wrong otp pin” issue with combined AD+OTP authentication in PrivacyIDEA 3.11.2 via FreeRADIUS.

I am happy to report that I have found the solution! In the PrivacyIDEA web UI, under Policies, on the Action tab of a relevant policy, I changed a setting related to the authentication outcome or PIN handling to ‘userstone’ (I suspect this corresponds to the ‘userstore’ setting for validating the PIN against the user backend).

After making this change, authentication using the combined ADPassword + currentOTP now works correctly, both in the SonicWall RADIUS test and NetExtender login.

Thank you very much for your time and assistance in debugging this complex issue. Your guidance helped significantly in narrowing down the problem to the PrivacyIDEA policy configuration.

1 Like

I was also realizing you are missing this one:

Thank you for your precise description and also for posting your finding/solution.