Skip to main content

SAML2 authentication backend for Django wrapping OneLogin's python-saml package https://github.com/onelogin/python-saml

Project description

[![Pypi version](https://img.shields.io/pypi/v/django-saml2-pro-auth.svg)](https://pypi.org/project/django-saml2-pro-auth/) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/MindPointGroup/django-saml2-pro-auth/master/LICENSE)

[![Coverage Status](https://coveralls.io/repos/github/MindPointGroup/django-saml2-pro-auth/badge.svg?branch=master)](https://coveralls.io/github/MindPointGroup/django-saml2-pro-auth?branch=master) [![CircleCI](https://circleci.com/gh/MindPointGroup/django-saml2-pro-auth.svg?style=svg)](https://circleci.com/gh/MindPointGroup/django-saml2-pro-auth)


![Python versions](https://img.shields.io/pypi/pyversions/django-saml2-pro-auth.svg) [![Django versions](https://img.shields.io/badge/django-1.8%2C%201.10%2C%201.11-44B78B.svg)](https://pypi.org/project/django-saml2-pro-auth/)


# django-saml2-pro-auth
SAML2 authentication backend for Django


## Installation

`pip install django-saml2-pro-auth`

### Prerequisites

On your OS you must install libxml, xmlsec1 and openssl (dev packages where available). The package name will vary by OS.

For example, on Ubuntu the prerequisite package names are `build-essential libssl-dev libffi-dev python-dev libxml2-dev libxmlsec1 xmlsec1 libxmlsec1-openssl libxmlsec1-dev`

You'll want to find the equivalent on your OS of choice.

## Configuration

### Installation

**Python 2**

```
pip install django-saml2-pro-auth
```

**Python 3**

```
pip3 install django-saml2-pro-auth
```


### settings.py

Here is an example full configuration. Scroll down to read about each option

```python

AUTHENTICATION_BACKENDS = [
'django_saml2_pro_auth.auth.Backend'
]

SAML_ROUTE = 'sso/saml/'

SAML_REDIRECT = '/'

SAML_USERS_MAP = [{
"MyProvider" : {
"email": dict(key="Email", index=0),
"name": dict(key="Username", index=0)
}

}]


SAML_PROVIDERS = [{
"MyProvider": {
"strict": True,
"debug": False,
"custom_base_path": "",
"sp": {
"entityId": "https://test.davila.io/sso/saml/metadata",
"assertionConsumerService": {
"url": "https://test.davila.io/sso/saml/?acs",
"binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
},
"singleLogoutService": {
"url": "https://test.davila.io/sso/saml/?sls",
"binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
},
"NameIDFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified",
## For the cert/key you can place their content in
## the x509cert and privateKey params
## as single-line strings or place them in
## certs/sp.key and certs/sp.crt or you can supply a
## path via custom_base_path which should contain
## sp.crt and sp.key
"x509cert": "",
"privateKey": "",
},
"idp": {
"entityId": "https://kdkdfjdfsklj.my.MyProvider.com/0f3172cf-5aa6-40f4-8023-baf9d0996cec",
"singleSignOnService": {
"url": "https://kdkdfjdfsklj.my.MyProvider.com/applogin/appKey/0f3172cf-5aa6-40f4-8023-baf9d0996cec/customerId/kdkdfjdfsklj",
"binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
},
"singleLogoutService": {
"url": "https://kdkdfjdfsklj.my.MyProvider.com/applogout",
"binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
},
"x509cert": open(os.path.join(BASE_DIR,'certs/MyProvider.crt'), 'r').read(),
},
"organization": {
"en-US": {
"name": "example inc",
"displayname": "Example Incorporated",
"url": "example.com"
}
},
"contact_person": {
"technical": {
"given_name": "Jane Doe",
"email_address": "jdoe@examp.com"
},
"support": {
"given_name": "Jane Doe",
"email_address": "jdoe@examp.com"
}
},
"security": {
"name_id_encrypted": False,
"authn_requests_signed": True,
"logout_requests_signed": False,
"logout_response_signed": False,
"sign_metadata": False,
"want_messages_signed": False,
"want_assertions_signed": True,
"want_name_id": True,
"want_name_id_encrypted": False,
"want_assertions_encrypted": True,
"signature_algorithm": "http://www.w3.org/2000/09/xmldsig#rsa-sha1",
"digest_algorithm": "http://www.w3.org/2000/09/xmldsig#rsa-sha1",
}

}
}]
```

**AUTHENTICATION_BACKENDS:** This is required exactly as in the example. It tells Django to use this as a valid auth mechanism.

**SAML_ROUTE (optional, default=/sso/saml/):** This tells Django where to do all SAML related activities. The default route is /sso/saml/. You still need to include the source urls in your own `urls.py`. For example:

```python
from django.conf.urls import include, url
from django.contrib import admin
from django.conf import settings
from django.conf.urls.static import static
import profiles.urls
import accounts.urls
import django_saml2_pro_auth.urls as saml_urls

from . import views

urlpatterns = [
url(r'^$', views.HomePage.as_view(), name='home'),
url(r'^about/$', views.AboutPage.as_view(), name='about'),
url(r'^users/', include(profiles.urls, namespace='profiles')),
url(r'^admin/', include(admin.site.urls)),
url(r'^', include(accounts.urls, namespace='accounts')),
url(r'^', include(saml_urls, namespace='saml')),
]

```
So first import the urls via `import django_saml2_pro_auth.urls as saml_urls` (it's up to you if you want name it or not). Then add it to your patterns via `url(r'^', include(saml_urls, namespace='saml'))`. This example will give you the default routes that this auth backend provides.

**SAML_REDIRECT (optional, default=None):** This tells the auth backend where to redirect users after they've logged in via the IdP. **NOTE**: This is not needed for _most_ users. Order of precedence is: SAML_REDIRECT value (if defined), RELAY_STATE provided in the SAML response, and the fallback is simply to go to the root path of your application.

**SAML_USERS_MAP (required):** This is what makes it possible to map the attributes as they come from your IdP into attributes that are part of your User model in Django. There a few ways you can define this. The dict keys (the left-side) are the attributes as defined in YOUR User model, the dict values (the right-side) are the attributes as supplied by your IdP.

```python
## Simplest Approach, when the SAML attributes supplied by the IdP are just plain strings
## This means my User model has an 'email' and 'name' attribute while my IdP passes 'Email' and 'Username' attrs
SAML_USERS_MAP = [{
"myIdp" : {
"email": "Email",
"name": "Username
}
}]
```

Sometimes, IdPs might provide values as Arrays (even when it really should just be a string). This package supports that too. For example, suppose your IdP supplied user attributes with the following data structure:
`{"Email": ["foo@example.com"], "Username": "foo"}`
You simply would make the key slightly more complex where `key` is the key and `index` represents the index where the desired value is located. See below:

```python
SAML_USERS_MAP = [{
"myIdp" : {
"email": {"key": "Email", "index": 0},
"name": "Username
}
```

And of course, you can use the dict structure even when there IdP supplied attribute isn't an array. For example:

```python
SAML_USERS_MAP = [{
"myIdp" : {
"email": {"key": "Email"},
"name": {"key": "Username
}
```



**SAML_PROVIDERS:** This is exactly the same spec as OneLogin's [python-saml and python3-saml packages](https://github.com/onelogin/python3-saml#settings). The big difference is here you supply a list of dicts where the top most key(s) must map 1:1 to the top most keys in `SAML_USERS_MAP`. Also, this package allows you to ref the cert/key files via `open()` calls. This is to allow those of you with multiple external customers to login to your platform with any N number of IdPs.


## Routes

| **Route** | **Uses** |
|-------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `/sso/saml/?acs&provider=MyProvider` | The Assertion Consumer Service Endpoint. This is where your IdP will be POSTing assertions. The 'provider' query string must have a value that matches a top level key of your SAML_PROVIDERS settings. |
| `/sso/saml/metadata?provider=MyProvider` | This is where the SP (ie your Django App) has metadata. Some IdPs request this to generate configuration. The 'provider' query string must have a value that matches a top level key of your SAML_PROVIDERS settings. |
| `/sso/saml/?provider=MyProvider` | Use this endpoint when you want to trigger an SP-initiated login. For example, this could be the `href`of a "Login with ClientX Okta" button. |

## Gotchas

The following are things that you may run into issue with. Here are some tips.

* Ensure the value of the SP `entityId` config matches up with what you supply in your IdPs configuration.
* Your IdP may default to particular Signature type, usually `Assertion` or `Response` are the options. Depending on how you define your SAML provider config, it will dictate what this value should be.

# Wishlist and TODOs

The following are things that arent present yet but would be cool to have

* Implement logic for Single Logout Service
* ADFS IdP support
* Integration test with full on mock saml interactions to test the actual backend auth
* Tests add coverage to views and the authenticate() get_user() methods in the auth backend
* models (with multi-tentant support) for idp and sp in order to facilitate management via django admin


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

django-saml2-pro-auth-0.0.4.tar.gz (9.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_saml2_pro_auth-0.0.4-py2.py3-none-any.whl (13.6 kB view details)

Uploaded Python 2Python 3

File details

Details for the file django-saml2-pro-auth-0.0.4.tar.gz.

File metadata

File hashes

Hashes for django-saml2-pro-auth-0.0.4.tar.gz
Algorithm Hash digest
SHA256 d9ee548368aaecf0fc28ba032769d35d205872406348d0f0f50a47268464afa8
MD5 2c731e599348eae4f71e2dd973e3d799
BLAKE2b-256 b9a93cb99109fe4c75d345eedc7a9c91d8a37bfc14f51759bb669e50a5b2d975

See more details on using hashes here.

File details

Details for the file django_saml2_pro_auth-0.0.4-py2.py3-none-any.whl.

File metadata

File hashes

Hashes for django_saml2_pro_auth-0.0.4-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 3f45f3d7e90f823ec5bc180dadc6d6638d42018750e93a947216bde9120efbe5
MD5 8fdc4088073e39261332dbe5510eefb5
BLAKE2b-256 ee70f4f83ce764352215e8e513812a7f081ca056b0dc428393b21df459aca2ff

See more details on using hashes here.

Supported by

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