Wrong OTP Pin although authentication policy is set to 'otppin': 'none'

Hi,

We don’t use PINs in addition to OTP, and I’m trying to get Privacyidea to work without them, but even if I enrol a new token and set up a PIN, it’s still not working.

When I test the token using curl it’s accepted:
root@privacyidea-new:/etc/freeradius/3.0# curl https://localhost/validate/check --insecure --request GET --data “user=george” --data “pass=811308” | jq
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 883 100 856 100 27 1889 59 --:–:-- --:–:-- --:–:-- 1953

{
  "detail": {
    "message": "matching 1 tokens",
    "otplen": 6,
    "serial": "TOTP0000E9B2",
    "threadid": 139846985991744,
    "type": "totp"
  },
  "id": 2,
  "jsonrpc": "2.0",
  "result": {
    "authentication": "ACCEPT",
    "status": true,
    "value": true
  },
  "time": 1717171164.3988345,
  "version": "privacyIDEA 3.9.2",
  "versionnumber": "3.9.2",
  "signature": "rsa_sha256_pss:206da5b9835e4db8dda088e3e4e9224c04e9eac3cf253788973b31b7ccb50025b8bc10ce51469e5cf4003e201b90c63d45ce258bb042b5142d38fde790d218e3af65f5165c60cb4a16688ef3bbfc10a73240bba89d91534fa85863e885087d6f37c7a8a3e960bc45c4e1dd5773969c921569e71c3ab40dd392252c714ee4f28bacef98706865d34443ccd598bc13470cf52848132b7fbf75ba9240c54470be4e8cf3cfced20250a94032ee58a88b5dcfabc81d74bfd04c860b62173843f12ecf08d48069d5b1dbf7e8d24daecfa799ccb9c72c54c85fa5c155154fa6f0f3cdebc6c579a00253844089941e0dba6b2cc13ab1f2b3cdd7373651193a733ec59425"
}

If I ssh into a client configured with radius authentication, after being prompted and entering the password it fails to validate the token:

