Skip to content

Instantly share code, notes, and snippets.

@alee alee/views.py
Last active Feb 26, 2019

Embed
What would you like to do?
Django Discourse SSO endpoint adapted from https://meta.discourse.org/t/sso-example-for-django/14258 - depends on settings.py DISCOURSE_BASE_URL and DISCOURSE_SSO_SECRET
import base64
import hmac
import hashlib
from urllib import parse
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseBadRequest, HttpResponseRedirect
from django.conf import settings
@login_required
def discourse_sso(request):
'''
Code adapted from https://meta.discourse.org/t/sso-example-for-django/14258
'''
payload = request.GET.get('sso')
signature = request.GET.get('sig')
if None in [payload, signature]:
return HttpResponseBadRequest('No SSO payload or signature. Please contact support if this problem persists.')
# Validate the payload
payload = bytes(parse.unquote(payload), encoding='utf-8')
decoded = base64.decodebytes(payload).decode('utf-8')
if len(payload) == 0 or 'nonce' not in decoded:
return HttpResponseBadRequest('Invalid payload. Please contact support if this problem persists.')
key = bytes(settings.DISCOURSE_SSO_SECRET, encoding='utf-8') # must not be unicode
h = hmac.new(key, payload, digestmod=hashlib.sha256)
this_signature = h.hexdigest()
if not hmac.compare_digest(this_signature, signature):
return HttpResponseBadRequest('Invalid payload. Please contact support if this problem persists.')
# Build the return payload
qs = parse.parse_qs(decoded)
user = request.user
params = {
'nonce': qs['nonce'][0],
'email': user.email,
'external_id': user.id,
'username': user.username,
'require_activation': 'true',
'name': user.get_full_name(),
}
return_payload = base64.encodebytes(bytes(parse.urlencode(params), 'utf-8'))
h = hmac.new(key, return_payload, digestmod=hashlib.sha256)
query_string = parse.urlencode({'sso': return_payload, 'sig': h.hexdigest()})
# Redirect back to Discourse
discourse_sso_url = '{0}/session/sso_login?{1}'.format(settings.DISCOURSE_BASE_URL, query_string)
logger.warning("discourse redirect url: %s", discourse_sso_url)
return HttpResponseRedirect(discourse_sso_url)
@DaniloGomez

This comment has been minimized.

Copy link

commented Mar 2, 2018

I think it should say
- depends on settings.py DISCOURSE_BASE_URL and DISCOURSE_SSO_SECRET
instead of
- depends on settings.py BASE_DISCOURSE_URL and DISCOURSE_SSO_SECRET

@alee

This comment has been minimized.

Copy link
Owner Author

commented Apr 13, 2018

Changed, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.