Sshd / PAM accepts password or MFA

Hello!

I have privacyIDEA set up and working well. Our linux host accepts SSH keys or passwords, plus it prompts for our MFA token via privacyIDEA.

When we log in with an ssh key, we are prompted for the MFA token. This is good.
When we log in (without an ssh key), we are prompted for our password, then MFA token. For example:

ssh target-host
my-user@target-host’s password: PASSWORD_HERE
Authenticated with partial success.
MFA_Passcode: MFA_CODE_HERE

This is great!
If you mistype your MFA code, then authentication fails (it prompts again, a couple of times, before terminating the session). This is good too!

We noticed, accidentally, that if the user types their password in the MFA prompt field, the authentication succeeds! (uhhhh, it shouldn’t because that is only one factor authentication) For example:

ssh target-host
my-user@target-host’s password: PASSWORD_HERE
Authenticated with partial success.
MFA_Passcode: PASSWORD_HERE__(AGAIN)__

Seemingly, something is amiss with my PAM configuration. The non-comment lines of /etc/pam.d/sshd are:

auth sufficient pam_python.so /usr/lib/python2.7/site-packages/privacyidea_pam-2.11.dev0-py2.7.egg/privacyidea_pam.py url=https://pimfa/mfa/ nosslverify prompt=MFA_Passcode debug
auth substack password-auth
auth include postlogin
account required pam_sepermit.so
account required pam_nologin.so
account include password-auth
password include password-auth
session required pam_selinux.so close
session required pam_loginuid.so
session required pam_selinux.so open env_params
session required pam_namespace.so
session optional pam_keyinit.so force revoke
session optional pam_motd.so
session include password-auth
session include postlogin

And also there is a comment block with some explanation:

privacyidea is SUFFICIENT because we only use this stack in keyboard-interactive authentication,
and sshd_config is set up to require two factors: 1) SSH-KEY or PASSWORD and then 2) MFA code via keyboard-interactive
AuthenticationMethods publickey,keyboard-interactive password,keyboard-interactive
where: publickey == sshkey based auth
where: password == prompt user for their AD password
where: keyboard-interactive == prompt user for their MFA passcode

Can you point me in the right direction so that the MFA passcode prompt accepts only the MFA value (and not the user’s password)?

I guess the PAM stack is doing, what you configured “sufficient pam_python” would be enough if given, but would not be required.

Hello, Are you suggesting replacing “sufficient” with “required”?

Not sure if this is helpful, but this is output from secure.log when sufficient is specified. Any help you can provide would be appreciated.

sshd[66172]: offline check returned: False, None
sshd[66172]: Authenticating userName against https://my-server
sshd[66172]: pam_sss(sshd:auth): authentication success; logname= uid=0 euid=0 tty=ssh ruser= rhost=XX.XXX.XXX.XX user=userName
sshd[66172]: Partial password for userName from XX.XXX.XXX.XX port YYYY ssh2
sshd[66172]: requests > 1.0
sshd[66172]: privacyidea_pam: result: {u’status’: True, u’value’: False}
sshd[66172]: privacyidea_pam: detail: {u’message’: u’wrong otp pin’, u’threadid’: 140577838913280}
sshd[66172]: pam_sss(sshd:auth): authentication success; logname= uid=0 euid=0 tty=ssh ruser= rhost=XX.XXX.XXX.XX user=userName
sshd[66172]: Partial password for userName from XX.XXX.XXX.XX port YYYY ssh2
sshd[66175]: offline check returned: False, None
sshd[66175]: Authenticating userName against https://my-server
sshd[66175]: requests > 1.0
sshd[66175]: privacyidea_pam: result: {u’status’: True, u’value’: False}
sshd[66175]: privacyidea_pam: detail: {u’message’: u’wrong otp pin’, u’threadid’: 140577897662208}
sshd[66175]: pam_sss(sshd:auth): authentication success; logname= uid=0 euid=0 tty=ssh ruser= rhost=XX.XXX.XXX.XX user=userName
sshd[66175]: pam_sss(sshd:auth): authentication success; logname= uid=0 euid=0 tty=ssh ruser= rhost=XX.XXX.XXX.XX user=userName
sshd[66172]: Accepted keyboard-interactive/pam for userName from XX.XXX.XXX.XX port YYYY ssh2
sshd[66172]: pam_unix(sshd:session): session opened for user userName by (uid=0)
sshd[66172]: Accepted keyboard-interactive/pam for userName from XX.XXX.XXX.XX port YYYY ssh2
systemd[1]: Started Session 126 of user userName.
systemd-logind[1432]: New session 126 of user userName.
sshd[66172]: pam_unix(sshd:session): session opened for user userName by (uid=0)