(2) Received Access-Request Id 79 from 127.0.0.1:34174 to 127.0.0.1:11812 length 117
(2)   User-Name = "george"
(2)   User-Password = "029427"
(2)   NAS-IP-Address = MASKED
(2)   NAS-Identifier = "sshd"
(2)   Calling-Station-Id = "MASKED"
(2)   State = 0x4f4c636d643568356659677a6c656f76
(2)   Message-Authenticator = 0xdde042cf3e8a3dd50d89fb7cdfe5aef5
(2)   Proxy-State = 0x313931
(2) session-state: No cached attributes
(2) # Executing section authorize from file /etc/freeradius/3.0/sites-enabled/pi_11812
(2)   authorize {
(2)     [preprocess] = ok
(2)     update control {
(2)       Auth-Type := perl
(2)     } # update control = noop
(2)   } # authorize = ok
(2) Found Auth-Type = perl
(2) # Executing group from file /etc/freeradius/3.0/sites-enabled/pi_11812
(2)   authenticate {
(2) perl:   $RAD_REQUEST{'User-Name'} = &request:User-Name -> 'george'
(2) perl:   $RAD_REQUEST{'User-Password'} = &request:User-Password -> '029427'
(2) perl:   $RAD_REQUEST{'NAS-IP-Address'} = &request:NAS-IP-Address -> 'MASKED'
(2) perl:   $RAD_REQUEST{'State'} = &request:State -> '0x4f4c636d643568356659677a6c656f76'
(2) perl:   $RAD_REQUEST{'Calling-Station-Id'} = &request:Calling-Station-Id -> 'MASKED'
(2) perl:   $RAD_REQUEST{'NAS-Identifier'} = &request:NAS-Identifier -> 'sshd'
(2) perl:   $RAD_REQUEST{'Proxy-State'} = &request:Proxy-State -> '0x313931'
(2) perl:   $RAD_REQUEST{'Event-Timestamp'} = &request:Event-Timestamp -> 'May 31 2024 16:01:35 UTC'
(2) perl:   $RAD_REQUEST{'Message-Authenticator'} = &request:Message-Authenticator -> '0xdde042cf3e8a3dd50d89fb7cdfe5aef5'
(2) perl:   $RAD_CHECK{'Auth-Type'} = &control:Auth-Type -> 'perl'
(2) perl:   $RAD_CONFIG{'Auth-Type'} = &control:Auth-Type -> 'perl'
rlm_perl: Config File /etc/privacyidea/rlm_perl.ini found!
rlm_perl: Debugging config: true
rlm_perl: Default URL https://localhost/validate/check
rlm_perl: Looking for config for auth-type perl
rlm_perl: RAD_REQUEST: Event-Timestamp = May 31 2024 16:01:35 UTC
rlm_perl: RAD_REQUEST: NAS-Identifier = sshd
rlm_perl: RAD_REQUEST: Message-Authenticator = 0xdde042cf3e8a3dd50d89fb7cdfe5aef5
rlm_perl: RAD_REQUEST: Calling-Station-Id = MASKED
rlm_perl: RAD_REQUEST: Proxy-State = 0x313931
rlm_perl: RAD_REQUEST: User-Name = george
rlm_perl: RAD_REQUEST: State = 0x4f4c636d643568356659677a6c656f76
rlm_perl: RAD_REQUEST: User-Password = 029427
rlm_perl: RAD_REQUEST: NAS-IP-Address = MASKED
rlm_perl: Password encoding guessed: ascii
rlm_perl: Setting client IP to MASKED.
rlm_perl: Auth-Type: perl
rlm_perl: url: https://localhost/validate/check
rlm_perl: user sent to privacyidea: george
rlm_perl: realm sent to privacyidea:
rlm_perl: resolver sent to privacyidea:
rlm_perl: client sent to privacyidea: MASKED
rlm_perl: state sent to privacyidea: OLcmd5h5fYgzleov
rlm_perl: George added password sent to privacyidea: 029427
rlm_perl: urlparam client = MASKED
rlm_perl: urlparam state = OLcmd5h5fYgzleov
rlm_perl: urlparam user = george
rlm_perl: urlparam pass = 029427
rlm_perl: Request timeout: 10
rlm_perl: Not verifying SSL certificate!
rlm_perl: elapsed time for privacyidea call: 0.361419
rlm_perl: Content {"detail": {"message": "wrong otp pin", "threadid": 139846977599040}, "id": 2, "jsonrpc": "2.0", "result": {"authentication": "REJECT", "status": true, "value": false}, "time": 1717171296.1040664, "version": "privacyIDEA 3.9.2", "versionnumber": "3.9.2", "signature": "rsa_sha256_pss:67f1f98b1734b968715d7cedccb2cdb864cd9af0037dee44697ae386da5d299c9439fe59a0cd0ba95ce351f88349e727bb82f7e0299a624763d2b5cb830378f74851a59dd5bd2a33afefbcbd7fc22513e046b09d0c01554e145fd200763390634eac70bbd7e29fe08543ba4ad2af0fe1a23846bd15f4663024d680e2981ccb22c4f3124bd2594be8699a5f62fc0710b9010ee8f1303ec5f65d66efa0277ff1c2af3934261814cb9e128e1d26e882a9316ea8d97daa165fe7651756b0a3ff78a23588c24d3cf453371fb6f267a26426239988e36029744f93de24e1c21349d014fd97e5d63137da07def8bf932866bed77d0850a637115273871f8f39f152a0cb"}
rlm_perl: privacyIDEA Result status is true!
rlm_perl: privacyIDEA access denied for george realm=' pass='029427'
rlm_perl: return RLM_MODULE_REJECT
(2) perl: &request:Event-Timestamp = $RAD_REQUEST{'Event-Timestamp'} -> 'May 31 2024 16:01:35 UTC'
(2) perl: &request:NAS-Identifier = $RAD_REQUEST{'NAS-Identifier'} -> 'sshd'
(2) perl: &request:Message-Authenticator = $RAD_REQUEST{'Message-Authenticator'} -> '0xdde042cf3e8a3dd50d89fb7cdfe5aef5'
(2) perl: &request:Calling-Station-Id = $RAD_REQUEST{'Calling-Station-Id'} -> 'MASKED'
(2) perl: &request:Proxy-State = $RAD_REQUEST{'Proxy-State'} -> '0x313931'
(2) perl: &request:User-Name = $RAD_REQUEST{'User-Name'} -> 'george'
(2) perl: &request:State = $RAD_REQUEST{'State'} -> '0x4f4c636d643568356659677a6c656f76'
(2) perl: &request:User-Password = $RAD_REQUEST{'User-Password'} -> '029427'
(2) perl: &request:NAS-IP-Address = $RAD_REQUEST{'NAS-IP-Address'} -> 'MASKED'
(2) perl: &reply:Reply-Message = $RAD_REPLY{'Reply-Message'} -> 'wrong otp pin'
(2) perl: &control:Auth-Type = $RAD_CHECK{'Auth-Type'} -> 'perl'
(2)     [perl] = reject
(2)   } # authenticate = reject
(2) Failed to authenticate the user
(2) Using Post-Auth-Type Reject
(2) Post-Auth-Type sub-section not found.  Ignoring.
(2) Delaying response for 1.000000 seconds
(1) Expecting proxy response no later than 29.611072 seconds from now
Waking up in 0.9 seconds.

