django csrf_token verification with python requests module - python

I want to send post request using python requests module. Since, I use Django for backend server. So, I need verify csrf_token for post method. I know that i have option to stop csrf_token verification using Django built in decorators. But, i don't want to do that for cross site protection.
My Django Sample Code:
from django.http import HttpResponse
from django.middleware.csrf import get_token
def pv(v, s):
print(f"----------Value of {s}-------")
print(f"Type= {type(v)}")
print()
print(v)
print()
def index(request):
pv(request.COOKIES,"HttpRequest.COOKIES")
pv(request.headers,"HttpRequest.headers")
token = get_token(request) # I think, Here have some worng. But What?
return HttpResponse("Hello World")
index() is work for both get and post reequest. Though i don't use redirect() for post method in sample code. Here is my get and post request code using python requests module:
import requests
import time
def pv(obj, s):
print(f"-----Value of {s} --------")
print(type(obj))
print(obj)
print()
url = "http://192.168.0.102:8000/home/"
data = {"a":"5", "b":4}
d = requests.get(url)
time.sleep(2)
requests.post(url, cookies=d.cookies, data=data)
# For Test
pv(d.headers, "d.headers")
pv(d.cookies['csrftoken'], "d.cookies")
get request work properly and return me csrf_token.when i use this toke with post method. Django server give me Forbidden (CSRF token missing or incorrect.): /home/ error and post request doesn't work properly. How can i verify csrf_token?

Related

Django Test Client client.post() sends GET request in my Testcase

