I'm trying to generate random passwords for the Active Directory that has the following password requirements: at least 8 characters, at least one special character, at least one digit, at least one lowercase and at least one uppercase.
With the following code I'm able to generate a random password and check whether it contains a special character. New password is generated until a special character is found.
special_char = "!@%/()=?+.-"
password_string = "".join([random.choice(string.ascii_lowercase + string.ascii_digits + string.ascii_uppercase + special_char) for n in range(8)])
while any(c in password_string for c in special_char) is not True:
password_string = "".join([random.choice(string.ascii_lowercase + string.ascii_digits + string.ascii_uppercase + special_char) for n in range(8)])
The problem with the following is that it's only checking for the special character and generating a new password might get rid of the other requirements assuming they existed. How could I implement the AD password requirements efficiently? Thanks for any help.
You could generate a matching password to begin with, by first picking a special char and a digit (and one lower- and one uppercase letter in the same manner), filling up with anything, and shuffling the order in the end:
pwlist = ([random.choice(special_char),
random.choice(string.ascii_digits),
random.choice(string.ascii_lowercase),
random.choice(string.ascii_uppercase),
]
+ [random.choice(string.ascii_lowercase
+ string.ascii_uppercase
+ special_char
+ string.ascii_digits) for i in range(4)])
random.shuffle(pwlist)
pw = ''.join(pwlist)
Test for all conditions in your while
test. It is easier to delegate testing for valid passwords to a function:
special_char = "!@%/()=?+.-"
password_characters = string.ascii_letters + string.ascii_digits + special_char
def is_valid(password):
if len(password) < 8:
return False
if not any(c in password for c in special_char):
return False
if not any(c.isdigit() for c in password):
return False
if not any(c.islower() for c in password):
return False
if not any(c.isupper() for c in password):
return False
return True
password_string = ''
while not is_valid(password_string):
password_string = "".join([random.choice(password_characters)
for n in range(8)])
Use sets and intersection to enforce constraints...
import string
import random
special_char = "!@%/()=?+.-"
set_lower = set(string.ascii_lowercase)
set_upper = set(string.ascii_uppercase)
set_digits = set(string.digits)
set_sp = set(special_char)
all_chars = string.ascii_lowercase + \
string.digits + \
string.ascii_uppercase + \
special_char
password_string = "".join([random.choice(all_chars) for n in range(8)])
def isOK(pw):
pw = set(pw)
for x in (set_lower, set_upper, set_digits, set_sp):
if len(pw.intersection(x)) == 0:
return False
return True
while not isOK(password_string):
password_string = "".join([random.choice(all_chars) for n in range(8)])
print password_string
I like Ulrich's answer better. He beat me to it.
import string
import random
string_specials = '!@%/()=?+.-'
string_pool = string_specials + string.ascii_letters + string.digits
pre_password = [
random.choice(string_specials),
random.choice(string.ascii_uppercase),
random.choice(string.ascii_lowercase),
random.choice(string.digits),
random.choice(string_pool),
random.choice(string_pool),
random.choice(string_pool),
random.choice(string_pool)]
scrambled = []
while pre_password:
scrambled.append(pre_password.pop(random.randint(0, len(pre_password)-1)))
password = ''.join(scrambled)
You could implement the requirements one by one..
- at least 8 characters
- at least one special character
- at least one digit
- at least one lowercase and
- at least one uppercase.
so before you do anything else
create a string that consists of
1 special character randomly chosen.
1 digit character randomly chosen.
1 lowercase character randomly chosen.
and 1 uppercase character randomly chosen.
thats 4 characters in total, the remaining characters can be randomly chosen, length must be larger than 8.
all generated passwords will no be valid, so no need to check for that..
now you could complain that the passwords will all have the same predictable pattern:
special, digit, lowercase, uppercase, randomized stuff..
so we shuffle it..
import string
SpecialChars = "!@%/()=?+.-"
password = ""
import random
password += random.choice(string.ascii_uppercase)
password += random.choice(string.ascii_lowercase)
password += random.choice(string.digits)
password += random.choice(SpecialChars)
i = random.randint(4, 8)
for i in range(0,i):
password += random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits+ SpecialChars)
password = ''.join(random.sample(password,len(password)))
print password