Validating the contents of a user entered string in Python? - python

As part of an assignment, I'm creating a program to ask a user to input a username and password.
I've completed the username part (easy), but in the assignment instructions, the password must:
contain an uppercase character
contain a lowercase character
be longer than 6 characters
contain a number
have no white space
There are 5 specific error messages that need to display if any of these conditions are not true.
What I've got currently has some weird behavior, the errors only show up in a specific order (for example, password "f" will have the error "must have an uppercase character" instead of "must be longer than 6 characters"). I know this is because of the nesting order of the if statements, but if there's a better way... It also for some reason doesn't catch white space in the password. I know it probably isn't the most efficient way but here's what I've got so far:
def validatePassword():
accept = "n"
while accept == "n":
password = input("Please enter a valid password: ")
upper = "n"
lower = "n"
digit = "n"
length = "n"
white = "n"
if len(password) >= 6:
length = "y"
for char in password:
if char in string.ascii_uppercase:
upper = "y"
if char in string.ascii_lowercase:
lower = "y"
if char in string.digits:
digit = "y"
if char not in string.whitespace:
white = "y"
if upper == "y":
if lower == "y":
if digit == "y":
if length == "y":
if white == "y":
accept = "y"
else:
print("::: ERROR :::",password,"must not have any white space character.")
else:
print("::: ERROR :::",password,"must be longer than 6 characters.")
else:
print("::: ERROR :::",password,"must contain a number.")
else:
print("::: ERROR :::",password,"must contain a lowercase character.")
else:
print("::: ERROR :::",password,"must contain an uppercase character.")
return password

You could try something like this:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def validatePassword(password):
if not any(x.isupper() for x in password):
return False, "No upper case character"
if not any(x.islower() for x in password):
return False, "No lower case character"
if len(password) < 6:
return False, "Not longer than 6 characters"
if not any(x.isdigit() for x in password):
return False, "No number"
if any(x.isspace() for x in password):
return False, "Contains hitespace"
return True, ""
def test():
# test some passwords
test_passwords = ["lkjasdf", "KAJSDF", "lfSF", "asdfADSF", "asdf ADSF 123", "asdfADSF123"]
for p in test_passwords:
print validatePassword(p)
# "real" usage
while True:
password = input("Please enter a valid password: ")
result, message = validatePassword(password)
if result is True:
break
else:
print(message)
if __name__ == '__main__':
test()

Obviously the correct way to do this is with any() and a generator expression, but seeing as how you said I'm like 8 weeks into a 10 week introductory course those probably don't help you.
Here's how you can do it without using any() by just looping through the characters checking for the presence of certain types of characters.
def validate_password(password):
hasUpper = hasLower = hasNumber = hasWhiteSpace = False
for char in passwordStr:
if char.isupper():
hasUpper = True
if char.islower():
hasLower = True
if char.isdigit():
hasNumber = True
if char.isspace():
hasWhiteSpace = True
if len(password) <= 6:
return False, "Password must be longer than 6 characters"
if not hasUpper:
return False, "Password must contain atleast one uppercase character"
if not hasLower:
return False, "Password must contain atleast one lowercase letter"
if not hasNumber:
return False, "Password must contain alteast one number"
if hasWhiteSpace:
return False, "Password cannot contain any white space"
return True

First, there's the data type bool which can represent the values True and False. You should use them to represent simple true/false states instead of assigning the strings "y" and "n".
Second, checking every character separately and storing whether the different conditions are met at least once is a possible way. However, Python has powerful string examination methods that can make your life much easier. Let me demonstrate them by writing a short function which takes aa password as argument and simply returns True or False depending on whether the passwords meets your restrictions:
def is_password_valid(password):
# check password length:
if len(password) < 6:
print("Your password is too short, at least 6 characters are required!")
return False
# check if password contains any non-alphanumeric letters (including whitespace):
# (isalnum() only returns true if the string only contains letters and digits, nothing else)
if not password.isalnum():
print("Your password may only contain letters and digits!")
return False
# check if password contains letters:
# (isdigit() only returns true if all of the characters are numbers)
if password.isdigit():
print("Your password does not contain any letters!")
return False
# check if password contains uppercase letters:
# (islower() only returns true if all of the letters are lowercase, non-letters are ignored)
if password.islower():
print("Your password does not contain any uppercase letters!")
return False
# check if password contains lowercase letters:
# (isupper() only returns true if all of the letters are uppercase, non-letters are ignored)
if password.isupper():
print("Your password does not contain any lowercase letters!")
return False
# check if password contains lowercase numbers:
# (isalpha() only returns true if all of the characters are letters)
if password.isalpha():
print("Your password does not contain any numbers!")
# if all conditions above are okay, the password is valid:
print("The password is okay.")
return True
You may of course reorder the blocks in my code above as you wish.
You can then simply use this helper function inside your loop which looks a lot simpler and cleaner now:
def validate_password():
accept = False
while not accept:
password = input("Please enter a valid password: ")
accept = is_password_valid(password)

