Description: Security fix for webhook authorization timing attack 
   * Security fix for timing attack on WEBHOOK_AUTHORIZATION secret (no CVE
     assigned) as described in https://github.com/anymail/django-anymail/
     releases/tag/v1.2.1 (Closes: #889450)
Author: Scott Kitterman <scott@kitterman.com>
Bug-Debian: http://bugs.debian.org/889450
Origin: upstream, https://github.com/anymail/django-anymail/commit/c07998304b4a31df4c61deddcb03d3607a04691b
Forwarded: not-needed

--- django-anymail-0.8.orig/anymail/webhooks/base.py
+++ django-anymail-0.8/anymail/webhooks/base.py
@@ -3,6 +3,7 @@ import warnings
 
 import six
 from django.http import HttpResponse
+from django.utils.crypto import constant_time_compare
 from django.utils.decorators import method_decorator
 from django.views.decorators.csrf import csrf_exempt
 from django.views.generic import View
@@ -41,8 +42,13 @@ class AnymailBasicAuthMixin(object):
     def validate_request(self, request):
         """If configured for webhook basic auth, validate request has correct auth."""
         if self.basic_auth:
-            basic_auth = get_request_basic_auth(request)
-            if basic_auth is None or basic_auth not in self.basic_auth:
+            request_auth = get_request_basic_auth(request)
+            # Use constant_time_compare to avoid timing attack on basic auth. (It's OK that any()
+            # can terminate early: we're not trying to protect how many auth strings are allowed,
+            # just the contents of each individual auth string.)
+            auth_ok = any(constant_time_compare(request_auth, allowed_auth)
+                          for allowed_auth in self.basic_auth)
+            if not auth_ok:
                 # noinspection PyUnresolvedReferences
                 raise AnymailWebhookValidationFailure(
                     "Missing or invalid basic auth in Anymail %s webhook" % self.esp_name)
@@ -78,8 +84,11 @@ class AnymailBaseWebhookView(AnymailBasi
         *All* definitions of this method in the class chain (including mixins)
         will be called. There is no need to chain to the superclass.
         (See self.run_validators and collect_all_methods.)
+
+        Security note: use django.utils.crypto.constant_time_compare for string
+        comparisons, to avoid exposing your validation to a timing attack.
         """
-        # if request.POST['signature'] != expected_signature:
+        # if not constant_time_compare(request.POST['signature'], expected_signature):
         #     raise AnymailWebhookValidationFailure("...message...")
         # (else just do nothing)
         pass
