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
|