How can I submit a POST request with Django test Client? I just want to test the login function of my application. It's strange that I put
response = self.client.post(reverse('rbac:login'), data=data) in my testcase, and I want to validate it so I print response.status_code.Actually it should return 302 coz it should turn to another page. but it return 200. This situation happens when I use "python manage.py test testmodel" to test. However, if I use "python manage.py shell" to make an InteractiveConsole and write exactly the same code, it return 302 at last.
I have nearly tried all the methods provided from stack overflow, e.g. change the url, offer the content-type when I post....but these are meaningless.
from django.test import TestCase
from django.test.utils import setup_test_environment,teardown_test_environment
from django.test import Client
from django.urls import reverse
import django
from rbac.models import RbacUser, RbacRole
from system_module.models import Redeploy
from urllib import urlencode
class CreateUser(TestCase):
#classmethod
def setUp(self):
self.client = Client()
def test_create_user(self):
data = {"Username": "admin_xy", "Password": "aaa"}
response = self.client.post(reverse('rbac:login'), data=data)
print response
and it shows me 200.....
However, in interactive console:
>>> response = client.post(reverse('rbac:login'), data=data)
>>> print response.status_code
302
it shows the right result.
I want to know how to cope with this annoying problem. Thx
I expect when I use test file to test my test case, it works fine....like show 302 code.
Before sending the POST or GET request by using Client, first you need to create the user make the user active and give necessary permissions and login through client and then send the post request.
Ex: self.client.login(username='username', 'password'='password)
It's been long time that this question is here, I hope you found the answer, but for other people I'll suggest to add this to this code to be redirected:
response = self.client.post(reverse('rbac:login'), data=data, follow=True)
The follow=True will follow the redirect .

How to test `#authenticated` handler using tornado.testing?

I am new to unit testing using script. I tried to verify login with arguments in post data, but I am getting login page as response and not get logged in.Because of #tornado.web.authenticated i can't access other functions without login and it responding to login page
import tornado
from tornado.testing import AsyncTestCase
from tornado.web import Application, RequestHandler
import app
import urllib
class MyTestCase(AsyncTestCase):
#tornado.testing.gen_test
def test_http_fetch_login(self):
data = urllib.urlencode(dict(username='admin', password=''))
client = AsyncHTTPClient(self.io_loop)
response = yield client.fetch("http://localhost:8888/console/login/?", method="POST",body=data)
# Test contents of response
self.assertIn("Automaton web console", response.body)
#tornado.testing.gen_test
def test_http_fetch_config(self):
client = AsyncHTTPClient(self.io_loop)
response = yield client.fetch("http://localhost:8888/console/configuration/?")
self.assertIn("server-version",response.body)
To test code that uses #authenticated (unless you are testing the redirection to the login page itself), you need to pass a cookie (or whatever form of authentication you're using) that will be accepted by your get_current_user method. The details of this will vary depending on how exactly you are doing your authentication, but if you're using Tornado's secure cookies you'll probably use the create_signed_value function to encode a cookie.
From documentation:
If you decorate post() methods with the authenticated decorator, and the user is not logged in, the server will send a 403 response. The #authenticated decorator is simply shorthand for if not self.current_user: self.redirect() and may not be appropriate for non-browser-based login schemes.
So you can use mock do like pointed in this answer: https://stackoverflow.com/a/18286742/1090700
Another 403 status will be thrown on POST calls if you have secure_cookies=True app param. If you want to test the code in a non debug fashion, you can also using mock POST actions while keeping the secure_cookies=True application parameter and then just mock the check_xsrf_cookie Handler method as well, like this:
# Some previous stuff...
with mock.patch.object(YourSecuredHandler, 'get_secure_cookie') as mget:
mget.return_value = 'user_email'
response = self.fetch('/', method='GET')
with mock.patch.object(
YourSecuredHandler, 'check_xsrf_cookie') as mpost:
mpost.return_value = None
response = self.fetch(
url, method="POST", body=parse.urlencode(body1),
headers=headers)
self.assertEqual(response.code, 201)

Python / Flask -- server is receiving POST requests as GET requests

I created an endpoint in the flask file that looks like this
#app.route("/update", methods=['POST', 'GET'])
def update_func():
results = {
"method": request.method
}
return json.dumps(results)
I tried calling this function using both Postman and python, both are saying Flask is processing it as a get request.
import requests
r = requests.post("http://site.fakeurl.org/update", json={})
print r.json()
Is there a config file I need to change for this process as a POST request?
Is this happening to anyone else?
Did you try using http://www.site.faekurl.org/update ?
Some servers redirect http:// to http://www.-- and as a result, the POST request + it's data gets lost in the process.

Github api v3 access via python oauth2 library - Redirect issue

Environment - Python 2.7.3, webpy.
I'm trying a simple oauth 3 way authentication for github using Python web.py. Per the basic oauth guide on github I'm doing something like this:
import web,requests
import oauth2,pymongo,json
from oauth2client.client import OAuth2WebServerFlow
urls=('/', 'githublogin',
'/session','session',
'/githubcallback','githubCallback');
class githublogin:
def GET(self):
new_url = 'https://github.com/login/oauth/authorize'
pay_load = {'client_id': '',
'client_secret':'',
'scope':'gist'
}
headers = {'content-type': 'application/json'}
r = requests.get(new_url, params=pay_load, headers=headers)
return r.content
This is sending me to the GH login page. Once I sign in - GH is not redirecting me to the callback. The redirect_uri parameter is configured in the github application. I've double checked to make sure that's correct.
class githubCallback:
def POST(self):
data = web.data()
print data
def GET(self):
print "callback called"
Instead in the browser I see
http://<hostname>:8080/session
and a 404 message, because I haven't configured the session URL. That's problem no 1. Problem no 2 - If I configure the session URL and print out the post message
class session:
def POST(self):
data = web.data()
print data
def GET(self):
print "callback called"
I can see some data posted to the URL with something called 'authenticity_token'.
I've tried to use the python_oauth2 library but can't get past the authorization_url call. So I've tried this much simpler requests library. Can someone please point out to me whats going wrong here.
So here's how I solved this. Thanks to #Ivanzuzak for the requestb.in tip.
I'm using Python webpy.
import web,requests
import oauth2,json
urls=('/', 'githublogin',
'/githubcallback','githubCallback');
render = web.template.render('templates/')
class githublogin:
def GET(self):
client_id = ''
url_string = "https://github.com/login/oauth/authorize?client_id=" + client_id
return render.index(url_string)
class githubCallback:
def GET(self):
data = json.loads(json.dumps(web.input()))
print data['code']
headers = {'content-type': 'application/json'}
pay_load = {'client_id': '',
'client_secret':'',
'code' : data['code'] }
r = requests.post('https://github.com/login/oauth/access_token', data=json.dumps(pay_load), headers=headers)
token_temp = r.text.split('&')
token = token_temp[0].split('=')
access_token = token[1]
repo_url = 'https://api.github.com/user?access_token=' + access_token
response = requests.get(repo_url)
final_data = response.content
print final_data
app = web.application(urls,globals())
if __name__ == "__main__":
app.run()
I was not using a html file before, but sending the request directly from the githublogin class. That didn't work. Here I'm using a html to direct the user first from where he'll login to gh. With this I added a html and rendered it using the templator.
def with (parameter)
<html>
<head>
</head>
<body>
<p>Well, hello there!</p>
<p>We're going to now talk to the GitHub API. Ready? <a href=$parameter>Click here</a> to begin!</a></p>
<p>If that link doesn't work, remember to provide your own Client ID!</p>
</body>
</html>
This file is taken straight from the dev guide, with just the client_id parameter changed.
Another point to be noted is that in the requests.post method - passing the pay_load directly doesn't work. It has to be serialized using json.dumps.
I'm not sure what the problem is at your end, but try reproducing this flow below, first manually using the browser, and then using your python library. It will help you debug the issue.
create a request bin on http://requestb.in/. A request bin is basically a service that logs all HTTP requests sent to it. You will use this instead of the callback, to log what is being sent to the callback. Copy the URL of the request bin, which is something like http://requestb.in/123a546b
Go to your OAuth application setup on GitHub (https://github.com/settings/applications), enter the setup of your specific application, and set the Callback URL to the URL of the request bin you just created.
Make a request to the GitHub OAuth page, with the client_id defined. Just enter this URL below into your browser, but change the YOUR_CLIENT_ID_HERE to be the client id of your OAuth application:
https://github.com/login/oauth/authorize?client_id=YOUR_CLIENT_ID_HERE
Enter your username and password and click Authorize. The GitHub app will then redirect you to the request bin service you created, and the URL in the browser should be something like (notice the code query parameter):
http://requestb.in/YOUR_REQUEST_BIN_ID?code=GITHUB_CODE
(for example, http://requestb.in/abc1def2?code=123a456b789cdef)
Also, the content of the page in the browser should be "ok" (this is the content returned by the request bin service).
Go to the request bin page that you created and refresh it. You will now see a log entry for the HTTP GET request that the GitHub OAuth server sent you, together with all the HTTP headers. Basically, you will see there the same code parameter that is present in the URL that you were redirected to. If you get this parameter, you are now ready to make a POST request with this code and your client secret, as described in step 2 of the guide you are using: http://developer.github.com/v3/oauth/#web-application-flow
Let me know if any of these steps are causing problems for you.

Web proxy in python/django?

I need to have a proxy that acts as an intermediary to fetch images. An example would be, my server requests domain1.com/?url=domain2.com/image.png and domain1.com server will respond with the data at domain2.com/image.png via domain1.com server.
Essentially I want to pass to the proxy the URL I want fetched, and have the proxy server respond with that resource.
Any suggestions on where to start on this?
I need something very easy to use or implement as I'm very much a beginner at all of this.
Most solutions I have found in python and/or django have the proxy acts as a "translater" i.e. domain1.com/image.png translates to domain2.com/image.png, which is obviously not the same.
I currently have the following code, but fetching images results in garbled data:
import httplib2
from django.conf.urls.defaults import *
from django.http import HttpResponse
def proxy(request, url):
conn = httplib2.Http()
if request.method == "GET":
url = request.GET['url']
resp, content = conn.request(url, request.method)
return HttpResponse(content)
Old question but for future googlers, I think this is what you want:
# proxies the google logo
def test(request):
url = "http://www.google.com/logos/classicplus.png"
req = urllib2.Request(url)
response = urllib2.urlopen(req)
return HttpResponse(response.read(), mimetype="image/png")
A very simple Django proxy view with requests and StreamingHttpResponse:
import requests
from django.http import StreamingHttpResponse
def my_proxy_view(request):
url = request.GET['url']
response = requests.get(url, stream=True)
return StreamingHttpResponse(
response.raw,
content_type=response.headers.get('content-type'),
status=response.status_code,
reason=response.reason)
The advantage of this approach is that you don't need to load the complete file in memory before streaming the content to the client.
As you can see, it forwards some response headers. Depending on your needs, you may want to forward the request headers as well; for example:
response = requests.get(url, stream=True,
headers={'user-agent': request.headers.get('user-agent')})
If you need something more complete than my previous answer, you can use this class:
import requests
from django.http import StreamingHttpResponse
class ProxyHttpResponse(StreamingHttpResponse):
def __init__(self, url, headers=None, **kwargs):
upstream = requests.get(url, stream=True, headers=headers)
kwargs.setdefault('content_type', upstream.headers.get('content-type'))
kwargs.setdefault('status', upstream.status_code)
kwargs.setdefault('reason', upstream.reason)
super().__init__(upstream.raw, **kwargs)
for name, value in upstream.headers.items():
self[name] = value
You can use this class like so:
def my_proxy_view(request):
url = request.GET['url']
return ProxyHttpResponse(url, headers=request.headers)
The advantage of this version is that you can reuse it in multiple views. Also, it forwards all headers, and you can easily extend it to add or exclude some other headers.
If the file you're fetching and returning is an image, you'll need to change the mimetype of your HttpResponse Object.
Use mechanize, it allow you to choose a proxy and act like a browser, making it easy to change the user agent, to go back and forth in the history and to handle authentification or cookies.

Categories

Resources