Issue
I would like to have a test pass/fail based on ssh public/private key verification in an automated way.
I know that I can use something like this:
ssh -T [email protected]
which will give a result such as:
Hi username! You've successfully authenticated, but GitHub does not provide shell access.
Obviously this is a custom message and will change for different services.
I had hoped that this would return a successful status, but when I use the following snippet in node.js
:
const { exec } = require('child_process');
exec('ssh -T [email protected]', (error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`);
} else {
console.log('success');
}
});
The result is in the error case:
exec error: Error: Command failed: ssh -T [email protected]
Hi username! You've successfully authenticated, but GitHub does not provide shell access.
This is because the exit code is determined by the remote in those cases and github gives an exit status of 1. I noticed that bitbucket, however, gives and exit code of 0 which I would think is more appropriate in this case.
I also noticed that if I use something invalid that I have not yet setup in my ssh config. for example: sst -T [email protected]
it will simply cause my test to eventually time out. I can use this as a failure, but I was just curios if there was a more standard/reliable way to detect this in an unattended test.
I looked at the man page for ssh and I can set a timeout for the request with something like:
ssh -T -o ConnectTimeout=1 [email protected]
I can also use echo $?
to inspect the exit code and found that if it fails to authenticate (if I do not have the public/private key setup) or if it times out I get an exit code of 255. This still isn't bullet proof as it seems like the server can send that as well if it wanted for any arbitrary reason.
The typical error message for authentication failure is something like:
[email protected]: Permission denied (publickey).
I think this may be a more standard error message... but the content can change for this as well (a custom banner for example).
Solution
The error message for an authentication failure is an ssh client message. You can check the source code at https://github.com/openssh/openssh-portable/blob/master/sshconnect2.c
Authmethod *method = authmethod_get(authlist);
if (method == NULL)
fatal("%s@%s: Permission denied (%s).",
authctxt->server_user, authctxt->host, authlist);
This part will be stable as long as you keep the same local ssh client. You can use this as an indicator for a failed authentication.
Answered By - Jens Dibbern