{"id":15206,"date":"2021-04-28T00:39:05","date_gmt":"2021-04-28T04:39:05","guid":{"rendered":"https:\/\/qxf2.com\/blog\/?p=15206"},"modified":"2021-04-28T00:39:05","modified_gmt":"2021-04-28T04:39:05","slug":"handling-set-new-password-prompt-with-paramiko","status":"publish","type":"post","link":"https:\/\/qxf2.com\/blog\/handling-set-new-password-prompt-with-paramiko\/","title":{"rendered":"Handling set new password prompt with Paramiko"},"content":{"rendered":"<h3>Why this post?<\/h3>\n<p>I hit an issue at one of our client recently &#8211; beginning from the latest version of the application, the remote server will prompt for a new password in the first login attempt, the password that comes out of the box will take you to the set new password prompt where you need to set a new password, re-type the new password &#038; then login again with the new password. While this change is a really good security feature, it led to our automation tests failing.<br \/>\nI was able to fix this, but while solving it, I realized that a solution using Paramiko was not easily available, I had to google for a few issues with my proposed solutions. I am sharing it to help another tester who might face this same problem.<\/p>\n<hr>\n<h3>My solution:<\/h3>\n<p>I created a method to invoke an interactive shell with the Paramiko SSH client to:<\/p>\n<ul>\n1. check for existing password prompt(to confirm new password prompt)<\/ul>\n<ul>\n2. verify new password prompt<\/ul>\n<ul>\n3. enter a new password<\/ul>\n<ul>\n4. re-enter the new password again<\/ul>\n<ul>\n5. get the confirmation message to assist debug<\/ul>\n<p><strong>NOTE: I am assuming you are working with a partially working code already. I am sharing the function alone hence. If you are new to Paramiko and wish to understand it better before solving this issue, refer our blog on <a href=\"https:\/\/qxf2.com\/blog\/ssh-using-python-paramiko\/\">Paramiko<\/a><\/strong><\/p>\n<pre lang='python'>\r\ndef handle_new_password_prompt():\r\n    \"\"\"\r\n    Check if new password is prompted and set it\r\n    \r\n    :param:\r\n    :return client: SSH client object\r\n    \"\"\"\r\n    client = None\r\n    host = your_host\r\n    user_name = your_user_name\r\n    port = your_port\r\n    old_pwd = your_old_password\r\n    new_pwd = your_new_password\r\n\r\n    try:\r\n\t# create an ssh client object\r\n\tclient = paramiko.SSHClient()\r\n\tlogging.getLogger(\"paramiko\").setLevel(logging.ERROR)\r\n\tclient.set_missing_host_key_policy(paramiko.AutoAddPolicy())\r\n\r\n\t# connect to the remote server with the old password\r\n\tclient.connect(host, username=user_name, password=old_pwd, port=port, timeout=30)\r\n        \r\n\t# invoke an shell\r\n\tshell_obj = ssh_client.invoke_shell()\r\n\r\n        # get the shell output, get the complete output with the while loop\r\n        out = ''\r\n        # sleep is essential, recv_ready returns False without sleep\r\n        time.sleep(1)\r\n\r\n        while shell_obj.recv_ready():\r\n            out += shell_obj.recv(2048)\r\n\r\n        # get the last line of the output\r\n        out = out.split('\\n')[-1]\r\n        \r\n        ########### step #1 ############\r\n        # verify if the last line of the output prompts existing password\r\n        if out.strip() == '(current) UNIX password:':\r\n            shell_obj.send(old_pwd+'\\n')\r\n\t    print(\"Old password when prompted was entered successfully\")\r\n\r\n        ########### step #2 ############\r\n        # check prompt for new password\r\n        out = ''\r\n        time.sleep(1)\r\n        while shell_obj.recv_ready():\r\n            out += shell_obj.recv(2048)\r\n\r\n        ########### step #2 ############\r\n        # if new password prompted, Enter new password\r\n        if out.strip() == 'New password:':\r\n            ########### step #3 ############\r\n            shell_obj.send(new_pwd+'\\n')\r\n\t    print(\"New password when prompted was entered successfully\")\r\n\r\n        ########### step #4 ############\r\n        # check re-enter new password prompt\r\n        out = ''\r\n        time.sleep(1)\r\n        while shell_obj.recv_ready():\r\n            out += shell_obj.recv(2048)\r\n\r\n        # if re-enter new password prompted, Enter the new password again\r\n        if out.strip() == 'Retype new password:':\r\n            shell_obj.send(new_pwd+'\\n')\r\n\t    print(\"Re-enter new password when prompted was entered successfully\")\r\n\r\n        ########### step #5 ############\r\n        # get the output after setting password - useful debug statement\r\n        out = ''\r\n        time.sleep(1)\r\n        while shell_obj.recv_ready():\r\n            out += shell_obj.recv(2048)\r\n        if out:\r\n\t    print(\"Confirmation after setting new password is - {}\".format(out))\r\n\t\r\n\tshell_obj.close()\r\n\r\n    except Exception as e:\r\n\tprint(\"Unable to set new password due to - {}\".format(str(e)))\r\n\r\n    else:\r\n\tclient.connect(host, username=user_name, password=new_pwd, port=port, timeout=30)\r\n\r\n    finally:\r\n\treturn client\r\n\r\n<\/pre>\n<p>I have posted the whole snippet as one big function to explain the flow of actions, I would suggest you break it down into smaller methods.<br \/>\nThis is what I learned while working on this fix :<br \/>\n1. <code>recv_ready()<\/code> method requires the <code>while<\/code> loop to read the complete data buffer<br \/>\n2. <code>time.sleep(1)<\/code> although is mundane is required(reference &#8211; <a href=\"https:\/\/github.com\/paramiko\/paramiko\/issues\/1091\">paramiko issue<\/a>) for the <code>shell_obj<\/code> to be ready to receive data<br \/>\n3. using <code>recv_ready()<\/code> in the end to read the output after setting the new password is very useful.<\/p>\n<hr>\n<p>This solution worked for me, I was able to run my automation tests with this fix. I hope this information is as useful to you as it was to me.<br \/>\nIf you have tried a different solution and it worked for you, great! let us know your solution in a comment.<\/p>\n<hr>\n","protected":false},"excerpt":{"rendered":"<p>Why this post? I hit an issue at one of our client recently &#8211; beginning from the latest version of the application, the remote server will prompt for a new password in the first login attempt, the password that comes out of the box will take you to the set new password prompt where you need to set a new [&hellip;]<\/p>\n","protected":false},"author":9,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[157,158],"tags":[],"class_list":["post-15206","post","type-post","status-publish","format-standard","hentry","category-paramiko","category-ssh"],"_links":{"self":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/15206","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/users\/9"}],"replies":[{"embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/comments?post=15206"}],"version-history":[{"count":26,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/15206\/revisions"}],"predecessor-version":[{"id":15238,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/15206\/revisions\/15238"}],"wp:attachment":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/media?parent=15206"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/categories?post=15206"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/tags?post=15206"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}