02. Authentication

First off, there are roughly three commands you can use without being authenticated. You can either authenticate(), protocol_info() or quit().

Authentication methods

Controller.protocol_info(), when successful provides a ReplyProtocolInfo, which contains important authentication information, such as the list of authorized authentication methods and the path to the cookie file used in most of these authentication methods.

Configuration for authentication methods is quite out of our scope here, but feel free to take a look at the torrc manpage, especially options HashedControlPassword and CookieAuthentication. Password hash can be generated with the following command:

$ tor --hash-password aiostem
16:431FE41EE9A6D2D8600C0F92F71A03D0A8C4E40EC1BBCC84716C95F022

The following code can be used to list available authentication methods for the target Tor daemon, and the cookie file used for COOKIE and SAFECOOKIE. It uses Controller.protocol_info() to get this information.

The full list of known authentication methods is documented on AuthMethod.

examples/authentication_listing.py
 1#!/usr/bin/env python
 2
 3import asyncio
 4import os
 5from aiostem import Controller
 6
 7async def main():
 8    host = os.environ.get('AIOSTEM_HOST', 'localhost')
 9    port = os.environ.get('AIOSTEM_PORT', 9051)
10
11    print(f'[>] Connecting to {host} on port {port}')
12    async with Controller.from_port(host, int(port)) as ctrl:
13        reply = await ctrl.protocol_info()
14        reply.raise_for_status()
15
16        print('[+] List of allowed authentication methods:')
17        for method in reply.data.auth_methods:
18            print(f' * {method}')
19        if reply.data.auth_cookie_file is not None:
20            print(f'[+] Path to the cookie file: {reply.data.auth_cookie_file}')
21
22if __name__ == '__main__':
23    asyncio.run(main())

Note here that we use raise_for_status() here to ensure that the command was successful before we go on with ReplyProtocolInfo.data.

This code, when executed provides an output such as follows:

$ python examples/authentication_listing.py
[>] Connecting to localhost on port 9051
[+] List of allowed authentication methods:
 * COOKIE
 * SAFECOOKIE
 * HASHEDPASSWORD
[+] Path to the cookie file: /run/tor/control.authcookie

Password authentication

This method covers AuthMethod.HASHEDPASSWORD and is the one related to HashedControlPassword from the configuration file. This is the only secure available method when dealing with Tor running on a remote host.

The following code authenticates with a password using Controller.authenticate():

examples/authenticate_with_password.py
 1#!/usr/bin/env python
 2
 3import asyncio
 4import os
 5from aiostem import Controller
 6
 7async def main():
 8    password = os.environ.get('AIOSTEM_PASS', 'password')
 9    host = os.environ.get('AIOSTEM_HOST', 'localhost')
10    port = os.environ.get('AIOSTEM_PORT', 9051)
11
12    print(f'[>] Connecting to {host} on port {port}')
13    async with Controller.from_port(host, int(port)) as ctrl:
14        reply = await ctrl.authenticate(password)
15        reply.raise_for_status()
16
17        print('[+] Authentication successful!')
18
19if __name__ == '__main__':
20    asyncio.run(main())

You can set the password directly from the environment:

$ AIOSTEM_PASS=aiostem python examples/authenticate_with_password.py
[>] Connecting to localhost on port 9051
[+] Authentication successful!

You can also check that when a wrong password is supplied, raise_for_status() raises a ReplyStatusError error with a meaningful message (provided by Tor).