Metadata-Version: 2.1
Name: django-tls-certificate-auth
Version: 1.0.1
Summary: Django authentication middleware using TLS client certificates
Author-Email: Mark Parncutt <me@markparncutt.com>
License: MIT
Requires-Python: >=3.10
Requires-Dist: Django>=5.0
Description-Content-Type: text/markdown

# django-tls-certificate-auth

Authenticate Django users using TLS client certificates terminated by a reverse proxy (for example, nginx).

The package reads certificate details from request headers and logs users in when they visit `settings.LOGIN_URL`.

## Installation

Install from PyPI:

```bash
pip install django-tls-certificate-auth
```

## Django Setup

### 1. Add middleware

Add the middleware to `MIDDLEWARE` (after session middleware so `login()` can write to the session):

```python
MIDDLEWARE = [
    "django.contrib.sessions.middleware.SessionMiddleware",
    # ...
    "django_tls_certificate_auth.TLSClientCertAuthenticationMiddleware",
    # ...
]
```

### 2. Add authentication backend

Add the backend to `AUTHENTICATION_BACKENDS`:

```python
AUTHENTICATION_BACKENDS = [
    "django_tls_certificate_auth.TLSClientCertAuthenticationBackend",
]
```

If you still want username/password (or other methods), include Django's default backend as well:

```python
AUTHENTICATION_BACKENDS = [
    "django_tls_certificate_auth.TLSClientCertAuthenticationBackend",
    "django.contrib.auth.backends.ModelBackend",
]
```

### 3. Configure login URLs

The middleware runs only when the request path matches `LOGIN_URL`.

```python
LOGIN_URL = "/accounts/login/"
LOGIN_REDIRECT_URL = "/"
```

When a valid certificate is present, the middleware authenticates the user and redirects to `LOGIN_REDIRECT_URL`.

## Required Proxy Headers

Your reverse proxy must verify client certificates and pass these headers to Django:

- `X-Client-Cert-Valid`: must be `SUCCESS`
- `X-Client-Cert-Dn`: certificate subject DN string containing `CN=<username>`

nginx example:

```nginx
ssl_client_certificate /etc/ssl/certs/mysite.ca.crt;
ssl_verify_client on;

proxy_set_header X-Client-Cert-Valid $ssl_client_verify;
proxy_set_header X-Client-Cert-Dn $ssl_client_s_dn;
```

## How Username Mapping Works

The backend extracts `CN` from `X-Client-Cert-Dn` and looks up a Django user by your user model's `USERNAME_FIELD`.

Example DN:

```text
/C=AU/O=Example/CN=alice
```

This maps to username `alice`.

## Package Settings

The following settings can be set in your Django project's `settings.py`:

### `TLS_CLIENT_AUTHENTICATION_AUTO_CREATE`

- Type: `bool`
- Default: `False`
- Behavior:
  - `False`: if the mapped user does not exist, authentication fails with `PermissionDenied`.
  - `True`: if the mapped user does not exist, the backend creates it using `create_user(...)`.

Example:

```python
TLS_CLIENT_AUTHENTICATION_AUTO_CREATE = True
```

### `TLS_CLIENT_AUTHENTICATION_DEBUG_FAKE_HEADERS`

- Type: `dict`
- Default: `{}`
- Behavior:
  - Any headers defined in this dictionary (with "HTTP_" prefix) will be treated by this authentication middleware as if they had been sent as HTTP headers.
  - This setting is ignored unless `DEBUG` is set to true. It is intended to simplify the use of this library during development.

Example:

```python
TLS_CLIENT_AUTHENTICATION_DEBUG_FAKE_HEADERS = {
    "HTTP_X_CLIENT_CERT_VALID": "SUCCESS",
    "HTTP_X_CLIENT_CERT_DN": "C=AU, ST=Victoria, L=Melbourne, CN=mp"
}
```

## Django Settings Used by This Package

These are standard Django settings consumed by the package:

- `LOGIN_URL`: path that triggers certificate authentication
- `LOGIN_REDIRECT_URL`: destination after successful TLS login

## Notes

- Header names and success value are currently fixed in code:
  - `X-Client-Cert-Valid` must equal `SUCCESS`
  - `X-Client-Cert-Dn` must include a `CN=...` component
- Ensure your proxy strips/overwrites client-supplied versions of these headers so users cannot spoof certificate identity.
