Skip to content

Commit aab7caf

Browse files
pkittenisiivanou
andauthored
Id auth (#268)
* Finish auth when identity auth succeeds * Moved main authentication function to base class. Updated libssh client code. Updated identity auth test and added test for libssh client. Updated setup.py * Added agent auth success test * Updated changelog Co-authored-by: Ivan Ivanou <[email protected]>
1 parent 90a4a1f commit aab7caf

File tree

9 files changed

+102
-79
lines changed

9 files changed

+102
-79
lines changed

Changelog.rst

+8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
Change Log
22
============
33

4+
2.5.1
5+
+++++
6+
7+
Fixes
8+
-----
9+
10+
* Successful identity file authentication would raise error - #264.
11+
412
2.5.0
513
+++++
614

pssh/clients/base/single.py

+28-3
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
from gevent.hub import Hub
3030
from gevent.select import poll
3131
from ssh2.utils import find_eol
32+
from ssh2.exceptions import AgentConnectionError, AgentListIdentitiesError, \
33+
AgentAuthenticationError, AgentGetIdentityError
3234

3335
from ..common import _validate_pkey_path
3436
from ...constants import DEFAULT_RETRIES, RETRY_DELAY
@@ -307,8 +309,8 @@ def _identity_auth(self):
307309
identity_file, ex)
308310
continue
309311
else:
310-
logger.debug("Authentication succeeded with identity file %s",
311-
identity_file)
312+
logger.info("Authentication succeeded with identity file %s",
313+
identity_file)
312314
return
313315
raise AuthenticationError("No authentication methods succeeded")
314316

@@ -319,7 +321,30 @@ def _keepalive(self):
319321
raise NotImplementedError
320322

321323
def auth(self):
322-
raise NotImplementedError
324+
if self.pkey is not None:
325+
logger.debug(
326+
"Proceeding with private key file authentication")
327+
return self._pkey_auth(self.pkey, password=self.password)
328+
if self.allow_agent:
329+
try:
330+
self._agent_auth()
331+
except (AgentAuthenticationError, AgentConnectionError, AgentGetIdentityError,
332+
AgentListIdentitiesError) as ex:
333+
logger.debug("Agent auth failed with %s"
334+
"continuing with other authentication methods", ex)
335+
except Exception as ex:
336+
logger.error("Agent auth failed with - %s", ex)
337+
else:
338+
logger.debug("Authentication with SSH Agent succeeded")
339+
return
340+
if self.identity_auth:
341+
try:
342+
return self._identity_auth()
343+
except AuthenticationError:
344+
if self.password is None:
345+
raise
346+
logger.debug("Private key auth failed, trying password")
347+
self._password_auth()
323348

324349
def _password_auth(self):
325350
raise NotImplementedError

pssh/clients/native/single.py

+1-28
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@
2424
from gevent.select import POLLIN, POLLOUT
2525
from ssh2.error_codes import LIBSSH2_ERROR_EAGAIN
2626
from ssh2.exceptions import SFTPHandleError, SFTPProtocolError, \
27-
Timeout as SSH2Timeout, AgentConnectionError, AgentListIdentitiesError, \
28-
AgentAuthenticationError, AgentGetIdentityError
27+
Timeout as SSH2Timeout
2928
from ssh2.session import Session, LIBSSH2_SESSION_BLOCK_INBOUND, LIBSSH2_SESSION_BLOCK_OUTBOUND
3029
from ssh2.sftp import LIBSSH2_FXF_READ, LIBSSH2_FXF_CREAT, LIBSSH2_FXF_WRITE, \
3130
LIBSSH2_FXF_TRUNC, LIBSSH2_SFTP_S_IRUSR, LIBSSH2_SFTP_S_IRGRP, \
@@ -218,32 +217,6 @@ def _keepalive(self):
218217
def _agent_auth(self):
219218
self.session.agent_auth(self.user)
220219