You can try Regular Expressions. If you don't know about regex, as you've mentioned in your comment, this is a great website.
For validation, check if the password matches with any of the rules which will render it invalid and if not, it is a valid password.
import re
def validate(passwd):
pattern = r'^(.{0,5}|[^0-9]*|[^A-Z]*|[^a-z]*|.*\s+.*)$'
result = re.search(pattern, passwd)
if result:
print 'Invalid Password'
else:
print 'Valid Password'
What this does is check if, passwd is less than 6 chars OR contains no numbers OR contains no uppercase chars OR contains no lowercase chars OR contains spaces. If none of the criteria matches, the password is valid.

Related

Python Program for Password with Certain Requirements

I'm trying to write a Python program that prompts the user for a password. It must meet the following requirements:
no less than 6 characters in length
no more than 12 characters in length
at least 1 numerical digit
at least 1 alphabetical character
no spaces
I can get through requirements 1-3, but as soon as I put in requirement 4, it stops working. I haven't even gotten to requirement 5 because I'm currently stuck. Any help is greatly appreciated! TIA!
Here is my code:
# --- Main ----------
def main():
#display student info
studentInfo()
#display welcome message
welcomeMsg()
#prompt user for a password
passWord = input("\nPlease create a password:\n")
#call function for password length validation
passWord = correctPW(passWord)
# --- Functions ----------
#student info
def studentInfo():
print("\nName:\tNAME")
print("Class:\tCMIS102")
print("Date:\t26 July 2022")
#welcome message
def welcomeMsg():
print("\nThis program will prompt the user to enter a password with the following requirements:")
print("\t- No less than 6 characters in length")
print("\t- No more than 12 characters in length")
print("\t- No spaces")
print("\t- At least one numerical digit")
print("\t- At least one alphabetical character")
#validate password requirements
def correctPW(passWord):
#check for minimum character requirement
while (len(passWord) < 6) or (len(passWord) > 12):
print("\nSorry! Your password is invalid.")
print("It must be no less than 6 characters and no more than 12 characters in length.")
passWord = input("\nPlease create a password:\n")
#check for one numerical digit and alphabetical character requirement
while (passWord.isdigit() < 1):
print("\nSorry! Your password is invalid.")
print("It must contain at least one numerical digit.")
passWord = input("\nPlease create a password:\n")
while (passWord.isalpha() < 1):
print("\nSorry! Your password is invalid.")
print("It must contain at least one alphabetical character.")
passWord = input("\nPlease create a password:\n")
#display if all password requirements are met
if (len(passWord) >= 6) and (len(passWord) <= 12) and (passWord.isdigit() >= 1) and (passWord.isalpha() >= 1):
print("\nCongratulations! Your password is valid!")
# --- Execute ----------
main()
The isdigit function will return True if all of the char in the password be numbers, like '65' or '1235' but if in the password, the user has any char near the numbers, like 'asdf3567' or '1a2b3c4d' or etc, it will return False, so this condition password.isdigit() < 1 is not a good condition
The isalpha function will return True if all of the char in the password be alphabets, like 'abc' or 'simplepassword' but if in the password, user has any char near the alphabets, like 'asdf3567' or '1a2/$b3c4d' or etc, it will return False, so this condition password.isalpha() < 1 is not a good condition
str.isdigit(): Return True if all characters in the string are digits and there is at least one character, False otherwise.
—https://docs.python.org/3/library/stdtypes.html#str.isdigit
Therefore, if passWord is (for example) "a1", then passWord.isdigit() will return False. You can, however, use it for each characters in the string, by using list (or generator) comprehension.
def check(password):
if not (6 <= len(password) <= 12):
print("Length must be between 6 and 12 (inclusive).")
return False
if any(char.isdigit() for char in password):
print("Must have a digit.")
return False
if any(char.isalpha() for char in password):
print("Must have an alphabet.")
return False
if any(char.isspace() for char in password):
print("Must not have a space.")
return False
return True
while True:
password = input("Enter a password: ")
if check(password):
break
print(f"Your password is: {password}... Oops, I said it out loud!")
If you want the actual number of digits in the password, you can use sum instead of any:
if sum(char.isdigit() for char in password) < 1:
Based on help(str) in python shell:
isdigit(self, /)
Return True if the string is a digit string, False otherwise.
A string is a digit string if all characters in the string are digits and there
is at least one character in the string.
isalpha(self, /)
Return True if the string is an alphabetic string, False otherwise.
A string is alphabetic if all characters in the string are alphabetic and there
is at least one character in the string.
So in lines:
while (passWord.isdigit() < 1): ...
while (passWord.isalpha() < 1): ...
passWord.isdigit() and passWord/.isalpha() even for your valid inputs are always False and for both of them < 1 will be True
and this will cause an infinite loop in your program.
I applied two new functions to your code to check if user inputs a valid pass you expected or not.
# --- Main ----------
def main():
#display student info
studentInfo()
#display welcome message
welcomeMsg()
#prompt user for a password
passWord = input("\nPlease create a password:\n")
#call function for password length validation
passWord = correctPW(passWord)
# --- Functions ----------
#student info
def studentInfo():
print("\nName:\tJessica Graeber")
print("Class:\tCMIS102")
print("Date:\t26 July 2022")
#welcome message
def welcomeMsg():
print("\nThis program will prompt the user to enter a password with the following requirements:")
print("\t- No less than 6 characters in length")
print("\t- No more than 12 characters in length")
print("\t- No spaces")
print("\t- At least one numerical digit")
print("\t- At least one alphabetical character")
def containsLetterAndNumber(input_password):
return input_password.isalnum() and not input_password.isalpha() and not input_password.isdigit()
def containsBlankSpace(input_password):
return (' ' in input_password)
#validate password requirements
def correctPW(passWord):
#check for minimum character requirement
while (len(passWord) < 6) or (len(passWord) > 12):
print("\nSorry! Your password is invalid.")
print("It must be no less than 6 characters and no more than 12 characters in length.")
passWord = input("\nPlease create a password:\n")
#check for one numerical digit and alphabetical character requirement
while not containsLetterAndNumber(passWord):
print("\nSorry! Your password is invalid.")
print("It must contain at least one alphabetical character and one numerical digit.")
passWord = input("\nPlease create a password:\n")
while containsBlankSpace(passWord):
print("\nSorry! Your password is invalid.")
print("It shouldn't have any blank space in it.")
passWord = input("\nPlease create a password:\n")
# display if all password requirements are met
if (len(passWord) >= 6) and (len(passWord) <= 12) and containsLetterAndNumber(passWord) and (not containsBlankSpace(passWord)):
print("\nCongratulations! Your password is valid!")
# --- Execute ----------
main()

