Skip to main content

Implement SAML Single Sign-On in your Django project quickly and easily.

Project description

Django SAML Toolkit

Quickly and easily add SAML Single Sign-On to your Django projects. This package is designed to be very simple for initial setup while also being easily customizable to meet all of your needs.

Installation

Dependencies (Linux)

The package xmlsec1 is required for this to work. On debian you can install it with the following:

sudo apt-get install libxml2-dev libxmlsec1-dev libxmlsec1-openssl

Dependencies (Windows)

The python-xmlsec package on Windows is having some issues with hosting, so you can install it manually here:

pip install https://github.com/mehcode/python-xmlsec/releases/download/1.3.5/xmlsec-1.3.52.dev0-cp36-cp36m-win_amd64.whl

For more information here is the related issue.

Pip

pip install python3-saml-django

Django

settings.py

INSTALLED_APPS = [
    ...,
    'django_saml'
]

AUTHENTICATION_BACKENDS = [
    'django_saml.backends.SamlUserBackend',
    ...
]

urls.py

Django >= 2.0

urlpatterns = [
    path('saml/', include('django_saml.urls')),
    ...
]

Django <= 1.11

urlpatterns = [
    url(r'^saml/', include('django_saml.urls')),
    ...
]

Configuration

Required Settings

SP Information

You must provide information about your site to be published as metadata.

SAML_SP = {
    "entityId": "https://<your_site>/saml/metadata/",
    "assertionConsumerService": {
        "url": "https://<your_site>/saml/acs/",
        # DO NOT CHANGE THIS
        "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
    },
    "singleLogoutService": {
        "url": "https://<your_site>/saml/sls/",
        # DO NOT CHANGE THIS
        "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
    },
    "NameIDFormat": "urn:oasis:names:tc:SAML:2.0:nameid-format:unspecified",
    "x509cert": "<can also be loaded by file, see SAML_BASE_DIRECTORY>",
    "privateKey": "<can also be loaded by file, see SAML_BASE_DIRECTORY>"
}

IdP Information

You must provide information about the IdP you will be using through one of the following means:

SAML_IDP = {
    "entityId": "https://example.com/saml/metadata/",
    "singleSignOnService": {
        "url": "https://example.com/trust/saml2/http-post/sso/",
        "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
    },
    "singleLogoutService": {
        "url": "https://example.com/trust/saml2/http-redirect/slo/",
        "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
    },
    "x509cert": "<cert here>"
}
SAML_IDP_FILE = os.path.join(BASE_DIR, 'idp_meta.xml')
SAML_IDP_URL = 'https://example.com/saml/metadata/'

Optional Settings

Setting Description Default Example
SAML_STRICT Incorrect SAML responses should be rejected. Should be True in production. True
SAML_DEBUG SAML warnings are displayed False
SAML_CREATE_USER New users are created on login if they don't exist True
SAML_UPDATE_USER Existing users are updated with information from SAML on login False
SAML_IDP_METADATA_TIMEOUT If using SAML_IDP_URL, the result will be cached for this many seconds before checking again. 3600
SAML_SECURITY Advanced security settings See below See below
SAML_CONTACT Contact information for site maintainers None See below
SAML_ORGANIZATION Organization information None See below
SAML_LOGIN_REDIRECT URL to redirect users after a successful login '/'
SAML_LOGOUT_REDIRECT URL to redirect users after a successful logout '/logged-out'
SAML_NO_USER_REDIRECT URL to redirect users if SAML_CREATE_USER = False and the user doesn't exist None (Raises PermissionDenied) '/permission-error'
SAML_USERNAME_ATTR SAML attribute to use to look up users 'uid' 'email'
SAML_ATTR_MAP List of 2-tuples to map SAML attributes to Django user attributes [] [('givenName', 'first_name')]
SAML_BASE_DIRECTORY File path to load SP certificates. Must contain a 'certs' folder with 'sp.key' and 'sp.crt' inside. None os.path.join(BASE_DIR, 'saml')
SAML_DESTINATION_HOST Static value to compare with the SAML Destination attribute instead of reading from the request. Useful for load balancers. None 'example.com'
SAML_DESTINATION_HTTPS Companion for SAML_DESTINATION_HOST. Set to True if the destination will be over HTTPS but the final request will not be. None True
SAML_DESTINATION_PORT Companion for SAML_DESTINATION_HOST. Set to a STRING of a number if you use a non-standard port that does not match SAML_DESTINATION_HTTPS. None '8080'

SAML_SECURITY Default and Example

SAML_SECURITY = {
    "nameIdEncrypted": False,
    "authnRequestsSigned": False,
    "logoutRequestSigned": False,
    "logoutResponseSigned": False,
    "signMetadata": False,
    "wantMessagesSigned": False,
    "wantAssertionsSigned": False,
    "wantNameId": True,
    "wantNameIdEncrypted": False,
    "wantAssertionsEncrypted": False,
    "signatureAlgorithm": "http://www.w3.org/2000/09/xmldsig#rsa-sha1",
    "digestAlgorithm": "http://www.w3.org/2000/09/xmldsig#sha1"
}

SAML_CONTACT Example

SAML_CONTACT = {
    "technical": {
        "givenName": "Technology Director",
        "emailAddress": "technology@thon.org"
    },
    "support": {
        "givenName": "Lead Systems Admin",
        "emailAddress": "systems@thon.org"
    }
}

SAML_ORGANIZATION Example

SAML_ORGANIZATION = {
    'en-US': {
        'name': 'thon', 
        'displayname': 'THON', 
        'url': 'thon.org'
    }
}

Advanced Configuration (Custom Backend)

For situations like advanced attribute mapping with groups, transforming SAML attributes, etc, you can create custom backends to use instead of the default.

Example:

from django_saml.backends import SamlUserBackend


class CustomSamlBackend(SamlUserBackend):

    def clean_username(self, username):
        """Return the first part of the email address.

        Example: test@example.com -> test.
        """
        return username.split('@')[0]

    def configure_user(self, session_data, user):
        """Custom attribute mapping with groups.

        NOTE: ALL SAML attributes in session_data are arrays, even if there is only one element.        
        """
        # Call super() to take care of the simple attribute mapping in SAML_ATTR_MAP
        user = super(CustomSamlBackend, self).configure_user(session_data, user)
        for group_name in session_data['psMemberOf']:
            group_name = group_name[5:]
            g = Group.objects.get(name=group_name)
            g.members.add(user)
        return user

Credit

This project is a wrapper around OneLogin's python3-saml library.

Support

If you would like to support the development of this package, please consider donating to THON and supporting our mission.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

python3-saml-django-1.1.2.tar.gz (11.0 kB view hashes)

Uploaded Source

Built Distribution

python3_saml_django-1.1.2-py3-none-any.whl (9.7 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page