Skip to content

Commit

Permalink
Added public key, agent, password auth, sftp read/write and non-block…
Browse files Browse the repository at this point in the history
…ing execute and sftp read example scripts.

Added example directory readme.
Updated utils.wait_socket for updated API.
Updated changelog.
Added examples readme.
Updated compiler flags in setup.py.
  • Loading branch information
pkittenis committed Aug 10, 2017
1 parent 93d754b commit 2abc1cc
Show file tree
Hide file tree
Showing 16 changed files with 2,044 additions and 1,086 deletions.
17 changes: 17 additions & 0 deletions Changelog.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
Change Log
=============

0.5.0
------

Changes
_________

* Implemented SFTP statvfs and SFTP handle fstatvfs methods and integration tests.
* Implemented SFTPStatVFS extension class for file system statistics.
* SFTP read and readdir functions now return size/error code along with data.
* SFTP handle fstat now returns attributes.
* Implemented SFTP handle readdir* methods as python generators,
* SFTP openddir can now be used as a context manager.
* Block directions function renamed to match libssh2.
* Example scripts.
* All session authentication methods now raise ``AuthenticationError`` on failure.


0.4.0
------

Expand Down
30 changes: 17 additions & 13 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ Super fast SSH2 protocol library. ``ssh2-python`` provides Python bindings for `
:alt: Latest Version
.. image:: https://travis-ci.org/ParallelSSH/ssh2-python.svg?branch=master
:target: https://travis-ci.org/ParallelSSH/ssh2-python
.. image:: https://readthedocs.org/projects/ssh2-python/badge/?version=latest
:target: http://ssh2-python.readthedocs.io/en/latest/?badge=latest
:alt: Documentation


Installation
______________


System packages are available on the `latest releases page <https://github.com/ParallelSSH/ssh2-python/releases/latest>`_ built on Centos/RedHat 6/7, Ubuntu 14.04/16.04, Debian 7/8 and Fedora 22/23/24.


Installation from Source
_________________________

Expand All @@ -46,15 +46,18 @@ RedHat
API Feature Set
________________

Currently the entirety of the `libssh2`_ API has been implemented. `API documentation is available <https://readthedocs.org/projects/ssh2-python/badge/?version=latest>`_ for ``ssh2-python``.

Complete example scripts for various operations can be found in the `examples directory`.
Currently the vast majority of the `libssh2`_ API has been implemented with only few exceptions.

Complete example scripts for various operations can be found in the `examples directory`_.

In addition, as ``ssh2-python`` is a thin wrapper of ``libssh2`` with Python semantics, its code examples can be ported straight over to Python with only minimal changes.

In addition, ``ssh2-python`` is a thin wrapper of ``libssh2`` with Python semantics - its code examples can be ported straight over to Python with only minimal changes.

Quick Start
_____________


Both byte and unicode strings are accepted as arguments and encoded appropriately. To change default encoding change the value of ``ssh2.utils.ENCODING``. Channel output is always byte strings.

See `Complete Example`_ for a complete example including socket connect.
Expand Down Expand Up @@ -124,7 +127,7 @@ Exit Code

.. code-block:: python
print("Exit status: {}".format(channel.get_exit_status()))
print("Exit status: %s" % (channel.get_exit_status()))
.. code-block:: python
Expand Down Expand Up @@ -161,7 +164,7 @@ SFTP Read
sftp = session.sftp_init()
with sftp.open(<remote file to read>, 0, 0) as remote_fh, \
open(<file to write>, 'wb') as local_fh:
for data in remote_fh:
for size, data in remote_fh:
local_fh.write(data)
Expand All @@ -170,6 +173,8 @@ __________________

A simple usage example looks very similar to ``libssh2`` `usage examples <https://www.libssh2.org/examples/>`_.

See `examples directory <https://github.com/ParallelSSH/ssh2-python/tree/master/examples>`_ for more complete example scripts.

As mentioned, ``ssh2-python`` is intentially a thin wrapper over ``libssh2`` and directly maps most of its API.

Clients using this library can be much simpler to use than interfacing with the ``libssh2`` API directly.
Expand Down Expand Up @@ -239,13 +244,13 @@ Extension features:
* Very low overhead
* Super fast as a consequence of the excellent C library it uses and that it uses native code prodigiously
* Object oriented - memory freed automatically and safely as objects expire
* Use Python semantics where applicable, such as iterator support for SFTP file handles
* Use Python semantics where applicable, such as iterator support for reading from SFTP file handles
* Expose errors as Python exceptions where possible
* Provide access to ``libssh2`` error code definitions


Comparison with other Python SSH2 libraries
---------------------------------------------
Comparison with other Python SSH libraries
-------------------------------------------

Performance of above example, compared with Paramiko.

Expand All @@ -269,7 +274,6 @@ Performance of above example, compared with Paramiko.
sys 0m0.021s


See `examples directory <https://github.com/ParallelSSH/ssh2-python/tree/master/examples>`_ for more complete example scripts.

.. _libssh2: https://www.libssh2.org
.. _Cython: https://www.cython.org
.. _`examples directory`: https://github.com/ParallelSSH/ssh2-python/tree/master/examples
91 changes: 91 additions & 0 deletions examples/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
Examples
==========

In this directory can be found example scripts using ``ssh2-python`` for various operations.

To try them out, install the library and run the scripts like so:

Pkey from file
---------------

.. code-block:: shell
python examples/publickey_fromfile.py ~/.ssh/id_rsa 'echo me'
me
Non-blocking execute
----------------------