How to check for a character in an input while it's being written?

So I'm creating a password manager, and my code is somewhat close to this,
I was wondering if there's a way to check for a character inside a string while it's still being written (i.e. before the user clicks Enter), so that I can change the color of the line that says "An uppercase character" to green when the user inputs an uppercase character, and goes back to original character if the user deletes the character.
from termcolor import colored
from getpass import getpass
import string
def check_for_owasp_standards(password):
uppercase_letters = string.ascii_uppercase
lowercase_letters = string.ascii_lowercase
digits = string.digits
special_characters = "!##$%^&*()-_"
length_is_over_8 = False
contains_uppercase_letter = False
contains_lowercase_letter = False
contains_digit = False
contains_special_character = False
Checklist = []
if len(password) >= 8 :
length_is_over_8 = True
Checklist.append(length_is_over_8)
for character in password:
if character in uppercase_letters:
contains_uppercase_letter = True
break
Checklist.append(contains_uppercase_letter)
for character in password:
if character in lowercase_letters:
contains_lowercase_letter = True
break
Checklist.append(contains_lowercase_letter)
for character in password:
if character in digits:
contains_digit = True
break
Checklist.append(contains_digit)
for character in password:
if character in special_characters:
contains_special_character = True
break
Checklist.append(contains_special_character)
if False in Checklist:
return False
else:
return True
print(colored("According to OWASP password standards 2021 your master password must contain the following :", "magenta"))
print(colored("*An uppercase character", "magenta"))
print(colored("*A lowercase character", "magenta"))
print(colored("*A digit", "magenta"))
print(colored("*Length has to be 8 or more characters\n", "magenta"))
master_password = getpass(colored("Enter your master password : ", "blue"))
if not check_for_owasp_standards(master_password):
print(colored("Password does not meet the standards, let's try again.\n", "yellow"))
else:
print(colored("Master password saved successfully!", "green"))
I created a solution to your problem.
This is a video showing how it works on my console >> YouTube.
You can get the whole code, organised here >> Github.
And here is explanation:
You will need to turn off console output, then capture each keypress, and at the end turn console output back on.
For this you will need from pynput.keyboard import Key, Listener, which works basically like this:
def on_release(key):
print(key)
if key in [Key.enter, Key.esc]:
return False
with Listener(on_release=on_release) as listener:
listener.join()
which will basically print every pressed key, and stop working when pressing Enter or Esc.
Tp stop it from being visible you will disable it by os.system("stty -echo") and enable back with os.system("stty echo")
Here is how I changed your code:
This method is similar to your check_for_owasp_standards(password) but will return a list of booleans for each standard that need to be checked:
def checkStandards(password):
uppercase_letters = string.ascii_uppercase
lowercase_letters = string.ascii_lowercase
digits = string.digits
special_characters = "!##$%^&*()-_"
length_is_over_8 = False
contains_uppercase_letter = False
contains_lowercase_letter = False
contains_digit = False
contains_special_character = False
checklist = []
if len(password) >= 8 :
length_is_over_8 = True
checklist.append(length_is_over_8)
for character in password:
if character in uppercase_letters:
contains_uppercase_letter = True
break
checklist.append(contains_uppercase_letter)
for character in password:
if character in lowercase_letters:
contains_lowercase_letter = True
break
checklist.append(contains_lowercase_letter)
for character in password:
if character in digits:
contains_digit = True
break
checklist.append(contains_digit)
for character in password:
if character in special_characters:
contains_special_character = True
break
checklist.append(contains_special_character)
return checklist
Next function will show this information as coloured. Green for accepted, red for not. The easiest way to show changes, overring previous lines written to console is to clear all console.
def updateStandards(password):
# clear console
os.system('clear')
# check
standards = checkStandards(password)
print(accept("Length >= 8", standards[0]))
print(accept("Contains uppercase letter", standards[1]))
print(accept("Contains lowercase letter", standards[2]))
print(accept("Contains digit", standards[3]))
print(accept("Contains special character", standards[4]))
using
def accept(text, accepted=False):
if accepted:
return f'\033[32;1m{text}\033[0m' # green
else:
return f'\033[31;1m{text}\033[0m' # red
The main function will look like this. It will first reset global variable storing user input to empty string. Then show all rules for password. Then ask user for password and turn off showing in console. At the end, it will turn it back.
def getPassword():
try:
# reset stored input to empty string
global user_input
user_input = ''
# show rules for password
updateStandards('')
# ask for password
print('Write your password:')
# turn off showing input
os.system("stty -echo")
# collect keys until ENTER/ESC
with Listener(on_release=on_release) as listener:
listener.join()
input()
except:
print(traceback.print_exc())
finally:
# turn on showing input
os.system("stty echo")
The last part is to write listener for key press:
def on_release(key):
global user_input
# store key
k = str(key).replace('\'', '')
if len(k) == 1:
user_input += k
# delete last char
if key == Key.backspace:
user_input = user_input[:-1]
updateStandards(user_input)
print('Write your password:', ''.join('*' for _ in range(len(user_input))))
# Stop listener
if key in [Key.enter, Key.esc]:
finished(user_input)
return False
When user end writing password, you can do anything you want with it:
def finished(password):
# do what you need to do, e.g. store password somewhere
standards = checkStandards(password)
if all(standards):
print('Your password is:', password)
else:
print('Your password should meet all the rules')

