Password Strength Checker

Password Strength Checker

Dependencies:

- Python 3

In today's interconnected digital landscape, data security stands as an unyielding fortress guarding our most sensitive information. At its core lies the crucial factor of password strength, the first line of defense against unauthorized access and breaches. In this blog post, we embark on an enlightening journey into the realm of cybersecurity, exploring a potent alliance of two cutting-edge technologies: FastAPI and GraphQL, fueled by the Strawberry library. This dynamic combination promises not only to evaluate password robustness but also to deliver a developer's dream - a seamless and agile development experience.

Our exploration commences with the establishment of stringent password rules. These rules, including checks for minimum length, uppercase and lowercase character requirements, mandatory digits, essential special characters, and the prevention of sequential letter repetition, serve as the bedrock of password fortification.

We'll delve into the details of this powerful combination and show you how it can elevate the security of your applications to a whole new level.

Install requirements:

CMD / Terminal
pip3 install fastapi==0.87.0 uvicorn==0.31.1 graphene==3.1.1 strawberry-graphql==0.246.2

1. Let's start by creating some rules for passwords.

min_size: This rule verifies the minimum password length.
min_upper_case: It ensures the presence of a minimum number of uppercase letters.
min_lower_case: This rule checks for the inclusion of a minimum number of lowercase letters.
min_digit: It verifies if the password contains the required minimum digits.
min_special_chars: This rule confirms the presence of the minimum required special characters.
no_repeted: Lastly, it checks for the absence of repeated sequential letters in the password.

rules_password.py
import re

def min_size(string, value) -> bool:
    return len(string) >= value

def count_matches(string, condition) -> int:
    return sum(1 for c in string if condition(c))

def min_upper_case(string, value) -> bool:
    return count_matches(string, str.isupper) >= value

def min_lower_case(string, value) -> bool:
    return count_matches(string, str.islower) >= value

def min_digit(string, value) -> bool:
    return count_matches(string, str.isdigit) >= value

def min_special_chars(string, value) -> bool:
    special_chars = r'[!@#$%^&*()\-+\\\/{}\[\]]'
    return len(re.findall(special_chars, string)) >= value

def no_repeted(string) -> bool:
    # https://stackoverflow.com/a/28007115
    return not re.search(r'(.)\1', string)    

to_do

main.py
import inspect
import strawberry
from typing import List, Optional
from fastapi import FastAPI
from strawberry.asgi import GraphQL
from rules_password import *

@strawberry.type
class PasswordResponse:
    isValid: bool
    failedRules: List[str]

@strawberry.input
class Rules:
    rule: str
    value: Optional[int] = None

@strawberry.type
class Query:
    @strawberry.field
    def validatePassword(self, password, rules) -> PasswordResponse:

        dictFunctions = {
            "minSize": min_size,
            "minUpperCase": min_upper_case,
            "minLowerCase": min_lower_case,
            "minDigit": min_digit,
            "minSpecialChars": min_special_chars,
            "noRepeted": no_repeted,
        }

        dictResponse = {}
        for ruleInput in rules:
            function = dictFunctions.get(ruleInput.rule)

            if function:
                num_params = len(inspect.signature(function).parameters)

                if num_params == 1:
                    dictResponse[ruleInput.rule] = function(password)
                elif num_params == 2:
                    dictResponse[ruleInput.rule] = function(password, ruleInput.value)
            else:
                dictResponse[ruleInput.rule] = False

        if all(dictResponse.values()):
            return PasswordResponse(isValid=True, failedRules=[])
        else:
            failed_checks = [rule for rule, passed in dictResponse.items() if not passed]
            return PasswordResponse(isValid=False, failedRules=failed_checks)

schema = strawberry.Schema(query=Query)
graphql_app = GraphQL(schema)

app = FastAPI()
app.add_route("/graphql", graphql_app)
app.add_websocket_route("/graphql", graphql_app)    

This is all required code.


Example of use:

Go go http://localhost:8000/graphql and you can insert queries like this:

Query Input
query {
    validatePassword(password: "TestStrengthPassword!12&", rules: [
        {rule: "minSize", value: 10},
        {rule: "minUpperCase", value: 5},
        {rule: "minLowerCase", value: 3},
        {rule: "minDigit", value: 3},
        {rule: "minSpecialChars", value: 2},
        {rule: "noRepeted"},
    ]) {
        isValid
        failedRules
    }
}
Output
response: {
    "data": {
        "validatePassword": {
            "isValid": false,
            "failedRules": [
                "minUpperCase",
                "minDigit",
                "noRepeted"
            ]
        }
    }
}

For use like a API, make a POST to http://localhost:8000/graphql

example_use.py
import json
import requests

url = "http://localhost:8000/graphql"
    
body = """
query {
    validatePassword(password: "TestStrengthPassword!12&", rules: [
        {rule: "minSize", value: 10},
        {rule: "minUpperCase", value: 5},
        {rule: "minLowerCase", value: 3},
        {rule: "minDigit", value: 3},
        {rule: "minSpecialChars", value: 2},
        {rule: "noRepeted"},
    ]) {
        isValid
        failedRules
    }
}
"""

print(body)
response = requests.post(url=url, json={"query": body})
print("response status code: ", response.status_code)
if response.status_code == 200:
    parsed = json.loads(response.content)
    print("response : ", json.dumps(parsed, indent=4))

# response status code:  200
# response :  {
#     "data": {
#         "validatePassword": {
#             "isValid": false,
#             "failedRules": [
#                 "minUpperCase",
#                 "minDigit",
#                 "noRepeted"
#             ]
#         }
#     }
# }

and its done!


All the code is available here too: Github - Password-Strength-Checker

CMD / Terminal
git clone https://github.com/AlfredoFilho/Password-Strength-Checker.git