Hi Patrick,
I have refactored the logic in your views.py so that it is a little more Pythonic. The main changes are that I've returned early further up the stack, and updated the formatting. I've left your comments in for completeness.
from django.shortcuts import render, redirect
from django_commento_sso.conf import settings
from django.http import HttpResponse
from django.contrib.auth.models import User
from django.contrib.auth import auth
#import hashlib
import hmac
import json
import logging
logger = logging.getLogger(__name__)
def get_user(request):
"""
Return active user
"""
if not hasattr(request, "_cached_user"):
request._cached_user = auth.get_user(request)
return request._cached_user
def sso(request):
"""
Process SSO request
"""
if settings.SECRET_KEY is None:
logger.error("django_commento_sso - COMMENTO_SECRET_KEY not found in settings.py")
return HttpResponse(status=204)
if not request.GET["token"]:
return HttpResponse(status=204)
logger.debug(f"Token as received {request.GET['token']}")
if not request.GET["hmac"]:
return HttpResponse(status=204)
logger.debug(f"Hmac as received {request.GET['hmac']}")
received_hmac_bytes = bytes.fromhex(request.GET["hmac"])
token_bytes = bytes.fromhex(request.GET["token"])
secret_key_bytes = bytes.fromhex(settings.COMMENTO_SECRET_KEY)
expected_hmac_bytes = hmac.digest(secret_key_bytes, token_bytes, "sha256")
logger.debug(f"Expected hmac was {expected_hmac_bytes.hex()}")
is_hmac_true = expected_hmac_bytes == received_hmac_bytes
if not is_hmac_true:
# Spoofed token attempt or error
logger.warning("django_commento_sso SSO HMAC comparison - No match")
return HttpResponse(status=404)
logger.debug("HMAC comparison of token - match")
if not request.user.is_authenticated:
#return redirect('%s?next=%s%s?hmac=%s&token=%s' % (settings.LOGIN_URL, request.get_host(), request.get_full_path(),request.GET['hmac'],request.GET['token']))
url = f"{settings.LOGIN_URL}?next={request.get_host()}{request.get_full_path()}?hmac={request.GET['hmac']}&token={request.GET['token']}"
return redirect(url)
logger.info(f"django_commento_sso SSO Success for User {request.user.username}")
if not request.user.email:
logger.error("django_commento_sso User must have email for Commento SSO")
return False
# try:
# uid = request.session['mid']
# userobj = User.objects.get(id=uid)
# except User.DoesNotExist as e:
# logger.error('Error, user does not exist', e)
# return false
# #
# thisUser = User.objects.get(username=request.user.username).first()
# #avoid simplelazyobject
payload = {
"token": request.GET["token"],
"email": request.user.email,
"name": settings.COMMENTO_USER_NAME_FUNCTION(get_user(request)),
}
if settings.COMMENTO_USER_LINK_FUNCTION:
payload["link"] = settings.COMMENTO_USER_LINK_FUNCTION(get_user(request))
if settings.COMMENTO_USER_PHOTO_FUNCTION:
payload["photo"] = settings.COMMENTO_USER_PHOTO_FUNCTION(get_user(request))
payload_hmac_hex = (hmac.digest(secret_key_bytes, bytes(json.dumps(payload), "utf8"), "sha256")).hex()
payload_hex = bytes(json.dumps(payload), "utf8").hex()
url = f"https://commento.io/api/oauth/sso/callback?payload={payload_hex}&hmac={payload_hmac_hex}"
return redirect(url)
Hi Patrick, I have refactored the logic in your
views.py
so that it is a little more Pythonic. The main changes are that I've returned early further up the stack, and updated the formatting. I've left your comments in for completeness.