Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to disable algorithms #439

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
20 changes: 16 additions & 4 deletions atest/login.robot
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ Login With Public Key When Non-Existing Key
Run Keyword And Expect Error Given key file 'not_existing_key' does not exist.
... Login With Public Key ${KEY USERNAME} not_existing_key

Login With Public Key And Disabled Algorithms
VAR @{pubkeys} diffie-hellman-group16-sha512
VAR &{disabled_algorithms} pubkeys=${pubkeys}
Login With Public Key ${KEY USERNAME} ${KEY} disabled_algorithms=${disabled_algorithms}

Logging In Returns Server Output
[Setup] Open Connection ${HOST}
${output}= Login ${USERNAME} ${PASSWORD}
Expand Down Expand Up @@ -83,7 +88,14 @@ Login With Empty Quotes No Password
Login ${USERNAME_NOPASSWD} ""

Login Using Config File Proxy Command
[Tags] no-gh-actions
[Setup] Open Connection ${TEST_PROXY_HOSTNAME} prompt=${PROMPT}
${output}= Login password=test read_config=True
Should Contain ${output} test@
[Tags] no-gh-actions
[Setup] Open Connection ${TEST_PROXY_HOSTNAME} prompt=${PROMPT}
${output}= Login password=test read_config=True
Should Contain ${output} test@

Login With Disabled Algorithms
[Setup] Open Connection ${HOST} prompt=${PROMPT}
VAR @{pubkeys} rsa-sha2-512 rsa-sha2-256
VAR &{disabled_algorithms} pubkeys=${pubkeys}
Login ${USERNAME} ${PASSWORD} disabled_algorithms=${disabled_algorithms}

23 changes: 14 additions & 9 deletions src/SSHLibrary/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ def close(self):
pass

def login(self, username=None, password=None, allow_agent=False, look_for_keys=False, delay=None, proxy_cmd=None,
read_config=False, jumphost_connection=None, keep_alive_interval='0 seconds'):
read_config=False, jumphost_connection=None, keep_alive_interval='0 seconds', disabled_algorithms=None):
"""Logs into the remote host using password authentication.

This method reads the output from the remote host after logging in,
Expand Down Expand Up @@ -225,7 +225,7 @@ def login(self, username=None, password=None, allow_agent=False, look_for_keys=F
password = self._encode(password)
try:
self._login(username, password, allow_agent, look_for_keys, proxy_cmd, read_config,
jumphost_connection, keep_alive_interval)
jumphost_connection, keep_alive_interval, disabled_algorithms)
except SSHClientException:
self.client.close()
raise SSHClientException(f"Authentication failed for user '{self._decode(username)}'.")
Expand All @@ -250,7 +250,8 @@ def _read_login_output(self, delay):

def login_with_public_key(self, username, keyfile, password, allow_agent=False,
look_for_keys=False, delay=None, proxy_cmd=None,
jumphost_connection=None, read_config=False, keep_alive_interval='0 seconds'):
jumphost_connection=None, read_config=False, keep_alive_interval='0 seconds',
disabled_algorithms=None):
"""Logs into the remote host using the public key authentication.

This method reads the output from the remote host after logging in,
Expand Down Expand Up @@ -296,7 +297,8 @@ def login_with_public_key(self, username, keyfile, password, allow_agent=False,
self._login_with_public_key(username, keyfile, password,
allow_agent, look_for_keys,
proxy_cmd, jumphost_connection,
read_config, keep_alive_interval)
read_config, keep_alive_interval,
disabled_algorithms)
except SSHClientException:
self.client.close()
raise SSHClientException(f"Login with public key failed for user '{self._decode(username)}'.")
Expand Down Expand Up @@ -879,7 +881,7 @@ def _get_jumphost_tunnel(self, jumphost_connection):
return jumphost_transport.open_channel("direct-tcpip", dest_addr, jump_addr)

