Server hook after terminal user auth failure

12 views
Skip to first unread message

Andrew Melo

unread,
Feb 23, 2023, 4:40:46 PM2/23/23
to asyncssh-users
Hi all,

First off, thanks for the great package!

I am wondering if there is a way where once a user has exhausted their authentication attempts, a banner is sent to the user with (say) instructions for how to get help. I see that there is SSHServer.auth_completed() [1] which fires on success, but I'm wondering if there's the equivalent for when a failure occurs.

Thanks!
Andrew




haliphax

unread,
Mar 1, 2023, 10:51:11 AM3/1/23
to asyncssh-users
I believe you would be able to do this in the validate_password() method. I'm logging a warning in this code [1] but you could also likely write a banner to the client.

Ron Frederick

unread,
Mar 2, 2023, 12:05:25 AM3/2/23
to haliphax, asyncssh-users
Putting something in the validate_password() callback works well for logging password failures, but it would be called on every auth attempt, not after all the attempts were exhausted. Also, there would be no way at that point to write a message back to the client.

The typical way this is done is to print an auth banner before you begin authentication. You can do this by calling conn.send_auth_banner() from within your SSHServer’s begin_auth() callback. I just did an experiment here and it looks like OpenSSH refuses to print this banner if you try to send it after authentication has started. So, calling conn.send_auth_banner() from validate_password() isn’t likely to work.

I think you’d probably need to use keyboard-interactive authentication to do this, implementing the get_kbdint_challenge() and validate_kbdint_response() callbacks. Since OpenSSH only tries a max of 3 times for this auth method, you’d probably only be able to allow for two passwords failures, and then you could replace the third challenge with a message that you wanted to send instead which didn’t include any prompt. The client will print that message and then report that permission was denied:

(user123@localhost) Password:
(user123@localhost) Password:
Your message here
user123@localhost: Permission denied (keyboard-interactive).


The methods in your SSHServer subclass would look something like:

    def connection_made(self, conn):
        self._conn = conn
        self._attempts = 2

    def begin_auth(self, username):
        return True

    def kbdint_auth_supported(self):
        return True

    def get_kbdint_challenge(self, username, lang, submethods):
        if self._attempts == 0:
            return '', ‘Final failure message here', '', []
        else:
            self._attempts -= 1
            return '', '', '', [('Password:', False)]

    def validate_kbdint_response(self, username, responses):
        # Check password in responses[0] for username and return True/False
        return False


-- 
Ron Frederick
ro...@timeheart.net



Andrew Melo

unread,
Mar 2, 2023, 9:44:34 AM3/2/23
to Ron Frederick, haliphax, asyncssh-users
Thank you so much!
> --
> Visit the AsyncSSH home page at http://asyncssh.timeheart.net
> ---
> You received this message because you are subscribed to the Google Groups "asyncssh-users" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to asyncssh-user...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/asyncssh-users/1188EEBA-87BE-461C-BD18-D6D64C0832BA%40timeheart.net.
Reply all
Reply to author
Forward
0 new messages