¿How can i to read request headers using django test? - django

I'm using ApiClient class but I don't know how to send a headers, I'm trying to do it like this, but the answer is that I'm not authorized.
I have been trying to solve it for several hours but I have not been able to, your contribution would be of great help.
self.client = APIClient()
self.jwt = response.json()["access"]
self.client.credentials(HTTP_AUTHORIZATION='Bearer ' + self.jwt)
self.client.headers.update({'Origin': 'https://travelingapps.com.co'})
this is te response:
('status_code', 401), ('content_type', 'application/json'), ('content', 'UNAUTHORIZED')])

you have 2 options.
You can add the header you need when you instantiate APIClient(), just pass the header as a parameter. example:
self.client = APIClient(HTTP_ORIGIN="https://travelingapps.com.co")
In this way, all the requests you make with APIClient() will carry that header. remember that you must set a valid header.
2.If you want to send the header only in a request, you can add it to the post method you are doing.
response = self.client.post(
self.url,
{
'email': "a#a.com",
'password': "abcd.1234",
},
format='json',
HTTP_ORIGIN="https://travelingapps.com.co"
)
Try it!

Related

Python Requests - Using variables within header and get request

I have two variables that must be injected into a PUT (curl -XPOST equivalent)
Variable1 (header)
Variable2 (part of the URL)
headers = {'Authorization': 'Bearer Variable1',
}
files = [
('server', '*'),
]
requests.get('https://URL/1/2/3/4/5/Variable2', headers=headers, files=files, verify=False)
I'm running into two issues:
What is the proper way to include variables into the request
Since this is run across HTTPS, how do I validate what is actually included within the request? I'd like to validate this for debugging purposes
What is the proper way to include variables into the request
Passing the headers dictionary as the headers argument, as you have it written, is fine. For your url string, I would just join() the base URL to your Variable2, and pass that as an argument.
Here's how I would write this code:
import requests
base_url = 'https://URL/1/2/3/4/5/'
url = ''.join([base_url, Variable2])
headers = {'Authorization': 'Bearer Variable1',}
files = [('server', '*'),]
resp = requests.put(url, headers=headers, files=files, verify=False)
Since this is run across HTTPS, how do I validate what is actually included within the request? I'd like to validate this for debugging purposes
You can utilize the PreparedRequest object:
from requests import Request, Session
r = Request('PUT', url, headers=headers, files=files)
prepped = r.prepare()
# now, for example, you can print out the url, headers, method...
# whatever you need to validate in your request.
# for example:
# print prepped.url, prepped.headers
# you can also send the request like this...
s = Session()
resp = s.send(prepped)

Django test Client can only login once?

Our team is currently writing tests for our application. I am currently writing code to acces the views. These views are behind a login-screen, so our test first have to login and than peform the rest of the test. I've run into a very strange error. Basically My tests can only login once.
As you can see in the example below, both classes are doing the exact same thing, yet only one of them succeeds with the login, the other gives a '302 doest not equal 200' assertion error.
If I comment out the bottom one, the one at the top works, and vice versa.
Code that is testing different views also doesnt work, unless I comment out all other tests.
It doesnt matter if I login like shown below, or use a different variant (like self.client.login(username='test', password='password')).
Me and my team have no idea why Django is behaving this way and what we are doing wrong. Its almost as if the connection remains open and we would have to add code to close it. But the django-documentation doesnt mention any of this. DOes anyone know what we are doing wrong?
class FunctieListView_tests(TestCase):
"""Function listview only shows the data for the current_user / tenant"""
def setUp(self):
self.tenant = get_tenant()
self.function = get_function(self.tenant)
self.client = Client(HTTP_HOST='tc.tc:8000')
self.user = get_user(self.tenant)
def test_correct_function_context(self):
# Test if the view is only displaying the correct context data
self.client.post(settings.LOGIN_URL, {
'username': self.user.username,
'password': 'password'
}, HTTP_HOST='tc.tc:8000')
response = self.client.get(reverse('functie_list'))
self.assertEqual(response.status_code, 200)
self.assertTrue(response.context['functie_templates'] != None)
self.assertEqual(response.context['functie_templates'][0],
FunctieTemplate.objects.filter(linked_tenant=self.tenant)[0])
class FunctieListView_2_tests(TestCase):
"""Role Listview only shows the data for the current_user / tenant"""
def setUp(self):
self.tenant = get_tenant()
self.function = get_function(self.tenant)
self.client = Client(HTTP_HOST='tc.tc:8000')
self.user = get_user(self.tenant)
def test_correct_function_context_second(self):
#login
# Test if the view is only displaying the correct context data
self.client.post(settings.LOGIN_URL, {
'username': self.user.username,
'password': 'password'
}, HTTP_HOST='tc.tc:8000')
response = self.client.get(reverse('functie_list'))
self.assertEqual(response.status_code, 200)
self.assertTrue(response.context['functie_templates'] != None)
self.assertEqual(response.context['functie_templates'][0],
FunctieTemplate.objects.filter(linked_tenant=self.tenant)[0])
The users, tenants and functions are defined in a seperate utils file like so:
def get_user(tenant, name='test'):
u = User.objects.create_user(name, '{}#test.test'.format(name), 'password')
u.save()
u.profile.tenant = tenant
u.profile.tenant_role = generis.models.TENANT_OWNER
u.profile.save()
return u
def get_function(tenant):
userfunction = UserFunction.objects.create(name='test_functie', linked_tenant=tenant)
userfunction.save()
return userfunction
def get_tenant(slug_var='tc'):
f = elearning.models.FontStyle(font='foobar')
f.save()
c = elearning.models.ColorScheme(name='foobar', title='foo', text='fleeb', background='juice', block_background='schleem', box='plumbus')
c.save()
t = elearning.models.Tenant(name='tc', slug=slug_var, default_font_style=f, default_color_scheme=c)
t.save()
return t
My guess is that it happens because you are instantiating the Client yourself in setUp. Although it looks fine the outcome is obviously different from the regular behavior. I never had problems with login using the preinitialized self.client of django.test.TestCase.
Looking at django.test.client.Client, it says in the inline documentation:
Client objects are stateful - they will retain cookie (and thus session) details for the lifetime of the Client instance.
and a still existing cookie would explain the behavior you describe.
I cannot find HTTP_HOST in django.test.client.py, so I'm not sure whether you are really using that Client class at all. If you need access to a live server instance during tests, you could use Django's LiveServerTestCase.

