Control port authentication failures don't differentiate failure types
The control-spec has a couple status codes for authentication failures...
514 Authentication required 515 Bad authentication
The 515 status is used for both rejection of the authentication credentials and of the authentication method entirely. For instance...
AUTHENTICATE "blarg" 515 Authentication failed: Password did not match HashedControlPassword value from configuration Connection closed by foreign host.
Rejected Authentication Method:
AUTHENTICATE 515 Authentication failed: Password did not match HashedControlPassword value from configuration. Maybe you tried a plain text password? If so, the standard requires that you put it in double quotes. Connection closed by foreign host.
This means that controllers need to read the message to translate these responses into an exception type. Needless to say this isn't great since it leads to sadness if we change or provide localization of the messages.
In stem's case I provide a warning in the pydocs and attempt to use the message...
""" Authenticates to a control socket that uses a password (via the HashedControlPassword torrc option). Quotes in the password are escaped. If authentication fails tor will disconnect and we'll make a best effort attempt to re-establish the connection. This may not succeed, so check is_alive() before using the socket further. For general usage use the authenticate() function instead. note: If you use this function directly, rather than authenticate(), we may mistakenly raise a PasswordAuthRejected rather than IncorrectPassword. This is because we rely on tor's error messaging which is liable to change in future versions. """ ... # if we got anything but an OK response then error if str(auth_response) != "OK": try: control_socket.connect() except: pass # all we have to go on is the error message from tor... # Password did not match HashedControlPassword value value from configuration... # Password did not match HashedControlPassword *or*... if "Password did not match HashedControlPassword" in str(auth_response): raise IncorrectPassword(str(auth_response), auth_response) else: raise PasswordAuthRejected(str(auth_response), auth_response)
I do this for both the authenticate_password and authenticate_cookie functions. In general this won't be very visible to library users since they'll usually use the authenticate() function instead, which has a PROTOCOLINFO response so it doesn't have this issue.
Feel free to resolve this as 'wont fix'. This isn't an issue if controller users do PROTOCOLINFO first, and the AUTHENTICATE function has no notion of the authentication type being attempted so it would be difficult for tor to differentiate those issues, even if it wanted to. Mostly just noting a minor gotcha I encountered while writing stem. :)