Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sécurité: activation de l'intergiciel LoginRequiredMiddleware #5178

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.auth.middleware.LoginRequiredMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
# Third party
Expand Down
27 changes: 22 additions & 5 deletions config/urls.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from anymail.webhooks.mailjet import MailjetTrackingWebhookView
from django.conf import settings
from django.contrib import admin
from django.contrib.auth.decorators import login_not_required
from django.urls import include, path, re_path, register_converter
from django.views.generic import TemplateView

Expand Down Expand Up @@ -88,13 +89,29 @@
path("versions/", include("itou.www.releases.urls")),
# Enable Mailjet status tracking
# https://anymail.readthedocs.io/en/stable/esps/mailjet/#status-tracking-webhooks
path("webhooks/anymail/mailjet/tracking/", MailjetTrackingWebhookView.as_view()),
path("webhooks/anymail/mailjet/tracking/", login_not_required(MailjetTrackingWebhookView.as_view())),
path("welcoming_tour/", include("itou.www.welcoming_tour.urls")),
# Static pages.
path("accessibility/", TemplateView.as_view(template_name="static/accessibility.html"), name="accessibility"),
path("legal/notice/", TemplateView.as_view(template_name="static/legal/notice.html"), name="legal-notice"),
path("legal/privacy/", TemplateView.as_view(template_name="static/legal/privacy.html"), name="legal-privacy"),
path("legal/terms/", TemplateView.as_view(template_name="static/legal/terms.html"), name="legal-terms"),
path(
"accessibility/",
login_not_required(TemplateView.as_view(template_name="static/accessibility.html")),
name="accessibility",
),
path(
"legal/notice/",
login_not_required(TemplateView.as_view(template_name="static/legal/notice.html")),
name="legal-notice",
),
path(
"legal/privacy/",
login_not_required(TemplateView.as_view(template_name="static/legal/privacy.html")),
name="legal-privacy",
),
path(
"legal/terms/",
login_not_required(TemplateView.as_view(template_name="static/legal/terms.html")),
name="legal-terms",
),
path("", include("itou.www.security.urls")),
path("gps/", include("itou.www.gps.urls")),
path("rdvi/", include("itou.www.rdv_insertion.urls")),
Expand Down
3 changes: 2 additions & 1 deletion itou/api/applicants_api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@
from itou.job_applications.models import JobApplication
from itou.users.enums import UserKind
from itou.users.models import User
from itou.utils.auth import LoginNotRequiredMixin

from .perms import ApplicantsAPIPermission
from .serializers import APIParametersSerializer, ApplicantSerializer


