[project @ Arch-1:robey@lag.net--2003-public%secsh--dev--1.0--patch-19]
renamed auth_key -> auth_publickey; more docs. renamed Transport.auth_key to auth_publickey for consistency. and lots more documentation.
This commit is contained in:
parent
daa8a2ec0d
commit
3a8887a420
2
README
2
README
|
@ -135,7 +135,5 @@ are still running (and you'll have to kill -9 from another shell window).
|
|||
* ctr forms of ciphers are missing (blowfish-ctr, aes128-ctr, aes256-ctr)
|
||||
* can't handle password-protected private key files
|
||||
* multi-part auth not supported (ie, need username AND pk)
|
||||
* should have a simple synchronous method that handles all auth & events,
|
||||
by pre-seeding the password or key info, and the expected key
|
||||
* server mode needs better doc
|
||||
|
||||
|
|
2
demo.py
2
demo.py
|
@ -108,7 +108,7 @@ try:
|
|||
if len(path) == 0:
|
||||
path = default_path
|
||||
key.read_private_key_file(path)
|
||||
t.auth_key(username, key, event)
|
||||
t.auth_publickey(username, key, event)
|
||||
elif auth == 'd':
|
||||
key = paramiko.DSSKey()
|
||||
default_path = os.environ['HOME'] + '/.ssh/id_dsa'
|
||||
|
|
|
@ -41,6 +41,10 @@ class ServerTransport(paramiko.Transport):
|
|||
return self.AUTH_SUCCESSFUL
|
||||
return self.AUTH_FAILED
|
||||
|
||||
def get_allowed_auths(self, username):
|
||||
return 'password,publickey'
|
||||
|
||||
|
||||
class ServerChannel(paramiko.Channel):
|
||||
"Channel descendant that pretends to understand pty and shell requests"
|
||||
|
||||
|
@ -86,7 +90,6 @@ try:
|
|||
print '(Failed to load moduli -- gex will be unsupported.)'
|
||||
raise
|
||||
t.add_server_key(host_key)
|
||||
t.ultra_debug = 0
|
||||
t.start_server(event)
|
||||
while 1:
|
||||
event.wait(0.1)
|
||||
|
|
|
@ -9,11 +9,15 @@ __author__ = "Robey Pointer <robey@lag.net>"
|
|||
__date__ = "10 Nov 2003"
|
||||
__version__ = "0.1-charmander"
|
||||
__credits__ = "Huzzah!"
|
||||
__license__ = "Lesser GNU Public License (LGPL)"
|
||||
|
||||
|
||||
import ssh_exception, transport, auth_transport, channel, rsakey, dsskey, util
|
||||
import ssh_exception, transport, auth_transport, channel, rsakey, dsskey
|
||||
|
||||
class SSHException (ssh_exception.SSHException):
|
||||
"""
|
||||
Exception thrown by failures in SSH2 protocol negotiation or logic errors.
|
||||
"""
|
||||
pass
|
||||
|
||||
class Transport (auth_transport.Transport):
|
||||
|
@ -34,9 +38,17 @@ class Channel (channel.Channel):
|
|||
pass
|
||||
|
||||
class RSAKey (rsakey.RSAKey):
|
||||
"""
|
||||
Representation of an RSA key which can be used to sign and verify SSH2
|
||||
data.
|
||||
"""
|
||||
pass
|
||||
|
||||
class DSSKey (dsskey.DSSKey):
|
||||
"""
|
||||
Representation of a DSS key which can be used to sign an verify SSH2
|
||||
data.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ class Transport (BaseTransport):
|
|||
"""
|
||||
return self.authenticated and self.active
|
||||
|
||||
def auth_key(self, username, key, event):
|
||||
def auth_publickey(self, username, key, event):
|
||||
"""
|
||||
Authenticate to the server using a private key. The key is used to
|
||||
sign data from the server, so it must include the private part. The
|
||||
|
@ -113,15 +113,70 @@ class Transport (BaseTransport):
|
|||
self.lock.release()
|
||||
|
||||
def get_allowed_auths(self, username):
|
||||
"override me!"
|
||||
"""
|
||||
I{(subclass override)}
|
||||
Return a list of authentication methods supported by the server.
|
||||
This list is sent to clients attempting to authenticate, to inform them
|
||||
of authentication methods that might be successful.
|
||||
|
||||
The "list" is actually a string of comma-separated names of types of
|
||||
authentication. Possible values are C{"password"}, C{"publickey"},
|
||||
and C{"none"}.
|
||||
|
||||
The default implementation always returns C{"password"}.
|
||||
|
||||
@param username: the username requesting authentication.
|
||||
@type username: string
|
||||
@return: a comma-separated list of authentication types
|
||||
@rtype: string
|
||||
"""
|
||||
return 'password'
|
||||
|
||||
def check_auth_none(self, username):
|
||||
"override me! return int ==> auth status"
|
||||
"""
|
||||
I{(subclass override)}
|
||||
Determine if a client may open channels with no (further)
|
||||
authentication. You should override this method in server mode.
|
||||
|
||||
Return C{AUTH_FAILED} if the client must authenticate, or
|
||||
C{AUTH_SUCCESSFUL} if it's okay for the client to not authenticate.
|
||||
|
||||
The default implementation always returns C{AUTH_FAILED}.
|
||||
|
||||
@param username: the username of the client.
|
||||
@type username: string
|
||||
@return: C{AUTH_FAILED} if the authentication fails; C{AUTH_SUCCESSFUL}
|
||||
if it succeeds.
|
||||
@rtype: int
|
||||
"""
|
||||
return self.AUTH_FAILED
|
||||
|
||||
def check_auth_password(self, username, password):
|
||||
"override me! return int ==> auth status"
|
||||
"""
|
||||
I{(subclass override)}
|
||||
Determine if a given username and password supplied by the client is
|
||||
acceptable for use in authentication. You should override this method
|
||||
in server mode.
|
||||
|
||||
Return C{AUTH_FAILED} if the password is not accepted,
|
||||
C{AUTH_SUCCESSFUL} if the password is accepted and completes the
|
||||
authentication, or C{AUTH_PARTIALLY_SUCCESSFUL} if your authentication
|
||||
is stateful, and this key is accepted for authentication, but more
|
||||
authentication is required. (In this latter case, L{get_allowed_auths}
|
||||
will be called to report to the client what options it has for
|
||||
continuing the authentication.)
|
||||
|
||||
The default implementation always returns C{AUTH_FAILED}.
|
||||
|
||||
@param username: the username of the authenticating client.
|
||||
@type username: string
|
||||
@param password: the password given by the client.
|
||||
@type password: string
|
||||
@return: C{AUTH_FAILED} if the authentication fails; C{AUTH_SUCCESSFUL}
|
||||
if it succeeds; C{AUTH_PARTIALLY_SUCCESSFUL} if the password auth is
|
||||
successful, but authentication must continue.
|
||||
@rtype: int
|
||||
"""
|
||||
return self.AUTH_FAILED
|
||||
|
||||
def check_auth_publickey(self, username, key):
|
||||
|
|
|
@ -176,10 +176,59 @@ class BaseTransport (threading.Thread):
|
|||
return out
|
||||
|
||||
def start_client(self, event=None):
|
||||
"""
|
||||
Negotiate a new SSH2 session as a client. This is the first step after
|
||||
creating a new L{Transport}. A separate thread is created for protocol
|
||||
negotiation, so this method returns immediately.
|
||||
|
||||
When negotiation is done (successful or not), the given C{Event} will
|
||||
be triggered. On failure, L{is_active} will return C{False}.
|
||||
|
||||
After a successful negotiation, you will usually want to authenticate,
|
||||
calling L{auth_password <Transport.auth_password>} or
|
||||
L{auth_publickey <Transport.auth_publickey>}.
|
||||
|
||||
@note: L{connect} is a simpler method for connecting as a client.
|
||||
|
||||
@note: After calling this method (or L{start_server} or L{connect}),
|
||||
you should no longer directly read from or write to the original socket
|
||||
object.
|
||||
|
||||
@param event: an event to trigger when negotiation is complete.
|
||||
@type event: threading.Event
|
||||
"""
|
||||
self.completion_event = event
|
||||
self.start()
|
||||
|
||||
def start_server(self, event=None):
|
||||
"""
|
||||
Negotiate a new SSH2 session as a server. This is the first step after
|
||||
creating a new L{Transport} and setting up your server host key(s). A
|
||||
separate thread is created for protocol negotiation, so this method
|
||||
returns immediately.
|
||||
|
||||
When negotiation is done (successful or not), the given C{Event} will
|
||||
be triggered. On failure, L{is_active} will return C{False}.
|
||||
|
||||
After a successful negotiation, the client will need to authenticate.
|
||||
Override the methods
|
||||
L{get_allowed_auths <Transport.get_allowed_auths>},
|
||||
L{check_auth_none <Transport.check_auth_none>},
|
||||
L{check_auth_password <Transport.check_auth_password>}, and
|
||||
L{check_auth_publickey <Transport.check_auth_publickey>} to control the
|
||||
authentication process.
|
||||
|
||||
After a successful authentication, the client should request to open
|
||||
a channel. Override L{check_channel_request} to allow channels to
|
||||
be opened.
|
||||
|
||||
@note: After calling this method (or L{start_client} or L{connect}),
|
||||
you should no longer directly read from or write to the original socket
|
||||
object.
|
||||
|
||||
@param event: an event to trigger when negotiation is complete.
|
||||
@type event: threading.Event
|
||||
"""
|
||||
self.server_mode = 1
|
||||
self.completion_event = event
|
||||
self.start()
|
||||
|
@ -301,9 +350,29 @@ class BaseTransport (threading.Thread):
|
|||
return self.active
|
||||
|
||||
def open_session(self):
|
||||
"""
|
||||
Request a new channel to the server, of type C{"session"}. This
|
||||
is just an alias for C{open_channel('session')}.
|
||||
|
||||
@return: a new L{Channel} on success, or C{None} if the request is
|
||||
rejected or the session ends prematurely.
|
||||
@rtype: L{Channel}
|
||||
"""
|
||||
return self.open_channel('session')
|
||||
|
||||
def open_channel(self, kind):
|
||||
"""
|
||||
Request a new channel to the server. L{Channel}s are socket-like
|
||||
objects used for the actual transfer of data across the session.
|
||||
You may only request a channel after negotiating encryption (using
|
||||
L{connect} or L{start_client} and authenticating.
|
||||
|
||||
@param kind: the kind of channel requested (usually C{"session"}).
|
||||
@type kind: string
|
||||
@return: a new L{Channel} on success, or C{None} if the request is
|
||||
rejected or the session ends prematurely.
|
||||
@rtype: L{Channel}
|
||||
"""
|
||||
chan = None
|
||||
try:
|
||||
self.lock.acquire()
|
||||
|
@ -361,7 +430,33 @@ class BaseTransport (threading.Thread):
|
|||
return True
|
||||
|
||||
def check_channel_request(self, kind, chanid):
|
||||
"override me! return object descended from Channel to allow, or None to reject"
|
||||
"""
|
||||
I{(subclass override)}
|
||||
Determine if a channel request of a given type will be granted, and
|
||||
return a suitable L{Channel} object. This method is called in server
|
||||
mode when the client requests a channel, after authentication is
|
||||
complete.
|
||||
|
||||
In server mode, you will generally want to subclass L{Channel} to
|
||||
override some of the methods for handling client requests (such as
|
||||
connecting to a subsystem or opening a shell) to determine what you
|
||||
want to allow or disallow. For this reason, L{check_channel_request}
|
||||
must return a new object of that type. The C{chanid} parameter is
|
||||
passed so that you can use it in L{Channel}'s constructor.
|
||||
|
||||
The default implementation always returns C{None}, rejecting any
|
||||
channel requests. A useful server must override this method.
|
||||
|
||||
@param kind: the kind of channel the client would like to open
|
||||
(usually C{"session"}).
|
||||
@type kind: string
|
||||
@param chanid: ID of the channel, required to create a new L{Channel}
|
||||
object.
|
||||
@type chanid: int
|
||||
@return: a new L{Channel} object (or subclass thereof), or C{None} to
|
||||
refuse the request.
|
||||
@rtype: L{Channel}
|
||||
"""
|
||||
return None
|
||||
|
||||
def accept(self, timeout=None):
|
||||
|
@ -385,8 +480,8 @@ class BaseTransport (threading.Thread):
|
|||
Negotiate an SSH2 session, and optionally verify the server's host key
|
||||
and authenticate using a password or private key. This is a shortcut
|
||||
for L{start_client}, L{get_remote_server_key}, and
|
||||
L{Transport.auth_password} or L{Transport.auth_key}. Use those methods
|
||||
if you want more control.
|
||||
L{Transport.auth_password} or L{Transport.auth_publickey}. Use those
|
||||
methods if you want more control.
|
||||
|
||||
You can use this method immediately after creating a Transport to
|
||||
negotiate encryption with a server. If it fails, an exception will be
|
||||
|
@ -450,7 +545,7 @@ class BaseTransport (threading.Thread):
|
|||
self.auth_password(username, password, event)
|
||||
else:
|
||||
self._log(DEBUG, 'Attempting password auth...')
|
||||
self.auth_key(username, pkey, event)
|
||||
self.auth_publickey(username, pkey, event)
|
||||
while 1:
|
||||
event.wait(0.1)
|
||||
if not self.active:
|
||||
|
|
Loading…
Reference in New Issue