Nivel: Intermedio
Tema: Aleatoriedad, reglas de validación, secrets vs random, composición de strings, tests con pytest
Objetivo: Generar contraseñas que cumplan reglas mínimas (longitud y diversidad de caracteres) usando prácticas seguras.
Enunciado
Crea una función llamada generar_contrasena(longitud=12, usar_mayusculas=True, usar_numeros=True, usar_simbolos=True) que:
- Reciba:
longitud(int): longitud total de la contraseña- flags booleanos para incluir tipos de caracteres
- Reglas de validación:
- Si
longitudesNoneo no esint, lanceTypeError - Si
longitud< 4, lanceValueError - Si alguno de los flags no es
bool, lanceTypeError - Si todos los flags (
usar_mayusculas,usar_numeros,usar_simbolos) sonFalse, igualmente debe generar una contraseña válida usando solo minúsculas (esto sigue siendo válido)
- Si
- La contraseña debe:
- Tener exactamente
longitudcaracteres - Contener al menos 1 minúscula siempre
- Si
usar_mayusculasesTrue, contener al menos 1 mayúscula - Si
usar_numerosesTrue, contener al menos 1 número - Si
usar_simbolosesTrue, contener al menos 1 símbolo
- Tener exactamente
- Usar el módulo
secrets(norandom) para elegir caracteres.
Debe devolver un str con la contraseña.
Ejemplos
generar_contrasena(12)→"aB3!k..."generar_contrasena(8, usar_simbolos=False)→ contiene minúsculas, mayúsculas y números, pero sin símbolosgenerar_contrasena(10, False, False, False)→ solo minúsculas, longitud 10generar_contrasena(3)→ ValueErrorgenerar_contrasena("12")→ TypeError
Pistas
- Define conjuntos de caracteres:
- minúsculas:
string.ascii_lowercase - mayúsculas:
string.ascii_uppercase - números:
string.digits - símbolos: por ejemplo
"!@#$%^&*()-_=+[]{}"
- minúsculas:
- Para garantizar reglas, construye primero una lista con los caracteres “obligatorios” y luego completa el resto.
- Mezcla el resultado con
secrets.SystemRandom().shuffle()o seleccionando posiciones aleatorias (más simple: shuffle conSystemRandom).
Solución explicada (paso a paso)
- Validamos tipos y rango de
longitud. - Validamos que los flags sean booleanos.
- Construimos:
- una lista
obligatorioscon 1 carácter de cada tipo requerido - un pool
permitidoscon todos los caracteres habilitados
- una lista
- Completamos la contraseña eligiendo caracteres al azar desde
permitidoshasta alcanzarlongitud. - Mezclamos el orden para que los “obligatorios” no queden siempre al inicio.
- Convertimos la lista en string y devolvemos.
Ejecuta:
pytest -q
Variantes para subir de nivel (opcional)
- Excluir caracteres ambiguos (O/0, l/1) para contraseñas “human-friendly”
- Permitir configuración del set de símbolos
- Generar múltiples contraseñas en una llamada
- Añadir parámetro
semilla(solo para modo demo, no para producción)
Lo que aprendiste
- Por qué
secretses preferible arandompara contraseñas - Cómo garantizar reglas mínimas de composición
- Cómo testear propiedades (no valores exactos) cuando hay aleatoriedad
- Diseño robusto con validación de entradas
Accede al código completo y a los tests en GitHub para ejecutar y modificar la solución localmente.
Continúa con Reto #20 — Manejo robusto de errores (try/except bien hecho) para escribir funciones resistentes y con mensajes de error útiles.