Skip to content

Instantly share code, notes, and snippets.

@jeromecc
Forked from alee/views.py
Created September 11, 2019 17:13
Show Gist options
  • Save jeromecc/a50a2bfef4ce654318091a660959f76f to your computer and use it in GitHub Desktop.
Save jeromecc/a50a2bfef4ce654318091a660959f76f to your computer and use it in GitHub Desktop.
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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment