Good Day.
Im trying to write a python script that will take a captured password then compare it
to the system shadowed password.
Im using Ubuntu 12.10 for this test. and running the script as sudo.
def login(user, password):
"Check if user would be able to login using password"
try:
pw1 = spwd.getspnam(user)[1]
allus = spwd.getspall()
print pw1
# pw2 = crypt.crypt(password, pw1[:2])
pw2 = crypt.crypt(password, '\$6\$SALTsalt\$')
print pw2
return pw1 == pw2
except KeyError:
return 0 # no such user
Now the above returns
2 diferent passwords but i do get the one from the shadowed.
So my question is how do i encrypt the supplied password so i can compare it to the
one retreived. Any Help would be awsome
Edit addon
def login(user, password):
"Check if user would be able to login using password"
try:
pw1 = spwd.getspnam(user)[1]
allus = spwd.getspall()
# print allus
print pw1
# pw2 = crypt.crypt(password, pw1[:2])
# pw2 = crypt.crypt(password, '\$6\$SALTsalt\$')
pw2 =hashlib.new()
pw2.update(password)
pw2.digest()
print pw2
return pw1 == pw2
except KeyError:
return 0 # no such user
That also did not work
How does one impliment the haslib to get the hash to match system password
I've made an example on how to authenticate using shadowed passwords. I added some comments to let the code speak for itself.
Some extra info:
https://en.wikipedia.org/wiki/Passwd#Shadow_file
http://docs.python.org/2/library/spwd.html
http://docs.python.org/2/library/crypt.html
Also note (from the crypt module docs):
This module implements an interface to the crypt(3) routine, which is a one-way hash function based upon a modified DES algorithm; see the Unix man page for further details. Possible uses include allowing Python scripts to accept typed passwords from the user, or attempting to crack Unix passwords with a dictionary.
Notice that the behavior of this module depends on the actual implementation of the crypt(3) routine in the running system. Therefore, any extensions available on the current implementation will also be available on this module.
This is also why you cannot use hashlib without problems.
import crypt # Interface to crypt(3), to encrypt passwords.
import getpass # To get a password from user input.
import spwd # Shadow password database (to read /etc/shadow).
def login(user, password):
"""Tries to authenticate a user.
Returns True if the authentication succeeds, else the reason
(string) is returned."""
try:
enc_pwd = spwd.getspnam(user)[1]
if enc_pwd in ["NP", "!", "", None]:
return "user '%s' has no password set" % user
if enc_pwd in ["LK", "*"]:
return "account is locked"
if enc_pwd == "!!":
return "password has expired"
# Encryption happens here, the hash is stripped from the
# enc_pwd and the algorithm id and salt are used to encrypt
# the password.
if crypt.crypt(password, enc_pwd) == enc_pwd:
return True
else:
return "incorrect password"
except KeyError:
return "user '%s' not found" % user
return "unknown error"
if __name__ == "__main__":
username = raw_input("Username:")
password = getpass.getpass()
status = login(username, password)
if status == True:
print("Logged in!")
else:
print("Login failed, %s." % status)
Related
I have a function in python that change my account password. That is something like follows :
def f(account):
new_password = # Some random string generation
# Do something and send password change request to remote
account.password = new_password
account.save()
In the second line of above function I send a post request to change my password and then do some processing and finally save my new password. In the processing phase some error has occurred, but unfortunately my request has been sent to server. I have called the function in python shell and now my password has changed but I don't have it. Is it possible to get new_password variable from my function in python shell?
First of all, that is not valid Python code. Functions are not defined with function, but with def. (It seems you updated your question after reading this).
If indeed the function is called with an account object, then the caller will have access to it after the call. So account.password should have the password, unless account.save() wiped it out.
For instance, this could work:
def f(account):
new_password = # Some random string generation
# Do something and send password change request to remote
account.password = new_password
account.save()
account = Account() # do here whatever you do to get an account object
try: # Trap errors
f(account)
except:
print("Something went wrong...")
finally: # Whether an exception occurred or not, print the password
print("The password is:", account.password)
Again, this can only provide the password if account.save() did not destroy the value assigned to account.password.
If you can change the f function to your needs, then include the error handling inside that function and have it return the password:
def f(account):
new_password = # Some random string generation
# Do something and send password change request to remote
account.password = new_password
try: # Trap errors
account.save()
except:
print("Something went wrong...")
return new_password
account = Account() # do here whatever you do to get an account object
new_password = f(account) # now you will have the password returned
print("The password is:", new_password)
If however you already called the function and the program ended, then it is of course too late now. You must take the necessary precautions before running the code, and only run it when you are sure you can recover the password whatever happens.
I am trying to write a unit test in python that tests a username and password entry. I am using prompts for user input for both the username and password.
I have two separate functions that prompt the user for username and password. Both functions then check length. The password function also checks for exceptions, that were made by us, if the password length is zero. Are their ways to mock these exceptions?
I am struggling because I can get passed the username prompt but the pytest script holds after the username input. Is there a way to mock both username and password?
I am fairly new to python and I have looked through documentation but everything I have seen is usually for Python 3.x.x which we currently aren't implementing at this time. Any help would be much appreciated.
I think the init function is actually causing most of the headaches I am having. Is there a way around this?
class Login(object):
def __init__(self, args, env="test"):
created_token = self.login()
def login(self):
username = self.args.username
if len(username) == 0:
username = self._get_username()
password = self.args.password
if len(password) == 0:
password = self._get_password(username)
def _get_username(self):
return prompt('%s Username (%s): ' % (self.domain)
def _get_password(self):
if password is None:
password = prompt_sensitive('%s Password: ' % self.domain)
try:
except ParseError,e:
print "ParseError message"
except ClientError,e:
print "ClientError message"
You can use dependency injection to inject the prompt.
def password_function(input_func=None):
input_func = input_func or input
...
def test_password_function(self, ...):
fake_input = Mock()
...
result = password_function(fake_input)
This won't break existing code since the previous call signature is valid. e.g. password_function(). However if you don't have access to change the code then you can patch the input function.
import __builtin__
#mock.patch(__builtins__, 'input', return_value=...)
def test_password_function(self, mock_input):
I am using the snippet below to encrypt user password before saving in the database.
from pbkdf2 import crypt
pwhash = crypt(password_from_user)
Example: $p5k2$$Y0qfZ64u$A/pYO.3Mt9HstUtEEhWH/RXBg16EXDMr
Then, I save this in database. Well locally, I can perform a check doing something like this:
from pbkdf2 import crypt
pwhash = crypt("secret")
alleged_pw = raw_input("Enter password: ")
if pwhash == crypt(alleged_pw, pwhash):
print "Password good"
else:
print "Invalid password"
but how do I perform checks with what is on the db as the encrypted string is not always the same. I'm using python-pbkdf2.
Okey, Did more research and figured out that to achieve this, i first have to encrypt the password and save in db.as:
pwhash = crypt("secret",iterations=1000)
which can produce a string like $p5k2$3e8$her4h.6b$.p.OE5Gy4Nfgue4D5OKiEVWdvbxBovxm
and to validate when a user wants to login with same password, i use the function below:
def isValidPassword(userPassword,hashKeyInDB):
result = crypt(userPassword,hashKeyInDB,iterations = 1000)
return reesult == hashKeyInDB #hashKeyInDB in this case is $p5k2$3e8$her4h.6b$.p.OE5Gy4Nfgue4D5OKiEVWdvbxBovxm
this method returns True if the password is same or False if otherwise.
I have modified the example python script:
service = 'passwd'
if len(sys.argv) == 3:
user = sys.argv[1]
password = sys.argv[2]
else:
print 'error'
auth = PAM.pam()
auth.start(service)
if user != None:
auth.set_item(PAM.PAM_USER, user)
auth.set_item(PAM.PAM_CONV, pam_conv)
try:
auth.authenticate()
auth.acct_mgmt()
except PAM.error, resp:
print 'Go away! (%s)' % resp
except:
print 'Internal error'
else:
print 'Good to go!'
This works, but asks me to input the password. I would like instead to verify the password which is passed as a parameter (sys.argv[2]). Documentation is non-existant, so how should I do it?
The example first lines are missing.
The provided 'pam_conv' function asks the password to the user.
You must define your own function returning a constant password:
def pam_conv(auth, query_list, userData):
return [(the_password,0)]
When I was finding solution for interactive password prompt, I only found this solution
python expect lib
I am trying to create a login.
I am not sure how to create/import a library of usernames and passwords; I am researching to find an answer at the moment but asked either way.
Match usernames with passwords (partially solved; need to add multiple usernames with matching passwords).
How to create a loop if password is incorrect? If incorrect password is entered the user needs to be prompted again to enter the password.
How to limit loop to certain number of attempts for password.
Below is what I have tried:
def check_password(user, password):
""" Return True if the user/pass combo is valid and False otherwise. """
# Code to lookup users and passwords goes here. Since the question
# was only about how to do a while loop, we have hardcoded usernames
# and passwords.
return user == "pi" and password == "123"
def login():
""" Prompt for username and password, repeatedly until it works.
Return True only if successful.
"""
try:
while True:
username = raw_input('username:')
password = raw_input('password:')
if check_password(username, password):
break
else:
print "Please try again"
print "Access granted"
return True
except:
return False
For testing: login().
This fixed lack of loop prompting if wrong password due to using return instead of print; and if instead of while.
def login():
#create login that knows all available user names and match to password ; if password is incorect returns try again and propmts for password again#
username = raw_input('username:')
if username !='pi':
#here is where I would need to import library of users and only accept those usernames; needs to be like 'pi' or 'bob' or 'tim'etc.
print'user not found'
username = raw_input('username')
password = raw_input('password:')
#how to match password with user? store in library ?
while password != '123':
print 'please try again' # You have to change the 'return' to 'print' here
password = raw_input('password')
return 'access granted'
#basically need to create loop saying 'try again' and prompting for password again; maybe smarter to ask limited number of
#times before returning 'you have reached limit of attempts#
if password == '123':
#again matching of passwords and users is required somehow
return 'access granted'
>>> login()
username:wronguser
user not found
usernamepi
password:wrongpass
please try again
password123
'access granted'
>>>
First attempt before updating thanks to Merigrim:
def login():
# Create login that knows all available user names and match to password;
# if password is incorect returns try again and propmts for password again#
username = raw_input('username:')
if username !='pi':
# Here is where I would need to import library of users and only
# accept those usernames; needs to be like 'pi' or 'bob' or 'tim'etc.
return 'user not found'
password = raw_input('password:')
# How to match password with user? store in library?
if password != '123':
return 'please try again'
password = raw_input('password:')
if password != '123':
return 'please try again'
# Basically need to create loop saying 'try again' and prompting
# for password again; maybe smarter to ask limited number of
# times before returning 'you have reached limit of attempts
elif password == '123':
# Again matching of passwords and users is required somehow
return 'access granted'
Here is how it currently works:
>>> login()
username:pi
password:123
'access granted'
>>> login()
username:pi
password:wrongpass
'please try again'
I need to create loop to prompt again for password.
What you want is the while statement.
Instead of nesting if-statements like this:
if password != '123':
return 'please try again'
password = raw_input('password:')
if password != '123':
return 'please try again'
elif password == '123':
return 'access granted'
You can do this:
while password != '123':
print 'please try again' # You have to change the 'return' to 'print' here
password = raw_input('password:')
return 'access granted'
This will continue prompting the user for a password until the right password is entered. If you want to become more familiar with the while statement, I suggest checking out some tutorials, like this one.
Please note that if you return something the function will exit there, so the user will never be prompted for a password. In the code above I changed the return to a print statement instead.
Here's another solution with the user name and password factored out, and an exception handler in case someone tries to abort the input.
Also, FYI it is best to take the user and password together so as not to let crackers know what is and is not a valid username.
def check_password(user, password):
""" Return True if the user/pass combo is valid and False otherwise. """
# Code to lookup users and passwords goes here. Since the question
# was only about how to do a while loop, we have hardcoded usernames
# and passwords.
return user == "pi" and password == "123"
def login():
""" Prompt for username and password, repeatedly until it works.
Return True only if successful.
"""
try:
while True:
username = raw_input('username:')
password = raw_input('password:')
if check_password(username, password):
break
else:
print "Please try again"
print "Access granted"
return True
except:
return False
# For testing
login()