From 058fd28db8d6abcab9c5fa88bb207f534bb54d95 Mon Sep 17 00:00:00 2001
From: Tanner Prestegard <tanner.prestegard@ligo.org>
Date: Tue, 9 Apr 2019 13:46:56 -0500
Subject: [PATCH] Prevent certificate or basic auth on AJAX requests to the API

Discovered that AJAX requests to the API from the web view were
using certificates in people's browsers even if they were logged
out of the Django session.  So when they wanted to view the page
as a public user they still saw some extra information.

No security risk since they needed to have a valid certificate
anyway, but a bit annoying.
---
 gracedb/api/backends.py | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/gracedb/api/backends.py b/gracedb/api/backends.py
index 02f6df921..5b2d2fffe 100644
--- a/gracedb/api/backends.py
+++ b/gracedb/api/backends.py
@@ -22,6 +22,7 @@ logger = logging.getLogger(__name__)
 
 
 class GraceDbBasicAuthentication(authentication.BasicAuthentication):
+    allow_ajax = False
     api_only = True
 
     def authenticate(self, request, *args, **kwargs):
@@ -33,6 +34,11 @@ class GraceDbBasicAuthentication(authentication.BasicAuthentication):
         if self.api_only and not is_api_request(request.path):
             return None
 
+        # Don't allow this auth type for AJAX requests, since we don't want it
+        # to work for API requests made by the web views.
+        if request.is_ajax() and not self.allow_ajax:
+            return None
+
         # Call base class authenticate() method
         return super(GraceDbBasicAuthentication, self).authenticate(request)
 
@@ -62,6 +68,7 @@ class GraceDbX509Authentication(authentication.BaseAuthentication):
     Authentication based on X509 certificate subject.
     Certificate should be verified by Apache already.
     """
+    allow_ajax = False
     api_only = True
     www_authenticate_realm = 'api'
     subject_dn_header = getattr(settings, 'X509_SUBJECT_DN_HEADER',
@@ -75,6 +82,13 @@ class GraceDbX509Authentication(authentication.BaseAuthentication):
         if self.api_only and not is_api_request(request.path):
             return None
 
+        # Don't allow this auth type for AJAX requests - this is because
+        # users with certificates in their browser can still authenticate via
+        # this mechanism in the web view (since it makes API queries), even
+        # when they are not logged in.
+        if request.is_ajax() and not self.allow_ajax:
+            return None
+
         # Try to get credentials from request headers.
         user_cert_dn = self.get_cert_dn_from_request(request)
 
@@ -166,6 +180,7 @@ class GraceDbX509CertInfosAuthentication(GraceDbX509Authentication):
     Authentication based on X509 "infos" header.
     Certificate should be verified by Traefik already.
     """
+    allow_ajax = False
     api_only = True
     infos_header = getattr(settings, 'X509_INFOS_HEADER',
         'HTTP_X_FORWARDED_TLS_CLIENT_CERT_INFOS')
-- 
GitLab