Skip to content

Commit

Permalink
create custom middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
JoshuaBaubry committed Mar 30, 2020
1 parent 762f346 commit ed1f3e3
Show file tree
Hide file tree
Showing 31 changed files with 929 additions and 708 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Compiled source #
# Compiled source #
###################
*.com
*.class
Expand Down
6 changes: 4 additions & 2 deletions pod/authentication/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,14 @@ def get_fields(self, request, obj=None):
class Media:
css = {
"all": (
'css/podfile.css',
'bootstrap-4/css/bootstrap.min.css',
'bootstrap-4/css/bootstrap-grid.css',
'css/pod.css'
)
}
js = (
'js/filewidget.js',
'podfile/js/filewidget.js',
'js/main.js',
'feather-icons/feather.min.js',
'bootstrap-4/js/bootstrap.min.js')

Expand Down
140 changes: 140 additions & 0 deletions pod/authentication/middleware.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
from django.contrib.auth.middleware import RemoteUserMiddleware
from django.contrib.auth.models import Group
from django.contrib import auth
from django.core.exceptions import ImproperlyConfigured
import re

from shibboleth.app_settings import SHIB_ATTRIBUTE_MAP, GROUP_ATTRIBUTES, GROUP_DELIMITERS


class ShibbolethRemoteUserMiddleware(RemoteUserMiddleware):
"""
Authentication Middleware for use with Shibboleth. Uses the recommended pattern
for remote authentication from: http://code.djangoproject.com/svn/django/tags/releases/1.3/django/contrib/auth/middleware.py
"""



def process_request(self, request):
# AuthenticationMiddleware is required so that request.user exists.
if not hasattr(request, 'user'):
raise ImproperlyConfigured(
"The Django remote user auth middleware requires the"
" authentication middleware to be installed. Edit your"
" MIDDLEWARE_CLASSES setting to insert"
" 'django.contrib.auth.middleware.AuthenticationMiddleware'"
" before the RemoteUserMiddleware class.")

# Locate the remote user header.
try:
print(request.META)
username = request.META["HTTP_REMOTE_USER"]
print("username")
except KeyError:
print("fail :(")
# If specified header doesn't exist then return (leaving
# request.user set to AnonymousUser by the
# AuthenticationMiddleware).
return
#If we got an empty value for request.META[self.header], treat it like
# self.header wasn't in self.META at all - it's still an anonymous user.
if not username:
return
# If the user is already authenticated and that user is the user we are
# getting passed in the headers, then the correct user is already
# persisted in the session and we don't need to continue.
is_authenticated = request.user.is_authenticated
if is_authenticated:
if request.user.username == self.clean_username(username, request):
return

# Make sure we have all required Shiboleth elements before proceeding.
shib_meta, error = self.parse_attributes(request)
# Add parsed attributes to the session.
request.session['shib'] = shib_meta
if error:
raise ShibbolethValidationError("All required Shibboleth elements"
" not found. %s" % shib_meta)

# We are seeing this user for the first time in this session, attempt
# to authenticate the user.
user = auth.authenticate(request, remote_user=username, shib_meta=shib_meta)
if user:
# User is valid. Set request.user and persist user in the session
# by logging the user in.
request.user = user
auth.login(request, user)

# Upgrade user groups if configured in the settings.py
# If activated, the user will be associated with those groups.
if GROUP_ATTRIBUTES:
self.update_user_groups(request, user)
# call make profile.
self.make_profile(user, shib_meta)
# setup session.
self.setup_session(request)

def make_profile(self, user, shib_meta):
"""
This is here as a stub to allow subclassing of ShibbolethRemoteUserMiddleware
to include a make_profile method that will create a Django user profile
from the Shib provided attributes. By default it does nothing.
"""
return

def setup_session(self, request):
"""
If you want to add custom code to setup user sessions, you
can extend this.
"""
return

def update_user_groups(self, request, user):
groups = self.parse_group_attributes(request)
# Remove the user from all groups that are not specified in the shibboleth metadata
for group in user.groups.all():
if group.name not in groups:
group.user_set.remove(user)
# Add the user to all groups in the shibboleth metadata
for g in groups:
group, created = Group.objects.get_or_create(name=g)
group.user_set.add(user)