def _login(self, username, password, allow_agent=False, look_for_keys=False, proxy_cmd=None,
read_config=False, jumphost_connection=None, keep_alive_interval=None):
read_config=False, jumphost_connection=None, keep_alive_interval=None, disabled_algorithms=None):
if read_config:
hostname = self.config.host
self.config.host, username, self.config.port, proxy_cmd = \
Expand All @@ -900,7 +902,8 @@ def _login(self, username, password, allow_agent=False, look_for_keys=False, pro
self.client.connect(self.config.host, self.config.port, username,
password, look_for_keys=look_for_keys,
allow_agent=allow_agent,
timeout=float(self.config.timeout), sock=sock_tunnel)
timeout=float(self.config.timeout), sock=sock_tunnel,
disabled_algorithms=disabled_algorithms)
except paramiko.SSHException:
pass
transport = self.client.get_transport()
Expand All @@ -911,7 +914,8 @@ def _login(self, username, password, allow_agent=False, look_for_keys=False, pro
self.client.connect(self.config.host, self.config.port, username,
password, look_for_keys=look_for_keys,
allow_agent=allow_agent,
timeout=float(self.config.timeout), sock=sock_tunnel)
timeout=float(self.config.timeout), sock=sock_tunnel,
disabled_algorithms=disabled_algorithms)
transport = self.client.get_transport()
transport.set_keepalive(keep_alive_interval)
except paramiko.AuthenticationException:
Expand All @@ -929,7 +933,7 @@ def _login(self, username, password, allow_agent=False, look_for_keys=False, pro
raise SSHClientException

def _login_with_public_key(self, username, key_file, password, allow_agent, look_for_keys, proxy_cmd=None,
jumphost_connection=None, read_config=False, keep_alive_interval=None):
jumphost_connection=None, read_config=False, keep_alive_interval=None, disabled_algorithms=None):
if read_config:
hostname = self.config.host
self.config.host, username, self.config.port, key_file, proxy_cmd = \
Expand Down Expand Up @@ -958,7 +962,8 @@ def _login_with_public_key(self, username, key_file, password, allow_agent, look
allow_agent=allow_agent,
look_for_keys=look_for_keys,
timeout=float(self.config.timeout),
sock=sock_tunnel)
sock=sock_tunnel,
disabled_algorithms=disabled_algorithms)
transport = self.client.get_transport()
transport.set_keepalive(keep_alive_interval)
except paramiko.AuthenticationException:
Expand Down
26 changes: 26 additions & 0 deletions src/SSHLibrary/library.py
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,7 @@ def login(
read_config=False,
jumphost_index_or_alias=None,
keep_alive_interval="0 seconds",
disabled_algorithms=None,
):
"""Logs into the SSH server with the given ``username`` and ``password``.

Expand Down Expand Up @@ -1082,6 +1083,11 @@ def login(

``keep_alive_interval`` is new in SSHLibrary 3.7.0.

``disabled_algorithms`` is a list of algorithms that should be disabled.
For example, if you need to disable diffie-hellman-group16-sha512 key exchange
(perhaps because your code talks to a server which implements it differently from Paramiko),
specify disabled_algorithms={"kex": ["diffie-hellman-group16-sha512"]}

Example that logs in and returns the output:

| `Open Connection` | linux.server.com |
Expand All @@ -1104,6 +1110,12 @@ def login(
First, add the key to the authentication agent with: ``ssh-add /path/to/keyfile``.
| `Open Connection` | linux.server.com |
| `Login` | johndoe | allow_agent=True |

Example login with disabled algorithms:
| `Open Connection` | linux.server.com |
| `VAR` | @{pubkeys} | rsa-sha2-512 rsa-sha2-256 |
| `VAR` | &{disabled_algorithms} | pubkeys=${pubkeys} |
| `Login` | username=johndoe | disabled_algorithms=${disabled_algorithms} |
"""
jumphost_connection_conf = (
self.get_connection(index_or_alias=jumphost_index_or_alias)
Expand All @@ -1127,6 +1139,7 @@ def login(
is_truthy(read_config),
jumphost_connection,
keep_alive_interval,
disabled_algorithms,
)

@keyword(tags=("login",))
Expand All @@ -1142,6 +1155,7 @@ def login_with_public_key(
jumphost_index_or_alias=None,
read_config=False,
keep_alive_interval="0 seconds",
disabled_algorithms=None,
):
"""Logs into the SSH server using key-based authentication.

Expand Down Expand Up @@ -1196,6 +1210,17 @@ def login_with_public_key(
set to ``0``, which means sending the ``keepalive`` packet is disabled.

``keep_alive_interval`` is new in SSHLibrary 3.7.0.

``disabled_algorithms`` is a list of algorithms that should be disabled.
For example, if you need to disable diffie-hellman-group16-sha512 key exchange
(perhaps because your code talks to a server which implements it differently from Paramiko),
specify disabled_algorithms={"kex": ["diffie-hellman-group16-sha512"]}

Example login with disabled algorithms:
| `Open Connection` | linux.server.com |
| `VAR` | @{pubkeys} | rsa-sha2-512 rsa-sha2-256 |
| `VAR` | &{disabled_algorithms} | pubkeys=${pubkeys} |
| `Login With Public Key` | username=johndoe | keyfile=key | disabled_algorithms=${disabled_algorithms} |
"""
if proxy_cmd and jumphost_index_or_alias:
raise ValueError(
Expand Down Expand Up @@ -1223,6 +1248,7 @@ def login_with_public_key(
jumphost_connection,
is_truthy(read_config),
keep_alive_interval,
disabled_algorithms,
)

def _login(self, login_method, username, *args):
Expand Down