File: auth_keyring.py

package info (click to toggle)
ddupdate 0.7.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 420 kB
  • sloc: python: 1,899; sh: 38; makefile: 35
file content (71 lines) | stat: -rw-r--r-- 2,554 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
"""Implement credentials lookup using python3-keyring.

The keyring just provides a basic username -> password lookup. However,
the get_auth() call should possibly return both username and password
for a given machine. To that end, the value stored for each hostname
is 'username<tab>password'

For hosts using just an api key i. e., without a username the username
field is set to 'api-key'
"""


KEYRING_MISSING_MSG = """
python keyring module not found. Please install python3-keyring
using package manager or the keyring package using pip.
"""

# pylint: disable=wrong-import-position

from ddupdate.ddplugin import AuthPlugin, AuthError
try:
    import keyring
    import keyring.errors
except (ModuleNotFoundError, ImportError):
    import sys
    print(KEYRING_MISSING_MSG)
    sys.exit(1)


class AuthKeyring(AuthPlugin):
    """Implement credentials lookup using python3-keyring.

    This is a reasonably secure way to handle the passwords. Before actually
    accessing the passwords the keyring must be unlocked. This makes this
    backend less suited to servers but is no problem on for example a
    notebook.

    Prior to 0.7.2 all passwords was stored in the .netrc file. See the
    ddupdate-netrc-to-keyring tool for migrating passwords from .netrc to
    the keyring backend.
    """

    _name = 'keyring'
    _oneliner = 'Store credentials in the system keyring'
    __version__ = '0.7.2'

    def get_auth(self, machine):
        """Implement AuthPlugin::get_auth()."""
        try:
            credentials = keyring.get_password('ddupdate', machine.lower())
            if not credentials:
                raise AuthError("Cannot get authentication for: " + machine)
            credentials = credentials.split('\t')
        except keyring.errors.KeyringError as err:
            raise AuthError("Cannot obtain credentials for: " + machine) \
                from err
        if len(credentials) != 2:
            raise AuthError("Cannot parse credentials for: " + machine)
        if credentials[0] == 'api-key':
            credentials[0] = None
        return credentials[0], credentials[1]

    def set_password(self, machine, username, password):
        """Implement AuthPlugin::set_password()."""
        if not username:
            username = 'api-key'
        credentials = username + '\t' + password
        try:
            keyring.set_password('ddupdate', machine.lower(), credentials)
        except keyring.errors.KeyringError as err:
            raise AuthError("Cannot set credentials for: " + machine) from err