django and python requests - getting a 403 on a post request

I am using requests to log into my Django site for testing (and yes, I know about the Django TestClient, but I need plain http here). I can log in and, as long as I do get requests, everything is OK.
When I try to use post instead, I get a 403 from the csrf middleware. I've worked around that for now by using a #crsf_exempt on my view, but would prefer a longer term solution.
This is my code:
with requests.Session() as ses:
try:
data = {
'username': self.username,
'password': self.password,
}
ses.get(login_url)
try:
csrftoken = ses.cookies["csrftoken"]
except Exception, e:
raise
data.update(csrfmiddlewaretoken=csrftoken)
_login_response = ses.post(login_url, data=data)
logger.info("ses.cookies:%s" % (ses.cookies))
assert 200 <= _login_response.status_code < 300, "_login_response.status_code:%s" % (_login_response.status_code)
response = ses.post(
full_url,
data=data,
)
return self._process_response(response)
The login works fine, and I can see the csrf token here.
INFO:tests.helper_fetch:ses.cookies:<RequestsCookieJar[<Cookie csrftoken=TmM97gnNHs4YCgQPzfNztrAWY3KcysAg for localhost.local/>, <Cookie sessionid=kj6wfmta
However, the middleware sees cookies as empty.
INFO:django.middleware.csrf:request.COOKIES:{}
I've added the logging code to it:
def process_view(self, request, callback, callback_args, callback_kwargs):
if getattr(request, 'csrf_processing_done', False):
return None
try:
csrf_token = _sanitize_token(
request.COOKIES[settings.CSRF_COOKIE_NAME])
# Use same token next time
request.META['CSRF_COOKIE'] = csrf_token
except KeyError:
# import pdb
# pdb.set_trace()
import logging
logger = logging.getLogger(__name__)
logger.info("request.COOKIES:%s" % (request.COOKIES))
Am I missing something with way I call request's session.post? I tried adding cookie to it, made no difference. But I can totally see why crsf middleware is bugging out. I thought the cookies were part of the session, so why are they missing in my second post?
response = ses.post(
self.res.full_url,
data=data,
cookies=ses.cookies,
)
This variation, inspired by How to send cookies in a post request with the Python Requests library?, also did not result in anything being passed to csrf middleware:
response = ses.post(
self.res.full_url,
data=data,
cookies=dict(csrftoken=csrftoken),
)
For subsequent requests after the login, try supplying it as header X-CSRFToken instead.
The following worked for me:
with requests.Session() as sesssion:
response = session.get(login_url)
response.raise_for_status() # raises HTTPError if: 400 <= status_code < 600
csrf = session.cookies['csrftoken']
data = {
'username': self.username,
'password': self.password,
'csrfmiddlewaretoken': csrf
}
response = session.post(login_url, data=data)
response.raise_for_status()
headers = {'X-CSRFToken': csrf, 'Referer': url}
response = session.post('another_url', data={}, headers=headers)
response.raise_for_status()
return response # At this point we probably made it
Docs reference: https://docs.djangoproject.com/en/dev/ref/csrf/#csrf-ajax
You could also try to use this decorator on your view, instead of the csrf_exempt. I tried to reproduce your issue, and this worked as well for me.
from django.views.decorators.csrf import ensure_csrf_cookie`
#ensure_csrf_cookie
def your_login_view(request):
# your view code

How to Test Stripe Webhooks with Mock Data

I'm trying to write a unit test that posts a mock event to my stripe webhook.
I went and pulled an event from my logs and tried sending that with the test mode enabled, but I (somewhat predictably) got an error:
a similar object exists in live mode, but a test mode key was used to make this request.
Fair enough. So how do I create a mock event that I can actually send to my webhook and get it processed correctly?
Here's my current test:
class StripeTest(TestCase):
def setUp(self):
self.client = Client()
def test_receiving_a_callback(self):
with open('donate/test_assets/stripe_event.json', 'r') as f:
stripe_event = simplejson.load(f)
self.client.post('/donate/callbacks/stripe/',
data=simplejson.dumps(stripe_event),
content_type='application/json')
The solution is to create your own mock data. In the code below we create a test payment by creating a stripe token, then submitting it via the front end (at the /donate/ endpoint).
Once the front end has worked properly, you can get the event from stripe and then send it to your development machine's webhook endpoint.
This is more work than I expected, and I don't love that my tests are hitting the network, but it seems to be a decent solution. I feel a lot more confident about my payments than before.
def test_making_a_donation_and_getting_the_callback(self):
"""These two tests must live together because they need to be done sequentially.
First, we place a donation using the client. Then we send a mock callback to our
webhook, to make sure it accepts it properly.
"""
stripe.api_key = settings.STRIPE_SECRET_KEY
# Create a stripe token (this would normally be done via javascript in the front
# end when the submit button was pressed)
token = stripe.Token.create(
card={
'number': '4242424242424242',
'exp_month': '6',
'exp_year': str(datetime.today().year + 1),
'cvc': '123',
}
)
# Place a donation as an anonymous (not logged in) person using the
# token we just got
r = self.client.post('/donate/', data={
'amount': '25',
'payment_provider': 'cc',
'first_name': 'Barack',
'last_name': 'Obama',
'address1': '1600 Pennsylvania Ave.',
'address2': 'The Whitehouse',
'city': 'DC',
'state': 'DC',
'zip_code': '20500',
'email': 'barack#freelawproject.org',
'referrer': 'footer',
'stripeToken': token.id,
})
self.assertEqual(r.status_code, 302) # 302 because we redirect after a post.
# Get the stripe event so we can post it to the webhook
# We don't know the event ID, so we have to get the latest ones, then filter...
events = stripe.Event.all()
event = None
for obj in events.data:
if obj.data.object.card.fingerprint == token.card.fingerprint:
event = obj
break
self.assertIsNotNone(event, msg="Unable to find correct event for token: %s" % token.card.fingerprint)
# Finally, we can test the webhook!
r = self.client.post('/donate/callbacks/stripe/',
data=simplejson.dumps(event),
content_type='application/json')
# Does it return properly?
self.assertEqual(r.status_code, 200)

TastyPie obj create method not being called

Am a newbie in TastyPie. I have a very simple resource and am overriding the obj_create method in following way.
Ajax Call :-
var data2 ={
"crave": data1,
"uid": "100",
"access_token": "AAA"
};
$.ajax({
url: "http://localhost:8000/restapi/v1/icrave/",
type: 'POST',
data: data2,
contentType: 'application/json',
dataType: 'json',
success: function (res) {
console.log(res);
},
});
In the resource
class IcravesResource(ModelResource):
person = fields.ForeignKey(UserResource, 'person')
class Meta:
queryset = Icrave.objects.filter(anonymous_or_not = False,is_active = True).order_by('-datetime')
resource_name = "icrave"
allowed_methods = ['get','post']
authentication = GetAuthentication()
authorization = GetAuthorization()
def obj_create(self,bundle,request=None, **kwargs):
print "Check if code reached here !!!"
return super( IcravesResource, self ).obj_create( self, bundle, request, **kwargs )
The code is not reaching here. What am i doing wrong ? I have checked the authorization and authentication they are both returning true. How can I debug this issue ?
You could use the Python Debugger. ( http://docs.python.org/library/pdb.html )
Find your copy of tastypie (possibly in your virtualenv), open the file resources.py and find the method *post_list*. This is the method that gets called when a POST request to a list-resource URL is send to Django.
You'll find a call to *obj_create* somewhere in that method. Now you can set a breakpoint by adding the lines:
import pdb
pdb.set_trace()
in that method. Maybe as the first statement.
Now, when you start your devserver and issue your ajax-call the execution should stop at the set_trace() and you should see a python prompt in the shell you did start the devserver.
Now you can explore the runtime-environment of the request. You can can for example inspect local variables by entering them at the prompt.
You can see the listing of the method you're in by typing 'l' (little L), execute the next line with 'n', step into a function with 's'.
This should help you make sense of what is happening. Take some time to learn how to use pdb, it's well worth it.
For more info on pdb and django, see:
http://ericholscher.com/blog/2008/aug/31/using-pdb-python-debugger-django-debugging-series-/
Can you verify based on the server logs, that the server actually got the POST request?
If so, you can also try specifying the allowed methods list, by putting:
list_allowed_methods = ['post', 'get']
instead of general allowed_methods one.
Here is a code snippet, which worked for me:
class EntryDetailsResource(CommonResource):
class Meta:
queryset = Entry.objects.all()
detail_allowed_methods = ['put','get','delete']
list_allowed_methods = ['post', 'get']
authorization = DjangoAuthorization()
validation = EntryDetailsValidation()
def obj_create(self, bundle, request=None, **kwargs):
import sys
print sys.stderr, 'aa'
return super(CommonResource, self).obj_create(bundle, request, user=request.user)