grafana-django-saml2-auth


Namegrafana-django-saml2-auth JSON
Version 3.18.0 PyPI version JSON
download
home_pageNone
SummaryDjango SAML2 Authentication Made Easy.
upload_time2024-11-08 15:28:57
maintainerNone
docs_urlNone
authorMostafa Moradian
requires_python<4.0,>=3.10
licenseApache 2.0
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Django SAML2 Authentication

[![PyPI](https://img.shields.io/pypi/v/grafana-django-saml2-auth?label=version&logo=pypi)](https://pypi.org/project/grafana-django-saml2-auth/) [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/grafana/django-saml2-auth/deploy.yml?branch=main&logo=github)](https://github.com/grafana/django-saml2-auth/actions) [![Coveralls](https://img.shields.io/coveralls/github/grafana/django-saml2-auth?logo=coveralls)](https://coveralls.io/github/grafana/django-saml2-auth) [![Downloads](https://pepy.tech/badge/grafana-django-saml2-auth)](https://pepy.tech/project/grafana-django-saml2-auth)

This plugin provides a simple way to integrate SAML2 Authentication into your Django-powered app. SAML SSO is a standard, so practically any SAML2 based SSO identity provider is supported.

This plugin supports both identity provider and service provider-initiated SSO:

- For IdP-initiated SSO, the user should sign in to their identity provider platform, e.g., Okta, and click on the application that authorizes and redirects the user to the service provider, that is your platform.
- For SP-initiated SSO, the user should first exist on your platform, either by signing in via the first method (IdP-initiated SSO) or any other custom solution. It can be configured to be redirected to the correct application on the identity provider platform.

For IdP-initiated SSO, the user will be created if it doesn't exist. Still, for SP-initiated SSO, the user should exist in your platform for the code to detect and redirect them to the correct application on the identity provider platform.

## Project Information

- Original Author: Fang Li ([@fangli](https://github.com/fangli))
- Maintainer: Mostafa Moradian ([@mostafa](https://github.com/mostafa))
- Version support matrix:

    | **Python**             | **Django** | **django-saml2-auth** | **End of extended support<br/>(Django)** |
    | ---------------------- | ---------- | --------------------- | ---------------------------------------- |
    | 3.10.x, 3.11.x, 3.12.x | 4.2.x      | >=3.4.0               | April 2026                               |
    | 3.10.x, 3.11.x, 3.12.x | 5.0.x      | >3.12.0               | April 2026                               |

- Release logs are available [here](https://github.com/grafana/django-saml2-auth/releases).

- For contribution, read [contributing guide](CONTRIBUTING.md).

## CycloneDX SBOM

This project provides a CycloneDX Software Bill of Materials (SBOM) in JSON format. The SBOM is generated by the [GitHub Actions workflow](.github/workflows/deploy.yml) and is available as an artifact for each release. The SBOM is generated using the [cyclonedx-python](https://github.com/CycloneDX/cyclonedx-python) library.

## Donate

Please give us a shiny ![star](https://img.shields.io/github/stars/grafana/django-saml2-auth.svg?style=social&label=Star&maxAge=86400) and help spread the word.

## Installation

You can install this plugin via `pip`. Make sure you update `pip` to be able to install from git:

```bash
pip install grafana-django-saml2-auth
```

or from source:

```bash
git clone https://github.com/grafana/django-saml2-auth
cd django-saml2-auth
python setup.py install
```

`xmlsec` is also required by `pysaml2`, so it must be installed:

``` bash
// RPM-based distributions
# yum install xmlsec1
// DEB-based distributions
# apt-get install xmlsec1
// macOS
# brew install xmlsec1
```

[Windows binaries](https://www.zlatkovic.com/projects/libxml/index.html) are also available.

## How to use?

1. Once you have the library installed or in your `requirements.txt`, import the views module in your root `urls.py`:

    ```python
    import django_saml2_auth.views
    ```

2. Override the default login page in the root `urls.py` file, by adding these lines **BEFORE** any `urlpatterns`:

    ```python
    # These are the SAML2 related URLs. (required)
    re_path(r'^sso/', include('django_saml2_auth.urls')),

    # The following line will replace the default user login with SAML2 (optional)
    # If you want to specific the after-login-redirect-URL, use parameter "?next=/the/path/you/want"
    # with this view.
    re_path(r'^accounts/login/$', django_saml2_auth.views.signin),

    # The following line will replace the admin login with SAML2 (optional)
    # If you want to specific the after-login-redirect-URL, use parameter "?next=/the/path/you/want"
    # with this view.
    re_path(r'^admin/login/$', django_saml2_auth.views.signin),
    ```

3. Add `'django_saml2_auth'` to `INSTALLED_APPS` in your django `settings.py`:

    ```python
    INSTALLED_APPS = [
        '...',
        'django_saml2_auth',
    ]
    ```

4. In `settings.py`, add the SAML2 related configuration:

    Please note, the only required setting is **METADATA\_AUTO\_CONF\_URL** or the existence of a **GET\_METADATA\_AUTO\_CONF\_URLS** trigger function. The following block shows all required and optional configuration settings and their default values.

    <details>
        <summary>Click to see the entire settings block</summary>

    ```python
    SAML2_AUTH = {
        # Metadata is required, choose either remote url or local file path
        'METADATA_AUTO_CONF_URL': '[The auto(dynamic) metadata configuration URL of SAML2]',
        'METADATA_LOCAL_FILE_PATH': '[The metadata configuration file path]',
        'KEY_FILE': '[The key file path]',
        'CERT_FILE': '[The certificate file path]',

        # If both `KEY_FILE` and `CERT_FILE` are provided, `ENCRYPTION_KEYPAIRS` will be added automatically. There is no need to provide it unless you wish to override the default value.
        'ENCRYPTION_KEYPAIRS': [
            {
                "key_file": '[The key file path]',
                "cert_file": '[The certificate file path]',
            }
        ],

        'DEBUG': False,  # Send debug information to a log file
        # Optional logging configuration.
        # By default, it won't log anything.
        # The following configuration is an example of how to configure the logger,
        # which can be used together with the DEBUG option above. Please note that
        # the logger configuration follows the Python's logging configuration schema:
        # https://docs.python.org/3/library/logging.config.html#logging-config-dictschema
        'LOGGING': {
            'version': 1,
            'formatters': {
                'simple': {
                    'format': '[%(asctime)s] [%(levelname)s] [%(name)s.%(funcName)s] %(message)s',
                },
            },
            'handlers': {
                'stdout': {
                    'class': 'logging.StreamHandler',
                    'stream': 'ext://sys.stdout',
                    'level': 'DEBUG',
                    'formatter': 'simple',
                },
            },
            'loggers': {
                'saml2': {
                    'level': 'DEBUG'
                },
            },
            'root': {
                'level': 'DEBUG',
                'handlers': [
                    'stdout',
                ],
            },
        },

        # Optional settings below
        'DEFAULT_NEXT_URL': '/admin',  # Custom target redirect URL after the user get logged in. Default to /admin if not set. This setting will be overwritten if you have parameter ?next= specificed in the login URL.
        'CREATE_USER': True,  # Create a new Django user when a new user logs in. Defaults to True.
        'NEW_USER_PROFILE': {
            'USER_GROUPS': [],  # The default group name when a new user logs in
            'ACTIVE_STATUS': True,  # The default active status for new users
            'STAFF_STATUS': False,  # The staff status for new users
            'SUPERUSER_STATUS': False,  # The superuser status for new users
        },
        'ATTRIBUTES_MAP': {  # Change Email/UserName/FirstName/LastName to corresponding SAML2 userprofile attributes.
            'email': 'user.email',
            'username': 'user.username',
            'first_name': 'user.first_name',
            'last_name': 'user.last_name',
            'token': 'Token',  # Mandatory, can be unrequired if TOKEN_REQUIRED is False
            'groups': 'Groups',  # Optional
        },
        'GROUPS_MAP': {  # Optionally allow mapping SAML2 Groups to Django Groups
            'SAML Group Name': 'Django Group Name',
        },
        'TRIGGER': {
            'EXTRACT_USER_IDENTITY': 'path.to.your.extract.user.identity.hook.method',
            # Optional: needs to return a User Model instance or None
            'GET_USER': 'path.to.your.get.user.hook.method',
            'CREATE_USER': 'path.to.your.new.user.hook.method',
            'BEFORE_LOGIN': 'path.to.your.login.hook.method',
            'AFTER_LOGIN': 'path.to.your.after.login.hook.method',
            # Optional. This is executed right before METADATA_AUTO_CONF_URL.
            # For systems with many metadata files registered allows to narrow the search scope.
            'GET_USER_ID_FROM_SAML_RESPONSE': 'path.to.your.get.user.from.saml.hook.method',
            # This can override the METADATA_AUTO_CONF_URL to enumerate all existing metadata autoconf URLs
            'GET_METADATA_AUTO_CONF_URLS': 'path.to.your.get.metadata.conf.hook.method',
            # This will override ASSERTION_URL to allow more dynamic assertion URLs
            'GET_CUSTOM_ASSERTION_URL': 'path.to.your.get.custom.assertion.url.hook.method',
            # This will override FRONTEND_URL for more dynamic URLs
            'GET_CUSTOM_FRONTEND_URL': 'path.to.your.get.custom.frontend.url.hook.method',
        },
        'ASSERTION_URL': 'https://mysite.com',  # Custom URL to validate incoming SAML requests against
        'ENTITY_ID': 'https://mysite.com/sso/acs/',  # Populates the Issuer element in authn request
        'NAME_ID_FORMAT': FormatString,  # Sets the Format property of authn NameIDPolicy element, e.g. 'user.email'
        'USE_JWT': True,  # Set this to True if you are running a Single Page Application (SPA) with Django Rest Framework (DRF), and are using JWT authentication to authorize client users
        'JWT_ALGORITHM': 'HS256',  # JWT algorithm to sign the message with
        'JWT_SECRET': 'your.jwt.secret',  # JWT secret to sign the message with
        'JWT_PRIVATE_KEY': '--- YOUR PRIVATE KEY ---',  # Private key to sign the message with. The algorithm should be set to RSA256 or a more secure alternative.
        'JWT_PRIVATE_KEY_PASSPHRASE': 'your.passphrase',  # If your private key is encrypted, you might need to provide a passphrase for decryption
        'JWT_PUBLIC_KEY': '--- YOUR PUBLIC KEY ---',  # Public key to decode the signed JWT token
        'JWT_EXP': 60,  # JWT expiry time in seconds
        'FRONTEND_URL': 'https://myfrontendclient.com',  # Redirect URL for the client if you are using JWT auth with DRF. See explanation below
        'LOGIN_CASE_SENSITIVE': True,  # whether of not to get the user in case_sentive mode
        'AUTHN_REQUESTS_SIGNED': True, # Require each authentication request to be signed
        'LOGOUT_REQUESTS_SIGNED': True,  # Require each logout request to be signed
        'WANT_ASSERTIONS_SIGNED': True,  # Require each assertion to be signed
        'WANT_RESPONSE_SIGNED': True,  # Require response to be signed
        'ACCEPTED_TIME_DIFF': None,  # Accepted time difference between your server and the Identity Provider
        'ALLOWED_REDIRECT_HOSTS': ["https://myfrontendclient.com"], # Allowed hosts to redirect to using the ?next parameter
        'TOKEN_REQUIRED': True,  # Whether or not to require the token parameter in the SAML assertion
        'DISABLE_EXCEPTION_HANDLER': True,  # Whether the custom exception handler should be used
    }

    ```

    </details>

5. In your SAML2 SSO identity provider, set the Single-sign-on URL and Audience URI (SP Entity ID) to <http://your-domain/sso/acs/>

## How to debug?

To debug what's happening between the SAMLP Identity Provider and your Django application, you can use SAML-tracer for [Firefox](https://addons.mozilla.org/en-US/firefox/addon/saml-tracer/) or [Chrome](https://chrome.google.com/webstore/detail/saml-tracer/mpdajninpobndbfcldcmbpnnbhibjmch?hl=en). Using this tool, you can see the SAML requests and responses that are being sent back and forth.

Also, you can enable the debug mode in the `settings.py` file by setting the `DEBUG` flag to `True` and enabling the `LOGGING` configuration. See above for configuration examples.

*Note:* Don't forget to disable the debug mode in production and also remove the logging configuration if you don't want to see internal logs of pysaml2 library.

## Module Settings

Some of the following settings are related to how this module operates. The rest are passed as options to the pysaml2 library. For more information on the pysaml2 library, see the [pysaml2 documentation](https://pysaml2.readthedocs.io/en/latest/howto/config.html), which contains examples of available settings. Also, note that all settings are not implemented in this module.

<details>
    <summary>Click to see the module settings</summary>

| **Field name**                              | **Description**                                                                                                                                                                                                                                                                                                                                                                                                                                             | **Data type(s)** | **Default value(s)**                                                                                                                     | **Example**                                                                             |
|---------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ---------------- |------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------|
| **METADATA\_AUTO\_CONF\_URL**               | Auto SAML2 metadata configuration URL                                                                                                                                                                                                                                                                                                                                                                                                                       | `str`            | `None`                                                                                                                                   | `https://ORG.okta.com/app/APP-ID/sso/saml/metadata`                                     |
| **METADATA\_LOCAL\_FILE\_PATH**             | SAML2 metadata configuration file path                                                                                                                                                                                                                                                                                                                                                                                                                      | `str`            | `None`                                                                                                                                   | `/path/to/the/metadata.xml`                                                             |
| **KEY_FILE**                                | SAML2 private key file path.  Required for AUTHN\_REQUESTS\_SIGNED                                                                                                                                                                                                                                                                                                                                                                                          | `str`            | `None`                                                                                                                                   | `/path/to/the/key.pem`                                                                  |
| **CERT_FILE**                               | SAML2 public certificate file path                                                                                                                                                                                                                                                                                                                                                                                                                          | `str`            | `None`                                                                                                                                   | `/path/to/the/cert.pem`                                                                 |
| **ENCRYPTION_KEYPAIRS**                     | Required for handling encrypted assertions. Will be automatically set if both `KEY_FILE` and `CERT_FILE` are set.                                                                                                                                                                                                                                                                                                                                           | `list`           | Not set.                                                                                                                                 | `[ { 'key_file': '[The key file path]', 'cert_file': '[The certificate file path]' } ]` |
| **DEBUG**                                   | Send debug information to a log file                                                                                                                                                                                                                                                                                                                                                                                                                        | `bool`           | `False`                                                                                                                                  |                                                                                         |
| **LOGGING**                                 | Logging configuration dictionary                                                                                                                                                                                                                                                                                                                                                                                                                            | `dict`           | Not set.                                                                                                                                 |                                                                                         |
| **DEFAULT\_NEXT\_URL**                      | Custom target redirect URL after the user get logged in. Default to /admin if not set. This setting will be overwritten if you have parameter `?next=` specificed in the login URL.                                                                                                                                                                                                                                                                         | `str`            | `admin:index`                                                                                                                            | `https://app.example.com/account/login`                                                 |
| **CREATE\_USER**                            | Determines if a new Django user should be created for new users                                                                                                                                                                                                                                                                                                                                                                                             | `bool`           | `True`                                                                                                                                   |                                                                                         |
| **CREATE\_GROUPS**                          | Determines if a new Django group should be created if the SAML2 Group does not exist                                                                                                                                                                                                                                                                                                                                                                        | `bool`           | `False`                                                                                                                                  |                                                                                         |
| **NEW\_USER\_PROFILE**                      | Default settings for newly created users                                                                                                                                                                                                                                                                                                                                                                                                                    | `dict`           | `{'USER_GROUPS': [], 'ACTIVE_STATUS': True, 'STAFF_STATUS': False, 'SUPERUSER_STATUS': False}`                                           |                                                                                         |
| **ATTRIBUTES\_MAP**                         | Mapping of Django user attributes to SAML2 user attributes                                                                                                                                                                                                                                                                                                                                                                                                  | `dict`           | `{'email': 'user.email', 'username': 'user.username', 'first_name': 'user.first_name', 'last_name': 'user.last_name', 'token': 'token'}` | `{'your.field': 'SAML.field'}`                                                          |
| **TOKEN\_REQUIRED**                         | Set this to `False` if you don't require the token parameter in the SAML assertion (in the attributes map)                                                                                                                                                                                                                                                                                                                                                  | `bool`           | `True`                                                                                                                                   |                                                                                         |
| **TRIGGER**                                 | Hooks to trigger additional actions during user login and creation flows. These `TRIGGER` hooks are strings containing a [dotted module name](https://docs.python.org/3/tutorial/modules.html#packages) which point to a method to be called. The referenced method should accept a single argument: a dictionary of attributes and values sent by the identity provider, representing the user's identity. Triggers will be executed only if they are set. | `dict`           | `{}`                                                                                                                                     |                                                                                         |
| **TRIGGER.EXTRACT\_USER\_IDENTITY**         | A method to be called upon extracting the user identity from the SAML2 response. This method should accept TWO parameters of the user_dict and the AuthnResponse. This method can return an enriched user_dict (user identity).                                                                                                                                                                                                                             | `str`            | `AuthnResponse`                                                                                                                          | `my_app.models.users.extract_user_identity`                                             |
| **TRIGGER.GET\_USER**                       | A method to be called upon getting an existing user. This method will be called before the new user is logged in and is used to customize the retrieval of an existing user record. This method should accept ONE parameter of user dict and return a User model instance or none.                                                                                                                                                                          | `str`            | `None`                                                                                                                                   | `my_app.models.users.get`                                                               |
| **TRIGGER.CREATE\_USER**                    | A method to be called upon new user creation. This method will be called before the new user is logged in and after the user's record is created. This method should accept ONE parameter of user dict.                                                                                                                                                                                                                                                     | `str`            | `None`                                                                                                                                   | `my_app.models.users.create`                                                            |
| **TRIGGER.BEFORE\_LOGIN**                   | A method to be called when an existing user logs in. This method will be called before the user is logged in and after the SAML2 identity provider returns user attributes. This method should accept ONE parameter of user dict.                                                                                                                                                                                                                           | `str`            | `None`                                                                                                                                   | `my_app.models.users.before_login`                                                      |
| **TRIGGER.AFTER\_LOGIN**                    | A method to be called when an existing user logs in. This method will be called after the user is logged in and after the SAML2 identity provider returns user attributes. This method should accept TWO parameters of session and user dict.                                                                                                                                                                                                               | `str`            | `None`                                                                                                                                   | `my_app.models.users.after_login`                                                       |
| **TRIGGER.GET\_METADATA\_AUTO\_CONF\_URLS** | A hook function that returns a list of metadata Autoconf URLs. This can override the `METADATA_AUTO_CONF_URL` to enumerate all existing metadata autoconf URLs.                                                                                                                                                                                                                                                                                             | `str`            | `None`                                                                                                                                   | `my_app.models.users.get_metadata_autoconf_urls`                                        |
| **TRIGGER.GET\_CUSTOM\_METADATA**           | A hook function to retrieve the SAML2 metadata with a custom method. This method should return a SAML metadata object as dictionary (`Mapping[str, Any]`). If added, it overrides all other configuration to retrieve metadata. An example can be found in `tests.test_saml.get_custom_metadata_example`. This method accepts the same three parameters of the django_saml2_auth.saml.get_metadata function: `user_id`, `domain`, `saml_response`.          | `str`            | `None`, `None`, `None`                                                                                                                   | `my_app.utils.get_custom_saml_metadata`                                                 |
| **TRIGGER.CUSTOM\_DECODE\_JWT**             | A hook function to decode the user JWT. This method will be called instead of the `decode_jwt_token` default function and should return the user_model.USERNAME_FIELD. This method accepts one parameter: `token`.                                                                                                                                                                                                                                          | `str`            | `None`                                                                                                                                   | `my_app.models.users.decode_custom_token`                                               |
| **TRIGGER.CUSTOM\_CREATE\_JWT**             | A hook function to create a custom JWT for the user. This method will be called instead of the `create_jwt_token` default function and should return the token. This method accepts one parameter: `user`.                                                                                                                                                                                                                                                  | `str`            | `None`                                                                                                                                   | `my_app.models.users.create_custom_token`                                               |
| **TRIGGER.CUSTOM\_TOKEN\_QUERY**            | A hook function to create a custom query params with the JWT for the user. This method will be called after `CUSTOM_CREATE_JWT` to populate a query and attach it to a URL; should return the query params containing the token (e.g., `?token=encoded.jwt.token`). This method accepts one parameter: `token`.                                                                                                                                             | `str`            | `None`                                                                                                                                   | `my_app.models.users.get_custom_token_query`                                            |
| **TRIGGER.GET\_CUSTOM\_ASSERTION\_URL**     | A hook function to get the assertion URL dynamically. Useful when you have dynamic routing, multi-tenant setup and etc. Overrides `ASSERTION_URL`.                                                                                                                                                                                                                                                                                                          | `str`            | `None`                                                                                                                                   | `my_app.utils.get_custom_assertion_url`                                                 |
| **TRIGGER.GET\_CUSTOM\_FRONTEND\_URL**      | A hook function to get a dynamic `FRONTEND_URL` dynamically (see below for more details). Overrides `FRONTEND_URL`. Acceots one parameter: `relay_state`.                                                                                                                                                                                                                                                                                                   | `str`            | `None`                                                                                                                                   | `my_app.utils.get_custom_frontend_url`                                                  |
| **ASSERTION\_URL**                          | A URL to validate incoming SAML responses against. By default, `django-saml2-auth` will validate the SAML response's Service Provider address against the actual HTTP request's host and scheme. If this value is set, it will validate against `ASSERTION_URL` instead - perfect for when Django is running behind a reverse proxy. This will only allow to customize the domain part of the URL, for more customization use `GET_CUSTOM_ASSERTION_URL`.   | `str`            | `None`                                                                                                                                   | `https://example.com`                                                                   |
| **ENTITY\_ID**                              | The optional entity ID string to be passed in the 'Issuer' element of authentication request, if required by the IDP.                                                                                                                                                                                                                                                                                                                                       | `str`            | `None`                                                                                                                                   | `https://exmaple.com/sso/acs`                                                           |
| **NAME\_ID\_FORMAT**                        | Set to the string `'None'`, to exclude sending the `'Format'` property of the `'NameIDPolicy'` element in authentication requests.                                                                                                                                                                                                                                                                                                                          | `str`            | `<urn:oasis:names:tc:SAML:2.0:nameid-format:transient>`                                                                                  |                                                                                         |
| **USE\_JWT**                                | Set this to the boolean `True` if you are using Django with JWT authentication                                                                                                                                                                                                                                                                                                                                                                              | `bool`           | `False`                                                                                                                                  |                                                                                         |
| **JWT\_ALGORITHM**                          | JWT algorithm (str) to sign the message with: [supported algorithms](https://pyjwt.readthedocs.io/en/stable/algorithms.html).                                                                                                                                                                                                                                                                                                                               | `str`            | `HS512` or `RS512`                                                                                                                       |                                                                                         |
| **JWT\_SECRET**                             | JWT secret to sign the message if an HMAC is used with the SHA hash algorithm (`HS*`).                                                                                                                                                                                                                                                                                                                                                                      | `str`            | `None`                                                                                                                                   |                                                                                         |
| **JWT\_PRIVATE\_KEY**                       | Private key (str) to sign the message with. The algorithm should be set to `RSA256` or a more secure alternative.                                                                                                                                                                                                                                                                                                                                           | `str` or `bytes` | `--- YOUR PRIVATE KEY ---`                                                                                                               |                                                                                         |
| **JWT\_PRIVATE\_KEY\_PASSPHRASE**           | If your private key is encrypted, you must provide a passphrase for decryption.                                                                                                                                                                                                                                                                                                                                                                             | `str` or `bytes` | `None`                                                                                                                                   |                                                                                         |
| **JWT\_PUBLIC\_KEY**                        | Public key to decode the signed JWT token.                                                                                                                                                                                                                                                                                                                                                                                                                  | `str` or `bytes` | `'--- YOUR PUBLIC KEY ---'`                                                                                                              |                                                                                         |
| **JWT\_EXP**                                | JWT expiry time in seconds                                                                                                                                                                                                                                                                                                                                                                                                                                  | `int`            | 60                                                                                                                                       |                                                                                         |
| **FRONTEND\_URL**                           | If `USE_JWT` is `True`, you should set the URL to where your frontend is located (will default to `DEFAULT_NEXT_URL` if you fail to do so). Once the client is authenticated through the SAML SSO, your client is redirected to the `FRONTEND_URL` with the JWT token as `token` query parameter. Example: `https://app.example.com/?&token=<your.jwt.token`. With the token, your SPA can now authenticate with your API.                                  | `str`            | `admin:index`                                                                                                                            |                                                                                         |
| **AUTHN\_REQUESTS\_SIGNED**                 | Set this to `False` if your provider doesn't sign each authorization request.  KEY_FILE is required if this is set True.                                                                                                                                                                                                                                                                                                                                    | `bool`           | `True`                                                                                                                                   |
| **LOGOUT\_REQUESTS\_SIGNED**                | Set this to `False` if your provider doesn't sign each logout request.                                                                                                                                                                                                                                                                                                                                                                                      | `bool`           | `True`                                                                                                                                   |                                                                                         |
| **WANT\_ASSERTIONS\_SIGNED**                | Set this to `False` if your provider doesn't sign each assertion.                                                                                                                                                                                                                                                                                                                                                                                           | `bool`           | `True`                                                                                                                                   |                                                                                         |
| **WANT\_RESPONSE\_SIGNED**                  | Set this to `False` if you don't want your provider to sign the response.                                                                                                                                                                                                                                                                                                                                                                                   | `bool`           | `True`                                                                                                                                   |                                                                                         |
| **ACCEPTED\_TIME\_DIFF**                    | Sets the [accepted time diff](https://pysaml2.readthedocs.io/en/latest/howto/config.html#accepted-time-diff) in seconds                                                                                                                                                                                                                                                                                                                                     | `int` or `None`  | `None`                                                                                                                                   |                                                                                         |
| **ALLOWED\_REDIRECT\_HOSTS**                | Allowed hosts to redirect to using the `?next=` parameter                                                                                                                                                                                                                                                                                                                                                                                                   | `list`           | `[]`                                                                                                                                     | `['https://app.example.com', 'https://api.exmaple.com']`                                |
| **DISABLE\_EXCEPTION\_HANDLER**             | Set this to `True` if you want to disable the exception handler. Make sure to handle the `SAMLAuthError`s and other exceptions.                                                                                                                                                                                                                                                                                                                             | `bool`           | `False`                                                                                                                                  |                                                                                         |

### Triggers

| **Setting name**                       | **Description**                                                                                                                             | **Interface**                                                                                |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| **GET\_METADATA\_AUTO\_CONF\_URLS**    | Auto SAML2 metadata configuration URL                                                                                                       | get_metadata_auto_conf_urls(user_id: Optional[str] = None) -> Optional[List[Dict[str, str]]] |
| **GET\_USER_ID\_FROM\_SAML\_RESPONSE** | Allows retrieving a user ID before GET_METADATA_AUTO_CONF_URLS gets triggered. Warning: SAML response still not verified. Use with caution! | get_user_id_from_saml_response(saml_response: str, user_id: Optional[str]) -> Optional[str]  |

</details>

## JWT Signing Algorithm and Settings

Both symmetric and asymmetric signing functions are [supported](https://pyjwt.readthedocs.io/en/stable/algorithms.html). If you want to use symmetric signing using a secret key, use either of the following algorithms plus a secret key:

- HS256
- HS384
- HS512

```python
{
    ...
    'USE_JWT': True,
    'JWT_ALGORITHM': 'HS256',
    'JWT_SECRET': 'YOU.ULTRA.SECURE.SECRET',
    ...
}
```

Otherwise if you want to use your PKI key-pair to sign JWT tokens, use either of the following algorithms and then set the following fields:

- RS256
- RS384
- RS512
- ES256
- ES256K
- ES384
- ES521
- ES512
- PS256
- PS384
- PS512
- EdDSA

```python
{
    ...
    'USE_JWT': True,
    'JWT_ALGORITHM': 'RS256',
    'JWT_PRIVATE_KEY': '--- YOUR PRIVATE KEY ---',
    'JWT_PRIVATE_KEY_PASSPHRASE': 'your.passphrase',  # Optional, if your private key is encrypted
    'JWT_PUBLIC_KEY': '--- YOUR PUBLIC KEY ---',
    ...
}
```

*Note:* If both PKI fields and `JWT_SECRET` are defined, the `JWT_ALGORITHM` decides which method to use for signing tokens.

### Custom token triggers

This is an example of the functions that could be passed to the `TRIGGER.CUSTOM_CREATE_JWT` (it uses the [DRF Simple JWT library](https://github.com/jazzband/djangorestframework-simplejwt/blob/master/docs/index.rst)) and to `TRIGGER.CUSTOM_TOKEN_QUERY`:

``` python
from rest_framework_simplejwt.tokens import RefreshToken


def get_custom_jwt(user):
    """Create token for user and return it"""
    return RefreshToken.for_user(user)


def get_custom_token_query(refresh):
    """Create url query with refresh and access token"""
    return "?%s%s%s%s%s" % ("refresh=", str(refresh), "&", "access=", str(refresh.access_token))

```

## Exception Handling
This library implements an exception handler that returns an error response with a default error template. See the 
section below if you want to implement a custom error template.

If you want to disable error handling, set `DISABLE_EXCEPTION_HANDLER` to `True`. In this case the library will raise
`SAMLAuthError` when an error happens and you might need to implement an exception handler. This might come in handy if
you are using the library for an API.

## Customize Error Messages and Templates

The default permission `denied`, `error` and user `welcome` page can be overridden.

To override these pages put a template named 'django\_saml2\_auth/error.html', 'django\_saml2\_auth/welcome.html' or 'django\_saml2\_auth/denied.html' in your project's template folder.
> [!Note]  
> If you set `DISABLE_EXCEPTION_HANDLER` to `True`, the custom error pages will not be displayed.

If a 'django\_saml2\_auth/welcome.html' template exists, that page will be shown to the user upon login instead of the user being redirected to the previous visited page. This welcome page can contain some first-visit notes and welcome words. The [Django user object](https://docs.djangoproject.com/en/1.9/ref/contrib/auth/#django.contrib.auth.models.User) is available within the template as the `user` template variable.

To enable a logout page, add the following lines to `urls.py`, before any `urlpatterns`:

```python
# The following line will replace the default user logout with the signout page (optional)
url(r'^accounts/logout/$', django_saml2_auth.views.signout),

# The following line will replace the default admin user logout with the signout page (optional)
url(r'^admin/logout/$', django_saml2_auth.views.signout),
```

To override the built in signout page put a template named 'django\_saml2\_auth/signout.html' in your project's template folder.

If your SAML2 identity provider uses user attribute names other than the defaults listed in the `settings.py` `ATTRIBUTES_MAP`, update them in `settings.py`.

## For Okta Users

I created this plugin originally for Okta. The `METADATA_AUTO_CONF_URL` needed in `settings.py` can be found in the Okta Web UI by navigating to the SAML2 app's `Sign On` tab. In the `Settings` box, you should see:

    Identity Provider metadata is available if this application supports dynamic configuration.

The `Identity Provider metadata` link is the `METADATA_AUTO_CONF_URL`.

More information can be found in the [Okta Developer Documentation](https://developer.okta.com/docs/guides/saml-application-setup/overview/).

## Release Process

I adopted a reasonably simple release process, which is almost automated, except for two actions that needed to be taken to start a release:

1. Tag the `main` branch locally with the the `vSEMVER`, e.g. `v3.9.0`, and push the tag.
2. After the tag is pushed, the release process will be triggered automatically.
3. The release process will:
   1. run the linters and tests.
   2. build the binary and source package.
   3. publish the package to PyPI.
   4. create a new release with auto-generated release notes on the tag.
   5. upload the SBOM artifacts and build artifacts to the release.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "grafana-django-saml2-auth",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.10",
    "maintainer_email": null,
    "keywords": null,
    "author": "Mostafa Moradian",
    "author_email": "mostafa@grafana.com",
    "download_url": "https://files.pythonhosted.org/packages/7c/7a/8eec0d548f3c795fb76b5c4c73a09d107204faef73ad0a8a9c235998b6be/grafana_django_saml2_auth-3.18.0.tar.gz",
    "platform": null,
    "description": "# Django SAML2 Authentication\n\n[![PyPI](https://img.shields.io/pypi/v/grafana-django-saml2-auth?label=version&logo=pypi)](https://pypi.org/project/grafana-django-saml2-auth/) [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/grafana/django-saml2-auth/deploy.yml?branch=main&logo=github)](https://github.com/grafana/django-saml2-auth/actions) [![Coveralls](https://img.shields.io/coveralls/github/grafana/django-saml2-auth?logo=coveralls)](https://coveralls.io/github/grafana/django-saml2-auth) [![Downloads](https://pepy.tech/badge/grafana-django-saml2-auth)](https://pepy.tech/project/grafana-django-saml2-auth)\n\nThis plugin provides a simple way to integrate SAML2 Authentication into your Django-powered app. SAML SSO is a standard, so practically any SAML2 based SSO identity provider is supported.\n\nThis plugin supports both identity provider and service provider-initiated SSO:\n\n- For IdP-initiated SSO, the user should sign in to their identity provider platform, e.g., Okta, and click on the application that authorizes and redirects the user to the service provider, that is your platform.\n- For SP-initiated SSO, the user should first exist on your platform, either by signing in via the first method (IdP-initiated SSO) or any other custom solution. It can be configured to be redirected to the correct application on the identity provider platform.\n\nFor IdP-initiated SSO, the user will be created if it doesn't exist. Still, for SP-initiated SSO, the user should exist in your platform for the code to detect and redirect them to the correct application on the identity provider platform.\n\n## Project Information\n\n- Original Author: Fang Li ([@fangli](https://github.com/fangli))\n- Maintainer: Mostafa Moradian ([@mostafa](https://github.com/mostafa))\n- Version support matrix:\n\n    | **Python**             | **Django** | **django-saml2-auth** | **End of extended support<br/>(Django)** |\n    | ---------------------- | ---------- | --------------------- | ---------------------------------------- |\n    | 3.10.x, 3.11.x, 3.12.x | 4.2.x      | >=3.4.0               | April 2026                               |\n    | 3.10.x, 3.11.x, 3.12.x | 5.0.x      | >3.12.0               | April 2026                               |\n\n- Release logs are available [here](https://github.com/grafana/django-saml2-auth/releases).\n\n- For contribution, read [contributing guide](CONTRIBUTING.md).\n\n## CycloneDX SBOM\n\nThis project provides a CycloneDX Software Bill of Materials (SBOM) in JSON format. The SBOM is generated by the [GitHub Actions workflow](.github/workflows/deploy.yml) and is available as an artifact for each release. The SBOM is generated using the [cyclonedx-python](https://github.com/CycloneDX/cyclonedx-python) library.\n\n## Donate\n\nPlease give us a shiny ![star](https://img.shields.io/github/stars/grafana/django-saml2-auth.svg?style=social&label=Star&maxAge=86400) and help spread the word.\n\n## Installation\n\nYou can install this plugin via `pip`. Make sure you update `pip` to be able to install from git:\n\n```bash\npip install grafana-django-saml2-auth\n```\n\nor from source:\n\n```bash\ngit clone https://github.com/grafana/django-saml2-auth\ncd django-saml2-auth\npython setup.py install\n```\n\n`xmlsec` is also required by `pysaml2`, so it must be installed:\n\n``` bash\n// RPM-based distributions\n# yum install xmlsec1\n// DEB-based distributions\n# apt-get install xmlsec1\n// macOS\n# brew install xmlsec1\n```\n\n[Windows binaries](https://www.zlatkovic.com/projects/libxml/index.html) are also available.\n\n## How to use?\n\n1. Once you have the library installed or in your `requirements.txt`, import the views module in your root `urls.py`:\n\n    ```python\n    import django_saml2_auth.views\n    ```\n\n2. Override the default login page in the root `urls.py` file, by adding these lines **BEFORE** any `urlpatterns`:\n\n    ```python\n    # These are the SAML2 related URLs. (required)\n    re_path(r'^sso/', include('django_saml2_auth.urls')),\n\n    # The following line will replace the default user login with SAML2 (optional)\n    # If you want to specific the after-login-redirect-URL, use parameter \"?next=/the/path/you/want\"\n    # with this view.\n    re_path(r'^accounts/login/$', django_saml2_auth.views.signin),\n\n    # The following line will replace the admin login with SAML2 (optional)\n    # If you want to specific the after-login-redirect-URL, use parameter \"?next=/the/path/you/want\"\n    # with this view.\n    re_path(r'^admin/login/$', django_saml2_auth.views.signin),\n    ```\n\n3. Add `'django_saml2_auth'` to `INSTALLED_APPS` in your django `settings.py`:\n\n    ```python\n    INSTALLED_APPS = [\n        '...',\n        'django_saml2_auth',\n    ]\n    ```\n\n4. In `settings.py`, add the SAML2 related configuration:\n\n    Please note, the only required setting is **METADATA\\_AUTO\\_CONF\\_URL** or the existence of a **GET\\_METADATA\\_AUTO\\_CONF\\_URLS** trigger function. The following block shows all required and optional configuration settings and their default values.\n\n    <details>\n        <summary>Click to see the entire settings block</summary>\n\n    ```python\n    SAML2_AUTH = {\n        # Metadata is required, choose either remote url or local file path\n        'METADATA_AUTO_CONF_URL': '[The auto(dynamic) metadata configuration URL of SAML2]',\n        'METADATA_LOCAL_FILE_PATH': '[The metadata configuration file path]',\n        'KEY_FILE': '[The key file path]',\n        'CERT_FILE': '[The certificate file path]',\n\n        # If both `KEY_FILE` and `CERT_FILE` are provided, `ENCRYPTION_KEYPAIRS` will be added automatically. There is no need to provide it unless you wish to override the default value.\n        'ENCRYPTION_KEYPAIRS': [\n            {\n                \"key_file\": '[The key file path]',\n                \"cert_file\": '[The certificate file path]',\n            }\n        ],\n\n        'DEBUG': False,  # Send debug information to a log file\n        # Optional logging configuration.\n        # By default, it won't log anything.\n        # The following configuration is an example of how to configure the logger,\n        # which can be used together with the DEBUG option above. Please note that\n        # the logger configuration follows the Python's logging configuration schema:\n        # https://docs.python.org/3/library/logging.config.html#logging-config-dictschema\n        'LOGGING': {\n            'version': 1,\n            'formatters': {\n                'simple': {\n                    'format': '[%(asctime)s] [%(levelname)s] [%(name)s.%(funcName)s] %(message)s',\n                },\n            },\n            'handlers': {\n                'stdout': {\n                    'class': 'logging.StreamHandler',\n                    'stream': 'ext://sys.stdout',\n                    'level': 'DEBUG',\n                    'formatter': 'simple',\n                },\n            },\n            'loggers': {\n                'saml2': {\n                    'level': 'DEBUG'\n                },\n            },\n            'root': {\n                'level': 'DEBUG',\n                'handlers': [\n                    'stdout',\n                ],\n            },\n        },\n\n        # Optional settings below\n        'DEFAULT_NEXT_URL': '/admin',  # Custom target redirect URL after the user get logged in. Default to /admin if not set. This setting will be overwritten if you have parameter ?next= specificed in the login URL.\n        'CREATE_USER': True,  # Create a new Django user when a new user logs in. Defaults to True.\n        'NEW_USER_PROFILE': {\n            'USER_GROUPS': [],  # The default group name when a new user logs in\n            'ACTIVE_STATUS': True,  # The default active status for new users\n            'STAFF_STATUS': False,  # The staff status for new users\n            'SUPERUSER_STATUS': False,  # The superuser status for new users\n        },\n        'ATTRIBUTES_MAP': {  # Change Email/UserName/FirstName/LastName to corresponding SAML2 userprofile attributes.\n            'email': 'user.email',\n            'username': 'user.username',\n            'first_name': 'user.first_name',\n            'last_name': 'user.last_name',\n            'token': 'Token',  # Mandatory, can be unrequired if TOKEN_REQUIRED is False\n            'groups': 'Groups',  # Optional\n        },\n        'GROUPS_MAP': {  # Optionally allow mapping SAML2 Groups to Django Groups\n            'SAML Group Name': 'Django Group Name',\n        },\n        'TRIGGER': {\n            'EXTRACT_USER_IDENTITY': 'path.to.your.extract.user.identity.hook.method',\n            # Optional: needs to return a User Model instance or None\n            'GET_USER': 'path.to.your.get.user.hook.method',\n            'CREATE_USER': 'path.to.your.new.user.hook.method',\n            'BEFORE_LOGIN': 'path.to.your.login.hook.method',\n            'AFTER_LOGIN': 'path.to.your.after.login.hook.method',\n            # Optional. This is executed right before METADATA_AUTO_CONF_URL.\n            # For systems with many metadata files registered allows to narrow the search scope.\n            'GET_USER_ID_FROM_SAML_RESPONSE': 'path.to.your.get.user.from.saml.hook.method',\n            # This can override the METADATA_AUTO_CONF_URL to enumerate all existing metadata autoconf URLs\n            'GET_METADATA_AUTO_CONF_URLS': 'path.to.your.get.metadata.conf.hook.method',\n            # This will override ASSERTION_URL to allow more dynamic assertion URLs\n            'GET_CUSTOM_ASSERTION_URL': 'path.to.your.get.custom.assertion.url.hook.method',\n            # This will override FRONTEND_URL for more dynamic URLs\n            'GET_CUSTOM_FRONTEND_URL': 'path.to.your.get.custom.frontend.url.hook.method',\n        },\n        'ASSERTION_URL': 'https://mysite.com',  # Custom URL to validate incoming SAML requests against\n        'ENTITY_ID': 'https://mysite.com/sso/acs/',  # Populates the Issuer element in authn request\n        'NAME_ID_FORMAT': FormatString,  # Sets the Format property of authn NameIDPolicy element, e.g. 'user.email'\n        'USE_JWT': True,  # Set this to True if you are running a Single Page Application (SPA) with Django Rest Framework (DRF), and are using JWT authentication to authorize client users\n        'JWT_ALGORITHM': 'HS256',  # JWT algorithm to sign the message with\n        'JWT_SECRET': 'your.jwt.secret',  # JWT secret to sign the message with\n        'JWT_PRIVATE_KEY': '--- YOUR PRIVATE KEY ---',  # Private key to sign the message with. The algorithm should be set to RSA256 or a more secure alternative.\n        'JWT_PRIVATE_KEY_PASSPHRASE': 'your.passphrase',  # If your private key is encrypted, you might need to provide a passphrase for decryption\n        'JWT_PUBLIC_KEY': '--- YOUR PUBLIC KEY ---',  # Public key to decode the signed JWT token\n        'JWT_EXP': 60,  # JWT expiry time in seconds\n        'FRONTEND_URL': 'https://myfrontendclient.com',  # Redirect URL for the client if you are using JWT auth with DRF. See explanation below\n        'LOGIN_CASE_SENSITIVE': True,  # whether of not to get the user in case_sentive mode\n        'AUTHN_REQUESTS_SIGNED': True, # Require each authentication request to be signed\n        'LOGOUT_REQUESTS_SIGNED': True,  # Require each logout request to be signed\n        'WANT_ASSERTIONS_SIGNED': True,  # Require each assertion to be signed\n        'WANT_RESPONSE_SIGNED': True,  # Require response to be signed\n        'ACCEPTED_TIME_DIFF': None,  # Accepted time difference between your server and the Identity Provider\n        'ALLOWED_REDIRECT_HOSTS': [\"https://myfrontendclient.com\"], # Allowed hosts to redirect to using the ?next parameter\n        'TOKEN_REQUIRED': True,  # Whether or not to require the token parameter in the SAML assertion\n        'DISABLE_EXCEPTION_HANDLER': True,  # Whether the custom exception handler should be used\n    }\n\n    ```\n\n    </details>\n\n5. In your SAML2 SSO identity provider, set the Single-sign-on URL and Audience URI (SP Entity ID) to <http://your-domain/sso/acs/>\n\n## How to debug?\n\nTo debug what's happening between the SAMLP Identity Provider and your Django application, you can use SAML-tracer for [Firefox](https://addons.mozilla.org/en-US/firefox/addon/saml-tracer/) or [Chrome](https://chrome.google.com/webstore/detail/saml-tracer/mpdajninpobndbfcldcmbpnnbhibjmch?hl=en). Using this tool, you can see the SAML requests and responses that are being sent back and forth.\n\nAlso, you can enable the debug mode in the `settings.py` file by setting the `DEBUG` flag to `True` and enabling the `LOGGING` configuration. See above for configuration examples.\n\n*Note:* Don't forget to disable the debug mode in production and also remove the logging configuration if you don't want to see internal logs of pysaml2 library.\n\n## Module Settings\n\nSome of the following settings are related to how this module operates. The rest are passed as options to the pysaml2 library. For more information on the pysaml2 library, see the [pysaml2 documentation](https://pysaml2.readthedocs.io/en/latest/howto/config.html), which contains examples of available settings. Also, note that all settings are not implemented in this module.\n\n<details>\n    <summary>Click to see the module settings</summary>\n\n| **Field name**                              | **Description**                                                                                                                                                                                                                                                                                                                                                                                                                                             | **Data type(s)** | **Default value(s)**                                                                                                                     | **Example**                                                                             |\n|---------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ---------------- |------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------|\n| **METADATA\\_AUTO\\_CONF\\_URL**               | Auto SAML2 metadata configuration URL                                                                                                                                                                                                                                                                                                                                                                                                                       | `str`            | `None`                                                                                                                                   | `https://ORG.okta.com/app/APP-ID/sso/saml/metadata`                                     |\n| **METADATA\\_LOCAL\\_FILE\\_PATH**             | SAML2 metadata configuration file path                                                                                                                                                                                                                                                                                                                                                                                                                      | `str`            | `None`                                                                                                                                   | `/path/to/the/metadata.xml`                                                             |\n| **KEY_FILE**                                | SAML2 private key file path.  Required for AUTHN\\_REQUESTS\\_SIGNED                                                                                                                                                                                                                                                                                                                                                                                          | `str`            | `None`                                                                                                                                   | `/path/to/the/key.pem`                                                                  |\n| **CERT_FILE**                               | SAML2 public certificate file path                                                                                                                                                                                                                                                                                                                                                                                                                          | `str`            | `None`                                                                                                                                   | `/path/to/the/cert.pem`                                                                 |\n| **ENCRYPTION_KEYPAIRS**                     | Required for handling encrypted assertions. Will be automatically set if both `KEY_FILE` and `CERT_FILE` are set.                                                                                                                                                                                                                                                                                                                                           | `list`           | Not set.                                                                                                                                 | `[ { 'key_file': '[The key file path]', 'cert_file': '[The certificate file path]' } ]` |\n| **DEBUG**                                   | Send debug information to a log file                                                                                                                                                                                                                                                                                                                                                                                                                        | `bool`           | `False`                                                                                                                                  |                                                                                         |\n| **LOGGING**                                 | Logging configuration dictionary                                                                                                                                                                                                                                                                                                                                                                                                                            | `dict`           | Not set.                                                                                                                                 |                                                                                         |\n| **DEFAULT\\_NEXT\\_URL**                      | Custom target redirect URL after the user get logged in. Default to /admin if not set. This setting will be overwritten if you have parameter `?next=` specificed in the login URL.                                                                                                                                                                                                                                                                         | `str`            | `admin:index`                                                                                                                            | `https://app.example.com/account/login`                                                 |\n| **CREATE\\_USER**                            | Determines if a new Django user should be created for new users                                                                                                                                                                                                                                                                                                                                                                                             | `bool`           | `True`                                                                                                                                   |                                                                                         |\n| **CREATE\\_GROUPS**                          | Determines if a new Django group should be created if the SAML2 Group does not exist                                                                                                                                                                                                                                                                                                                                                                        | `bool`           | `False`                                                                                                                                  |                                                                                         |\n| **NEW\\_USER\\_PROFILE**                      | Default settings for newly created users                                                                                                                                                                                                                                                                                                                                                                                                                    | `dict`           | `{'USER_GROUPS': [], 'ACTIVE_STATUS': True, 'STAFF_STATUS': False, 'SUPERUSER_STATUS': False}`                                           |                                                                                         |\n| **ATTRIBUTES\\_MAP**                         | Mapping of Django user attributes to SAML2 user attributes                                                                                                                                                                                                                                                                                                                                                                                                  | `dict`           | `{'email': 'user.email', 'username': 'user.username', 'first_name': 'user.first_name', 'last_name': 'user.last_name', 'token': 'token'}` | `{'your.field': 'SAML.field'}`                                                          |\n| **TOKEN\\_REQUIRED**                         | Set this to `False` if you don't require the token parameter in the SAML assertion (in the attributes map)                                                                                                                                                                                                                                                                                                                                                  | `bool`           | `True`                                                                                                                                   |                                                                                         |\n| **TRIGGER**                                 | Hooks to trigger additional actions during user login and creation flows. These `TRIGGER` hooks are strings containing a [dotted module name](https://docs.python.org/3/tutorial/modules.html#packages) which point to a method to be called. The referenced method should accept a single argument: a dictionary of attributes and values sent by the identity provider, representing the user's identity. Triggers will be executed only if they are set. | `dict`           | `{}`                                                                                                                                     |                                                                                         |\n| **TRIGGER.EXTRACT\\_USER\\_IDENTITY**         | A method to be called upon extracting the user identity from the SAML2 response. This method should accept TWO parameters of the user_dict and the AuthnResponse. This method can return an enriched user_dict (user identity).                                                                                                                                                                                                                             | `str`            | `AuthnResponse`                                                                                                                          | `my_app.models.users.extract_user_identity`                                             |\n| **TRIGGER.GET\\_USER**                       | A method to be called upon getting an existing user. This method will be called before the new user is logged in and is used to customize the retrieval of an existing user record. This method should accept ONE parameter of user dict and return a User model instance or none.                                                                                                                                                                          | `str`            | `None`                                                                                                                                   | `my_app.models.users.get`                                                               |\n| **TRIGGER.CREATE\\_USER**                    | A method to be called upon new user creation. This method will be called before the new user is logged in and after the user's record is created. This method should accept ONE parameter of user dict.                                                                                                                                                                                                                                                     | `str`            | `None`                                                                                                                                   | `my_app.models.users.create`                                                            |\n| **TRIGGER.BEFORE\\_LOGIN**                   | A method to be called when an existing user logs in. This method will be called before the user is logged in and after the SAML2 identity provider returns user attributes. This method should accept ONE parameter of user dict.                                                                                                                                                                                                                           | `str`            | `None`                                                                                                                                   | `my_app.models.users.before_login`                                                      |\n| **TRIGGER.AFTER\\_LOGIN**                    | A method to be called when an existing user logs in. This method will be called after the user is logged in and after the SAML2 identity provider returns user attributes. This method should accept TWO parameters of session and user dict.                                                                                                                                                                                                               | `str`            | `None`                                                                                                                                   | `my_app.models.users.after_login`                                                       |\n| **TRIGGER.GET\\_METADATA\\_AUTO\\_CONF\\_URLS** | A hook function that returns a list of metadata Autoconf URLs. This can override the `METADATA_AUTO_CONF_URL` to enumerate all existing metadata autoconf URLs.                                                                                                                                                                                                                                                                                             | `str`            | `None`                                                                                                                                   | `my_app.models.users.get_metadata_autoconf_urls`                                        |\n| **TRIGGER.GET\\_CUSTOM\\_METADATA**           | A hook function to retrieve the SAML2 metadata with a custom method. This method should return a SAML metadata object as dictionary (`Mapping[str, Any]`). If added, it overrides all other configuration to retrieve metadata. An example can be found in `tests.test_saml.get_custom_metadata_example`. This method accepts the same three parameters of the django_saml2_auth.saml.get_metadata function: `user_id`, `domain`, `saml_response`.          | `str`            | `None`, `None`, `None`                                                                                                                   | `my_app.utils.get_custom_saml_metadata`                                                 |\n| **TRIGGER.CUSTOM\\_DECODE\\_JWT**             | A hook function to decode the user JWT. This method will be called instead of the `decode_jwt_token` default function and should return the user_model.USERNAME_FIELD. This method accepts one parameter: `token`.                                                                                                                                                                                                                                          | `str`            | `None`                                                                                                                                   | `my_app.models.users.decode_custom_token`                                               |\n| **TRIGGER.CUSTOM\\_CREATE\\_JWT**             | A hook function to create a custom JWT for the user. This method will be called instead of the `create_jwt_token` default function and should return the token. This method accepts one parameter: `user`.                                                                                                                                                                                                                                                  | `str`            | `None`                                                                                                                                   | `my_app.models.users.create_custom_token`                                               |\n| **TRIGGER.CUSTOM\\_TOKEN\\_QUERY**            | A hook function to create a custom query params with the JWT for the user. This method will be called after `CUSTOM_CREATE_JWT` to populate a query and attach it to a URL; should return the query params containing the token (e.g., `?token=encoded.jwt.token`). This method accepts one parameter: `token`.                                                                                                                                             | `str`            | `None`                                                                                                                                   | `my_app.models.users.get_custom_token_query`                                            |\n| **TRIGGER.GET\\_CUSTOM\\_ASSERTION\\_URL**     | A hook function to get the assertion URL dynamically. Useful when you have dynamic routing, multi-tenant setup and etc. Overrides `ASSERTION_URL`.                                                                                                                                                                                                                                                                                                          | `str`            | `None`                                                                                                                                   | `my_app.utils.get_custom_assertion_url`                                                 |\n| **TRIGGER.GET\\_CUSTOM\\_FRONTEND\\_URL**      | A hook function to get a dynamic `FRONTEND_URL` dynamically (see below for more details). Overrides `FRONTEND_URL`. Acceots one parameter: `relay_state`.                                                                                                                                                                                                                                                                                                   | `str`            | `None`                                                                                                                                   | `my_app.utils.get_custom_frontend_url`                                                  |\n| **ASSERTION\\_URL**                          | A URL to validate incoming SAML responses against. By default, `django-saml2-auth` will validate the SAML response's Service Provider address against the actual HTTP request's host and scheme. If this value is set, it will validate against `ASSERTION_URL` instead - perfect for when Django is running behind a reverse proxy. This will only allow to customize the domain part of the URL, for more customization use `GET_CUSTOM_ASSERTION_URL`.   | `str`            | `None`                                                                                                                                   | `https://example.com`                                                                   |\n| **ENTITY\\_ID**                              | The optional entity ID string to be passed in the 'Issuer' element of authentication request, if required by the IDP.                                                                                                                                                                                                                                                                                                                                       | `str`            | `None`                                                                                                                                   | `https://exmaple.com/sso/acs`                                                           |\n| **NAME\\_ID\\_FORMAT**                        | Set to the string `'None'`, to exclude sending the `'Format'` property of the `'NameIDPolicy'` element in authentication requests.                                                                                                                                                                                                                                                                                                                          | `str`            | `<urn:oasis:names:tc:SAML:2.0:nameid-format:transient>`                                                                                  |                                                                                         |\n| **USE\\_JWT**                                | Set this to the boolean `True` if you are using Django with JWT authentication                                                                                                                                                                                                                                                                                                                                                                              | `bool`           | `False`                                                                                                                                  |                                                                                         |\n| **JWT\\_ALGORITHM**                          | JWT algorithm (str) to sign the message with: [supported algorithms](https://pyjwt.readthedocs.io/en/stable/algorithms.html).                                                                                                                                                                                                                                                                                                                               | `str`            | `HS512` or `RS512`                                                                                                                       |                                                                                         |\n| **JWT\\_SECRET**                             | JWT secret to sign the message if an HMAC is used with the SHA hash algorithm (`HS*`).                                                                                                                                                                                                                                                                                                                                                                      | `str`            | `None`                                                                                                                                   |                                                                                         |\n| **JWT\\_PRIVATE\\_KEY**                       | Private key (str) to sign the message with. The algorithm should be set to `RSA256` or a more secure alternative.                                                                                                                                                                                                                                                                                                                                           | `str` or `bytes` | `--- YOUR PRIVATE KEY ---`                                                                                                               |                                                                                         |\n| **JWT\\_PRIVATE\\_KEY\\_PASSPHRASE**           | If your private key is encrypted, you must provide a passphrase for decryption.                                                                                                                                                                                                                                                                                                                                                                             | `str` or `bytes` | `None`                                                                                                                                   |                                                                                         |\n| **JWT\\_PUBLIC\\_KEY**                        | Public key to decode the signed JWT token.                                                                                                                                                                                                                                                                                                                                                                                                                  | `str` or `bytes` | `'--- YOUR PUBLIC KEY ---'`                                                                                                              |                                                                                         |\n| **JWT\\_EXP**                                | JWT expiry time in seconds                                                                                                                                                                                                                                                                                                                                                                                                                                  | `int`            | 60                                                                                                                                       |                                                                                         |\n| **FRONTEND\\_URL**                           | If `USE_JWT` is `True`, you should set the URL to where your frontend is located (will default to `DEFAULT_NEXT_URL` if you fail to do so). Once the client is authenticated through the SAML SSO, your client is redirected to the `FRONTEND_URL` with the JWT token as `token` query parameter. Example: `https://app.example.com/?&token=<your.jwt.token`. With the token, your SPA can now authenticate with your API.                                  | `str`            | `admin:index`                                                                                                                            |                                                                                         |\n| **AUTHN\\_REQUESTS\\_SIGNED**                 | Set this to `False` if your provider doesn't sign each authorization request.  KEY_FILE is required if this is set True.                                                                                                                                                                                                                                                                                                                                    | `bool`           | `True`                                                                                                                                   |\n| **LOGOUT\\_REQUESTS\\_SIGNED**                | Set this to `False` if your provider doesn't sign each logout request.                                                                                                                                                                                                                                                                                                                                                                                      | `bool`           | `True`                                                                                                                                   |                                                                                         |\n| **WANT\\_ASSERTIONS\\_SIGNED**                | Set this to `False` if your provider doesn't sign each assertion.                                                                                                                                                                                                                                                                                                                                                                                           | `bool`           | `True`                                                                                                                                   |                                                                                         |\n| **WANT\\_RESPONSE\\_SIGNED**                  | Set this to `False` if you don't want your provider to sign the response.                                                                                                                                                                                                                                                                                                                                                                                   | `bool`           | `True`                                                                                                                                   |                                                                                         |\n| **ACCEPTED\\_TIME\\_DIFF**                    | Sets the [accepted time diff](https://pysaml2.readthedocs.io/en/latest/howto/config.html#accepted-time-diff) in seconds                                                                                                                                                                                                                                                                                                                                     | `int` or `None`  | `None`                                                                                                                                   |                                                                                         |\n| **ALLOWED\\_REDIRECT\\_HOSTS**                | Allowed hosts to redirect to using the `?next=` parameter                                                                                                                                                                                                                                                                                                                                                                                                   | `list`           | `[]`                                                                                                                                     | `['https://app.example.com', 'https://api.exmaple.com']`                                |\n| **DISABLE\\_EXCEPTION\\_HANDLER**             | Set this to `True` if you want to disable the exception handler. Make sure to handle the `SAMLAuthError`s and other exceptions.                                                                                                                                                                                                                                                                                                                             | `bool`           | `False`                                                                                                                                  |                                                                                         |\n\n### Triggers\n\n| **Setting name**                       | **Description**                                                                                                                             | **Interface**                                                                                |\n| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |\n| **GET\\_METADATA\\_AUTO\\_CONF\\_URLS**    | Auto SAML2 metadata configuration URL                                                                                                       | get_metadata_auto_conf_urls(user_id: Optional[str] = None) -> Optional[List[Dict[str, str]]] |\n| **GET\\_USER_ID\\_FROM\\_SAML\\_RESPONSE** | Allows retrieving a user ID before GET_METADATA_AUTO_CONF_URLS gets triggered. Warning: SAML response still not verified. Use with caution! | get_user_id_from_saml_response(saml_response: str, user_id: Optional[str]) -> Optional[str]  |\n\n</details>\n\n## JWT Signing Algorithm and Settings\n\nBoth symmetric and asymmetric signing functions are [supported](https://pyjwt.readthedocs.io/en/stable/algorithms.html). If you want to use symmetric signing using a secret key, use either of the following algorithms plus a secret key:\n\n- HS256\n- HS384\n- HS512\n\n```python\n{\n    ...\n    'USE_JWT': True,\n    'JWT_ALGORITHM': 'HS256',\n    'JWT_SECRET': 'YOU.ULTRA.SECURE.SECRET',\n    ...\n}\n```\n\nOtherwise if you want to use your PKI key-pair to sign JWT tokens, use either of the following algorithms and then set the following fields:\n\n- RS256\n- RS384\n- RS512\n- ES256\n- ES256K\n- ES384\n- ES521\n- ES512\n- PS256\n- PS384\n- PS512\n- EdDSA\n\n```python\n{\n    ...\n    'USE_JWT': True,\n    'JWT_ALGORITHM': 'RS256',\n    'JWT_PRIVATE_KEY': '--- YOUR PRIVATE KEY ---',\n    'JWT_PRIVATE_KEY_PASSPHRASE': 'your.passphrase',  # Optional, if your private key is encrypted\n    'JWT_PUBLIC_KEY': '--- YOUR PUBLIC KEY ---',\n    ...\n}\n```\n\n*Note:* If both PKI fields and `JWT_SECRET` are defined, the `JWT_ALGORITHM` decides which method to use for signing tokens.\n\n### Custom token triggers\n\nThis is an example of the functions that could be passed to the `TRIGGER.CUSTOM_CREATE_JWT` (it uses the [DRF Simple JWT library](https://github.com/jazzband/djangorestframework-simplejwt/blob/master/docs/index.rst)) and to `TRIGGER.CUSTOM_TOKEN_QUERY`:\n\n``` python\nfrom rest_framework_simplejwt.tokens import RefreshToken\n\n\ndef get_custom_jwt(user):\n    \"\"\"Create token for user and return it\"\"\"\n    return RefreshToken.for_user(user)\n\n\ndef get_custom_token_query(refresh):\n    \"\"\"Create url query with refresh and access token\"\"\"\n    return \"?%s%s%s%s%s\" % (\"refresh=\", str(refresh), \"&\", \"access=\", str(refresh.access_token))\n\n```\n\n## Exception Handling\nThis library implements an exception handler that returns an error response with a default error template. See the \nsection below if you want to implement a custom error template.\n\nIf you want to disable error handling, set `DISABLE_EXCEPTION_HANDLER` to `True`. In this case the library will raise\n`SAMLAuthError` when an error happens and you might need to implement an exception handler. This might come in handy if\nyou are using the library for an API.\n\n## Customize Error Messages and Templates\n\nThe default permission `denied`, `error` and user `welcome` page can be overridden.\n\nTo override these pages put a template named 'django\\_saml2\\_auth/error.html', 'django\\_saml2\\_auth/welcome.html' or 'django\\_saml2\\_auth/denied.html' in your project's template folder.\n> [!Note]  \n> If you set `DISABLE_EXCEPTION_HANDLER` to `True`, the custom error pages will not be displayed.\n\nIf a 'django\\_saml2\\_auth/welcome.html' template exists, that page will be shown to the user upon login instead of the user being redirected to the previous visited page. This welcome page can contain some first-visit notes and welcome words. The [Django user object](https://docs.djangoproject.com/en/1.9/ref/contrib/auth/#django.contrib.auth.models.User) is available within the template as the `user` template variable.\n\nTo enable a logout page, add the following lines to `urls.py`, before any `urlpatterns`:\n\n```python\n# The following line will replace the default user logout with the signout page (optional)\nurl(r'^accounts/logout/$', django_saml2_auth.views.signout),\n\n# The following line will replace the default admin user logout with the signout page (optional)\nurl(r'^admin/logout/$', django_saml2_auth.views.signout),\n```\n\nTo override the built in signout page put a template named 'django\\_saml2\\_auth/signout.html' in your project's template folder.\n\nIf your SAML2 identity provider uses user attribute names other than the defaults listed in the `settings.py` `ATTRIBUTES_MAP`, update them in `settings.py`.\n\n## For Okta Users\n\nI created this plugin originally for Okta. The `METADATA_AUTO_CONF_URL` needed in `settings.py` can be found in the Okta Web UI by navigating to the SAML2 app's `Sign On` tab. In the `Settings` box, you should see:\n\n    Identity Provider metadata is available if this application supports dynamic configuration.\n\nThe `Identity Provider metadata` link is the `METADATA_AUTO_CONF_URL`.\n\nMore information can be found in the [Okta Developer Documentation](https://developer.okta.com/docs/guides/saml-application-setup/overview/).\n\n## Release Process\n\nI adopted a reasonably simple release process, which is almost automated, except for two actions that needed to be taken to start a release:\n\n1. Tag the `main` branch locally with the the `vSEMVER`, e.g. `v3.9.0`, and push the tag.\n2. After the tag is pushed, the release process will be triggered automatically.\n3. The release process will:\n   1. run the linters and tests.\n   2. build the binary and source package.\n   3. publish the package to PyPI.\n   4. create a new release with auto-generated release notes on the tag.\n   5. upload the SBOM artifacts and build artifacts to the release.\n",
    "bugtrack_url": null,
    "license": "Apache 2.0",
    "summary": "Django SAML2 Authentication Made Easy.",
    "version": "3.18.0",
    "project_urls": null,
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "9e9210fed0345ff1650d38683673ef832b9546be56f50f30e19086196113a22b",
                "md5": "a45512fd8a18602caaa12a79f7b3081e",
                "sha256": "2e22f5d08b8b122f8b0051e710630f4203c05106b6724eba43d468a4ffc30f54"
            },
            "downloads": -1,
            "filename": "grafana_django_saml2_auth-3.18.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "a45512fd8a18602caaa12a79f7b3081e",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.10",
            "size": 50235,
            "upload_time": "2024-11-08T15:28:56",
            "upload_time_iso_8601": "2024-11-08T15:28:56.357488Z",
            "url": "https://files.pythonhosted.org/packages/9e/92/10fed0345ff1650d38683673ef832b9546be56f50f30e19086196113a22b/grafana_django_saml2_auth-3.18.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "7c7a8eec0d548f3c795fb76b5c4c73a09d107204faef73ad0a8a9c235998b6be",
                "md5": "f505b29ea76dfff518084aa0bb5863e0",
                "sha256": "33b76140e7492086eb8ce7ee971c57dec71edeab5984a43128dd219d28e6ab54"
            },
            "downloads": -1,
            "filename": "grafana_django_saml2_auth-3.18.0.tar.gz",
            "has_sig": false,
            "md5_digest": "f505b29ea76dfff518084aa0bb5863e0",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.10",
            "size": 52256,
            "upload_time": "2024-11-08T15:28:57",
            "upload_time_iso_8601": "2024-11-08T15:28:57.682198Z",
            "url": "https://files.pythonhosted.org/packages/7c/7a/8eec0d548f3c795fb76b5c4c73a09d107204faef73ad0a8a9c235998b6be/grafana_django_saml2_auth-3.18.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-11-08 15:28:57",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "grafana-django-saml2-auth"
}
        
Elapsed time: 0.42879s