Password validator: password needs to contain EXACTLY one spacial character?

Task: Password validator
a. The length of the password needs to be from 8 to 30 characters.
b. The password needs to contain at least 2 uppercase characters.
c. The password needs to contain at least 2 lowercase characters.
d. The password needs to contain at least 1 digit.
e. The password needs to contain exactly 1, but not more of the following special characters:
#/%&*_-
This is my code:
special_character_set = "#/%&*_-"
is_valid = False
import re
while True:
password = input("please enter a password: ")
if len(password) > 30 or len(password)< 8:
print("The length of the password needs to be from 8 to 30 characters!")
continue
elif re.search('[0-9]', password) is None:
print("The password needs to contain at least 1 digit!")
continue
elif re.search ('[A-Z][A-Z]', password) is None:
print("The password needs to contain at least 2 uppercase characters!")
continue
elif re.search('[a-z][a-z]', password) is None:
print("The password needs to contain at least 2 lowercase characters!")
continue
elif re.search('[#/%&*_-]', password) is None:
print("The password needs to contain one of the following special characters: #/%&*_-!")
continue
else:
is_valid = True
if is_valid:
print("valid password")
break
It works. However, the condition e) has not been completely fulfilled. How can I make the password contain ONLY ONE of the special characters?
What about len + re.findall():
...
elif len(re.findall('[#/%&*_-]', password)) != 1:
# Some number of special characters other than 1 was found
...
or
...
elif len(re.findall('[#/%&*_-]', password)) == 0:
# No special characters were found
...
elif len(re.findall('[#/%&*_-]', password)) > 1:
# Too many special characters were found
(and if you do the latter, try not to run the regex twice)
Don't use regex for this; add up the counts of special characters in the proposed password:
>>> passwd = "My_Pass#"
>>> special = '[#/%&*_-]'
>>> special_count = sum(passwd.count(c) for c in special)
>>> special_count
2
You can now use special_count as desired.

