Programmatic POST to django website that uses basic authentication? - python

I have a Django restful API (using django-rest-framework) where the POST requests require prior authentication. I would like to populate the database by sending data to the API, however, I cannot figure out how to do the authentication programmatically. I tried requests, pycurl and httplib2 so far:
import httplib2
from urllib.parse import urlencode
h = httplib2.Http(".cache")
h.add_credentials(username, password)
headers = {'Content-type': 'application/x-www-form-urlencoded'}
data = {
"label": "SA2",
"flagged": "false",
"notes": ""
}
resp, content = h.request(
"https://example.com/api/data", "POST", urlencode(data), headers=headers
)
resp
>>>
{
'server': 'nginx/1.18.0 (Ubuntu)',
'date': 'Sat, 05 Mar 2022 00:06:32 GMT',
'content-type': 'text/html',
'transfer-encoding': 'chunked',
'connection': 'keep-alive',
'cross-origin-opener-policy': 'same-origin',
'referrer-policy': 'same-origin',
'vary': 'Origin',
'x-content-type-options': 'nosniff',
'x-frame-options': 'DENY',
'status': '403',
'content-length': '1867',
'-content-encoding': 'gzip'
}
content
>>>
b'{"detail":"Authentication credentials were not provided."}'
In the browser, I first have to visit the login page. Then the website sends a CRFT token.
Here is a solution using curl and bash. I prefer to use Python.

You need to provide the credentials in the header.
import base64
# ...
username="<username>"
password="<password>"
credentials=username + ":" + password
encoded_credentials = base64.b64encode(credentials.encode()).decode()
headers["Authorization"] = "Basic " + encoded_credentials
# ...
https://www.ibm.com/docs/en/ibm-mq/9.0?topic=security-using-http-basic-authentication-rest-api

Related

Getting ForbiddenException response with python requests and AWS API Gateway

I am getting an ForbiddenException reponse when I programmatically make an API call with python requests library while I am getting a proper 200 response in POSTMAN or the python shell. Here, I am sending a request to API gateway which invokes the AWS Lambda function to send email alerts to user via AWS SNS.
Request
url = "https://12wzlxw026.execute-api.us-east-1.amazonaws.com/default/app-notifier"
payload = {"content":"The file is ready.", "email":"preuseralerts#gmail.com"}
headers = {
'x-api-key': "RcO1ipqwqmaYaWTpPsXAP7l2KWz41wRBaa24Tt13",
'Cache-Control': "no-cache",
}
response = requests.request("POST", url, data=json.dumps(payload), headers=headers)
print(response.text)
print(response.headers)
Response
{"message":"Forbidden"}
Response headers
{'Date': 'Mon, 05 Sep 2022 09:07:47 GMT', 'Content-Type': 'application/json', 'Content-Length': '23', 'Connection': 'keep-alive', 'x-amzn-RequestId': '8d14db8b-4cc4-44c3-8ec5-640b999981f6', 'x-amzn-ErrorType': 'ForbiddenException', 'x-amz-apigw-id': 'X-pfiHQ_oAMFSyg='}
The same request works properly when send via POSTMAN or REPL. The response headers in that case-
{"statusCode": 200, "body": "\"User notification sent successfully.\""}
Response headers -
{'Date': 'Mon, 05 Sep 2022 08:56:54 GMT', 'Content-Type': 'application/json', 'Content-Length': '71', 'Connection': 'keep-alive', 'x-amzn-RequestId': 'fcf33e9a-888c-4a50-a615-d6f4e69933d3', 'x-amz-apigw-id': 'X-n5NHq-IAMFyyw=', 'X-Amzn-Trace-Id': 'Root=1-6315b9d4-739fe273163d7b382926ece0;Sampled=0'}

Failed to upload file to server using Python Requests

I use Requests and python2.7 in order to fill some values in a form and upload (submit) an image to the server.
I actually execute the script from the server pointing to the file I need to upload. The file is located in the /home directory and I have made sure it has full permissions.
Although I get a 200 Response, nothing is uploaded. This is part of my code:
import requests
try:
headers = {
"Referer": 'url_for_upload_form',
"sessionid": sessionid # retrieved earlier
}
files = {'file': ('doc_file', open('/home/test.png', 'rb'))}
payload = {
'title': 'test',
'source': 'source',
'date': '2016-10-26 02:13',
'csrfmiddlewaretoken': csrftoken # retrieved earlier -
}
r = c.post(upload_url, files=files, data=payload, headers=headers)
print r.headers
print r.status_code
except:
print "Error uploading file"
As I said I get a 200 Response and the headers returned are:
{'Content-Language': 'en', 'Transfer-Encoding': 'chunked', 'Set-Cookie': 'csrftoken=fNfJU8vrvOLAnJ5h7QriPIQ7RkI755VQ; expires=Tue, 17-Oct-2017 08:04:58 GMT; Max-Age=31449600; Path=/', 'Vary': 'Accept-Language, Cookie', 'Server': 'nginx/1.6.0', 'Connection': 'keep-alive', 'Date': 'Tue, 18 Oct 2016 08:04:58 GMT', 'X-Frame-Options': 'SAMEORIGIN', 'Content-Type': 'text/html; charset=utf-8'}
Does anyone have any idea what I am doing wrong? Am I missing something basic here?

