mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2025-07-10 04:50:16 +02:00
109 lines
3.5 KiB
Python
109 lines
3.5 KiB
Python
from __future__ import unicode_literals
|
|
|
|
from django.conf import settings
|
|
from django.contrib import messages
|
|
from django.contrib.auth.decorators import login_required
|
|
from django.shortcuts import render, redirect
|
|
|
|
from .manager import DiscourseManager
|
|
from .tasks import DiscourseTasks
|
|
from .models import DiscourseUser
|
|
|
|
import base64
|
|
import hmac
|
|
import hashlib
|
|
|
|
try:
|
|
from urllib import unquote, urlencode
|
|
except ImportError: #py3
|
|
from urllib.parse import unquote, urlencode
|
|
try:
|
|
from urlparse import parse_qs
|
|
except ImportError: #py3
|
|
from urllib.parse import parse_qs
|
|
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
ACCESS_PERM = 'discourse.access_discourse'
|
|
|
|
|
|
@login_required
|
|
def discourse_sso(request):
|
|
|
|
## Check if user has access
|
|
|
|
if not request.user.has_perm(ACCESS_PERM):
|
|
messages.error(request, 'You are not authorized to access Discourse.')
|
|
return redirect('auth_dashboard')
|
|
|
|
if not request.user.profile.main_character:
|
|
messages.error(request, "You must have a main character set to access Discourse.")
|
|
return redirect('auth_characters')
|
|
|
|
main_char = request.user.profile.main_character
|
|
if main_char is None:
|
|
messages.error(request, "Your main character is missing a database model. Please select a new one.")
|
|
return redirect('auth_characters')
|
|
|
|
payload = request.GET.get('sso')
|
|
signature = request.GET.get('sig')
|
|
|
|
if None in [payload, signature]:
|
|
messages.error(request, 'No SSO payload or signature. Please contact support if this problem persists.')
|
|
return redirect('auth_dashboard')
|
|
|
|
# Validate the payload
|
|
try:
|
|
payload = unquote(payload).encode('utf-8')
|
|
decoded = base64.decodestring(payload).decode('utf-8')
|
|
assert 'nonce' in decoded
|
|
assert len(payload) > 0
|
|
except AssertionError:
|
|
messages.error(request, 'Invalid payload. Please contact support if this problem persists.')
|
|
return redirect('auth_dashboard')
|
|
|
|
key = str(settings.DISCOURSE_SSO_SECRET).encode('utf-8')
|
|
h = hmac.new(key, payload, digestmod=hashlib.sha256)
|
|
this_signature = h.hexdigest()
|
|
|
|
if this_signature != signature:
|
|
messages.error(request, 'Invalid payload. Please contact support if this problem persists.')
|
|
return redirect('auth_dashboard')
|
|
|
|
## Build the return payload
|
|
|
|
username = DiscourseManager._sanitize_username(main_char.character_name)
|
|
|
|
qs = parse_qs(decoded)
|
|
params = {
|
|
'nonce': qs['nonce'][0],
|
|
'email': request.user.email,
|
|
'external_id': request.user.pk,
|
|
'username': username,
|
|
'name': username,
|
|
}
|
|
|
|
if main_char:
|
|
params['avatar_url'] = 'https://image.eveonline.com/Character/%s_256.jpg' % main_char.main_char_id
|
|
|
|
return_payload = base64.encodestring(urlencode(params).encode('utf-8'))
|
|
h = hmac.new(key, return_payload, digestmod=hashlib.sha256)
|
|
query_string = urlencode({'sso': return_payload, 'sig': h.hexdigest()})
|
|
|
|
# Record activation and queue group sync
|
|
if not DiscourseTasks.has_account(request.user):
|
|
discourse_user = DiscourseUser()
|
|
discourse_user.user = request.user
|
|
discourse_user.enabled = True
|
|
discourse_user.save()
|
|
# wait 30s for new user creation on Discourse before triggering group sync
|
|
DiscourseTasks.update_groups.apply_async(args=[request.user.pk], countdown=30)
|
|
|
|
# Redirect back to Discourse
|
|
url = '%s/session/sso_login' % settings.DISCOURSE_URL
|
|
return redirect('%s?%s' % (url, query_string))
|
|
|