ray
ray

Reputation: 15227

Python - password generation with complexity requirement

I need to generate random passwords for my company's 200k+ customers.

The password complexity requirement is a common one:

  1. length > 8
  2. contains at least one upper case character
  3. contains at least one lower case character
  4. contains at least one number
  5. contains at least one symbols (e.g. @#$%)

Here is the python 3.8 code I used to generate a random password string following the guides on Google search result(like this and this):

import secrets
import string

def getRandomPasswordString(length):
    
    alphabet = string.ascii_letters + string.digits + string.punctuation
    password = ''.join(secrets.choice(alphabet) for i in range(length))

    return password

This works fine for most of the time but for some rare cases that the password generated does not comply with the complexity requirement like below:

=Y[&PE-XXP[//F, (missing lower case letter)

^f~+""uwan]ny)b (missing upper case letter)

AQvoMApuNFyRkJd (missing symbols and numbers)

I know that I can do something like this to ensure each types of character are chosen:

import secrets
import string

def getRandomPasswordString(length):
    
    alphabet = string.ascii_letters + string.digits + string.punctuation

    password = secrets.choice(string.ascii_uppercase) + \
            secrets.choice(string.ascii_lowercase) + \
            secrets.choice(string.digits) + \
            secrets.choice(string.punctuation) + \
            ''.join(secrets.choice(alphabet) for i in range(length-4))

    return password

This works ok, but I am not sure if imposing some password patterns in the first 4 characters will cause any problem or not(i.e. the pattern is UPPERCASE > LOWERCASE > DIGIT > SYMBOLS)

Therefore, I would like to explore if there is any clean, one-line/shorter solution for generating the required passwords.

Many thanks in advance

Upvotes: 0

Views: 3442

Answers (4)

pshute
pshute

Reputation: 61

I prefer to keep my generated passwords a little more complex. You can change the variation of amount of upper, lower, punctuation or numbers in the if statement:

    import string
    import secrets


    opts = string.ascii_letters + string.digits + string.punctuation
    #Generate a random password with at least two lower case, two upper case, one digit, and two symbols
    while True:
        psswd = ''.join(secrets.choice(opts) for i in range(12))
        if (sum(c.islower() for c in psswd) >=2 and
            sum(c.isupper() for c in psswd) >=2 and
            sum(c in string.punctuation for c in psswd) >=2 and
            any(c.isdigit() for c in psswd) ):
            break
    return psswd

Upvotes: 2

Lafftar
Lafftar

Reputation: 183

For anyone looking for something a lot simpler, you could just use the faker package. There's a method .password() you can feed args to, to make your passwords more or less complex.

Obviously, install faker: pip install faker

Then, just 3 lines of code:

from faker import Faker
fake = Faker()
print(fake.password())

This will output a string of length 10, these are the default arguments you can use:

password(length=10, special_chars=True, digits=True, upper_case=True, lower_case=True)

This is just a simple run in my terminal:

from faker import Faker
fake = Faker()
fake.password()
'S9tBRdbf^C'
fake.password()
'NWN8FB4ku&'
fake.password()
'*0B7Z_TisD'
fake.password()
'L2R_bTkw_^'

Feel free to comment if you got questions.

Upvotes: 1

Alain T.
Alain T.

Reputation: 42143

simply shuffle the resulting password at the end by adding this:

password = "".join(random.sample(password,len(password)))

This way you meet the requirements without creating a pattern.

or you could shuffle the requirements and write the function like this:

from random  import sample
from secrets import choice
from string  import *

def getRandomPassword(length):
    alphabet      = ascii_letters + digits + punctuation
    requirements  = [ascii_uppercase,        # at least one uppercase letter
                     ascii_lowercase,        # at least one lowercase letter
                     digits,                 # at least one digit
                     punctuation,            # at least one symbol
                     *(length-4)*[alphabet]] # rest: letters digits and symbols
    return "".join(choice(req) for req in sample(requirements,length)) 

Upvotes: 1

FeddrikScheper
FeddrikScheper

Reputation: 17

import random
import string

def get_random_string(length):
    letters = string.ascii_letters + string.digits + string.punctuation
    result_str = ''.join(random.choice(letters) for i in range(length))
    print("Random string of length", length, "is:", result_str)

get_random_string(8)
get_random_string(8)
get_random_string(6)
get_random_string(11)
get_random_string(22)

Upvotes: 1

Related Questions