This is output from secure.log when required is specified in which login fails:

sshd[66314]: offline check returned: False, None
sshd[66314]: Authenticating userName against my-server
sshd[66314]: pam_sss(sshd:auth): authentication success; logname= uid=0 euid=0 tty=ssh ruser= rhost=XX.XXX.XXX.XX user=userName
sshd[66314]: requests > 1.0
sshd[66314]: privacyidea_pam: result: {u’status’: True, u’value’: False}
sshd[66314]: privacyidea_pam: detail: {u’message’: u’wrong otp pin’, u’threadid’: 140577838913280}
sshd[66314]: pam_sss(sshd:auth): authentication success; logname= uid=0 euid=0 tty=ssh ruser= rhost=XX.XXX.XXX.XX user=userName
sshd[66314]: Failed password for userName from XX.XXX.XXX.XX port YYYYY ssh2
sshd[66314]: Failed password for userName from XX.XXX.XXX.XX port YYYYY ssh2
sshd[66314]: offline check returned: False, None
sshd[66314]: Authenticating userName against https://my-server
sshd[66314]: requests > 1.0
sshd[66314]: privacyidea_pam: result: {u’status’: True, u’value’: False}
sshd[66314]: privacyidea_pam: detail: {u’message’: u’wrong otp pin’, u’threadid’: 140577897662208}
sshd[66314]: pam_sss(sshd:auth): authentication success; logname= uid=0 euid=0 tty=ssh ruser= rhost=XX.XXX.XXX.XX user=userName
sshd[66314]: pam_sss(sshd:auth): authentication success; logname= uid=0 euid=0 tty=ssh ruser= rhost=XX.XXX.XXX.XX user=userName
sshd[66314]: Failed password for userName from XX.XXX.XXX.XX port YYYYY ssh2
sshd[66314]: Failed password for userName from XX.XXX.XXX.XX port YYYYY ssh2
sshd[66314]: offline check returned: False, None
sshd[66314]: Authenticating userName against https://my-server
sshd[66314]: requests > 1.0
sshd[66314]: privacyidea_pam: result: {u’status’: True, u’value’: False}
sshd[66314]: pam_sss(sshd:auth): authentication success; logname= uid=0 euid=0 tty=ssh ruser= rhost=XX.XXX.XXX.XX user=userName
sshd[66314]: privacyidea_pam: detail: {u’message’: u’wrong otp pin’, u’threadid’: 140577838913280}
sshd[66314]: pam_sss(sshd:auth): authentication success; logname= uid=0 euid=0 tty=ssh ruser= rhost=XX.XXX.XXX.XX user=userName
sshd[66314]: Failed password for userName from XX.XXX.XXX.XX port YYYYY ssh2
sshd[66314]: Failed password for userName from XX.XXX.XXX.XX port YYYYY ssh2
sshd[66314]: Connection closed by authenticating user userName XX.XXX.XXX.XX port YYYYY [preauth]
sshd[66314]: Connection closed by authenticating user userName XX.XXX.XXX.XX port YYYYY [preauth]

I am suggesting, that this could be a point to look at.