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
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'}
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?
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'})
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."
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.