Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

python 2.7 #186

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,6 @@ target/

#Ipython Notebook
.ipynb_checkpoints

# VSCode
.vscode
5 changes: 5 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,11 @@ You should see :

The `Identity Provider metadata` link is the METADATA_AUTO_CONF_URL.

Additional Notes
================

- in the acs method, the local user is determined from the SAML assertion returned by the identity provider, based on a `username` match


How to Contribute
=================
Expand Down
38 changes: 30 additions & 8 deletions django_saml2_auth/views.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-


from saml2 import (
BINDING_HTTP_POST,
BINDING_HTTP_REDIRECT,
Expand All @@ -22,8 +21,8 @@
from django.http import HttpResponseRedirect
from django.utils.http import is_safe_url

from rest_auth.utils import jwt_encode

if settings.SAML2_AUTH.get('USE_JWT') is True:
from rest_auth.utils import jwt_encode

# default User or custom User. Now both will work.
User = get_user_model()
Expand All @@ -35,6 +34,9 @@
import urllib.error
import urllib.parse

import logging
logger = logging.getLogger('saml2-auth')

if parse_version(get_version()) >= parse_version('1.7'):
from django.utils.module_loading import import_string
else:
Expand Down Expand Up @@ -155,20 +157,29 @@ def _create_new_user(username, email, firstname, lastname):

@csrf_exempt
def acs(r):
logging.info('received login request from identity provider')

saml_client = _get_saml_client(get_current_domain(r))
resp = r.POST.get('SAMLResponse', None)
next_url = r.session.get('login_next_url', _default_next_url())

if not resp:
logging.error('login request from identity provider does not contain a saml response ')
return HttpResponseRedirect(get_reverse([denied, 'denied', 'django_saml2_auth:denied']))

authn_response = saml_client.parse_authn_request_response(
resp, entity.BINDING_HTTP_POST)

authn_response = saml_client.parse_authn_request_response(resp, entity.BINDING_HTTP_POST)
if authn_response is None:
authn_response = saml_client.parse_authn_request_response(resp, entity.BINDING_HTTP_ARTIFACT)

if authn_response is None:
logging.error(
'login request from identity provider contains a SAML response that could not be parsed: {}'.format(resp))

return HttpResponseRedirect(get_reverse([denied, 'denied', 'django_saml2_auth:denied']))

user_identity = authn_response.get_identity()
if user_identity is None:
logging.info('SAML response in login request from identity provider does not contains an identity')
return HttpResponseRedirect(get_reverse([denied, 'denied', 'django_saml2_auth:denied']))

user_email = user_identity[settings.SAML2_AUTH.get('ATTRIBUTES_MAP', {}).get('email', 'Email')][0]
Expand All @@ -184,24 +195,33 @@ def acs(r):
if settings.SAML2_AUTH.get('TRIGGER', {}).get('BEFORE_LOGIN', None):
import_string(settings.SAML2_AUTH['TRIGGER']['BEFORE_LOGIN'])(user_identity)
except User.DoesNotExist:
logging.info('no local match found for externally authenticated identity {}'.format(user_name))
new_user_should_be_created = settings.SAML2_AUTH.get('CREATE_USER', True)
if new_user_should_be_created:
target_user = _create_new_user(user_name, user_email, user_first_name, user_last_name)
if settings.SAML2_AUTH.get('TRIGGER', {}).get('CREATE_USER', None):
import_string(settings.SAML2_AUTH['TRIGGER']['CREATE_USER'])(user_identity)
import_string(settings.SAML2_AUTH['TRIGGER']['CREATE_USER'])(user_identity, target_user)
is_new_user = True
else:
logging.info('externally authenticated user identity {} does not exist locally, and automatic creation is forbidden'.format(user_name))
return HttpResponseRedirect(get_reverse([denied, 'denied', 'django_saml2_auth:denied']))

r.session.flush()

if target_user.is_active:
target_user.backend = 'django.contrib.auth.backends.ModelBackend'

AUTHENTICATION_BACKEND = settings.SAML2_AUTH.get('AUTHENTICATION_BACKEND', 'django.contrib.auth.backends.ModelBackend')
target_user.backend = AUTHENTICATION_BACKEND
login(r, target_user)
logger.info('user {} logged in'.format(user_name))
if settings.SAML2_AUTH.get('TRIGGER', {}).get('LOGIN', None):
import_string(settings.SAML2_AUTH['TRIGGER']['LOGIN'])(user_identity, target_user)
else:
logging.info('denied user {} access due to user being marked as inactive'.format(user_name))
return HttpResponseRedirect(get_reverse([denied, 'denied', 'django_saml2_auth:denied']))

if settings.SAML2_AUTH.get('USE_JWT') is True:
logging.info('generating a fresh JWT token for {}'.format(user_name))
# We use JWT auth send token to frontend
jwt_token = jwt_encode(target_user)
query = '?uid={}&token={}'.format(target_user.id, jwt_token)
Expand All @@ -217,6 +237,7 @@ def acs(r):
except TemplateDoesNotExist:
return HttpResponseRedirect(next_url)
else:
logging.info('saml authentication complete, redirecting user {} to {}'.format(user_name, next_url))
return HttpResponseRedirect(next_url)


Expand Down Expand Up @@ -256,6 +277,7 @@ def signin(r):
redirect_url = value
break

logging.info('redirecting to {}'.format(redirect_url))
return HttpResponseRedirect(redirect_url)


Expand Down
11 changes: 3 additions & 8 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
setup(
name='django_saml2_auth',

version='2.2.1',
version='2.2.2',

description='Django SAML2 Authentication Made Easy. Easily integrate with SAML2 SSO identity providers like Okta',
long_description=long_description,
Expand Down Expand Up @@ -49,19 +49,14 @@
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
],

keywords='Django SAML2 Authentication Made Easy, integrate with SAML2 SSO such as Okta easily',

packages=find_packages(),

install_requires=['pysaml2>=4.5.0',
install_requires=['pysaml2==4.5.0',
'djangorestframework-jwt',
'django-rest-auth', ],
include_package_data=True,
)
)