Python code to do GET request from pipedrive API

I am using python-pipedrive to wrap Pipedrive's API though it doesn't quite work out of the box on python3 (which I'm using) so I modified it. I'm having trouble with just the Http requests portion.
This is what taught me how to use Httplib2: https://github.com/jcgregorio/httplib2/wiki/Examples-Python3
Basically, I just want to send a GET request to this:
https://api.pipedrive.com/v1/persons/123?api_token=1234abcd1234abcd
This works:
from httplib2 import Http
from urllib.parse import urlencode
PIPEDRIVE_API_URL = "https://api.pipedrive.com/v1/persons/123?api_token=1234abcd1234abcd"
response, data = http.request(PIPEDRIVE_API_URL, method='GET',
headers={'Content-Type': 'application/x-www-form-urlencoded'})
However, Pipedrive returns an error 401 with 'You need to be authorized to make this request.' if I do this:
PIPEDRIVE_API_URL = "https://api.pipedrive.com/v1/"
parameters = 'persons/123'
api_token = '1234abcd1234abcd'
response, data = http.request(PIPEDRIVE_API_URL + parameters,
method='GET', body=urlencode(api_token),
headers={'Content-Type': 'application/x-www-form-urlencoded'})
The actual response is:
response =
{'server': 'nginx',
'status': '401',
'connection': 'keep-alive',
'set-cookie': 'pipe-session=7b6ddadbc67abdadb6a67dbadcb; path=/; domain=.pipedrive.com; secure; httponly',
'date': 'Sat, 11 Jun 2016 06:50:13 GMT',
'transfer-encoding': 'chunked',
'x-frame-options': 'SAMEORIGIN',
'content-type': 'application/json, charset=UTF-8',
'x-xss-protection': '1; mode=block'}
data =
{'success': False,
'error': 'You need to be authorized to make this request.'}
How do I properly provide the api_token as a parameter (body) to the GET request? Anyone know what I'm doing wrong?
You need to provide the api_token as a query parameter. Concatenate the stings like this
PIPEDRIVE_API_URL = "https://api.pipedrive.com/v1/"
route = 'persons/123'
api_token = '1234abcd1234abcd'
response, data = http.request(PIPEDRIVE_API_URL + route + '?api_token=' + api_token,
method='GET',
headers={'Content-Type': 'application/x-www-form-urlencoded'})

Python Requests Digest Authorization

Hi I am working on a simple program to get a token-id from a router using REST API. The problem that I am facing, is that I do not see the Authorization headers when I use HTTPDigestAuth. When I use the Google App POSTMAN, I can see the headers and it work. What I am missing in my code?
My code:
import requests
from requests.auth import HTTPBasicAuth, HTTPDigestAuth
user = 'pod1u1'
passwd = 'pass'
url = 'https://10.0.236.188/api/v1/auth/token-services'
auth = HTTPDigestAuth(user, passwd)
r = requests.post(url, auth=auth, verify=False)
print 'Request headers:', r.request.headers
print 'Status Code: ', r.status_code
print 'response Headers: ', r.headers
print '######################################'
auth = HTTPBasicAuth(user, passwd)
r = requests.post(url, auth=auth, verify=False)
print 'Request headers:', r.request.headers
print 'Status Code: ', r.status_code
print 'response Headers: ', r.headers
Shell commands w/ output:
My script --
$python digest.py
Request headers: CaseInsensitiveDict({'Content-Length': '0', 'Accept-Encoding': 'gzip, deflate, compress', 'Accept': '*/*', 'User-Agent': 'python-requests/2.2.0 CPython/2.7.5 Darwin/13.0.0'})
Status Code: 401
response Headers: CaseInsensitiveDict({'date': 'Tue, 14 Jan 2014 00:28:27 GMT', 'content-length': '83', 'content-type': 'application/json', 'connection': 'keep-alive', 'server': 'nginx/1.4.2'})
######################################
Request headers: CaseInsensitiveDict({'Accept': '*/*', 'Content-Length': '0', 'Accept- Encoding': 'gzip, deflate, compress', 'Authorization': u'Basic cG9kMXUxOkMxc2NvTDF2Mw==', 'User-Agent': 'python-requests/2.2.0 CPython/2.7.5 Darwin/13.0.0'})
Status Code: 401
response Headers: CaseInsensitiveDict({'date': 'Tue, 14 Jan 2014 00:28:27 GMT', 'content-length': '448', 'content-type': 'text/html', 'connection': 'keep-alive', 'server': 'nginx/1.4.2'})
POSTMAN
POST /api/v1/auth/token-services HTTP/1.1
Host: 10.0.236.188
Authorization: Digest username="pod1u1", realm="pod1u1#ecatsrtpdmz.cisco.com", nonce="", uri="/api/v1/auth/token-services", response="08ac88b7f5e0533986e9fc974f132258", opaque=""
Cache-Control: no-cache
{
"kind": "object#auth-token",
"expiry-time": "Tue Jan 14 00:09:27 2014",
"token-id": "Vj7mYUMTrsuljaiXEPoNJNiXLzf8UeDsRnEgh3DvQcU=",
"link": "https://10.0.236.188/api/v1/auth/token-services/9552418862"
}
You are doing a POST, so intuitively, you need to pass 'params' argument to requests.post method
You can use a sniffer to see exactly what POSTMAN send to the url and do the same...
Just for info, I did a requests.get with digest credentials (on another url), it worked and I saw auth headers.
Maybe you could first start with a GET to create a "session" then do your POST, just a guess :)
[ADDED]
I would also try to use "raw" headers as a workaround :
[...]
headers = {
"Host": "10.0.236.188",
"Authorization": '''Digest username="pod1u1", realm="pod1u1#ecatsrtpdmz.cisco.com", nonce="", uri="/api/v1/auth/token-services", response="08ac88b7f5e0533986e9fc974f132258", opaque=""''',
"Cache-Control": "no-cache"
}
r = requests.post(url, auth=auth, headers=headers, verify=False)
[/ADDED]
The Problem is in the server side: Lukasa # GitHUB help me. "That doesn't look like a service that requires Digest Auth. If Digest Auth is required, the 401 should contain a header like this: WWW-Authenticate: Digest qop="auth". This does not. Instead, you're being returned a JSON body that contains an error message.
Digest Auth should not send headers on the initial message, because the server needs to inform you how to generate the digest. I invite you to open up the section of code that generates the digest. We require the realm, nonce and qop from the server before we can correctly generate the header."