@staticmethod
def parse_attributes(request):
"""
Parse the incoming Shibboleth attributes and convert them to the internal data structure.
From: https://github.com/russell/django-shibboleth/blob/master/django_shibboleth/utils.py
Pull the mapped attributes from the apache headers.
"""
shib_attrs = {}
error = False
meta = request.META
for header, attr in list(SHIB_ATTRIBUTE_MAP.items()):
if len(attr) == 3:
required, name, attr_processor = attr
else:
required, name = attr
attr_processor = lambda x: x
value = meta.get(header, None)
if value:
shib_attrs[name] = attr_processor(value)
elif required:
error = True
return shib_attrs, error

@staticmethod
def parse_group_attributes(request):
"""
Parse the Shibboleth attributes for the GROUP_ATTRIBUTES and generate a list of them.
"""
groups = []
for attr in GROUP_ATTRIBUTES:
parsed_groups = re.split('|'.join(GROUP_DELIMITERS),
request.META.get(attr, ''))
groups += filter(bool, parsed_groups)
return groups


class ShibbolethValidationError(Exception):
pass
3 changes: 3 additions & 0 deletions pod/authentication/templates/authentication/login.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ <h2>{% trans 'Authentication' %}</h2>
{% if USE_CAS %}
<a class="btn btn-success" href="{% url 'cas-login' %}?next={{ referrer|urlencode }}" title="{% trans "Single sign on" %} {{TITLE_ETB}}">{% trans "Single sign on" %} {{TITLE_ETB}}</a>
{% endif %}
{% if USE_SHIB %}
<a class="btn btn-info" href="{{SHIB_URL }}?target={{ referrer|urlencode }}" title="{{ SHIB_NAME }}">{{ SHIB_NAME}}</a>
{% endif %}
<a class="btn btn-primary" href="{% url 'local-login'%}?{% if request.GET.is_iframe %}is_iframe=true&{%endif%}next={{ referrer|urlencode }}" title="">{% trans "local sign on" %}</a>
</div>

Expand Down
17 changes: 12 additions & 5 deletions pod/authentication/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,21 @@
from django.contrib import messages
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.decorators import login_required

from shibboleth.decorators import login_optional
from urllib.parse import quote
from cas.decorators import gateway
from .middleware import ShibbolethRemoteUserMiddleware

from pod.authentication.forms import FrontOwnerForm

USE_CAS = getattr(
settings, 'USE_CAS', False)
USE_SHIB = getattr(
settings, 'USE_SHIB', False)
CAS_GATEWAY = getattr(
settings, 'CAS_GATEWAY', False)
SHIB_URL = getattr(
settings, 'SHIB_URL',"" )

if CAS_GATEWAY:
@gateway()
Expand All @@ -29,9 +35,7 @@ def authentication_login_gateway(request):
})
else:
def authentication_login_gateway(request):
return HttpResponse(
"You must set CAS_GATEWAY to True to use this view")

return HttpResponse("You must set CAS_GATEWAY to True to use this view")

def authentication_login(request):
referrer = request.GET['referrer'] if request.GET.get('referrer') else '/'
Expand All @@ -43,7 +47,7 @@ def authentication_login(request):
url = reverse('authentication_login_gateway')
url += '?%snext=%s' % (iframe_param, referrer)
return redirect(url)
elif USE_CAS:
elif USE_CAS or USE_SHIB :
return render(request, 'authentication/login.html', {
'USE_CAS': USE_CAS, 'referrer': referrer
})
Expand All @@ -53,6 +57,8 @@ def authentication_login(request):
return redirect(url)




def authentication_logout(request):
if USE_CAS:
return redirect(reverse('cas-logout'))
Expand Down Expand Up @@ -83,3 +89,4 @@ def userpicture(request):
return render(request, 'userpicture/userpicture.html', {
'frontOwnerForm': frontOwnerForm}
)

3 changes: 2 additions & 1 deletion pod/chapter/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@

from pod.video.models import Video
from pod.main.models import get_nextautoincrement
from select2 import fields as select2_fields