221-
def auth(self):
222-
if self.pkey is not None:
223-
logger.debug(
224-
"Proceeding with private key file authentication")
225-
return self._pkey_auth(self.pkey, password=self.password)
226-
if self.allow_agent:
227-
try:
228-
self._agent_auth()
229-
except (AgentAuthenticationError, AgentConnectionError, AgentGetIdentityError,
230-
AgentListIdentitiesError) as ex:
231-
logger.debug("Agent auth failed with %s"
232-
"continuing with other authentication methods", ex)
233-
except Exception as ex:
234-
logger.error("Unknown error during agent authentication - %s", ex)
235-
else:
236-
logger.debug("Authentication with SSH Agent succeeded")
237-
return
238-
if self.identity_auth:
239-
try:
240-
self._identity_auth()
241-
except AuthenticationError:
242-
if self.password is None:
243-
raise
244-
logger.debug("Private key auth failed, trying password")
245-
self._password_auth()
246-
247220
def _pkey_auth(self, pkey_file, password=None):
248221
self.session.userauth_publickey_fromfile(
249222
self.user,

pssh/clients/ssh/single.py

+3-27
Original file line numberDiff line numberDiff line change
@@ -153,38 +153,14 @@ def _init_session(self, retries=1):
153153
raise ex
154154

155155
def auth(self):
156-
if self.pkey is not None:
157-
logger.debug(
158-
"Proceeding with private key file authentication")
159-
return self._pkey_auth(self.pkey, password=self.password)
160-
if self.allow_agent:
161-
try:
162-
self.session.userauth_agent(self.user)
163-
except Exception as ex:
164-
logger.debug(
165-
"Agent auth failed with %s, "
166-
"continuing with other authentication methods",
167-
ex)
168-
else:
169-
logger.debug(
170-
"Authentication with SSH Agent succeeded.")
171-
return
172156
if self.gssapi_auth or (self.gssapi_server_identity or self.gssapi_client_identity):
173157
try:
174-
self.session.userauth_gssapi()
158+
return self.session.userauth_gssapi()
175159
except Exception as ex:
176160
logger.error(
177161
"GSSAPI authentication with server id %s and client id %s failed - %s",
178-
self.gssapi_server_identity, self.gssapi_client_identity,
179-
ex)
180-
if self.identity_auth:
181-
try:
182-
self._identity_auth()
183-
except AuthenticationError:
184-
if self.password is None:
185-
raise
186-
logger.debug("Private key auth failed, trying password")
187-
self._password_auth()
162+
self.gssapi_server_identity, self.gssapi_client_identity, ex)
163+
return super(SSHClient, self).auth()
188164

189165
def _password_auth(self):
190166
if not self.password:

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
'License :: OSI Approved :: GNU Lesser General Public License v2 (LGPLv2)',
4545
'Intended Audience :: Developers',
4646
'Operating System :: OS Independent',
47-
'Programming Language :: C',
47+
'Programming Language :: Python',
4848
'Programming Language :: Python :: 3',
4949
'Programming Language :: Python :: 3.4',
5050
'Programming Language :: Python :: 3.5',

tests/native/base_ssh2_case.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ def setUpClass(cls):
5858
cls.user = pwd.getpwuid(os.geteuid()).pw_name
5959
cls.client = SSHClient(cls.host, port=cls.port,
6060
pkey=PKEY_FILENAME,
61-
num_retries=1)
61+
num_retries=1,
62+
identity_auth=False,
63+
)
6264

6365
@classmethod
6466
def tearDownClass(cls):

tests/native/test_single_client.py

+35-12
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,17 @@
1515
# License along with this library; if not, write to the Free Software
1616
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1717

18-
import unittest
1918
import os
20-
import time
2119
import subprocess
2220
import shutil
2321
import tempfile
2422
from hashlib import sha256
2523
from datetime import datetime
2624

27-
from gevent import socket, sleep, spawn, Timeout as GTimeout
25+
from gevent import sleep, spawn, Timeout as GTimeout
2826

2927
from pssh.clients.native import SSHClient
3028
from ssh2.session import Session
31-
from ssh2.channel import Channel
3229
from ssh2.exceptions import SocketDisconnectError, BannerRecvError, SocketRecvError, \
3330
AgentConnectionError, AgentListIdentitiesError, \
3431
AgentAuthenticationError, AgentGetIdentityError, SFTPProtocolError
@@ -37,7 +34,6 @@
3734
AuthenticationError
3835

3936
from .base_ssh2_case import SSH2TestCase
40-
from ..embedded_server.openssh import OpenSSHServer
4137

4238

4339
class SSH2ClientTest(SSH2TestCase):
@@ -175,21 +171,32 @@ def test_manual_auth(self):
175171
client.session.handshake(client.sock)
176172
self.assertRaises(AuthenticationException, client.auth)
177173

