Python - change password for user in JunOS - python-2.7

I need assistance with this project and issues im having.
I am able to make changes to this juniper router with no issues.. The issue comes in when I need to change the password for a user.
Per the screen or the output below...
I have attempted:
user sends the command to change the password. Then it's suppose to get prompted with the New Password from the CLI which I'm attempting to enter it with the passwd1 and 2 string to be sent over per below. I even attempted to hid the output with getpass() but nothing.. it idles then since is unable to enter the password then it gets skipped and goes to the expect:
screenshot

There is another way of implimenting it:
from passlib.hash import md5_crypt
from getpass import getpass
user = getpass()
p1 = getpass()
hashpwd = md5_crypt.encrypt(p1)
commands = 'set system login user '+user+' class read-only authentication encrypted-password '+hashpwd
print (commands)
Output:
Password:
Password:
set system login user Vijay class read-only authentication encrypted-password $1$siC6W8.B$8FeEjf/Nt7shR1e8Axl.v1
For handling Junos devices using python, I would recommend you to use PyEZ - https://github.com/Juniper/py-junos-eznc
Example:
from jnpr.junos import Device
from lxml import etree
dev = Device('hostname', user='username', password='Password123')
dev.open()
cnf = dev.rpc.get_config() # similar to 'show configuration | no-more' on cli
print (etree.tounicode(cnf))
dev.close()

The resolution to this is to set the prompt of the interactive cli. For example
if you know you are expecting an unsupported prompt "interactive prompt" for example "=" - then you need to tell python that you are expecting that... submit your command and reset the prompt.
Example:
def JunOS(self,host_ips,config,commit):
try:
conn = SSH2(verify_fingerprint = False)
conn.connect(host_ips)
print "Connecting to : ", host_ips
conn.login(account)
print "**********************"
conn.execute(config)
print conn.response
conn.set_prompt(r'.$')
conn.execute('set system login user admin authen plain')
conn.execute(psswd)
conn.set_prompt()
conn.execute(psswd)
conn.execute(commit)
print conn.response
time.sleep(3)
print "********************************"
print "Password Updated !"
print "********************************"
except:
print "IP for this device : ", host_ips
print "Unable to connect or Username/password are incorrect"
print "**********************"
time.sleep(2)

Related

Typeform Security API and Django: Not Verifiying Hash Correctly

