Authentication - Rewrite auth system to use Django's user model
This commit is contained in:
parent
325af6929f
commit
5fb6911960
@ -42,6 +42,11 @@ ALLOWED_HOSTS = []
|
||||
|
||||
# Application definition
|
||||
|
||||
AUTHENTICATION_BACKENDS = (
|
||||
'LandingPage.backends.OAuthBackend',
|
||||
'django.contrib.auth.backends.ModelBackend',
|
||||
)
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'LandingPage.apps.LandingpageConfig',
|
||||
'Show.apps.ShowConfig',
|
||||
|
@ -3,7 +3,7 @@ from .models import *
|
||||
|
||||
# Register your models here.
|
||||
admin.site.register(Show)
|
||||
admin.site.register(User)
|
||||
admin.site.register(ExternalUser)
|
||||
admin.site.register(Admin)
|
||||
admin.site.register(Ban)
|
||||
admin.site.register(ShowModerator)
|
||||
|
64
LandingPage/backends.py
Normal file
64
LandingPage/backends.py
Normal file
@ -0,0 +1,64 @@
|
||||
import requests
|
||||
import hashlib
|
||||
import json
|
||||
import logging
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.backends import ModelBackend
|
||||
from .models import ExternalUser
|
||||
|
||||
class OAuthBackend(ModelBackend):
|
||||
def authenticate(self, code=None):
|
||||
resp = requests.post(
|
||||
settings.AUTH_TOKEN_ENDPOINT+"token",
|
||||
data={
|
||||
'grant_type':'authorization_code',
|
||||
'code':code,
|
||||
'redirect_uri':settings.AUTH_REDIRECT_URL,
|
||||
'client_id':settings.AUTH_CLIENT_ID
|
||||
},
|
||||
headers = {
|
||||
'Authorization':'Basic %s'%settings.AUTH_B64
|
||||
}
|
||||
)
|
||||
resp_json = resp.json()
|
||||
if 'error' in resp_json:
|
||||
logging.warn('OAuth server returned an error: %s'%json.dumps(resp_json))
|
||||
else:
|
||||
user_info = requests.get(
|
||||
settings.AUTH_TOKEN_ENDPOINT+"user",
|
||||
headers = {
|
||||
'Authorization': 'Bearer ' + resp_json['access_token']
|
||||
}
|
||||
).json()
|
||||
|
||||
usermodel = get_user_model()
|
||||
matches = usermodel.objects.filter(externaluser__icy_id=user_info['uuid'])
|
||||
match = None
|
||||
|
||||
if not len(matches):
|
||||
user = usermodel.objects.create_user(
|
||||
username = user_info['username'],
|
||||
email = user_info['email'],
|
||||
)
|
||||
|
||||
if 'privilege' in user_info:
|
||||
priv = user_info['privilege']
|
||||
user.is_superuser = (priv == 5)
|
||||
user.is_staff = (priv > 0)
|
||||
|
||||
user.save()
|
||||
user.externaluser = ExternalUser(
|
||||
user = user,
|
||||
icy_id = user_info['uuid'],
|
||||
display_name = user_info['display_name']
|
||||
)
|
||||
user.externaluser.save()
|
||||
match = user
|
||||
else:
|
||||
match = matches[0]
|
||||
|
||||
match.access_token = resp_json['access_token']
|
||||
|
||||
return match
|
||||
return None
|
@ -1,4 +1,5 @@
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.files.storage import FileSystemStorage
|
||||
from django.conf import settings
|
||||
import os
|
||||
@ -71,14 +72,17 @@ class Show(TimestampedModel):
|
||||
def __str__(self):
|
||||
return '%s [%s]'%(self.name,self.abbr)
|
||||
|
||||
class User(TimestampedModel):
|
||||
user_id = models.CharField(
|
||||
class ExternalUser(TimestampedModel):
|
||||
user = models.OneToOneField(
|
||||
User,
|
||||
on_delete=models.CASCADE,
|
||||
help_text='The internal Django user',
|
||||
verbose_name="User"
|
||||
)
|
||||
icy_id = models.CharField(
|
||||
max_length=36,
|
||||
help_text='The UUID assigned to this user by IcyNet\'s auth servers'
|
||||
)
|
||||
email = models.EmailField(
|
||||
help_text='This user\'s email address'
|
||||
)
|
||||
display_name=models.CharField(
|
||||
max_length=20,
|
||||
help_text="The name shown to other users",
|
||||
@ -95,7 +99,7 @@ class User(TimestampedModel):
|
||||
through='Watch'
|
||||
)
|
||||
def __str__(self):
|
||||
return self.email
|
||||
return 'External for %s (%s)'%(self.user.email, self.display_name)
|
||||
|
||||
class Admin(User):
|
||||
pass
|
||||
@ -285,7 +289,7 @@ class Submission(TimestampedModel):
|
||||
verbose_name='Submitted For'
|
||||
)
|
||||
user = models.ForeignKey(
|
||||
'User',
|
||||
User,
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
related_name='submissions',
|
||||
@ -309,7 +313,7 @@ class SubmissionVote(TimestampedModel):
|
||||
help_text='What this submission was cast on'
|
||||
)
|
||||
user = models.ForeignKey(
|
||||
'User',
|
||||
User,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='votes',
|
||||
help_text='The user who cast this vote'
|
||||
@ -322,7 +326,7 @@ class SubmissionVote(TimestampedModel):
|
||||
|
||||
class Favorite(TimestampedModel):
|
||||
user = models.ForeignKey(
|
||||
User,
|
||||
ExternalUser,
|
||||
on_delete=models.CASCADE
|
||||
)
|
||||
episode = models.ForeignKey(
|
||||
@ -334,7 +338,7 @@ class Favorite(TimestampedModel):
|
||||
|
||||
class Watch(TimestampedModel):
|
||||
user = models.ForeignKey(
|
||||
User,
|
||||
ExternalUser,
|
||||
on_delete=models.CASCADE
|
||||
)
|
||||
episode = models.ForeignKey(
|
||||
|
@ -20,8 +20,8 @@
|
||||
<div class="unibar">
|
||||
<span class="logo">Episodes<span class="period">.</span>Community</span>
|
||||
<div class="userdata">
|
||||
{% if request.session.user_id %}
|
||||
{{ request.session.disp_name }}
|
||||
{% if user.is_authenticated %}
|
||||
{{ user.externaluser.display_name }}
|
||||
{% else %}
|
||||
<a href="/login">Log in</a>
|
||||
{% endif %}
|
||||
|
@ -1,6 +1,7 @@
|
||||
from django.shortcuts import render
|
||||
from django.views import View
|
||||
from django.views.generic.base import TemplateView
|
||||
from django.contrib.auth import login as auth_login, authenticate
|
||||
from django.conf import settings
|
||||
from django.http import HttpResponse
|
||||
from django.http import HttpResponseRedirect
|
||||
@ -29,52 +30,21 @@ class LoginRedirect(View):
|
||||
userstate = generateState(req)
|
||||
if userstate == req.GET['state']:
|
||||
code = req.GET['code']
|
||||
resp = requests.post(
|
||||
settings.AUTH_TOKEN_ENDPOINT+"token",
|
||||
data={
|
||||
'grant_type':'authorization_code',
|
||||
'code':code,
|
||||
'redirect_uri':settings.AUTH_REDIRECT_URL,
|
||||
'client_id':settings.AUTH_CLIENT_ID
|
||||
},
|
||||
headers = {
|
||||
'Authorization':'Basic %s'%settings.AUTH_B64
|
||||
}
|
||||
)
|
||||
resp_json = resp.json()
|
||||
if 'error' in resp_json:
|
||||
r = HttpResponse('<h1>OAuth Error</h1><pre>%s</pre>'%json.dumps(resp_json))
|
||||
r.status = 500
|
||||
return r
|
||||
else:
|
||||
user_info = requests.get(
|
||||
settings.AUTH_TOKEN_ENDPOINT+"user",
|
||||
headers = {
|
||||
'Authorization': 'Bearer ' + resp_json['access_token']
|
||||
}
|
||||
).json()
|
||||
req.session['user_id'] = user_info['uuid']
|
||||
matches = User.objects.filter(user_id=user_info['uuid'])
|
||||
match = None
|
||||
if not len(matches):
|
||||
user = User(
|
||||
user_id = user_info['uuid'],
|
||||
email = user_info['email'],
|
||||
display_name = user_info['display_name']
|
||||
)
|
||||
user.save()
|
||||
match = user
|
||||
else:
|
||||
match = matches[0]
|
||||
req.session['token'] = resp_json['access_token']
|
||||
req.session['disp_name'] = match.display_name
|
||||
|
||||
user = authenticate(code=code)
|
||||
|
||||
if user is not None and user.is_active:
|
||||
auth_login(req, user)
|
||||
|
||||
return HttpResponseRedirect('/')
|
||||
else:
|
||||
|
||||
return HttpResponse('<h1>Error</h1><br><p>It looks like something went wrong while trying to authenticate you. Please try again later.</p>', status=500)
|
||||
|
||||
return HttpResponse('<h1>Unmatching state tokens</h1><br><p>It looks like the request to login wasn\'t started by you. Try going back to the home page and logging in again.</p>', status=400)
|
||||
|
||||
class Login(View):
|
||||
def get(self, req):
|
||||
url = '%sauthorize?response_type=code&client_id=%s&redirect_uri=%s&scope=email&state=%s'%(settings.AUTH_TOKEN_ENDPOINT,settings.AUTH_CLIENT_ID,settings.AUTH_REDIRECT_URL, generateState(req))
|
||||
url = '%sauthorize?response_type=code&client_id=%s&redirect_uri=%s&scope=email privilege&state=%s'%(settings.AUTH_TOKEN_ENDPOINT,settings.AUTH_CLIENT_ID,settings.AUTH_REDIRECT_URL, generateState(req))
|
||||
response = HttpResponse("Redirecting you to the IcyNet auth page...")
|
||||
response.status_code = 302
|
||||
response['Location'] = url
|
||||
|
Reference in New Issue
Block a user