How to get Twilio's RequestValidator to work - python

I'm not sure why this doesn't work. I have been looking at Twilio's documentation here, and I tried just making it a function call, but that didn't work, so I put it directly in my view, and it still didn't work. It always returns 403.
I have verified that my auth token is the same as what is on Twilio as well.
from braces.views import CsrfExemptMixin
from django.http import HttpResponse, HttpResponseForbidden
from twilio.util import RequestValidator
from secretphone.settings import TWILIO_AUTH_TOKEN
class SMSWebhook(CsrfExemptMixin, View):
def post(self, request):
validator = RequestValidator(TWILIO_AUTH_TOKEN)
request_valid = validator.validate(
request.build_absolute_uri(),
request.POST,
request.META.get('HTTP_X_TWILIO_SIGNATURE', '')
)
if not request_valid:
return HttpResponseForbidden()

So that nobody has the same problem I did, and no answer, apparently ngrok's https URL does not get passed through to django. My problem was that my webhook was passed using ngrok's https link, but when it got to my app, it changed to an http link. My guess is that request.build_absolute_uri() gets the protocol from django(webserver) itself, which uses http as the protocol.
So anyone having this problem while using ngrok, make sure you are not using the https link.

Related

Why isn't my POST Webhook working in Django?

I use the app Salesmate and am trying to write a a client on my site that adds features through the API. For this to work I need Salesmate's Webhooks. My client is in Django.
When I send a GET request webhook it makes it into my client.
When I send a POST request webhook it never makes it into the view.
When I send a test POST request from https://reqbin.com/ it makes it into the view and performs as expected.
I've played endlessly with the JSON body and headers. There could still be something I'm missing here, or there could be a flag raised in Django invalidating the sender, or something else...
Here is Salesmate webhook request, in the app. I've played with many headers, and sent requests with and without JSON bodies.
[deleted for privacy]
Here is my django view. Super simple, but it never gets called.
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
#csrf_exempt
def pab(request):
#Do something simple and trackable
return HttpResponse(keep)
I was using the Django module "Moderna" which was causing some issues, still not sure what. I started a naked django app and it started working.

Django REST: OPTIONS request is registered as PUT

Whenever the browser sends an OPTIONS request, Django REST registers that as a PUT request.
I was writing my permission code when I noticed it. I use the default request parameter that is passed into the def has_object_permission( self, request, view, obj ):.
Using request.method will return the correct request method for every request except for OPTIONS.
However, when I use request.method in a my get_permission( self, request, view ): function in a different part of the project, correct response is returned. Could there be something wrong with the has_object_permission() function?
Currently I just check if the request is PUT, as I believe PUT requests are not used by Django anyway. But it would be nice if I could use the actual name instead.
My Django REST version is 3.9.0
OPTIONS requests are often used for what are called "pre-flight" requests in Cross-origin resource sharing (CORS). This is not anything wrong with has_object_permission(), it's just that these pre-flight requests are probably not intended to handled by your view. There is a more detailed answer in this SO post: https://stackoverflow.com/a/29954326/784648

How to pass CSRF token between django applications by reading it from request using urllib

How to pass CSRF token between Django applications by reading it from request using urllib.
I am having two servers running with Django applications, based on URL need to send request to other server and give the response back.
Django middelware either returns None or Response.
In case of None: it processes request on same server.
In case of Response: it sends the response bake to client and bypassing request to same server.
Say I have two servers "S1" and "S2", and for URL ("/user/1/profile") I have to send request to "S2".
I am doing request cloning in django middleware which checks the matching URL and makes https request(using urllib) with all cookies and headers to "S2" server and sending response back by converting it from urllib-response to django-response.
With "GET" requests its working fine, but I am getting "403 CSRF" with "POST" requests.
Any suggestions what I am missing here.
As I understand you are building a REST api.
The DjangoCSRF Token is browser dedicated.
You can disable the DjangoCsrf Protection by adding the csrf_exempt decorator
From the docs:
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
#csrf_exempt
def my_view(request):
return HttpResponse('Hello world')
But you should consider using the Django Rest Framework And it's Authentication Methods for improved security.