I am trying to use Typeform's security for their webhooks. This involves
1) Receiving the signed packets and extracting the signature
2) Getting the body of the requst
3) Creating a hash with a secret key on the payload
4) Matching the hash with the received signature
My web framework is Django (Python based). I am following the example at the TypeForm link here: https://developer.typeform.com/webhooks/secure-your-webhooks/.
For the life of me, I can't figure out what's going on. I've tried it in both Python and Ruby, and I can't get the hash right. I call a Ruby script from Python to match the output, but they are different and neither work. Does anyone have any insight? I'm starting to think that it might have something to do with the way that Django sends request bodies. Does anyone have any input?
Python implementation:
import os
import hashlib
import hmac
import base64
import json
class Typeform_Verify:
# take the request body in and encrypt with string
def create_hash(payload):
# convert the secret string to bytes
file = open("/payload.txt", "w")
# write to a payload file for the ruby script to read later
file.write(str(payload))
# access the secret string
secret = bytearray(os.environ['DT_TYPEFORM_STRING'], encoding="utf-8")
file.close()
# need to have the ruby version also write to a file
# create a hash with payload as the thing
# and the secret as the key`
pre_encode = hmac.new(secret,
msg=payload, digestmod=hashlib.sha256).digest()
post_encode = base64.b64encode(pre_encode)
return post_encode
# another approach is to make a ruby script
# that returns a value and call it from here
def verify(request):
file = open("/output.txt", "w")
# check the incoming hash values
received_hash = request.META["HTTP_TYPEFORM_SIGNATURE"]
# create the hash of the payload
hash = Typeform_Verify.create_hash(request.body)
# call ruby script on it
os.system(f"ruby manager/ruby_version.rb {received_hash} &> /oops.txt")
# concatenate the strings together to make the hash
encoded_hash = "sha256=" + hash.decode("utf-8")
file.write(f"Secret string: {os.environ['DT_TYPEFORM_STRING']}\n")
file.write(f"My hash : {encoded_hash}\n")
file.write(f"Their hash : {received_hash}\n")
file.close()
return received_hash == encoded_hash
Ruby script (called from Python)
require 'openssl'
require 'base64'
require 'rack'
def verify_signature(received_signature, payload_body, secret)
hash = OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), secret, payload_body)
# the created signature
actual_signature = 'sha256=' + Base64.strict_encode64(hash)
# write created signature to the file
out_file = File.new("/output.txt", "a")
out_file.write("Ruby output: ")
out_file.write(actual_signature)
out_file.close()
return 500, "Signatures don't match!" unless Rack::Utils.secure_compare(actual_signature, received_signature)
end
# MAIN EXECUTION
# get the hash from the python scriupt
received_hash = ARGV[0]
# read the content of the file into the f array
# note that this is the json payload from the python script
f = IO.readlines("/payload.txt")
# declare the secret string
secret = "SECRET"
# call the funtion with the recieved hash, file data, and key
result = verify_signature(received_hash, f[0], secret)
Code output:
Typeform hash: sha256=u/A/F6u3jnG9mr8KZH6j8/gO+Uny6YbSYFz7+oGmOik=
Python hash: sha256=sq7Kl2qBwRrwgGJeND6my4UPli8rseuwaK+f/sl8dko=
Ruby output: sha256=BzMxPZGmxgOMeJ236eAxSOXj85rEWI84t+6CtQBYliA=
UPDATED First see this github article as the one you referred to may be based on it.
The idea is that your requests should be signed. Here is a more basic pure ruby example which should illustrate how this should work.
# test.rb
ENV['SECRET_TOKEN'] = 'foobar'
require 'openssl'
require 'base64'
require 'rack'
def stub_request(body)
key = ENV['SECRET_TOKEN']
digest = OpenSSL::Digest.new('sha256')
hmac_signature = OpenSSL::HMAC.hexdigest(digest, key, body)
{ body: body, hmac_signature: hmac_signature }
end
def verify_signature(payload_body, request_signature)
digest = OpenSSL::Digest.new('sha256')
hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), ENV['SECRET_TOKEN'], payload_body)
if Rack::Utils.secure_compare(request_signature, hmac)
puts "They match"
else
puts "They don't match"
end
puts "request_signature: #{request_signature}"
puts " hmac: #{hmac}"
puts " body: #{payload_body}"
end
request = stub_request(ARGV[0])
verify_signature(request[:body], request[:hmac_signature])
Now to test this, just run:
ruby test.rb 'this is some random body string'
Here is a Python version of the same code. But this is vulnerable to timing attack vulnerability. There is probably a Python equivalent somewhere to mitigate this but I didn't do the research to find it. It shouldn't be hard to write something like the Ruby Rack version here in Python if your server doesn't already have something like it.
#test.py
import sys
import hashlib
import binascii
import hmac
import base64
KEY = 'foobar'
def stub_request(body):
key = bytes(KEY, 'utf-8')
body_bytes = bytes(body, 'utf-8')
hmac_signature = hmac.new(key,
msg=body_bytes, digestmod=hashlib.sha256).digest()
return {'body': body, 'hmac_signature': hmac_signature}
def verify_signature(payload_body, request_signature):
key = bytes(KEY, 'utf-8')
hmac_sig = hmac.new(key, msg=bytes(payload_body,'utf-8'), digestmod=hashlib.sha256).digest()
if hmac_sig == request_signature:
print("They match")
else :
print("They don't match")
print(f"request_signature: {binascii.hexlify(request_signature)}")
print(f" hmac: {binascii.hexlify(hmac_sig)}")
print(f" body: {payload_body}")
return request_signature
body = sys.argv[-1]
request = stub_request(body)
verify_signature(request['body'], request['hmac_signature'])
I ended up figuring it out. The Python implementation I had worked fine. The problem was in how I was saving the secret string. Apparently, environment variables in Python will not allow characters like $ or *. My Ruby implementation started working when I hardcoded my secret into the code, which led me to believe that the problem was in how I was saving the secret string. I recommend the Python implementation to anyone trying to do this kind of authentication. Cheers!

How can I make my registration test case run 5 times creating a new username each time?

I have a registration test that creates one account but I want to add a loop to this so that if will run 5 times in a row entering different usernames and email address, I already have the usernames I want to use stored in a seperate python file. Any ideas on how to do this?
Welcome to SO. There are different approaches but below is the simple approach.
Store all the required details in the list and then iterate.
users = [['user1','pass1'],['user2','pass2'],['user3','pass3'],['user5','pass5'],['user5','pass5']]
for user in users:
# get user name and use in registration
userName = user[0]
# get password and use in registration
passWord = user[1]
print (userName + ":" + passWord)

Python - Text does not appear in code-triggered email sent if string is result of a formula

I am attempting to write a program that sends an email from Gmail, with a body of text that includes real time stock quotes. I am using a module to get stock quotes in string format (this works), and I wrote a function to send an email from gmail. The message_send function is only working if I give it a simple string. It is not working if I pass it the aapl_string variable. See code below:
from yahoo_finance import *
import smtplib
def message_send(messagebody):
fromaddr = 'REDACTED'
toaddrs = 'REDACTED'
msg = messagebody
# Credentials (if needed)
username = 'REDACTED'
password = 'REDACTED'
# The actual mail send
server = smtplib.SMTP('smtp.gmail.com:587')
server.starttls()
server.login(username,password)
server.sendmail(fromaddr, toaddrs, msg)
server.quit()
aapl = Share('AAPL')
aapl.refresh()
price_aapl = aapl.get_price()
aapl_string = "The current price of AAPL is: " + price_aapl
print(aapl_string)
message_send(aapl_string)
Any ideas why the email sends, but contains blank text when using aapl_string as the argument for the message_send function?
Thanks!
You could do
message_send("The current value is %s" %price_aapl)
and that should make it work :)
I'm assuming price_aapl is an integer, and if that's the case then that is your whole problem. This is due to the inability of being able to add integers to strings so what you could do is use a format string.
ex:
aapl_string = "The current price of AAPL is: %d" % price_aapl
the %d is a placeholder for the integer price_aapl.
You can look here -> http://www.diveintopython.net/native_data_types/formatting_strings.html
for more information on formatting strings in python.

