Python Usernames and Passwords

19,503

Solution 1

What you want is a mapping, or a dictionary. Its key would be username, its contents the password for that username.

users = {} # this is the mapping
users["joe"] = "123" # it currently contains username "joe" with password "123"
...
username = raw_input("What is your username? ")
password = raw_input("What is your password? ")
if username in users.keys():
  expected_password = users[username]
  if expected_password == password:
    print "Welcome to Telemology,", username
  else:
    print "Didn't you forget your password,", username
else:
  print "Unknown user"

Of course, in a real system you'd store passwords salted and encrypted.

Solution 2

You should use the getpass module to ensure that the password is not echoed to the screen and the hashlib module to mean that the raw password isn't stored. Here is a class which uses both modules and should work on python2 and python3. If you want to load it out of a file the you should store the UserDB.users attribute in a file, you could use the json module to do that.

import getpass
import hashlib
import random
import sys
class UserDB():
    def __init__(self, users=dict(), unprompt='Username:', pwprompt='Password:'):
        self.users=dict(users)
        self.unprompt=unprompt
        self.pwprompt=pwprompt
    def adduser(self):
        if sys.version_info.major==3:
            name=input(self.unprompt)
        elif sys.version_info.major==2:
            name=raw_input(self.unprompt)
        passwd=getpass.getpass(self.pwprompt).encode('utf-8')
        salt=bytes(random.randint(30, 95) for i in range(10))
        passwd=hashlib.pbkdf2_hmac('sha512', passwd, salt, 10*10)
        self.users[name]=[salt, passwd]
    def deluser(self, name):
        del self.users[name]
    def __str__(self):
        return str(self.users)
    def __repr__(self):
        return 'UserDB(users=%s, unprompt=%s, pwprompt=%s)' % (self.users,
                                                           ascii(self.unprompt),
                                                           ascii(self.pwprompt))
    def login(self):
        if sys.version_info.major==3:
            name=input(self.unprompt)
        elif sys.version_info.major==2:
            name=raw_input(self.unprompt)
        if name not in self.users:
            return False
        passwd=getpass.getpass(self.pwprompt).encode('utf-8')
        salt=self.users[name][0]
        passwd=hashlib.pbkdf2_hmac('sha512', passwd, salt, 10*10)
        return self.users[name][1]==passwd

Solution 3

Since it is login, it should be unique, and you can make a dictionary:

users = {'username':'password', ...}

and then check like this:

choice = raw_input("What is your username? ")
choice2 = raw_input("What is your password? ")
if (choice in users) and (choice2 == users[choice]):
   # valid user
else:
   # login or password incorrect.

Solution 4

Create one list of users instead, and create User objects, which have username and password as attributes.

Having two lists is going to get desynchronized sooner or later.

Solution 5

Some problems I'm seeing:

  1. You're displaying the password that the user types.
  2. You'll accept any username and any password, meaning I could log in to any account with my password.
  3. Never store a cleartext password.

I haven't found the portable way to not echo passwords. #2 is solved with a dictionary. As for #3, you'll probably want to use the hashlib module:

from hashlib import sha224

PASSWORD_HASHES = {}

def set_password(account, raw_password):
    PASSWORD_HASHES[account] = sha224(raw_password).digest()

def authenticate(account, raw_password):
    if account not in PASSWORD_HASHES:
        return False
    return PASSWORD_HASHES[account] == sha224(raw_password).digest()

Replace sha224 with whatever hash algorithm you want; I haven't kept track of which ones are still good for passwords.

EDIT: Regarding problem #1, if you're running a POSIX-based system (i.e. not at a Windows prompt), you can use some example code from Python's page for the termios module to get a password without echoing it to the screen:

def getpass(prompt="Password: "):
    import termios, sys
    fd = sys.stdin.fileno()
    old = termios.tcgetattr(fd)
    new = termios.tcgetattr(fd)
    new[3] = new[3] & ~termios.ECHO          # lflags
    try:
        termios.tcsetattr(fd, termios.TCSADRAIN, new)
        passwd = raw_input(prompt)
    finally:
        termios.tcsetattr(fd, termios.TCSADRAIN, old)
    return passwd

This doesn't put *'s up for the characters; it just suppresses input. To put up *'s, you have to handle input one character at a time and write more code.

Share:
19,503
user547853
Author by

user547853

Updated on June 04, 2022

Comments

  • user547853
    user547853 almost 2 years

    I am trying to create a program in which you can create, log in, and delete accounts. I have made 2 lists, one with usernames and one with passwords. The script asks for an input and if you say log in, it says:

    if loginchoice=='login':
        choice = raw_input("What is your username? ")
        choice2 = raw_input("What is your password? ")
        if choice in accounts:
            option1=1
        else:
            option1=0
        if choice2 in password:
            option2=1
        else:
            option2=0
        if option1==1 and option2==1:
            print "Welcome to Telemology,", choice
        else:
            print "The username or password you entered is incorrect. Please try again or register."
    

    As you can see, it only checks to see if the inputs are already in the lists. It doesn't see if the inputs have the same index. I can't put "accounts.index(choice)" because it treats 'choice' as an integer. The same goes for quotations because of strings. It doesn't treat them as variables. Is there any way around this?

    I hope that if my question gets answered, two people won't register simultaneously and glitch the indices.