From 96a6ac85dfc554c3598ee4d04135d3ebaec45e89 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Mon, 29 Jun 2020 19:13:07 +0200 Subject: [PATCH] audit: add cleanse_dict function to ensure no passwords end in logs --- passbook/audit/models.py | 19 ++++++++++++++++++- passbook/flows/views.py | 4 ++-- passbook/stages/password/views.py | 2 +- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/passbook/audit/models.py b/passbook/audit/models.py index 4c211e6a3..e5dfebab6 100644 --- a/passbook/audit/models.py +++ b/passbook/audit/models.py @@ -12,6 +12,7 @@ from django.core.exceptions import ValidationError from django.db import models from django.http import HttpRequest from django.utils.translation import gettext as _ +from django.views.debug import CLEANSED_SUBSTITUTE, HIDDEN_SETTINGS from guardian.shortcuts import get_anonymous_user from structlog import get_logger @@ -20,6 +21,22 @@ from passbook.lib.utils.http import get_client_ip LOGGER = get_logger() +def cleanse_dict(source: Dict[Any, Any]) -> Dict[Any, Any]: + """Cleanse a dictionary, recursively""" + final_dict = {} + for key, value in source.items(): + try: + if HIDDEN_SETTINGS.search(key): + final_dict[key] = CLEANSED_SUBSTITUTE + else: + final_dict[key] = value + except TypeError: + final_dict[key] = value + if isinstance(value, dict): + final_dict[key] = cleanse_dict(value) + return final_dict + + def sanitize_dict(source: Dict[Any, Any]) -> Dict[Any, Any]: """clean source of all Models that would interfere with the JSONField. Models are replaced with a dictionary of { @@ -107,7 +124,7 @@ class Event(models.Model): ) if not app: app = getmodule(stack()[_inspect_offset][0]).__name__ - cleaned_kwargs = sanitize_dict(kwargs) + cleaned_kwargs = cleanse_dict(sanitize_dict(kwargs)) event = Event(action=action.value, app=app, context=cleaned_kwargs) return event diff --git a/passbook/flows/views.py b/passbook/flows/views.py index fa670b8be..c78f1aa38 100644 --- a/passbook/flows/views.py +++ b/passbook/flows/views.py @@ -15,7 +15,7 @@ from django.views.decorators.clickjacking import xframe_options_sameorigin from django.views.generic import TemplateView, View from structlog import get_logger -from passbook.audit.models import sanitize_dict +from passbook.audit.models import cleanse_dict from passbook.core.views.utils import PermissionDeniedView from passbook.flows.exceptions import EmptyFlowException, FlowNonApplicableException from passbook.flows.models import Flow, FlowDesignation, Stage @@ -162,7 +162,7 @@ class FlowExecutorView(View): LOGGER.debug( "f(exec): User passed all stages", flow_slug=self.flow.slug, - context=sanitize_dict(self.plan.context), + context=cleanse_dict(self.plan.context), ) return self._flow_done() diff --git a/passbook/stages/password/views.py b/passbook/stages/password/views.py index 051553ba4..98d0e77a7 100644 --- a/passbook/stages/password/views.py +++ b/passbook/stages/password/views.py @@ -22,7 +22,7 @@ class ChangeFlowInitView(LoginRequiredMixin, View): raise Http404 plan = FlowPlanner(stage.change_flow).plan( - request, {PLAN_CONTEXT_PENDING_USER: request.user,} + request, {PLAN_CONTEXT_PENDING_USER: request.user} ) request.session[SESSION_KEY_PLAN] = plan return redirect_with_qs(