Webhooks: fix 403 Forbidden errors (csrf check)

* csrf_exempt must be applied to View.dispatch,
  not View.post.

* In base WebhookTestCase, enable Django test Client
  enforce_csrf_checks. (Test Client by default disables
  CSRF protection.)

Closes #19
This commit is contained in:
medmunds
2016-05-31 11:54:18 -07:00
parent 34af81aee6
commit af0e36ab65
3 changed files with 19 additions and 2 deletions

View File

@@ -104,11 +104,14 @@ class AnymailBaseWebhookView(AnymailBasicAuthMixin, View):
http_method_names = ["post", "head", "options"]
@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
return super(AnymailBaseWebhookView, self).dispatch(request, *args, **kwargs)
def head(self, request, *args, **kwargs):
# Some ESPs verify the webhook with a HEAD request at configuration time
return HttpResponse()
@method_decorator(csrf_exempt)
def post(self, request, *args, **kwargs):
# Normal Django exception handling will do the right thing:
# - AnymailWebhookValidationFailure will turn into an HTTP 400 response

View File

@@ -7,6 +7,8 @@ import warnings
from base64 import b64decode
from contextlib import contextmanager
from django.test import Client
def decode_att(att):
"""Returns the original data from base64-encoded attachment content"""
@@ -142,3 +144,13 @@ class _AssertWarnsContext(object):
self.expected_regex.pattern, str(first_matching)))
self._raiseFailure("{} not triggered".format(exc_name))
class ClientWithCsrfChecks(Client):
"""Django test Client that enforces CSRF checks
https://docs.djangoproject.com/en/1.9/ref/csrf/#testing
"""
def __init__(self, **defaults):
super(ClientWithCsrfChecks, self).__init__(
enforce_csrf_checks=True, **defaults)

View File

@@ -6,7 +6,7 @@ from mock import create_autospec, ANY
from anymail.exceptions import AnymailInsecureWebhookWarning
from anymail.signals import tracking, inbound
from .utils import AnymailTestMixin
from .utils import AnymailTestMixin, ClientWithCsrfChecks
def event_handler(sender, event, esp_name, **kwargs):
@@ -22,6 +22,8 @@ class WebhookTestCase(AnymailTestMixin, SimpleTestCase):
- sets up basic auth by default (since most ESP webhooks warn if it's not enabled)
"""
client_class = ClientWithCsrfChecks
def setUp(self):
super(WebhookTestCase, self).setUp()
# Use correct basic auth by default (individual tests can override):