user authentication script to run program using python - python-2.7

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"

Related

Cannot obtain user by using filter with username and password

I am using the following code
email = validated_data["login"]
password = validated_data["password"]
user_obj = User.objects.filter(Q(email__exact=email) & Q(password__exact=password))
I changed the password from admin however no user is returned. However if I remove the password check then I get a user object back.The object that I get back if I remove the Q(password__exact=password) condition has _password field as None. This code has been working fine for a while but today it is not returning back the object. Am I missing something here ? I verified that I am receiving the correct username and password from the client.I also tried accessing the admin with that username and password (The account has staff status) and I was able to log in. So the password is correct but for some reason I cant obtain that user by filtering. ? What might I be doing wrong ?
password isn't stored in plain text, but as a hash (and a little more). Get the user by username and check the password:
# assumes there can be only one
user = User.objects.get(email=email)
# this checks the plaintext password against the stored hash
correct = user.check_password(password)
BTW, you don't need Q objects for logical AND. filter(email__exact=email, password__exact=password) would suffice, even though it doesn't make much sense, in this case.
it is because Django doesn't stores password as the simple text they are hashed, you cant perform a password__exact on that it will return none every time unless you are getting the same hash password = validated_data["password"] here

Python - change password for user in JunOS

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)

Django 1.9 "Common Password Validator" - Strange Behaviour

I'm attempting to replace the built in common-passwords.txt.gz file, which supposedly contains the top 1,000 common passwords, with my own identical version which contains the top 10,000 common passwords for my country, but I've encountered some rather strange behaviour.
Firstly I directly substituted Django's common-passwords.txt.gz file (4KB) with my own containing my .txt file with the same utf-8 encoding as Django (which comes in at 34KB), then restarted the test server. When changing a users password to "password" it does not raise the expected error as it does with Django's common password file.
The first line of both the built in password list and my new one begins 123456password12345678qwerty123456789... so it clearly should do.
When I append a few extra passwords to their common-passwords file it appears to work as it should and raise an error if I try to use them as passwords, so I don't think that it's cached somewhere or anything like that.
Is there some kind of built in file size limit for the common password list or for the gzip.open(password_list_path).read().decode('utf-8').splitlines() function?
Secondly, trying to figure out the above led me to a strange bug. Using Django's built in common-passwords.txt.gz (of which the first line starts 123456password12345678qwerty123456789...) successfully raises a validation error for "password" and "password1", but not for "password12" or "password123"!
As I read it, the Django validation code basically checks if the submitted password is in each line from the common passwords file, and I cannot find any code that exempts passwords above a certain length from the validation. Am I missing something or is this a bug?
The "common password validation" function in Django 1.9 is found in \venv\Lib\site-packages\django\contrib\auth\password_validation.py, the relevant class is below:
class CommonPasswordValidator(object):
"""
Validate whether the password is a common password.
The password is rejected if it occurs in a provided list, which may be gzipped.
The list Django ships with contains 1000 common passwords, created by Mark Burnett:
https://xato.net/passwords/more-top-worst-passwords/
"""
DEFAULT_PASSWORD_LIST_PATH = os.path.join(
os.path.dirname(os.path.realpath(upath(__file__))), 'common-passwords.txt.gz'
)
def __init__(self, password_list_path=DEFAULT_PASSWORD_LIST_PATH):
try:
common_passwords_lines = gzip.open(password_list_path).read().decode('utf-8').splitlines()
except IOError:
with open(password_list_path) as f:
common_passwords_lines = f.readlines()
self.passwords = {p.strip() for p in common_passwords_lines}
def validate(self, password, user=None):
if password.lower().strip() in self.passwords:
raise ValidationError(
_("This password is too common (it would be trivial to crack!)"),
code='password_too_common',
)
def get_help_text(self):
return _("Your password can't be a commonly used password.")
Finally got to the bottom of this!
There is some kind of invisible unrendered character in-between the passwords contained in Django's built in common passwords validation file, this explains both issues I encountered.
I changed my top 10k common passwords file to have the usual newline characters between them instead and now it all works great! Even though there are now 10 times as many passwords for it to compare against it still runs pretty much instantaneously!
I've uploaded my 10,000 most common passwords file to github for any future people who encounter this issue or who just want to improve Django's built-in common password validation: https://github.com/timboss/Django-Common-Password-Validation/

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

Django-registation : Error on activate new user

I'm using Django registration inside my project on a development server.
When I register a new user, I use EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend' to get the activation link.
When I try to put the activation link into the web browser, I have an error, and the account is not activated.
It is said :
Thank you.
This function is used to generate the key.
def create_profile(self, user):
"""
Create a ``RegistrationProfile`` for a given
``User``, and return the ``RegistrationProfile``.
The activation key for the ``RegistrationProfile`` will be a
SHA1 hash, generated from a combination of the ``User``'s
username and a random salt.
"""
salt = hashlib.sha1(str(random.random())).hexdigest()[:5]
username = user.username
if isinstance(username, unicode):
username = username.encode('utf-8')
activation_key = hashlib.sha1(salt+username).hexdigest()
return self.create(user=user,
activation_key=activation_key)
I received that mail. But I use EMAIL_BACKEND'django.core.mail.backends.filebased.EmailBackend'.
I think the problem comes from here. But I can't test in production server.
I solved the problem actually It's because I generate the email to send inside a file thanks to the file email backends provided by django for development purpose. Inside this file, when there is a carriage return, it adds an = characters. And this is the case with the link to active the account.
You shouldn't have a = character in your activation key.
Although sergzach's answer will work, I'd be more interested in finding out why that = is there in the first place.
django-registration usually generates the key as follows:
salt = sha.new(str(random.random())).hexdigest()[:5]
activation_key = sha.new(salt+user.username).hexdigest()
Where are you generating yours?
The character '=' is not in the range of \w+. Use [\w=]+ instead of \w+.
Replace ?P<activation_key>\w+ to ?P<activation_key>[\w=]+