# Django Better Passwords

This app provides tools to enforce stronger password policies and expiration.

## Features

* Configurable password expiration;
* Customizable password validator;
* Uses Django messages framework to warn the user about the expiration;
* Prevents user from logging in after expiration and redirects to password change page;
* Compatible with default Django admin and Django CMS (django-cms) admin;
* Can be used to expire only staff passwords, or for all users;
* Force password update immediately after user creation.

## Requirements

Requires Python >= 3.6 and Django >=2.
Recommended Python 3.11 or 3.12 and Django 4.2 or 5.0;

## Quick start

1. Install the lib with `pip install django-better-passwords`.
2. Add `'django_better_passwords'` to `INSTALLED_APPS`.
3. Add `'django_better_passwords.middleware.PasswordExpirationMiddleware'` to `MIDDLEWARE`. <br>It should be listed after authentication, session and message middlewares, like this:
   ```python
   MIDDLEWARE = [
      "django.middleware.security.SecurityMiddleware",
      "django.contrib.sessions.middleware.SessionMiddleware",
      "django.middleware.common.CommonMiddleware",
      "django.middleware.csrf.CsrfViewMiddleware",
      "django.contrib.auth.middleware.AuthenticationMiddleware",
      "django.contrib.messages.middleware.MessageMiddleware",
      "django_better_passwords.middleware.PasswordExpirationMiddleware",
      "django.middleware.clickjacking.XFrameOptionsMiddleware",
   ]
   ```
4. Add `'django_better_passwords.validators.custom_password_validator.CustomPasswordValidator'` to `AUTH_PASSWORD_VALIDATORS`.<br>
Comment out or remove `'django.contrib.auth.password_validation.MinimumLengthValidator'` to avoid conflicting:
   ```python
   AUTH_PASSWORD_VALIDATORS = [
      ...
      # {
      #     "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
      # },
      {
         "NAME": "django_better_passwords.validators.custom_password_validator.CustomPasswordValidator",
         "OPTIONS": {
               "min_length": 8,
               "max_length": 20,
               "required_characters": "!#$%^&*()_+{}[]:\"-=,./<>?",
               "forbidden_characters": "@",
         },
      },
   ]
   ```
5. The validator accepts 4 parameters, being:
   1. `min_length (int)`: the minimum password length;
   2. `max_length (int)`: the maximum password length;
   3. `required_characters (str)`: a string containing a list of characters of which at least one must be present in the password;
   4. `forbidden_characters (str)`: a string containing a list of characters none of which can be present in the password;
6. Aditional app settings:
   ```python
   DBP_PASSWORD_EXPIRATION_DAYS = 60
   DBP_PASSWORD_CHANGE_REDIRECT_URL = "password_change"
   DBP_LOGOUT_URL = "logout"
   ```
   <span style="color:tomato">Attention</span>: If `DBP_PASSWORD_CHANGE_REDIRECT_URL` is present, when a user tries
   to log in or navigate to any url, he will be redirected to the `password_change` page.
   If it is not present, only users who try to access the admin area will be redirected.

## Contributing

We use pre-commit paired with black, flake8 and isort to keep things in their rightful place.

After cloning the project:

* Create and activate a venv;
* Install pip-tools;
* Run `pip-compile requirements.in` and `pip-sync requirements.txt` to install dependencies;
* Run `pre-commit install -f` to install pre-commit hook. It will create a **git hook**, that will **run automatically before every commit**;

## Acknowledgements

This app is inspired by [django-password-policies-iplweb](https://github.com/iplweb/django-password-policies-iplweb) and [django-password-expire](https://pypi.org/project/django-password-expire/).

### Author

André Corrêa - andre.lccorrea@gmail.com