Validating the token in the UI works as well, and LDAP authentication works fine too (in the UI as well as the first factor validated by radius)

These are the policies configured, and I tried with “otppin: none” in the authentication policy, as well as “otppin: userstore”, but the OTP validation fails for both.

{   'policy': [   {   'action': {   'adduser': True,
                                    'assign': True,
                                    'auditlog': True,
                                    'auditlog_download': True,
                                    'caconnectordelete': True,
                                    'caconnectorread': True,
                                    'caconnectorwrite': True,
                                    'clienttype': True,
                                    'configdelete': True,
                                    'configread': True,
                                    'configwrite': True,
                                    'copytokenpin': True,
                                    'copytokenuser': True,
                                    'daypassword_force_server_generate': True,
                                    'delete': True,
                                    'deleteuser': True,
                                    'disable': True,
                                    'enable': True,
                                    'enroll4EYES': True,
                                    'enrollAPPLSPEC': True,
                                    'enrollCERTIFICATE': True,
                                    'enrollDAPLUG': True,
                                    'enrollDAYPASSWORD': True,
                                    'enrollEMAIL': True,
                                    'enrollHOTP': True,
                                    'enrollINDEXEDSECRET': True,
                                    'enrollMOTP': True,
                                    'enrollOCRA': True,
                                    'enrollPAPER': True,
                                    'enrollPUSH': True,
                                    'enrollPW': True,
                                    'enrollQUESTION': True,
                                    'enrollRADIUS': True,
                                    'enrollREGISTRATION': True,
                                    'enrollREMOTE': True,
                                    'enrollSMS': True,
                                    'enrollSPASS': True,
                                    'enrollSSHKEY': True,
                                    'enrollTAN': True,
                                    'enrollTIQR': True,
                                    'enrollTOTP': True,
                                    'enrollU2F': True,
                                    'enrollVASCO': True,
                                    'enrollWEBAUTHN': True,
                                    'enrollYUBICO': True,
                                    'enrollYUBIKEY': True,
                                    'enrollpin': True,
                                    'eventhandling_read': True,
                                    'eventhandling_write': True,
                                    'fetch_authentication_items': True,
                                    'getchallenges': True,
                                    'getrandom': True,
                                    'getserial': True,
                                    'importtokens': True,
                                    'losttoken': True,
                                    'machinelist': True,
                                    'manage_machine_tokens': True,
                                    'managesubscription': True,
                                    'mresolverdelete': True,
                                    'mresolverread': True,
                                    'mresolverwrite': True,
                                    'periodictask_read': True,
                                    'periodictask_write': True,
                                    'policydelete': True,
                                    'policyread': True,
                                    'policywrite': True,
                                    'privacyideaserver_read': True,
                                    'privacyideaserver_write': True,
                                    'radiusserver_read': True,
                                    'radiusserver_write': True,
                                    'reset': True,
                                    'resolverdelete': True,
                                    'resolverread': True,
                                    'resolverwrite': True,
                                    'resync': True,
                                    'revoke': True,
                                    'serviceid_add': True,
                                    'serviceid_delete': True,
                                    'serviceid_list': True,
                                    'set': True,
                                    'set_hsm_password': True,
                                    'setdescription': True,
                                    'setpin': True,
                                    'setrandompin': True,
                                    'settokeninfo': True,
                                    'smsgateway_read': True,
                                    'smsgateway_write': True,
                                    'smtpserver_read': True,
                                    'smtpserver_write': True,
                                    'statistics_delete': True,
                                    'statistics_read': True,
                                    'system_documentation': True,
                                    'tokengroup_add': True,
                                    'tokengroup_delete': True,
                                    'tokengroup_list': True,
                                    'tokengroups': True,
                                    'tokenlist': True,
                                    'tokenrealms': True,
                                    'triggerchallenge': True,
                                    'unassign': True,
                                    'updateuser': True,
                                    'userlist': True},
                      'active': True,
                      'adminrealm': [],
                      'adminuser': ['admin'],
                      'check_all_resolvers': False,
                      'client': ['10.10.10.0/24', '10.12.5.155/32'],
                      'conditions': [],
                      'name': 'admin_localadmin',
                      'pinode': [],
                      'priority': 1,
                      'realm': [],
                      'resolver': [],
                      'scope': 'admin',
                      'time': '',
                      'user': []},
                  {   'action': {   'admin_dashboard': True,
                                    'login_mode': 'userstore',
                                    'logout_time': '600',
                                    'show_node': True},
                      'active': True,
                      'adminrealm': [],
                      'adminuser': [],
                      'check_all_resolvers': False,
                      'client': ['10.10.10.0/24', '10.12.5.155/32'],
                      'conditions': [],
                      'name': 'webui_admin',
                      'pinode': ['localnode'],
                      'priority': 1,
                      'realm': ['admin'],
                      'resolver': ['MASKED'],
                      'scope': 'webui',
                      'time': '',
                      'user': []},
                  {   'action': {   'tokenissuer': 'MASKED',
                                    'tokenlabel': '{user}'},
                      'active': True,
                      'adminrealm': [],
                      'adminuser': [],
                      'check_all_resolvers': False,
                      'client': [],
                      'conditions': [],
                      'name': 'enrollment_token_issuer',
                      'pinode': [],
                      'priority': 1,
                      'realm': ['MASKED'],
                      'resolver': [],
                      'scope': 'enrollment',
                      'time': '',
                      'user': []},
                  {   'action': {   'adduser': True,
                                    'assign': True,
                                    'auditlog': True,
                                    'auditlog_download': True,
                                    'caconnectordelete': True,
                                    'caconnectorread': True,
                                    'caconnectorwrite': True,
                                    'clienttype': True,
                                    'configdelete': True,
                                    'configread': True,
                                    'configwrite': True,
                                    'copytokenpin': True,
                                    'copytokenuser': True,
                                    'daypassword_force_server_generate': True,
                                    'delete': True,
                                    'deleteuser': True,
                                    'disable': True,
                                    'enable': True,
                                    'enroll4EYES': True,
                                    'enrollAPPLSPEC': True,
                                    'enrollCERTIFICATE': True,
                                    'enrollDAPLUG': True,
                                    'enrollDAYPASSWORD': True,
                                    'enrollEMAIL': True,
                                    'enrollHOTP': True,
                                    'enrollINDEXEDSECRET': True,
                                    'enrollMOTP': True,
                                    'enrollOCRA': True,
                                    'enrollPAPER': True,
                                    'enrollPUSH': True,
                                    'enrollPW': True,
                                    'enrollQUESTION': True,
                                    'enrollRADIUS': True,
                                    'enrollREGISTRATION': True,
                                    'enrollREMOTE': True,
                                    'enrollSMS': True,
                                    'enrollSPASS': True,
                                    'enrollSSHKEY': True,
                                    'enrollTAN': True,
                                    'enrollTIQR': True,
                                    'enrollTOTP': True,
                                    'enrollU2F': True,
                                    'enrollVASCO': True,
                                    'enrollWEBAUTHN': True,
                                    'enrollYUBICO': True,
                                    'enrollYUBIKEY': True,
                                    'enrollpin': True,
                                    'eventhandling_read': True,
                                    'eventhandling_write': True,
                                    'fetch_authentication_items': True,
                                    'getchallenges': True,
                                    'getrandom': True,
                                    'getserial': True,
                                    'importtokens': True,
                                    'losttoken': True,
                                    'machinelist': True,
                                    'manage_machine_tokens': True,
                                    'managesubscription': True,
                                    'mresolverdelete': True,
                                    'mresolverread': True,
                                    'mresolverwrite': True,
                                    'periodictask_read': True,
                                    'periodictask_write': True,
                                    'policydelete': True,
                                    'policyread': True,
                                    'policywrite': True,
                                    'privacyideaserver_read': True,
                                    'privacyideaserver_write': True,
                                    'radiusserver_read': True,
                                    'radiusserver_write': True,
                                    'reset': True,
                                    'resolverdelete': True,
                                    'resolverread': True,
                                    'resolverwrite': True,
                                    'resync': True,
                                    'revoke': True,
                                    'serviceid_add': True,
                                    'serviceid_delete': True,
                                    'serviceid_list': True,
                                    'set': True,
                                    'set_hsm_password': True,
                                    'setdescription': True,
                                    'setpin': True,
                                    'setrandompin': True,
                                    'settokeninfo': True,
                                    'smsgateway_read': True,
                                    'smsgateway_write': True,
                                    'smtpserver_read': True,
                                    'smtpserver_write': True,
                                    'statistics_delete': True,
                                    'statistics_read': True,
                                    'system_documentation': True,
                                    'tokengroup_add': True,
                                    'tokengroup_delete': True,
                                    'tokengroup_list': True,
                                    'tokengroups': True,
                                    'tokenlist': True,
                                    'tokenrealms': True,
                                    'triggerchallenge': True,
                                    'unassign': True,
                                    'updateuser': True,
                                    'userlist': True},
                      'active': True,
                      'adminrealm': [],
                      'adminuser': ['george', 'MASKED'],
                      'check_all_resolvers': False,
                      'client': ['10.10.10.0/24'],
                      'conditions': [],
                      'name': 'admin_sysadmins',
                      'pinode': [],
                      'priority': 1,
                      'realm': [],
                      'resolver': [],
                      'scope': 'admin',
                      'time': '',
                      'user': []},
                  {   'action': {   'default_tokentype': 'totp',
                                    'login_mode': 'userstore',
                                    'show_seed': True},
                      'active': True,
                      'adminrealm': [],
                      'adminuser': [],
                      'check_all_resolvers': False,
                      'client': [],
                      'conditions': [],
                      'name': 'webui_oicr_defaults',
                      'pinode': [],
                      'priority': 1,
                      'realm': ['MASKED'],
                      'resolver': [],
                      'scope': 'webui',
                      'time': '',
                      'user': []},
                  {   'action': {   'totp_max_token_per_user': '3',
                                    'verify_enrollment': 'TOTP'},
                      'active': True,
                      'adminrealm': [],
                      'adminuser': [],
                      'check_all_resolvers': False,
                      'client': [],
                      'conditions': [],
                      'name': 'enrollment_totp_settings',
                      'pinode': [],
                      'priority': 1,
                      'realm': ['MASKED'],
                      'resolver': [],
                      'scope': 'enrollment',
                      'time': '',
                      'user': []},
                  {   'action': {   'delete': True,
                                    'enrollTOTP': True,
                                    'setdescription': True,
                                    'totp_force_server_generate': True,
                                    'totp_hashlib': 'sha1',
                                    'totp_otplen': '6',
                                    'totp_timestep': '30'},
                      'active': True,
                      'adminrealm': [],
                      'adminuser': [],
                      'check_all_resolvers': False,
                      'client': [],
                      'conditions': [],
                      'name': 'user_totp_selfservice',
                      'pinode': [],
                      'priority': 1,
                      'realm': ['MASKED'],
                      'resolver': [],
                      'scope': 'user',
                      'time': '',
                      'user': []},
                  {   'action': {'otppin': 'none'},
                      'active': True,
                      'adminrealm': [],
                      'adminuser': [],
                      'check_all_resolvers': False,
                      'client': [],
                      'conditions': [],
                      'name': 'NoPIN',
                      'pinode': [],
                      'priority': 1,
                      'realm': ['MASKED'],
                      'resolver': ['MASKED'],
                      'scope': 'authentication',
                      'time': '',
                      'user': []},
                  {   'action': {'login_mode': 'disable'},
                      'active': True,
                      'adminrealm': [],
                      'adminuser': [],
                      'check_all_resolvers': False,
                      'client': [],
                      'conditions': [],
                      'name': 'webui_admin_default_disable',
                      'pinode': [],
                      'priority': 10,
                      'realm': ['admin'],
                      'resolver': [],
                      'scope': 'webui',
                      'time': '',
                      'user': []},
                  {   'action': {   'deletion_confirmation': True,
                                    'hide_buttons': True,
                                    'hide_welcome_info': True,
                                    'timeout_action': 'logout'},
                      'active': True,
                      'adminrealm': [],
                      'adminuser': [],
                      'check_all_resolvers': False,
                      'client': [],
                      'conditions': [],
                      'name': 'webui_defaults',
                      'pinode': [],
                      'priority': 10,
                      'realm': [],
                      'resolver': [],
                      'scope': 'webui',
                      'time': '',
                      'user': []}]}

Thank you for taking the time to look at this issue,
George

It is important to understand, that privacyIDEA takes the string, entered by the user or sent to the validate/check API and splits it according to the OTPlength of the token.

So if the RADIUS client would send a password (maybe due to wrong RADIUS secret or not using PAP), that is longer than 6 characters, privacyIDEA could strip the last six chars and result in a faulty OTP pin.

Pro Tip: Look into the privacyIDEA webui in the audit log and check the validate/check entry.
It will show you, which policies were applied. Maybe during the auth process for some condition reasons the NoPIN policy was not applied?

Rule of thumb: Keep your policy logic as simple as possible.

You have one authenticatoin policy. Why do you have entered realm and resolver?
If not necessary, remove these from the policy.