Regex password program

I'm working on an exercise problem from the regex chapter in 'Automate the boring stuff with Python' the question and my code is below. I got the regex working in the Python shell and I think its correct but I just can't get it to work within my function so that it returns the correct answer.
Write a function that uses regular expressions to make sure the password string it is passed is strong. A strong password is defined as one that is at least eight characters long, contains both uppercase and lowercase characters, and has at least one digit. You may need to test the string against multiple regex patterns to validate its strength.
import re
def pwRegex():
print "Please enter a password"
user_pw = raw_input("> ")
#your_pw = str(user_pw)
passGex = re.compile(r'^(?=.*\d)(?=.*[A-Z])\w{8,15}$')
pass_w = passGex.search(user_pw)
if pass_w != '':
print "Well done"
else:
print "Try again"
pwRegex()
the output I get is "Try again" every time even when I'm entering a password that should pass the regex. I tried making the if statement pass_w == True: but then everything that I entered seemed to pass the regex even if incorrect.
Regex searching in python gives back a MatchObject, not a string. If it does not find the required pattern, it will return None. You should check for None, or, more pythonically, check for truthiness
# if pass_w != None: # => less pythonic
if pass_w:
print 'Well done'
else:
print 'Try again'
import re
print('Please set a new password: ')
def strongpassword():
while True:
password = input()
if lowcase.search(password) == None:
print('The entered password doesn\'t have a lower case character')
continue
if upcase.search(password) == None:
print('The entered password doesn\'t have an upper case character')
continue
if digit.search(password) == None:
print('The entered password doesn\'t have a digit')
continue
if space_8.search(password) == None:
print('The entered password should have atleast 8 characters and no space in between')
continue
else:
print('New Password is Valid and Saved')
break
lowcase = re.compile(r'[a-z]') # this regex searches for atleast one lower case alphabet
upcase = re.compile(r'[A-Z]') # this regex searches for atleast one upper case alphabet
digit = re.compile(r'(\d)') # this regex searches for atleast one digit
space_8 = re.compile(r'^[a-zA-Z0-9]{8,}$') # this regex searches for expressions without any space and atleast 8 characters
strongpassword()
I guess, it is not relevant anymore. However, I would like to suggest this:
import re
pasword = re.compile(r'''(
\d+ #have at lest one digit
.* # anything
[A-Z]+ # at least 1 capital
.*
[a-z]+ # at least one lower
.*
)''', re.VERBOSE)
# test
pasword.search('1##A!a').group()
def is_strong_password():
pas = input('Enter a password:')
if len(pas) < 8:
return False
else:
check = pasword.search(''.join(sorted(pas))).group() #sorted is important to be sure that user can write symbols in any order he/she wants
if (not check):
print('Not strong pasword')
return False
else:
print('Strong password')
return True
I was also working on the same exercise, I'm learning python as well. You can search() instead of findall(). i just used it just to test it out.
import re
print('Enter new password')
def strongPW():
while True:
pw = input()
lowercase = [] # lowercase
uppercase = [] # uppercase
digit = [] # number
if len(pw) < 8:
print('your password must have 8 characters or more')
break
# lowercase verification
pwRegex = re.compile(r'[a-z]')
lowercase = pwRegex.search(pw)
if lowercase == []:
print('Your password must have at least one lowercase')
break
# uppercase verification
uppercaseRegex = re.compile(r'[A-Z]')
uppercase = uppercaseRegex.findall(pw)
if uppercase == []:
print('Your password must have at least one uppercase')
break
# digit verification
DigitRegex = re.compile(r'[0-9]')
digit = DigitRegex.findall(pw)
if digit == []:
print('Your password must have at least one digit')
break
else:
print('Your password meets all requirements ')
break
strongPW()

