Metadata-Version: 2.3
Name: django-simple-saml
Version: 2.0.0
Summary: Django app for managing multiple SAML Identity Providers.
Home-page: https://github.com/yunojuno/django-simple-saml
License: MIT
Author: YunoJuno
Author-email: code@yunojuno.com
Maintainer: YunoJuno
Maintainer-email: code@yunojuno.com
Requires-Python: >=3.12,<4.0
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Framework :: Django :: 5.2
Classifier: Framework :: Django :: 6.0
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3 :: Only
Provides-Extra: heroku
Provides-Extra: localhost
Requires-Dist: dj_database_url ; extra == "heroku"
Requires-Dist: django (>=5.2,<7.0)
Requires-Dist: django-sslserver ; extra == "localhost"
Requires-Dist: gunicorn ; extra == "heroku"
Requires-Dist: psycopg2-binary ; extra == "heroku"
Requires-Dist: python3-saml
Requires-Dist: social-auth-app-django
Requires-Dist: whitenoise ; extra == "heroku" or extra == "localhost"
Project-URL: Documentation, https://github.com/yunojuno/django-simple-saml
Project-URL: Repository, https://github.com/yunojuno/django-simple-saml
Description-Content-Type: text/markdown

# Django Simple SAML

Django app to manage SAML Identity Providers

## Version support

This app supports Python 3.12+ and Django 5.2-6.0.

## Background

This library builds on top of `social-auth-app-django` and
`python3-saml`, which together handle the heavy lifting of a SAML
authentication flow. It assumes that you are building a service that
will act as the Service Provider (SP) in the flow, and that you will be
integrating with a number of external Identity Providers (IdP) for user
authentication.

The core change to those libraries that this package adds is a new
`SAMLAuth` backend called `SimpleSAMLAuth` that reads in IdP data from a
model (i.e. the database) rather than using the settings config dict
`SOCIAL_AUTH_SAML_ENABLED_IDPS`.

The reason for this is to make it easy to update / test new IdPs on a
live environment without having to deploy. If you are running a platform
that offers SSO to clients as a feature, having to embed their IdP
details in the settings (which also requires a redeployment) isn't a
practical option.

The IdP data is input via the Django admin site.

## Settings

This package relies on the existing `python-social-auth` settings. See
their documentation for details, or refer to the `demo.settings.base`
module for an example.

## Configuration

Click this button to deploy to Heroku:

[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy)

You must supply three SAML settings that should be available from your
test IdP provider. If you have a Google Workspace account, that can be
used - see https://admin.google.com/ac/security/ssocert for details.

## IdentityProvider model

`django-simple-saml` stores each SAML Identity Provider in
`simple_saml.models.IdentityProvider`.

The existing IdP metadata and attribute mapping fields still populate the
`social-auth-app-django` / `python-social-auth` IdP configuration.

Requested authentication context is configured separately per IdP via
these fields:

- `requested_authn_context_mode`
- `requested_authn_context_values`
- `requested_authn_context_comparison`

This configuration is merged into the generated `python3-saml`
`security` settings when the AuthnRequest is built.

## RequestedAuthnContext configuration

By default, `django-simple-saml` now disables
`RequestedAuthnContext` for every `IdentityProvider`.

That means new and existing `IdentityProvider` rows behave like:

- `security["requestedAuthnContext"] = False`

This overrides the upstream `python3-saml` default, which would
otherwise send the password-based context implicitly.

### Modes

#### `DISABLED`

Do not send `RequestedAuthnContext`.

Equivalent `python3-saml` security config:

- `requestedAuthnContext = False`

#### `PASSWORD`

Send the upstream password-based context:

- `urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport`

Equivalent `python3-saml` security config:

- `requestedAuthnContext = True`
- `requestedAuthnContextComparison = <configured comparison>`

This preserves the previous package behavior for IdPs that still require
it, but it must now be enabled explicitly per `IdentityProvider`.

#### `CUSTOM`

Send one or more explicit AuthnContext class refs.

Equivalent `python3-saml` security config:

- `requestedAuthnContext = <list of configured values>`
- `requestedAuthnContextComparison = <configured comparison>`

`CUSTOM` requires at least one value in
`requested_authn_context_values`.

### Supported comparison values

`requested_authn_context_comparison` is stored in the database as one of:

- `EXACT`
- `MINIMUM`
- `MAXIMUM`
- `BETTER`

Those values are mapped to the lowercase `python3-saml` equivalents.

### Example

```python
from simple_saml.models import IdentityProvider

IdentityProvider.objects.create(
    label="acme",
    provider="Acme Okta",
    entity_id="https://acme.okta.example/app/sso/saml/metadata",
    sso_url="https://acme.okta.example/app/sso/saml",
    x509_cert="MIIC...",
    user_permanent_id_attr="email",
    requested_authn_context_mode=IdentityProvider.RequestedAuthnContextMode.CUSTOM,
    requested_authn_context_values=[
        "urn:example:loa:2",
        "urn:example:loa:3",
    ],
    requested_authn_context_comparison=(
        IdentityProvider.RequestedAuthnContextComparison.MINIMUM
    ),
)
```

## Admin support

The Django admin exposes the RequestedAuthnContext fields directly on the
`IdentityProvider` form.

Validation rules:

- `CUSTOM` requires at least one authn context value.
- `DISABLED` and `PASSWORD` ignore stored custom values.
- `requested_authn_context_comparison` is restricted to the supported
  `python3-saml` values.