Why is Facebook authentication via Python producing an error?

I am trying to authenticate users of my Django application into Facebook via the oauth2 Python package.
def myView(request):
consumer = oauth2.Consumer(
key = settings.FACEBOOK_APP_ID,
secret = settings.FACEBOOK_APP_SECRET)
# Request token URL for Facebook.
request_token_url = "https://www.facebook.com/dialog/oauth/"
# Create client.
client = oauth2.Client(consumer)
# The OAuth Client request works just like httplib2 for the most part.
resp, content = client.request(request_token_url, "GET")
# Return a response that prints out the Facebook response and content.
return HttpResponse(str(resp) + '\n\n ------ \n\n' + content)
However, I am directed to a page that contains an error when I go to this view. The error has this response from Facebook.
{'status': '200', 'content-length': '16418', 'x-xss-protection': '0',
'content-location': u'https://www.facebook.com/dialog/oauth/?oauth_body_hash=2jmj7l5rSw0yVb%2FvlWAYkK%2FYBwk%3D&oauth_nonce=53865791&oauth_timestamp=1342666292&oauth_consumer_key=117889941688718&oauth_signature_method=HMAC-SHA1&oauth_version=1.0&oauth_signature=XD%2BZKqhJzbOD8YBJoU1WgQ4iqtU%3D',
'x-content-type-options': 'nosniff',
'transfer-encoding': 'chunked',
'expires': 'Sat, 01 Jan 2000 00:00:00 GMT',
'connection': 'keep-alive',
'-content-encoding': 'gzip',
'pragma': 'no-cache',
'cache-control': 'private, no-cache, no-store, must-revalidate',
'date': 'Thu, 19 Jul 2012 02:51:33 GMT',
'x-frame-options': 'DENY',
'content-type': 'text/html; charset=utf-8',
'x-fb-debug': 'yn3XYqMylh3KFcxU9+FA6cQx8+rFtP/9sJICRgj3GOQ='}
Does anyone see anything awry in my code? I have tried concatenating arguments as strings to request_token_url to no avail. I am sure that my Facebook app ID and secret string are correct.

Categories

Resources