Django, Testing Redirects to External Pages

I have a routing rule in my Django app for downloads that redirect to a external CDN. I am now writing tests for my app, and I want to test that the route does successfully redirect to the configured url in my Django settings. Here is a simplified example that should help explain what I'm trying to do:
from django.test import SimpleTestCase
from django.test.client import Client
from django.conf import settings
class MyTestCase(SimpleTestCase):
def setUp(self):
self.client = Client()
def test_download(self):
response = self.client.get('/download/mac/')
self.assertRedirects(response, settings.URLS.get('mac'))
Now this doesn't work, the redirect gets a 404 even though when I print settings.DOWNLOAD_URL in this method it is correct, and a copy/paste into the browser proves it works. I started to look into why it wasn't working, and I noticed this in the Django source code:
Note that assertRedirects won't work for external links since it uses
TestClient to do a request.
So then, how does one test these redirects? I'm not looking for anything super fancy, what I expect to check is the response's status_code and location. I saw that response has a follow parameter, and tried something like this, but it still didn't work:
def test_download(self):
response = self.client.get('/download/mac/', follow=True)
self.assertEqual(response.status_code, 302)
self.assertEqual(response['Location'], settings.URLS.get('mac')
It was requested that I include the relevant parts from my urls.py and views.py, here they are:
# urls.py
from django.conf.urls import patterns, url
urlpatterns = patterns('myapp.views',
url(r'^download/(?P<platform>\w+)/$', 'download_app', name='download'),
)
#views.py
from django.conf import settings
from django.shortcuts import redirect
from django.http import Http404
def download_app(request, platform):
if platform in settings.URLS:
return redirect( settings.URLS.get(platform) )
else:
raise Http404
Any help in solving this would be much appreciated. Thanks in advance.
Probably the original poster has solved his problems and moved on long ago, but the solution here is to not specify follow=True as he did in the alternative proposal that didn't work either.
The following will simply check that the view being tested redirects as expected, without relying on the external resources.
def test_download(self):
response = self.client.get('/download/mac')
self.assertEqual(response.status_code, 302)
self.assertEqual(response['Location'], 'http://external/resource')
In Django 1.7 assertRedirect got a new parameter fetch_redirect_response which can be set to False to get the same effect, but I haven't tried it myself.

Adding csrf_token to my post request from iPhone app

I have an iPhone application from which I would like to call a post service passing parameters in its request, doing so caused a server error 500.
I have read Django documentation here and I still haven't figure out how to get a csrf_token and how to add it to the AFNetworking AFHTTPRequestOperationManager POST method.
On the server side I've added django.middleware.csrf.CsrfViewMiddleware in the MIDDLEWARE_CLASSES section, but it doesn't seem to do the trick.
My view looks like this; I am not doing much, just hoping to pass.
from django.core.context_processors import csrf
from django.shortcuts import render_to_response
def foo(request):
c={}
c.update(csrf(request))
if request.method == 'POST':
return HttpResponseRedirect("Post received");
The Django CSRF Middleware uses cookies and forms and whatnot to send a code to the page, then make sure the correct page is the one sending information back. In both cases, you must do a GET request to the server, and if you have the middleware installed correctly, it will put the CSRF token into a cookie for you.
Check out the documentation for more info on this.
Now, I noticed you're using a library that uses NSURLConnection, so that should handle cookies for you. I got this bundle of code (untested) that lets you pull the cookie name that you specify in your settings file (again, check out the documentation link above) then put that in your POST.
NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL: networkServerAddress];
for (NSHTTPCookie *cookie in cookies)
{
// get the right cookie
}
Of course, if you're only making POSTs and never GETs first, you don't have a CSRF token to send!
And that's why we have the #csrf_exempt tag. (Docs here) This is the way to go 99% of the time, since most apps you won't do a GET before you do a POST. (in webpages you have to do a GET first). Note that this is intended only when an app is sending only POSTs and there's no session to speak of. You really need to think about your own security when using this, and how you verify that a given app/user really is who they claim to be. And how you disable people from hitting this URL from a webbrowser.
TLDR: Probably use #csrf_exempt on the view, but be careful.

Categories