Make login through CAS and local auth available
So far, CAS-created users don't get any privilege based on rhosts
This commit is contained in:
parent
a62272d82e
commit
17e71451fe
9 changed files with 193 additions and 0 deletions
|
@ -29,6 +29,7 @@ INSTALLED_APPS = [
|
|||
'django.contrib.staticfiles',
|
||||
'solo',
|
||||
'markdownx',
|
||||
'django_cas_ng',
|
||||
'mainsite',
|
||||
'api',
|
||||
]
|
||||
|
@ -41,6 +42,7 @@ MIDDLEWARE = [
|
|||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
'django_cas_ng.middleware.CASMiddleware',
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'bocal.urls'
|
||||
|
@ -83,6 +85,15 @@ AUTH_PASSWORD_VALIDATORS = [
|
|||
},
|
||||
]
|
||||
|
||||
AUTHENTICATION_BACKENDS = [
|
||||
'django.contrib.auth.backends.ModelBackend',
|
||||
'django_cas_ng.backends.CASBackend',
|
||||
]
|
||||
|
||||
CAS_ADMIN_PREFIX = '/yaes5eiS' # we don't want CAS to take over /admin auth
|
||||
|
||||
LOGIN_URL = '/accounts/login'
|
||||
LOGIN_REDIRECT_URL = '/'
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/1.11/howto/static-files/
|
||||
|
|
|
@ -33,3 +33,13 @@ USE_TZ = True
|
|||
|
||||
STATIC_ROOT = os.path.join(PUBLIC_DIR, 'static')
|
||||
MEDIA_ROOT = os.path.join(PUBLIC_DIR, 'media')
|
||||
|
||||
# Cas
|
||||
CAS_SERVER_URL = 'https://cas.eleves.ens.fr/'
|
||||
CAS_VERIFY_URL = 'https://cas.eleves.ens.fr/'
|
||||
CAS_VERSION = 'CAS_2_SAML_1_0'
|
||||
CAS_IGNORE_REFERER = True
|
||||
CAS_FORCE_CHANGE_USERNAME_CASE = 'lower'
|
||||
CAS_REDIRECT_URL = '/'
|
||||
CAS_EMAIL_FORMAT = "%s@clipper.ens.fr"
|
||||
CAS_LOGOUT_COMPLETELY = False
|
||||
|
|
|
@ -44,3 +44,13 @@ USE_TZ = True
|
|||
|
||||
STATIC_ROOT = os.path.join(PUBLIC_DIR, 'static')
|
||||
MEDIA_ROOT = os.path.join(PUBLIC_DIR, 'media')
|
||||
|
||||
# Cas
|
||||
CAS_SERVER_URL = 'https://example.com/' # FIXME
|
||||
CAS_VERIFY_URL = 'https://example.com/' # FIXME
|
||||
CAS_VERSION = 'CAS_2_SAML_1_0' # FIXME
|
||||
CAS_IGNORE_REFERER = True
|
||||
CAS_FORCE_CHANGE_USERNAME_CASE = 'lower'
|
||||
CAS_REDIRECT_URL = '/'
|
||||
CAS_EMAIL_FORMAT = "%s@clipper.ens.fr" # FIXME
|
||||
CAS_LOGOUT_COMPLETELY = False
|
||||
|
|
|
@ -15,14 +15,39 @@ Including another URLconf
|
|||
"""
|
||||
from django.conf.urls import url, include
|
||||
from django.contrib import admin
|
||||
from django.contrib.auth.decorators import login_required
|
||||
import django.contrib.auth.views as dj_auth_views
|
||||
|
||||
import mainsite.urls
|
||||
import mainsite.auth_views as auth_views
|
||||
import markdownx.urls
|
||||
import api.urls
|
||||
|
||||
import django_cas_ng.views
|
||||
|
||||
|
||||
# Force the user to login through the custom login page
|
||||
admin.site.login = login_required(admin.site.login)
|
||||
|
||||
cas_patterns = [
|
||||
url(r'^login$', django_cas_ng.views.login, name='cas_ng_login'),
|
||||
url(r'^logout$', django_cas_ng.views.logout, name='cas_ng_logout'),
|
||||
url(r'^callback$', django_cas_ng.views.callback,
|
||||
name='cas_ng_proxy_callback'),
|
||||
]
|
||||
|
||||
accounts_patterns = [
|
||||
url(r'^cas/', include(cas_patterns)),
|
||||
url(r'^login$', auth_views.login, name='login'),
|
||||
url(r'^logout$', auth_views.logout, name='logout'),
|
||||
url(r'^password_login$', dj_auth_views.LoginView.as_view(),
|
||||
name='password_login'),
|
||||
]
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^admin/', admin.site.urls),
|
||||
url(r'^markdownx/', include(markdownx.urls)),
|
||||
url(r'^api/', include(api.urls)),
|
||||
url(r'^accounts/', include(accounts_patterns)),
|
||||
url(r'^', include(mainsite.urls)),
|
||||
]
|
||||
|
|
42
mainsite/auth_views.py
Normal file
42
mainsite/auth_views.py
Normal file
|
@ -0,0 +1,42 @@
|
|||
from django.shortcuts import render, redirect
|
||||
from django.urls import reverse
|
||||
from django.contrib.auth import logout as auth_logout
|
||||
from django.contrib.auth.decorators import login_required
|
||||
|
||||
from urllib.parse import quote as urlquote
|
||||
|
||||
|
||||
def login(req):
|
||||
if req.user.is_authenticated():
|
||||
return redirect('homepage')
|
||||
|
||||
if req.method == 'GET':
|
||||
reqDict = req.GET
|
||||
elif req.method == 'POST':
|
||||
reqDict = req.POST
|
||||
if 'next' in reqDict:
|
||||
nextUrl = reqDict['next']
|
||||
context = {
|
||||
'pass_url': '{}?next={}'.format(
|
||||
reverse('password_login'),
|
||||
urlquote(nextUrl, safe='')),
|
||||
'cas_url': '{}?next={}'.format(
|
||||
reverse('cas_ng_login'),
|
||||
urlquote(nextUrl, safe='')),
|
||||
}
|
||||
else:
|
||||
context = {
|
||||
'pass_url': reverse('password_login'),
|
||||
'cas_url': reverse('cas_ng_login'),
|
||||
}
|
||||
|
||||
return render(req, 'mainsite/login.html', context=context)
|
||||
|
||||
|
||||
@login_required
|
||||
def logout(req):
|
||||
CAS_BACKEND_NAME = 'django_cas_ng.backends.CASBackend'
|
||||
if req.session['_auth_user_backend'] != CAS_BACKEND_NAME:
|
||||
auth_logout(req)
|
||||
return redirect('homepage')
|
||||
return redirect('cas_ng_logout')
|
33
mainsite/static/css/plain-site.css
Normal file
33
mainsite/static/css/plain-site.css
Normal file
|
@ -0,0 +1,33 @@
|
|||
body {
|
||||
background-color: #eba367;
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
@media (min-height: 480px) {
|
||||
body {
|
||||
margin-top: 150px;
|
||||
}
|
||||
}
|
||||
|
||||
#main {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.login-btn {
|
||||
padding: 20px;
|
||||
border-radius: 15px;
|
||||
background-color: white;
|
||||
border: 3px solid #9c0635;
|
||||
color: black;
|
||||
font-size: 24px;
|
||||
width: 200px;
|
||||
height: 100px;
|
||||
margin: 30px;
|
||||
}
|
||||
|
||||
#content-area {
|
||||
background-color: white;
|
||||
width: 500px;
|
||||
padding: 50px;
|
||||
margin: auto;
|
||||
}
|
10
mainsite/templates/mainsite/login.html
Normal file
10
mainsite/templates/mainsite/login.html
Normal file
|
@ -0,0 +1,10 @@
|
|||
{% extends "plain_base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<a href="{{ cas_url }}">
|
||||
<button class="login-btn">Clipper</button>
|
||||
</a>
|
||||
<a href="{{ pass_url }}">
|
||||
<button class="login-btn">Mot de passe</button>
|
||||
</a>
|
||||
{% endblock content %}
|
17
mainsite/templates/plain_base.html
Normal file
17
mainsite/templates/plain_base.html
Normal file
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="keywords" lang="fr" content="COF,BOcal,ENS,AEENS">
|
||||
<title>Le BOcal</title>
|
||||
|
||||
<link rel="stylesheet" href="/static/css/plain-site.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="main">
|
||||
{% block content %}
|
||||
{% endblock content %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
35
mainsite/templates/registration/login.html
Normal file
35
mainsite/templates/registration/login.html
Normal file
|
@ -0,0 +1,35 @@
|
|||
{% extends "plain_base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div id="content-area">
|
||||
{% if form.errors %}
|
||||
<p>Login ou mot de passe incorrect</p>
|
||||
{% endif %}
|
||||
|
||||
{% if next %}
|
||||
{% if user.is_authenticated %}
|
||||
<p>Accès non autorisé.</p>
|
||||
{% else %}
|
||||
<p>Merci de vous connecter.</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<form method="post" action="{% url 'password_login' %}">
|
||||
{% csrf_token %}
|
||||
<table>
|
||||
<tr>
|
||||
<td>{{ form.username.label_tag }}</td>
|
||||
<td>{{ form.username }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ form.password.label_tag }}</td>
|
||||
<td>{{ form.password }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<input type="submit" value="login" />
|
||||
<input type="hidden" name="next" value="{{ next }}" />
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
Loading…
Reference in a new issue