class ApplicantsView(generics.ListAPIView):
class ApplicantsView(LoginNotRequiredMixin, generics.ListAPIView):
authentication_classes = (
authentication.TokenAuthentication,
authentication.SessionAuthentication,
Expand Down
3 changes: 2 additions & 1 deletion itou/api/c4_api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from itou.api.c4_api.serializers import C4CompanySerializer
from itou.companies.enums import COMPANY_KIND_RESERVED
from itou.companies.models import Company, CompanyMembership
from itou.utils.auth import LoginNotRequiredMixin


class C4APIUser(AnonymousUser):
Expand All @@ -27,7 +28,7 @@ def authenticate_credentials(self, key):
return C4APIUser(), None


class C4CompanyView(generics.ListAPIView):
class C4CompanyView(LoginNotRequiredMixin, generics.ListAPIView):
"""API pour le Marché de l'inclusion"""

authentication_classes = [C4Authentication]
Expand Down
3 changes: 2 additions & 1 deletion itou/api/data_inclusion_api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from itou.api.data_inclusion_api import enums, serializers
from itou.companies.models import Company
from itou.prescribers.models import PrescriberOrganization
from itou.utils.auth import LoginNotRequiredMixin


@extend_schema(
Expand All @@ -18,7 +19,7 @@
many=True,
)
)
class DataInclusionStructureView(generics.ListAPIView):
class DataInclusionStructureView(LoginNotRequiredMixin, generics.ListAPIView):
"""
# API au format data.inclusion

Expand Down
3 changes: 2 additions & 1 deletion itou/api/employee_record_api/viewsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from itou.api import AUTH_TOKEN_EXPLANATION_TEXT
from itou.employee_record.models import EmployeeRecord, EmployeeRecordUpdateNotification, Status
from itou.utils.auth import LoginNotRequiredMixin

from .perms import EmployeeRecordAPIPermission
from .serializers import EmployeeRecordAPISerializer, EmployeeRecordUpdateNotificationAPISerializer
Expand All @@ -22,7 +23,7 @@ class EmployeeRecordRateThrottle(UserRateThrottle):
rate = "60/min"


class AbstractEmployeeRecordViewSet(viewsets.ReadOnlyModelViewSet):
class AbstractEmployeeRecordViewSet(LoginNotRequiredMixin, viewsets.ReadOnlyModelViewSet):
throttle_classes = [EmployeeRecordRateThrottle]

# Possible authentication frameworks:
Expand Down
3 changes: 2 additions & 1 deletion itou/api/geiq/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from itou.companies.models import Company
from itou.job_applications.enums import JobApplicationState, Prequalification, ProfessionalSituationExperience
from itou.job_applications.models import JobApplication, PriorAction
from itou.utils.auth import LoginNotRequiredMixin
from itou.utils.validators import validate_siren

from .serializers import GeiqJobApplicationSerializer
Expand Down Expand Up @@ -41,7 +42,7 @@ class InvalidSirenError(exceptions.APIException):
status_code = status.HTTP_400_BAD_REQUEST


class GeiqJobApplicationListView(generics.ListAPIView):
class GeiqJobApplicationListView(LoginNotRequiredMixin, generics.ListAPIView):
authentication_classes = (
GeiqApiAuthentication,
authentication.SessionAuthentication,
Expand Down
4 changes: 3 additions & 1 deletion itou/api/redoc_views.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from django.templatetags.static import static
from drf_spectacular.views import SpectacularRedocView

from itou.utils.auth import LoginNotRequiredMixin

class ItouSpectacularRedocView(SpectacularRedocView):

class ItouSpectacularRedocView(LoginNotRequiredMixin, SpectacularRedocView):
@staticmethod
def _redoc_standalone():
return static("vendor/redoc/redoc.standalone.js")
3 changes: 2 additions & 1 deletion itou/api/siae_api/viewsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from itou.cities.models import City
from itou.common_apps.address.departments import DEPARTMENTS
from itou.companies.models import Company, JobDescription
from itou.utils.auth import LoginNotRequiredMixin

from .serializers import SiaeSerializer

Expand Down Expand Up @@ -119,7 +120,7 @@ class RestrictedUserRateThrottle(UserRateThrottle):
rate = "12/minute"


class SiaeViewSet(viewsets.ReadOnlyModelViewSet):
class SiaeViewSet(LoginNotRequiredMixin, viewsets.ReadOnlyModelViewSet):
"""
# Liste des SIAE

Expand Down
3 changes: 2 additions & 1 deletion itou/api/token_auth/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from rest_framework.response import Response

from itou.api import AUTH_TOKEN_EXPLANATION_TEXT
from itou.utils.auth import LoginNotRequiredMixin


logger = logging.getLogger(__name__)
Expand All @@ -14,7 +15,7 @@
TOKEN_ID_STR = "__token__"