.. code-block:: shell
python examples/nonblocking_execute.py 'echo me'
Would block, waiting for socket to be ready
Would block, waiting for socket to be ready
Waiting for command to finish
Waiting for command to finish
me
SFTP write
-----------

.. code-block:: shell
python examples/sftp_write.py ~/<my source file> ~/<my dest file>
Starting copy of local file <source file> to remote localhost:<dest file>
Finished writing remote file in 0:00:00.006304
Do *not* use the same filename for source and destination when connecting to localhost if you want to keep your file intact.

SFTP read
-----------

.. code-block:: shell
python examples/sftp_read.py ~/<remote file>
Starting read for remote file <remote file>
Finished file read in 0:00:00.045763
Non-blocking SFTP read
-----------------------

Note there is no error checking and file is assumed to exist. The script will hang if it does not.

.. code-block:: shell
python examples/nonblocking_sftp_read.py <remote file>
Would block on sftp init, waiting for socket to be ready
<..>
Would block on sftp init, waiting for socket to be ready
Starting read for remote file <remote file>
Would block on handle open
Would block on read, waiting..
Finished file read in 0:00:00.056730
Password authentication
-------------------------

Authentication with wrong password raises ``AuthenticationError`` exception.

.. code-block:: shell
python examples/password_auth.py 'asdfadf' 'echo me'
Traceback (most recent call last):
File "examples/password_auth.py", line 45, in <module>
main()
File "examples/password_auth.py", line 35, in main
s.userauth_password(args.user, args.password)
File "ssh2/session.pyx", line 250, in ssh2.session.Session.userauth_password
raise AuthenticationError(
ssh2.exceptions.AuthenticationError: ('Error authenticating user %s with password', '<user>')
SSH Agent authentication
--------------------------
.. code-block:: shell
python examples/agent_auth.py 'echo me'
me
43 changes: 43 additions & 0 deletions examples/agent_auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Example script for authentication with SSH Agent"""

from __future__ import print_function

import argparse
import socket
import os
import pwd

from ssh2.session import Session


USERNAME = pwd.getpwuid(os.geteuid()).pw_name

parser = argparse.ArgumentParser()

parser.add_argument('cmd', help="Command to run")
parser.add_argument('--host', dest='host',
default='localhost',
help='Host to connect to')
parser.add_argument('--port', dest='port', default=22,
help="Port to connect on", type=int)
parser.add_argument('-u', dest='user', default=USERNAME,
help="User name to authenticate as")


def main():
args = parser.parse_args()
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((args.host, args.port))
s = Session()
s.handshake(sock)
s.agent_auth(args.user)
chan = s.open_session()
chan.execute(args.cmd)
size, data = chan.read()
while size > 0:
print(data)
size, data = chan.read()


if __name__ == "__main__":
main()
86 changes: 86 additions & 0 deletions examples/nonblocking_execute.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"""Example script for non-blocking execute.
Note that `ssh2.utils.wait_socket` is not a co-operative routine and will block
the main thread for up to <timeout> (default 1sec). Use for testing purposes
only."""

from __future__ import print_function

import argparse
import socket
import os
import pwd
from select import select

from ssh2.session import Session
# from ssh2.utils import wait_socket
from ssh2.error_codes import LIBSSH2_ERROR_EAGAIN
from ssh2.session import LIBSSH2_SESSION_BLOCK_INBOUND, \
LIBSSH2_SESSION_BLOCK_OUTBOUND


USERNAME = pwd.getpwuid(os.geteuid()).pw_name

parser = argparse.ArgumentParser()

parser.add_argument('cmd', help="Command to run")
parser.add_argument('--host', dest='host',
default='localhost',
help='Host to connect to')
parser.add_argument('--port', dest='port', default=22,
help="Port to connect on", type=int)
parser.add_argument('-u', dest='user', default=USERNAME,
help="User name to authenticate as")


def wait_socket(_socket, session, timeout=1):
"""Helper function for testing non-blocking mode.
This function blocks the calling thread for <timeout> seconds -
to be used only for testing purposes.
Also available at `ssh2.utils.wait_socket`
"""
directions = session.block_directions()
if directions == 0:
return 0
readfds = [_socket] \
if (directions & LIBSSH2_SESSION_BLOCK_INBOUND) else ()
writefds = [_socket] \
if (directions & LIBSSH2_SESSION_BLOCK_OUTBOUND) else ()
return select(readfds, writefds, (), timeout)


def main():
args = parser.parse_args()
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((args.host, args.port))
s = Session()
s.handshake(sock)
# Agent connections cannot be used as non-blocking
s.agent_auth(args.user)
# Now we can set non-blocking mode
s.set_blocking(False)
chan = s.open_session()
while chan is None:
print("Would block on session open, waiting for socket to be ready")
wait_socket(sock, s)
chan = s.open_session()
while chan.execute(args.cmd) == LIBSSH2_ERROR_EAGAIN:
print("Would block on channel execute, waiting for socket to be ready")
wait_socket(sock, s)
while chan.wait_eof() == LIBSSH2_ERROR_EAGAIN:
print("Waiting for command to finish")
wait_socket(sock, s)
size, data = chan.read()
while size == LIBSSH2_ERROR_EAGAIN:
print("Waiting to read data from channel")
wait_socket(sock, s)
size, data = chan.read()
while size > 0:
print(data)
size, data = chan.read()


if __name__ == "__main__":
main()

0 comments on commit 2abc1cc

Please sign in to comment.