Tweepy location on Twitter API filter always throws 406 error

I'm using the following code (from django management commands) to listen to the Twitter stream - I've used the same code on a seperate command to track keywords successfully - I've branched this out to use location, and (apparently rightly) wanted to test this out without disrupting my existing analysis that's running.
I've followed the docs and have made sure the box is in Long/Lat format (in fact, I'm using the example long/lat from the Twitter docs now). It looks broadly the same as the question here, and I tried using their version of the code from the answer - same error. If I switch back to using 'track=...', the same code works, so it's a problem with the location filter.
Adding a print debug inside streaming.py in tweepy so I can see what's happening, I print out the self.parameters self.url and self.headers from _run, and get:
{'track': 't,w,i,t,t,e,r', 'delimited': 'length', 'locations': '-121.7500,36.8000,-122.7500,37.8000'}
/1.1/statuses/filter.json?delimited=length and
{'Content-type': 'application/x-www-form-urlencoded'}
respectively - seems to me to be missing the search for location in some way shape or form. I don't believe I'm/I'm obviously not the only one using tweepy location search, so think it's more likely a problem in my use of it than a bug in tweepy (I'm on 2.3.0), but my implementation looks right afaict.
My stream handling code is here:
consumer_key = 'stuff'
consumer_secret = 'stuff'
access_token='stuff'
access_token_secret_var='stuff'
import tweepy
import json
# This is the listener, resposible for receiving data
class StdOutListener(tweepy.StreamListener):
def on_data(self, data):
# Twitter returns data in JSON format - we need to decode it first
decoded = json.loads(data)
#print type(decoded), decoded
# Also, we convert UTF-8 to ASCII ignoring all bad characters sent by users
try:
user, created = read_user(decoded)
print "DEBUG USER", user, created
if decoded['lang'] == 'en':
tweet, created = read_tweet(decoded, user)
print "DEBUG TWEET", tweet, created
else:
pass
except KeyError,e:
print "Error on Key", e
pass
except DataError, e:
print "DataError", e
pass
#print user, created
print ''
return True
def on_error(self, status):
print status
l = StdOutListener()
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret_var)
stream = tweepy.Stream(auth, l)
#locations must be long, lat
stream.filter(locations=[-121.75,36.8,-122.75,37.8], track='twitter')
The issue here was the order of the coordinates.
Correct format is:
SouthWest Corner(Long, Lat), NorthEast Corner(Long, Lat). I had them transposed. :(
The streaming API doesn't allow to filter by location AND keyword simultaneously.
you must refer to this answer i had the same problem earlier
https://stackoverflow.com/a/22889470/4432830

user authentication script to run program using python

i am new on python and just started learning, i want to create a simple script to run a program by authenticating user, valid or not...
main problem, i am facing is that i have a file "users" in which i mentioned all valid users,
so i need a program which searches the input given by user in "users" file, if found then continue otherwise "authentication failed"
what i tried is ...
fp = open("users", "r")
for line in fp.readlines():
if "michel" in line : # user michel is available in users file
print "true"
else :
print "false"
it works, prints 'true' because michel is in file.. but in case of when user enters "mic" .. also prints true ...... so what will be the solution...
For starters, it is probably best for security purposes to use os.getlogin() to determine the user's login name rather than prompting the user to type their username. This will at least guarantee that the user logged in via some authentication mechanism to get onto the system, meaning that they have a known & consistent username.
So if you wanted to turn this into a function you could write:
def is_valid_user(username):
fp = open("users", "r")
for line in fp.readlines():
if username in line:
fp.close()
return True
fp.close()
return False
You could then call the function using:
import os
is_valid = is_valid_user(os.getlogin())
if is_valid:
print("valid user")
else:
print("invalid user")
Some suggestions for added security now and in the future:
Modify your "users" file to contain names surrounded by delimiters such as ":jonesj:" rather than "jonesj" and search for ":" + username + ":" in line which will avoid false positives in situations where a user "jones" is currently logged in and a username "jonesj" is in your "users" file but "jones" is not, and you incorrectly identify "jones" as being an authorized user (since "jones" is a subset of the string "jonesj").
Make sure the permissions on your "users" file is set to read-only so that users can't go add their username to the file to grant permissions to themselves.
Sometime in the future you may want to consider using LDAP or Kerberos server or some other more formal authentication mechanism rather than a "users" file. There are good python client libraries for quite a number of authentication backend servers.
You can use re to make sure the whole line is a match:
import re
fp = open("users", "r")
for line in fp.readlines():
if re.match('^michel$', line, re.I):
print "true"
else :
print "false"