class ObtainAuthToken(drf_authtoken_views.ObtainAuthToken):
class ObtainAuthToken(LoginNotRequiredMixin, drf_authtoken_views.ObtainAuthToken):
def post(self, request, *args, **kwargs):
if request.data.get("username") == TOKEN_ID_STR:
password = request.data.get("password")
Expand Down
3 changes: 2 additions & 1 deletion itou/api/urls.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.contrib.auth.decorators import login_not_required
from django.urls import include, path
from drf_spectacular.views import SpectacularAPIView
from rest_framework import routers
Expand Down Expand Up @@ -41,7 +42,7 @@
# OAS 3 YAML schema (downloadable)
path(
"oas3/",
SpectacularAPIView.as_view(),
login_not_required(SpectacularAPIView.as_view()),
name="openapi_schema",
),
path(
Expand Down
4 changes: 4 additions & 0 deletions itou/openid_connect/france_connect/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from django.conf import settings
from django.contrib import messages
from django.contrib.auth import login
from django.contrib.auth.decorators import login_not_required
from django.http import HttpResponseRedirect, JsonResponse
from django.urls import reverse
from django.utils import crypto
Expand Down Expand Up @@ -35,6 +36,7 @@ def _redirect_to_job_seeker_login_on_error(error_msg, request=None, extra_tags="
return HttpResponseRedirect(reverse("login:job_seeker"))


@login_not_required
def france_connect_authorize(request):
# The redirect_uri should be defined in the FC settings to be allowed
# NB: the integration platform allows "http://127.0.0.1:8000/franceconnect/callback"
Expand All @@ -53,6 +55,7 @@ def france_connect_authorize(request):
return HttpResponseRedirect(f"{url}?{urlencode(data)}")


@login_not_required
def france_connect_callback(request):
code = request.GET.get("code")
if code is None:
Expand Down Expand Up @@ -157,6 +160,7 @@ def france_connect_callback(request):
return HttpResponseRedirect(next_url)


@login_not_required
def france_connect_logout(request):
# The user can be authentified on FC w/o a session on itou.
# https://partenaires.franceconnect.gouv.fr/fcp/fournisseur-service#sign_out
Expand Down
5 changes: 5 additions & 0 deletions itou/openid_connect/inclusion_connect/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from django.conf import settings
from django.contrib import messages
from django.contrib.auth import login
from django.contrib.auth.decorators import login_not_required
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.utils import crypto
Expand Down Expand Up @@ -120,6 +121,7 @@ def _add_user_kind_error_message(request, existing_user, new_user_kind):
)


@login_not_required
def inclusion_connect_authorize(request):
# Block access if ProConnect is enabled
if settings.PRO_CONNECT_BASE_URL:
Expand Down Expand Up @@ -166,6 +168,7 @@ def inclusion_connect_authorize(request):
return HttpResponseRedirect(f"{base_url}?{urlencode(data)}")


@login_not_required
def inclusion_connect_activate_account(request):
params = request.GET.copy()
email = params.get("user_email")
Expand Down Expand Up @@ -228,6 +231,7 @@ def _get_user_info(request, access_token):
return response.json(), None


@login_not_required
def inclusion_connect_callback(request):
# Block access if ProConnect is enabled
if settings.PRO_CONNECT_BASE_URL:
Expand Down Expand Up @@ -356,6 +360,7 @@ def inclusion_connect_callback(request):
return HttpResponseRedirect(next_url)


@login_not_required
def inclusion_connect_logout(request):
token = request.GET.get("token")
post_logout_redirect_url = request.GET.get("redirect_url", reverse("search:employers_home"))
Expand Down
5 changes: 5 additions & 0 deletions itou/openid_connect/pe_connect/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from django.conf import settings
from django.contrib import messages
from django.contrib.auth import login
from django.contrib.auth.decorators import login_not_required
from django.http import HttpResponseRedirect, JsonResponse
from django.shortcuts import render
from django.urls import reverse
Expand Down Expand Up @@ -39,6 +40,7 @@ def _redirect_to_job_seeker_login_on_error(error_msg, request=None, extra_tags="
return HttpResponseRedirect(reverse("login:job_seeker"))


@login_not_required
def pe_connect_authorize(request):
# The redirect_uri should be defined in the PEAMU settings to be allowed
# NB: the integration platform allows "http://127.0.0.1:8000/pe_connect/callback"
Expand All @@ -57,6 +59,7 @@ def pe_connect_authorize(request):
return HttpResponseRedirect(f"{url}?{urlencode(data)}")


@login_not_required
def pe_connect_callback(request):
code = request.GET.get("code")
if code is None:
Expand Down Expand Up @@ -180,10 +183,12 @@ def pe_connect_callback(request):
return HttpResponseRedirect(next_url)


@login_not_required
def pe_connect_no_email(request, template_name="account/peamu_no_email.html"):
return render(request, template_name)


@login_not_required
def pe_connect_logout(request):
id_token = request.GET.get("id_token")

Expand Down
5 changes: 5 additions & 0 deletions itou/openid_connect/pro_connect/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from django.conf import settings
from django.contrib import messages
from django.contrib.auth import login
from django.contrib.auth.decorators import login_not_required
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.utils import crypto
Expand Down Expand Up @@ -109,6 +110,7 @@ def _add_user_kind_error_message(request, existing_user, new_user_kind):
)


@login_not_required
def pro_connect_authorize(request):
# Start a new session.
user_kind = request.GET.get("user_kind")
Expand Down Expand Up @@ -185,6 +187,7 @@ def _get_user_info(request, access_token):
return decoded_id_token, None


@login_not_required
def pro_connect_callback(request):
code = request.GET.get("code")
state = request.GET.get("state")
Expand Down Expand Up @@ -307,6 +310,7 @@ def pro_connect_callback(request):
return HttpResponseRedirect(next_url)


@login_not_required
def pro_connect_logout(request):
token = request.GET.get("token")
post_logout_redirect_url = reverse("pro_connect:logout_callback")
Expand All @@ -330,6 +334,7 @@ def pro_connect_logout(request):
return HttpResponseRedirect(complete_url)


@login_not_required
def pro_connect_logout_callback(request):
state = request.GET.get("state")
if state is None:
Expand Down
2 changes: 2 additions & 0 deletions itou/status/views.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from django.contrib.auth.decorators import login_not_required
from django.shortcuts import render

from . import models, probes


@login_not_required
def index(request):
probes_classes = sorted(probes.get_probes_classes(), key=lambda p: p.name)
probes_status_by_name = {ps.name: ps for ps in models.ProbeStatus.objects.all()}
Expand Down
8 changes: 8 additions & 0 deletions itou/utils/auth.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from functools import wraps

from django.contrib.auth.decorators import login_not_required
from django.core.exceptions import PermissionDenied


Expand All @@ -15,3 +16,10 @@ def _check_user_view_wrapper(request, *args, **kwargs):
return wraps(view_func)(_check_user_view_wrapper)

return decorator


class LoginNotRequiredMixin:
@classmethod
def as_view(cls, *args, **kwargs):
view = super().as_view(*args, **kwargs)
return login_not_required(view)
Comment on lines +21 to +25
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

2 changes: 2 additions & 0 deletions itou/utils/redirect_legacy_views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from django.contrib.auth.decorators import login_not_required
from django.http import HttpResponsePermanentRedirect


@login_not_required
def redirect_siaes_views(request, *args, **kwargs):
return HttpResponsePermanentRedirect(request.get_full_path().replace("/siae", "/company", 1))
3 changes: 2 additions & 1 deletion itou/www/announcements/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@

from itou.communications.models import AnnouncementCampaign, AnnouncementItem
from itou.users.enums import UserKind
from itou.utils.auth import LoginNotRequiredMixin
from itou.utils.pagination import pager
from itou.utils.urls import get_safe_url


class NewsView(TemplateView):
class NewsView(LoginNotRequiredMixin, TemplateView):
template_name = "announcements/news.html"

def get_context_data(self):
Expand Down
Loading
Loading