summaryrefslogtreecommitdiff
path: root/paramiko/authenticator.py
blob: 91377e1550311d4ba284fd750c6887e3c348052c (plain)
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
72
73
74
"""
High level authentication logic module.

Largely replaces what used to be implemented solely within `SSHClient` and its
``_auth()`` method.

Technically, this module's main API member - `Authenticator` - sits below
`SSHClient` (meaning it can be used by non-Client-based code) and above
`Transport` (which provides the bare auth SSH message 'levers' only.)

.. note::
    This is not to be confused with the `paramiko.auth_handler` module, which
    sits *below* (or within) `Transport`, handling the low level guts of
    submitting authentication protocol messages and awaiting their responses.
"""

class Authenticator(object):
    """
    Wraps a `Transport` and uses it to authenticate or die trying.

    Lifecycle is relatively straightforward:

    - Instantiate with a handle onto a `Transport` object. This object must
      already have been prepared for authentication by calling
      `Transport.start_client`.
    - Call the instance's `authenticate_with_kwargs` method with as many or few
      auth-source keyword arguments as needed, which will:
        - attempt to authenticate in a documented order of preference
        - if successful, return an `AuthenticationResult`
        - if unsuccessful or if additional auth factors are required, raise an
          `AuthenticationException` (or subclass thereof) which will exhibit a
          ``.result`` attribute whose value is an `AuthenticationResult`.
        - either way, the point is that the caller will have access to an
          `AuthenticationResult` object exposing the various auth sources
          tried, what order they were tried in, and what the result was.
        - see API docs for `authenticate` for further details.
    - Alternately, for tighter control of which auth sources are tried and in
      what order, call `authenticate` directly (it's what implements the guts
      of `authenticate_with_kwargs`) which foregoes most kwargs in lieu of an
      iterable containing `AuthSource` objects.
    """
    def __init__(self, transport):
        # TODO: probably sanity check transport state and bail early if it's
        # not ready.
        # TODO: consider adding some more of SSHClient.connect (optionally, if
        # the caller didn't already do these things) like the call to
        # .start_client; then update lifecycle in docstring.
        pass

    def authenticate_with_kwargs(self, lots_o_kwargs_here):
        # Basically SSHClient._auth signature...then calls
        # sources_from_kwargs() and stuffs result into authenticate()?
        # TODO: at the start, just copypasta/tweak SSHClient._auth so the
        # break-up is tested; THEN move to the newer cleaner shit?
        # TODO: this is probably a good spot to reject the
        # password-as-passphrase bit; accept distinct kwargs and require
        # SSHClient to implement the fallback on its end.
        pass

    def authenticate(self, username, *sources):
        # TODO: define AuthSource (maybe rename...lol), should be lightweight,
        # pairing an auth type with some value or iterable of values
        # TODO: implement cleaner version of SSHClient._auth, somehow, that
        # handles multi-factor auth much better than the current shite
        # trickledown. (Be very TDD here...! Perhaps wait until single-source
        # tests all pass first, then can ensure they continue to do so?)
        pass

    def sources_from_kwargs(self, kwargs):
        # TODO: **kwargs? whatever, this is mostly internal
        # TODO: this should implement, and document, the current (and/or then
        # desired) way that a pile of kwargs becomes an ordered set of
        # attempted auths...
        pass