Python: How to display errors in "Making a Valid Password" and indicate if first character is a letter?

I'm trying to make a password with typical requirements like it has at least 1 uppercase/lowercase, etc. If the password is not valid according to the requirements, we have to display the errors in order for the user to try to get it correct again.
I started out with a while loop so that in the end the user will have an option to continue with another test or not. These are general steps I did.
At the end, if the user's text input is determined to not be valid, I have to display what his/her errors were. That's my main problem now. The code is better after a suggestion. Now I just have to display the errors somehow.
Here's how my code went
while True:
pw = input('Enter password to be tested if valid or not: ')
correct_length = False
uc_letter = False
lc_letter = False
digit = False
no_blanks = True
first_letter = False
if len(pw) >= 8:
correct_length = True
for ch in pw:
if ch.isupper():
uc_letter = True
if ch.islower():
lc_letter = True
if pw.isalnum():
digit = True
if pw[:1].isalpha():
first_letter = True
if not pw.find(' '):
no_blanks = True
if correct_length and uc_letter and lc_letter and digit and first_letter and no_blanks:
valid_pw = True
else:
valid_pw = False
#This is the part where I'm suppose to display the errors if the user gets it wrong.
#Initially, in the test for ch. above, I put in an else: with a print statement but because of the for- statement, it prints it out for every single character.
answer = input('Try another password input? y/n ')
if answer == 'y'
answer = True
else:
break
isdigit only returns True or False.
if ch.isdigit():
If you want to check if the first two characters are digits, do it outside the loop:
if pw[:2].isdigit():
digit = True
for ch in pw:
...
And to check if there are spaces in the string:
if not pw.find(' '):
no_blanks = True
Or if you want to escape all kinds of white spaces and blanks, including newline characters:
import string
...
if not any(c in string.whitespace for c in pw):
no_blanks = True
for ch in pw:
...
For the white space I would use (don't forget to import string):
import string
for ws in string.whitespace:
if ws in pw:
no_blanks = False
break
This checks for all kinds of white space, including for example Space and Tab
For the digits I would define dig_count = 0 before your for-loop.
Inside the for-loop:
if ch.isdigit():
dig_count += 1
After the for-loop:
if dig_count >= 2:
digit = True

Categories

Resources