class Chapter(models.Model):
video = models.ForeignKey(Video, verbose_name=_('video'))
video = select2_fields.ForeignKey(Video, verbose_name=_('video'))
title = models.CharField(_('title'), max_length=100)
slug = models.SlugField(
_('slug'),
Expand Down
12 changes: 8 additions & 4 deletions pod/completion/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,14 @@ class DocumentAdmin(admin.ModelAdmin):
class Media:
css = {
"all": (
'css/podfile.css',
'bootstrap-4/css/bootstrap.min.css',
'bootstrap-4/css/bootstrap-grid.css',
'css/pod.css'
)
}
js = (
'js/filewidget.js',
'podfile/js/filewidget.js',
'js/main.js',
'feather-icons/feather.min.js',
'bootstrap-4/js/bootstrap.min.js')

Expand Down Expand Up @@ -85,12 +87,14 @@ class TrackAdmin(admin.ModelAdmin):
class Media:
css = {
"all": (
'css/podfile.css',
'bootstrap-4/css/bootstrap.min.css',
'bootstrap-4/css/bootstrap-grid.css',
'css/pod.css'
)
}
js = (
'js/filewidget.js',
'js/main.js',
'podfile/js/filewidget.js',
'feather-icons/feather.min.js',
'bootstrap-4/js/bootstrap.min.js')

Expand Down
9 changes: 5 additions & 4 deletions pod/completion/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from ckeditor.fields import RichTextField
from pod.video.models import Video
from pod.main.models import get_nextautoincrement
from select2 import fields as select2_fields

if getattr(settings, 'USE_PODFILE', False):
FILEPICKER = True
Expand Down Expand Up @@ -47,7 +48,7 @@

class Contributor(models.Model):

video = models.ForeignKey(Video, verbose_name=_('video'))
video = select2_fields.ForeignKey(Video, verbose_name=_('video'))
name = models.CharField(_('lastname / firstname'), max_length=200)
email_address = models.EmailField(
_('mail'), null=True, blank=True, default='')
Expand Down Expand Up @@ -110,7 +111,7 @@ def get_noscript_mail(self):


class Document(models.Model):
video = models.ForeignKey(Video, verbose_name=_('Video'))
video = select2_fields.ForeignKey(Video, verbose_name=_('Video'))
document = models.ForeignKey(
CustomFileModel,
null=True,
Expand Down Expand Up @@ -161,7 +162,7 @@ def __str__(self):

class Track(models.Model):

video = models.ForeignKey(Video, verbose_name=_('Video'))
video = select2_fields.ForeignKey(Video, verbose_name=_('Video'))
kind = models.CharField(
_('Kind'),
max_length=10,
Expand Down Expand Up @@ -238,7 +239,7 @@ class Overlay(models.Model):
('left', _(u'left')),
)

video = models.ForeignKey(Video, verbose_name=_('Video'))
video = select2_fields.ForeignKey(Video, verbose_name=_('Video'))
title = models.CharField(_('Title'), max_length=100)
slug = models.SlugField(
_('Slug'),
Expand Down
12 changes: 8 additions & 4 deletions pod/enrichment/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@ class EnrichmentAdmin(admin.ModelAdmin):
class Media:
css = {
"all": (
'css/podfile.css',
'bootstrap-4/css/bootstrap.min.css',
'bootstrap-4/css/bootstrap-grid.css',
'css/pod.css'
)
}
js = (
'js/filewidget.js',
'js/main.js',
'podfile/js/filewidget.js',
'feather-icons/feather.min.js',
'bootstrap-4/js/bootstrap.min.js')

Expand Down Expand Up @@ -59,12 +61,14 @@ def get_file_name(self, obj):
class Media:
css = {
"all": (
'css/podfile.css',
'bootstrap-4/css/bootstrap.min.css',
'bootstrap-4/css/bootstrap-grid.css',
'css/pod.css'
)
}
js = (
'js/filewidget.js',
'js/main.js',
'podfile/js/filewidget.js',
'feather-icons/feather.min.js',
'bootstrap-4/js/bootstrap.min.js')

Expand Down
11 changes: 6 additions & 5 deletions pod/enrichment/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

from pod.video.models import Video
from pod.main.models import get_nextautoincrement
from select2 import fields as select2_fields

import os
import datetime
Expand Down Expand Up @@ -110,7 +111,7 @@ class Enrichment(models.Model):
('embed', _("embed")),
)

video = models.ForeignKey(Video, verbose_name=_('video'))
video = select2_fields.ForeignKey(Video, verbose_name=_('video'))
title = models.CharField(_('title'), max_length=100)
slug = models.SlugField(
_('slug'),
Expand Down Expand Up @@ -305,10 +306,10 @@ def verify_attributs(self):


class EnrichmentGroup(models.Model):
video = models.OneToOneField(Video, verbose_name=_('Video'),
# editable=False, null=True,
on_delete=models.CASCADE)
groups = models.ManyToManyField(
video = select2_fields.OneToOneField(Video, verbose_name=_('Video'),
# editable=False, null=True,
on_delete=models.CASCADE)
groups = select2_fields.ManyToManyField(
Group, blank=True, verbose_name=_('Groups'),
help_text=_('Select one or more groups who'
' can access to the'
Expand Down
Loading

0 comments on commit ed1f3e3

Please sign in to comment.