178-
def test_default_identities_auth(self):
174+
def test_identity_auth(self):
175+
class _SSHClient(SSHClient):
176+
IDENTITIES = (self.user_key,)
179177
client = SSHClient(self.host, port=self.port,
180178
pkey=self.user_key,
181179
num_retries=1,
182180
allow_agent=False)
183-
client.session.disconnect()
181+
client.disconnect()
184182
client.pkey = None
185183
del client.session
186184
del client.sock
187185
client._connect(self.host, self.port)
188186
client._init_session()
189-
# Default identities auth only
190-
self.assertRaises(AuthenticationException, client._identity_auth)
191-
# Default auth
192-
self.assertRaises(AuthenticationException, client.auth)
187+
client.IDENTITIES = (self.user_key,)
188+
# Default identities auth only should succeed
189+
client._identity_auth()
190+
client.disconnect()
191+
client._connect(self.host, self.port)
192+
client._init_session()
193+
# Auth should succeed
194+
self.assertIsNone(client.auth())
195+
# Standard init with custom identities
196+
client = _SSHClient(self.host, port=self.port,
197+
num_retries=1,
198+
allow_agent=False)
199+
self.assertIsInstance(client, SSHClient)
193200

194201
def test_agent_auth_failure(self):
195202
class UnknownError(Exception):
@@ -201,7 +208,8 @@ def _agent_auth_agent_err():
201208
client = SSHClient(self.host, port=self.port,
202209
pkey=self.user_key,
203210
num_retries=1,
204-
allow_agent=True)
211+
allow_agent=True,
212+
identity_auth=False)
205213
client.session.disconnect()
206214
client.pkey = None
207215
client._connect(self.host, self.port)
@@ -210,6 +218,20 @@ def _agent_auth_agent_err():
210218
client._agent_auth = _agent_auth_agent_err
211219
self.assertRaises(AuthenticationError, client.auth)
212220

221+
def test_agent_auth_fake_success(self):
222+
def _agent_auth():
223+
return
224+
client = SSHClient(self.host, port=self.port,
225+
pkey=self.user_key,
226+
num_retries=1,
227+
allow_agent=True,
228+
identity_auth=False)
229+
client.session.disconnect()
230+
client.pkey = None
231+
client._connect(self.host, self.port)
232+
client._agent_auth = _agent_auth
233+
self.assertIsNone(client.auth())
234+
213235
def test_agent_fwd(self):
214236
client = SSHClient(self.host, port=self.port,
215237
pkey=self.user_key,
@@ -317,6 +339,7 @@ def __init__(self, host, port, num_retries):
317339
super(SSHClient, self).__init__(
318340
host, port=port, num_retries=2,
319341
allow_agent=True)
342+
self.IDENTITIES = set()
320343

321344
def _init_session(self):
322345
self.session = Session()

tests/ssh/base_ssh_case.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,9 @@ def setUpClass(cls):
7575
cls.user = USER
7676
cls.client = SSHClient(cls.host, port=cls.port,
7777
pkey=PKEY_FILENAME,
78-
num_retries=1)
78+
num_retries=1,
79+
identity_auth=False,
80+
)
7981

8082
@classmethod
8183
def tearDownClass(cls):

tests/ssh/test_single_client.py

+20-6
Original file line numberDiff line numberDiff line change
@@ -88,21 +88,35 @@ def test_stderr(self):
8888
self.assertListEqual(expected, stderr)
8989
self.assertEqual(len(output), 0)
9090

91-
def test_default_identities_auth(self):
91+
def test_identity_auth(self):
92+
class _SSHClient(SSHClient):
93+
IDENTITIES = (self.user_key,)
9294
client = SSHClient(self.host, port=self.port,
9395
pkey=self.user_key,
9496
num_retries=1,
97+
timeout=1,
9598
allow_agent=False)
96-
client.session.disconnect()
99+
client.disconnect()
97100
client.pkey = None
98101
del client.session
99102
del client.sock
100103
client._connect(self.host, self.port)
101104
client._init_session()
102-
# Default identities auth only
103-
self.assertRaises(AuthenticationException, client._identity_auth)
104-
# Default auth
105-
self.assertRaises(AuthenticationException, client.auth)
105+
client.IDENTITIES = (self.user_key,)
106+
# Default identities auth only should succeed
107+
client._identity_auth()
108+
client.disconnect()
109+
del client.session
110+
del client.sock
111+
client._connect(self.host, self.port)
112+
client._init_session()
113+
# Auth should succeed
114+
self.assertIsNone(client.auth())
115+
# Standard init with custom identities
116+
client = _SSHClient(self.host, port=self.port,
117+
num_retries=1,
118+
allow_agent=False)
119+
self.assertIsInstance(client, SSHClient)
106120

107121
def test_long_running_cmd(self):
108122
host_out = self.client.run_command('sleep 2; exit 2')

0 commit comments

Comments
 (0)