Cerrar sesión SAML

parent 7e085fdf
Pipeline #427 passed with stage
in 8 seconds
......@@ -18,6 +18,7 @@ django-crispy-forms = "==1.7.2"
django-summernote = "*"
django-templated-email = "*"
pypandoc = "*"
django-annoying = "*"
[requires]
python_version = "3.7"
{
"_meta": {
"hash": {
"sha256": "1384080fab35e45a327687b8d4bdda953df7f2739799216cbea0d643754944d3"
"sha256": "4449b80f25d66ee94c09828817afdfc6562ebf9657c6fe99d79b9d3215e0753c"
},
"pipfile-spec": 6,
"requires": {
......@@ -66,6 +66,14 @@
"index": "pypi",
"version": "==2.2.6"
},
"django-annoying": {
"hashes": [
"sha256:3654d16f9e2f86a2f8688820bcf6d797c93db89197a117b1930d350e7a9509dd",
"sha256:d9fe882258bf7278915e7835b4f93e12e7fd9b14c226eb06e210f9542aa5de5b"
],
"index": "pypi",
"version": "==0.10.5"
},
"django-crispy-forms": {
"hashes": [
"sha256:5952bab971110d0b86c278132dae0aa095beee8f723e625c3d3fa28888f1675f",
......
from django.contrib.auth import views as auth_views
from django.urls import path
from . import views
urlpatterns = [
# Evita que un usuario ya autenticado pueda volver a la página de inicio de sesión
path(
......@@ -9,6 +11,10 @@ urlpatterns = [
auth_views.LoginView.as_view(redirect_authenticated_user=True),
name="login",
),
# Logout personalizado para solicitar el fin de la sesión SAML.
path("logout/", views.LogoutView.as_view(), name="logout"),
# Finalizar la sesión SAML.
path("sls/", views.SlsView.as_view(), name="sls"),
# Muestra los metadatos para el Proveedor de Identidad (IdP) de SAML.
path("metadata", views.metadata_xml, name="metadata"),
# Muestra los datos del usuario.
......
from annoying.functions import get_config
from django.contrib.auth import logout
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponse
from django.shortcuts import render
from django.urls import reverse
from django.views.generic.base import View
from social_django.utils import load_strategy, load_backend
from django.shortcuts import redirect, render
from django.urls import reverse, reverse_lazy
from django.utils.decorators import method_decorator
from django.views.decorators.cache import never_cache
from django.views.generic.base import RedirectView, View
from social_django.utils import load_backend, load_strategy
def metadata_xml(request):
"""Muestra los metadatos para el Proveedor de Identidad (IdP) de SAML"""
"""Muestra los metadatos para el Proveedor de Identidad (IdP) de SAML."""
complete_url = reverse("social:complete", args=("saml",))
saml_backend = load_backend(
load_strategy(request), "saml", redirect_uri=complete_url
)
metadata, errors = saml_backend.generate_metadata_xml()
if not errors:
return HttpResponse(content=metadata, content_type="text/xml")
if errors:
raise Exception("\n".join(errors))
return HttpResponse(content=metadata, content_type="text/xml")
class UserdataView(LoginRequiredMixin, View):
......@@ -27,3 +32,54 @@ class UserdataView(LoginRequiredMixin, View):
for field in request.user._meta.fields
}
return render(request, "registration/userdata.html", context=context)
@method_decorator(never_cache, name="dispatch")
class LogoutView(LoginRequiredMixin, RedirectView):
"""Log out the current user.
This view logs out a locally authenticated user,
or sends a Logout request to the SAML2 Identity Provider.
"""
url = reverse_lazy(get_config("LOGOUT_REDIRECT_URL"))
def get(self, request, *args, **kwargs):
saml_backend = load_backend(
load_strategy(request), "saml", redirect_uri="/accounts/sls/"
)
# As of now, this code only handles the first association.
association = request.user.social_auth.first()
if association:
idp_name = association.uid.split(":")[0]
sls_url = saml_backend.request_logout(idp_name, association)
return redirect(sls_url)
logout(request)
return super().get(request, *args, **kwargs)
@method_decorator(never_cache, name="dispatch")
class SlsView(View):
"""
The Single Logout Service processes the Logout response from the Identity Provider.
The logout request may have been generated by this Service Provider, or other SP.
"""
url = reverse_lazy(get_config("LOGOUT_REDIRECT_URL"))
def get(self, request, *args, **kwargs):
saml_backend = load_backend(
load_strategy(request), "saml", redirect_uri=str(self.url)
)
# As of now, this code only handles the first association.
association = request.user.social_auth.first()
idp_name = association.uid.split(":")[0]
_, errors = saml_backend.process_logout(idp_name, None)
if errors:
messages = "\n".join(errors)
raise Exception(messages)
logout(request)
return redirect(str(self.url))
......@@ -34,7 +34,7 @@ DEBUG = os.environ.get("DEBUG", False) == "True"
ALLOWED_HOSTS = [] # ['*']
DEFAULT_FROM_EMAIL = "leocricia@manhattan.local"
DEFAULT_FROM_EMAIL = "La Maestra <leocricia@manhattan.local>"
# Production value: 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
EMAIL_HOST = "smtp.manhattan.local"
......@@ -205,6 +205,7 @@ SOCIAL_AUTH_SAML_ENABLED_IDPS = {
"lord": {
"entity_id": "https://FIXME.idp.com/saml2/idp/metadata.php",
"url": "https://FIXME.idp.com/saml2/idp/SSOService.php",
"slo_url": "https://FIXME.idp.com/saml2/idp/SingleLogoutService.php",
"x509cert": "Lovely spam, wonderful spam",
"attr_user_permanent_id": "uid",
"attr_full_name": "cn", # "urn:oid:2.5.4.3"
......
......@@ -3,6 +3,7 @@ certifi==2019.9.11
chardet==3.0.4
cx-oracle==7.2.3
defusedxml==0.6.0 ; python_version >= '3.0'
django-annoying==0.10.5
django-crispy-forms==1.7.2
django-render-block==0.6
django-summernote==0.8.11.4
......
......@@ -12,10 +12,11 @@
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
crossorigin="anonymous"
/>
{# SubResource Integrity: openssl dgst -sha384 -binary FICHERO | openssl base64 #}
<link
rel="stylesheet"
href="https://use.fontawesome.com/releases/v5.5.0/css/all.css"
integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU"
href="https://use.fontawesome.com/releases/v5.11.2/css/all.css"
integrity="sha384-KA6wR/X5RY4zFAHpv/CnoG2UW1uogYfdnP67Uv7eULvTveboZJg0qUpmJZb5VqzN"
crossorigin="anonymous"
/>
<link rel="stylesheet" href="{% static 'css/base.css' %}" />
......@@ -39,7 +40,7 @@
<meta
name="description"
content="{% block description %}Proyectos de innovación docente{% endblock description %}"
content="{% block description %}{% trans 'Proyectos de innovación docente' %}{% endblock description %}"
/>
<meta
name="author"
......@@ -52,6 +53,7 @@
<a class="navbar-brand" href="http://www.unizar.es">
<span class="icon-logoUZ"></span> <span class="screen-reader">{% trans "Universidad de Zaragoza" %}</span>
</a>
<button
class="navbar-toggler"
type="button"
......@@ -63,47 +65,59 @@
>
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav ml-auto">
{% if user.is_authenticated %}
<ul class="navbar-nav" style="margin-left: 150px;">
<li class="nav-item">
{% now "Y" as anyo_actual %}
<a class="nav-link" href="{% url 'mis_proyectos' anyo_actual %}">
<span class="fas fa-project-diagram"></span> &nbsp;{% trans "Mis proyectos" %}
<a class="nav-link" href="{% url 'home' %}">
<span class="fas fa-project-diagram"></span>&nbsp;
{% trans "Proyectos de Innovación Docente" %}
</a>
</li>
</ul>
<ul class="navbar-nav ml-auto">
{% if user.is_authenticated %}
<li class="nav-item">
{% now "Y" as anyo_actual %}
<a class="nav-link" href="{% url 'mis_proyectos' anyo_actual %}">
<span class="fas fa-project-diagram"></span> &nbsp;{% trans "Mis proyectos" %}
</a>
</li>
{% endif %}
<li class="nav-item">
<a class="nav-link" href="{% url 'ayuda' %}"
><span class="fas fa-question-circle"></span> &nbsp;{% trans "Ayuda" %}</a
>
<a class="nav-link" href="{% url 'ayuda' %}">
<span class="fas fa-question-circle"></span>&nbsp; {% trans "Ayuda" %}
</a>
</li>
<li class="nav-item">
{% if user.is_authenticated %}
<a
class="nav-link dropdown-toggle"
href="#"
id="userMenu"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
<span class="fas fa-user"></span>&nbsp; {{ user.username }}
</a>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="userMenu">
<a class="dropdown-item" href="{% url 'password_change' %}"
><span class="fas fa-key"></span> {% trans "Cambiar contraseña" %}</a
>
<div class="dropdown-divider"></div>
{# Follow https://github.com/python-social-auth/social-core/issues/199 #}
<a class="dropdown-item" href="{% url 'logout' %}"
><span class="fas fa-sign-out-alt"></span> {% trans "Cerrar sesión" %}</a
<a
class="nav-link dropdown-toggle"
href="#"
id="userMenu"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
</div>
<span class="fas fa-user"></span>&nbsp; {{ user.username }}
</a>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="userMenu">
{% if not user.social_auth.get %}
<a class="dropdown-item" href="{% url 'password_change' %}">
<span class="fas fa-key"></span> {% trans "Cambiar contraseña" %}
</a>
<div class="dropdown-divider"></div>
{% endif %}
{# Follow https://github.com/python-social-auth/social-core/issues/199 #}
<a class="dropdown-item" href="{% url 'logout' %}">
<span class="fas fa-sign-out-alt"></span> {% trans "Cerrar sesión" %}
</a>
</div>
{% else %}
<a class="nav-link" href="{% lord_url %}"
><span class="fas fa-sign-in-alt"></span> &nbsp;{% trans "Iniciar sesión" %}</a
>
<a class="nav-link" href="{% lord_url %}">
<span class="fas fa-sign-in-alt"></span>&nbsp; {% trans "Iniciar sesión" %}
</a>
{% endif %}
</li>
</ul>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment