From b1bc7b42b49c37ac9a2dca79986b710a62a098b8 Mon Sep 17 00:00:00 2001 From: Ahmed Karic Date: Wed, 9 Oct 2024 19:21:01 +0200 Subject: [PATCH] test: Verify fetching data using ssh public key Add a test case to verify that a new (guest) user can retrieve data (i.e. syslog data) using ssh public key Fixes #304 --- test/case/ietf_system/ietf_system.yaml | 3 + .../ssh_key_authentication/test.py | 94 ++++++++++++++++++ .../ssh_key_authentication/topology.dot | 1 + .../ssh_key_authentication/topology.png | Bin 0 -> 3111 bytes test/infamy/ssh.py | 49 +++++++++ 5 files changed, 147 insertions(+) create mode 100755 test/case/ietf_system/ssh_key_authentication/test.py create mode 120000 test/case/ietf_system/ssh_key_authentication/topology.dot create mode 100644 test/case/ietf_system/ssh_key_authentication/topology.png diff --git a/test/case/ietf_system/ietf_system.yaml b/test/case/ietf_system/ietf_system.yaml index 2e3e4e56e..d5c31b36e 100644 --- a/test/case/ietf_system/ietf_system.yaml +++ b/test/case/ietf_system/ietf_system.yaml @@ -13,3 +13,6 @@ - name: timezone_utc_offset case: timezone_utc_offset/test.py + +- name: ssh_key_authentication + case: ssh_key_authentication/test.py diff --git a/test/case/ietf_system/ssh_key_authentication/test.py b/test/case/ietf_system/ssh_key_authentication/test.py new file mode 100755 index 000000000..0a68386f1 --- /dev/null +++ b/test/case/ietf_system/ssh_key_authentication/test.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +""" +Generate ssh key pair + +Verify that 'guest' user can fetch data using only the 'public' key +""" + +import infamy +import os +import tempfile +from infamy import ssh + +with infamy.Test() as test: + with test.step("Connect to the target device"): + env = infamy.Env() + target = env.attach("target", "mgmt") + + private_key = """-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn +NhAAAAAwEAAQAAAQEAn3zL3StVQZLsP9dnrXxK/PT4m2tjW0M+2GN6JdiIUZyKI9KKHWaf +2uHNdXNUPo0JGwgyj1geOcN2TEdkPd113mO9qrS87wgSzs3gpF93MzACSy8c55dxF5g50w +FnrRNZ1JgciyzryncNQjxYkvbbrIcHX4+ojn3sdx70MJbVeYv60M9IeyXksBENF5+rAYA8 +VpQ+k7cGJeHIdMx6MURwo6nUIoOzTKJ4WhedwTCkWGlEixE98PsynyvB2Ih8a8uiX/nXLb +PT0MsaQohFt0aFOuZ8J6taRu1wHZk/w3hikkKl5HZ5l74GZK0GGfuB1tr3kJR88MBCAITE +7HEvkIjl/wAAA8hbDYq6Ww2KugAAAAdzc2gtcnNhAAABAQCffMvdK1VBkuw/12etfEr89P +iba2NbQz7YY3ol2IhRnIoj0oodZp/a4c11c1Q+jQkbCDKPWB45w3ZMR2Q93XXeY72qtLzv +CBLOzeCkX3czMAJLLxznl3EXmDnTAWetE1nUmByLLOvKdw1CPFiS9tushwdfj6iOfex3Hv +QwltV5i/rQz0h7JeSwEQ0Xn6sBgDxWlD6TtwYl4ch0zHoxRHCjqdQig7NMonhaF53BMKRY +aUSLET3w+zKfK8HYiHxry6Jf+dcts9PQyxpCiEW3RoU65nwnq1pG7XAdmT/DeGKSQqXkdn +mXvgZkrQYZ+4HW2veQlHzwwEIAhMTscS+QiOX/AAAAAwEAAQAAAQAOYsviyc9ZaF7ODWiJ +Mg5zjcdFAaVHLKQlEagJdOQq9GNTguC5cTHXJQoK35nIQKGDIjSpUGn9jN+FVuU4XVsN8d +JAbSgjqYdExzZNrVzLrbdvP7MsQrFNTwpcOaK37mhqcEQW27jzHNUB1f6pVwIOqGlmWcd6 +/unO/uhI37omyfCkZT7lU4E+iCGrbIiwmutT2KmUJ6FZOedDl7XbwyUZMqmtjOGbN+0Hc3 +ahtA79+C4MaIptGVr10c85WLz/Rh9oN9tDYZRqhU5cARUd9LyEeKF9R7L+kCq4b2zuEqNI +BSYLGIu859f+IEXeA2Hq965tCTMMgwauMAS1If9R+rlRAAAAgHeoqdL7d3FX1iijZWSBua +Bran5mNdcGzf/8SD25WRMUPhsoqHOvtDWuOkop6nAu/9GGigJaBICuDxJz3KN1Hhpuer+g +/x7+Dgwd5mW41hXOTezp2hGO98OwHLJpmohCz1NIZIHz0h6NZbRZ4vozMtYBs1aq1Qv6h2 +DLsxLMLY7FAAAAgQDKkDQXxiXr7Bv7UJaYA4BZAg6qPMvW943mOreLl0uO8urE3mt2MnVy +Et1r2dEhxwqsWrDj5rsBVSXrg/8kXYHrqAgldZ3TxEOCU8xVV4RAzxfE0uFwdawZHdsIJL +JWwNnQ8TdWXPZze0lE9R5b2E4EvJilHvD13pdcIN+hyvGE0QAAAIEAyY+JAtJjDS6wW07E +eTVndLHpDiTZO+tCIP+OO45uYA/8O+IMc+wvIsHCpZC7e3bskg6z2gt5B0DwSnf2Q4zXxP +OFXdOBTFO8XcgWKRo9BIPV6BNH9qrx0Z0m5G45rY6SE9c5Ypv0ExjXRZ/iPWLBSarsv1fF +lrH5aNT6hzZKsc8AAAAMcm9vdEBpbmZhbXkwAQIDBAUGBw== +-----END OPENSSH PRIVATE KEY----- +""" + + public_key_alg = "ssh-rsa" + public_key_data = "AAAAB3NzaC1yc2EAAAADAQABAAABAQCffMvdK1VBkuw/12etfEr89Piba2NbQz7YY3ol2IhRnIoj0oodZp/a4c11c1Q+jQkbCDKPWB45w3ZMR2Q93XXeY72qtLzvCBLOzeCkX3czMAJLLxznl3EXmDnTAWetE1nUmByLLOvKdw1CPFiS9tushwdfj6iOfex3HvQwltV5i/rQz0h7JeSwEQ0Xn6sBgDxWlD6TtwYl4ch0zHoxRHCjqdQig7NMonhaF53BMKRYaUSLET3w+zKfK8HYiHxry6Jf+dcts9PQyxpCiEW3RoU65nwnq1pG7XAdmT/DeGKSQqXkdnmXvgZkrQYZ+4HW2veQlHzwwEIAhMTscS+QiOX/" + + with test.step("Create a guest user on the target device"): + USER = "guest" + + target.put_config_dict("ietf-system", { + "system": { + "authentication": { + "user": [ + { + "name": USER, + "authorized-key": [ + { + "name":"guest-ssh-key", + "algorithm":public_key_alg, + "key-data":public_key_data + } + ], + "infix-system:shell":"bash" + } + ] + } + } + }) + + with test.step("Write private key to a temporary file"): + with tempfile.NamedTemporaryFile(delete=False, mode='w') as key_file: + key_file.write(private_key) + key_file_name = key_file.name + + os.chmod(key_file_name, 0o600) + + with test.step("Verify it is possible to fetch syslog data using public key"): + address = target.get_mgmt_ip() + syslog_file = "./syslog_copy" + + ssh.fetch_file( + remote_user=USER, + remote_address=address, + remote_file="/var/log/syslog", + local_file=syslog_file, + key_file=key_file_name, + check=True, + remove=True + ) + + test.succeed() diff --git a/test/case/ietf_system/ssh_key_authentication/topology.dot b/test/case/ietf_system/ssh_key_authentication/topology.dot new file mode 120000 index 000000000..02b788692 --- /dev/null +++ b/test/case/ietf_system/ssh_key_authentication/topology.dot @@ -0,0 +1 @@ +../../../infamy/topologies/1x1.dot \ No newline at end of file diff --git a/test/case/ietf_system/ssh_key_authentication/topology.png b/test/case/ietf_system/ssh_key_authentication/topology.png new file mode 100644 index 0000000000000000000000000000000000000000..21661c1820991c72b55ff3a883c46a8868eb56a3 GIT binary patch literal 3111 zcmb7GcTiJV7k>gv7m&6B0wM?!K|!ekQk7mL^j<>f9T%jpA_%CIEFwaJNXbeODIp+D zKq(6W>Alxb5=ww23GhAluWx2&zM1d5nfuDz`|dgC{?70GlFdwXFEaBp0|0PQUr)yz z0B9t^XH`ZTaFlx7tOwrc-3)bgfb*Z%`(`u(09a=9bu=v^@^)rpjG*HJ47;JzTJ}yW z#Wyy__;)NaO=>Padc;co+7tgO;}Nco&8!9{%a5D;AOPjfX=8=AoAu4TCMxuu; z=-Sn*8E7s5i05NyW&nVM#5r03(9$Me0DuDhzuEcu`Pqb2H$Gax-z&~Vh>DAM4%-3| z$j;7ADmB{F^8$gJhX)gN96(r{UsK!J+2P^gd5T_%rGM7uA`@|sg#iMAOifR#A%BTi z+}z$S|MSn!Hc}`PSoOtO1M3&#tt4WQlf} zmuM)k>r-4@e0Fw*>UT4*uBjo;G%T-T^Z?T11!CK&5CCxSN3sI|>6wols-f<7u(Nh> z^YTW@&;SuNafZ^I@r{|J&7TPy=KRMCfAi)pFS$=n&33o4%SJaVTgWMKUZ4%2)KYn+ zGYyKFpD&%P=eI^4LgKzYV_-ib&Q}h4(a_LbyLQdo+&q@Lr%Tu;c#1H6$i)1`HF#ay23FQj*d8)z5?x} zyfgrS>Rik4o34`<6&00{37T(-5l47`PvK#H?nazzo_R|k5R7vbB)L=GzkiR*RSXXg zzsp)U>Vtf_a2?a_R+V?}F+^J0_@jkEv3ZsO#-sO5U7bR%S=xQ_#&Vi^fAw~faBRIx z+tc)PjtZ;k(a{HKuc5dbHIq%@#JTQny&R(wvl|KlGZRx&o6(tE9s7S|XHReQL7`AC z5!k^RPE%9U;YxT;{HQ6J258sC*GRP^}DN)IBe4_rt~OM8;!6p6pCr57Arg}BtI$tZdIcK8|| z=#v{A9Zleot;v`2{X!3N84W>Z(U9-(7i}c+glBuU_$!Hh{Y|( z*i@8Qj?qJRlzJSB!`#g5EAlzTsMd1;1^)C`r-%X!27|?7Yimg(AE8_+AO;|Ea-^f3 z>8>omKp>CyPW67WwEB&)czfWalg%o5Oc=USLGK$dX@sW|4 z#_&KGtf;K)rlKMijZP~0YkYkCxJM#Cnv6#a3JT87&N|1PK8}b`3bw#8iZnDdfN0d$ z*SG%Uz<2p_{o}1M3b8frnBe%OXmV%OWU2kw?9rn~!qK}IW^diNaYI_#-`l%@eIQR+ zn^8GvLBqg+Sw!sW)rH>MtyHi+ZadV=C@I~@?qw2bYio0>Qo4WNNsRO4jzq&FCN&{VyFF zf7{uftN}sDBoZ7P9Jq)tA=7!VWkrDk{p>Hpc{A$c|s>bd`6vtt&5=QdOmr@WU-FEeRYA z4yfE*d(fcJyF3HkhjShIDTzr*6f*f84o==(!{sKV%lnQ6(ZcRbLQT~yq0rE+F=>pQ zF{7lUuw zA1)Y)rmo+zTaMrsA>A|A(1^z=G(RMD3CF$ozO=F770`4lU%Mw7kvuds1UgDN4b$qB z$TIM5T@1CsMMg$$AZ66m)!Q2nw9-Ia{x}U-iL5}Y3$b;`ID80u))=o)^6lF<^>gY$ zcZR6p8!2xuFPqlb)6LN`3Weg>-?h^j%{voH2Lx)&7m(a<&Xzb!^RkE}c-STdF8
    )Z*PQw?})0Wmf*DpEXdp%5BtYikEU&ko0(*Xe&) z2SHE@`8HBQ2U5(>ugS>lPGNkHiSz6Cr6!!Ege0D7Lr!p{^FJl>WWR=uPfXaH&69h& zY(KlS1-72T<@nv*+%{0M^X+U;>Ub|{1!OA^MIhk{ayu9d@?u^;SaFFGrcBU|3Z73@%Baz7Dm3!i(^^;`*6@gRX?iiZ>#qot)47#Qf`u?i9nGHv_wJ6YDkVSGwT zN}b^EzK{hf)SA-5Wctcpr5N65wx z5edo=|U#!p#f4h?4lqA`J9gs1yw6rua zd2Ls5w718^#uiIxSij}eR1Y%5Jq>Y$yquihRIPr6m0_`YvH8hT>TLx%IWIZ>Tr=S~ zYLy9^g@q-wx$)jL-qfFITs+tz?uT=0hu2*TtppsUCN1VXzgDfW6m) zP#r!BV0Dwp@{~+goH&7AXOAk z%;*k;;^P*;@4t|U=q9iT0@74Vm~c^aYn?u8=^6(pyqL0b1K7~Y%2J)&r6CYzM#cq# zJxzS}bd|dW z^C||+d_F-ofrVCIuVlKqtm$NllOYB#P)`o7`^Yf9%L-rLv5o%;Q!k_6@F?yiha#-P`TmmF0s zZc7bRI%T8GxkG>0V0^OB&>*9-QAm~nsBjlvt%3Md^LZ2&R*Q!2GJ}i^wlb<3Yi~8` mFM0rgi_iQcmjCU-IqfNVDekrp3n!@j0sRLiI-j&$p8f~+&ndD1 literal 0 HcmV?d00001 diff --git a/test/infamy/ssh.py b/test/infamy/ssh.py index 59bd4290e..7e3395d18 100644 --- a/test/infamy/ssh.py +++ b/test/infamy/ssh.py @@ -12,6 +12,55 @@ class Location: port: int = 22 +import subprocess +import os + +def fetch_file(remote_user, remote_address, remote_file, local_file, key_file, check=False, remove=False): + """ + Fetches a file over SSH using scp and the provided private key. + + :param remote_user: The user on the remote machine. + :param remote_address: The address of the remote machine. + :param remote_file: The file to fetch from the remote machine. + :param local_file: The local path where the file will be stored. + :param key_file: The path to the private SSH key. + :param check: check the return code of the command. + :param remove: remove the fetched local file after copying. + """ + try: + result = subprocess.run( + f"scp -q -o StrictHostKeyChecking=no -i {key_file} {remote_user}@[{remote_address}]:{remote_file} {local_file}", + shell=True + ) + + if check: + if result.returncode != 0: + raise RuntimeError("Failed to copy file from remote host") + + if not os.path.exists(local_file): + raise RuntimeError(f"File {local_file} does not exist after copy") + + if os.path.getsize(local_file) == 0: + raise RuntimeError(f"File {local_file} is empty after copy") + + except Exception as e: + print(f"Error during file transfer: {e}") + raise + + finally: + if os.path.exists(key_file): + try: + os.remove(key_file) + except OSError as e: + print(f"Error removing key file {key_file}: {e}") + + if remove: + try: + if os.path.exists(local_file): + os.remove(local_file) + except OSError as e: + print(f"Error removing fetched file {local_file}: {e}") + class Device(object): def __init__(self, name: str, location: Location): self.name = name