Python Requests Returns 400 - python

i have this command
curl -X POST --data-urlencode "payload={\"channel\": \"#test\", \"username\": \"kuhkuh\", \"text\": \"This is posted to #test\", \"icon_emoji\": \":ghost:\"}" https://hooks.slack.com/services/123/123/123
im trying to create it using python so i can use it on my project
import requests
import json
class SlackWrapper:
def __init__(self):
pass
#classmethod
def post_message_to_slack(self, err):
url = 'https://hooks.slack.com/services/123/123/123'
payload = {
'channel' : '#test',
'username' : 'kuhkuh',
'message' : err,
'icon_emoji' : ':ghosts:'
}
try:
alert = requests.post(url, data=payload, headers={'Content-Type': 'application/json'})
print(alert.status_code, ' - ', alert.text, ' - ', json.dumps(payload))
except Exception as e:
print(e)
SlackWrapper.post_message_to_slack("testing error message requests")
the problem is, i keep geting this error
<Response [400]>
where did i went wrong?

Error 400 means "Bad Request", so your payload is wrong.
If your payload is already a dict there is no need to json.dumps it in the json parameter of the post request. Also requests is smart enough to infer the Content-Type, so no need to explicitly set this Header.
#classmethod
def post_message_to_slack(self, err):
url = 'https://hooks.slack.com/services/123/123/123'
# changed the payload
payload = {
"channel": "#test",
"username": "kuhkuh",
"text": "This is posted to #test",
"icon_emoji": ":ghost:"
}
try:
# changed the parameters for posting
alert = requests.post(url, json=payload)
print(alert.status_code, ' - ', alert.text, ' - ', json.dumps(payload))
except Exception as e:
print(e)

You can paste the curl code to postman then get the python code and use that.
For your code the equivalent python code :
import requests
url = "https://hooks.slack.com/services/123/123/123"
payload = 'payload=%7B%22channel%22%3A%20%22%23test%22%2C%20%22username%22%3A%20%22kuhkuh%22%2C%20%22text%22%3A%20%22This%20is%20posted%20to%20%23test%22%2C%20%22icon_emoji%22%3A%20%22%3Aghost%3A%22%7D'
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
response = requests.request("POST", url, headers=headers, data = payload)
print(response.text.encode('utf8'))

You are trying to send the data to the server as a dictionary.
Instead try sending it as a json data using requests POST json attribute
payload = {
"channel" = '#test',
"username" = 'kuhkuh',
"message" = err,
"icon_emoji" = ':ghosts:'
}
alert = requests.post(url, json = payload)

Related

AADSTS900144: The request body must contain the following parameter: 'grant_type' with Microsoft Defender for Endpoint API

I am attempting to authenticate with Microsoft Defender for Endpoint's API service by following this learn article:
https://learn.microsoft.com/en-us/microsoft-365/security/defender-endpoint/run-advanced-query-sample-python?view=o365-worldwide#get-token
I typically use the "request" library for REST calls, so I didn't follow the above code snippet exactly. When running my version of the above code:
import json
import requests
MDE_CLIENT_ID = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX'
MDE_CLIENT_SECRET = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
TENANT_ID = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX'
AUTHORITY = 'https://login.microsoftonline.com/'
MDE_URI = 'https://api.securitycenter.microsoft.com'
class RESTError(Exception):
def __init__(self, status_code, message):
self.status_code = status_code
self.message = str(self.status_code) + ' ' + json.dumps(message)
super().__init__(self.message)
def authenticate_mde():
headers = {
'content-type': 'application/x-www-form-urlencoded'
}
body = {
'resource': MDE_URI,
'client_id': MDE_CLIENT_ID,
'client_secret': MDE_CLIENT_SECRET,
'grant_type': 'client_credentials'
}
response = requests.post(AUTHORITY + TENANT_ID + '/oauth2/token', data = json.dumps(body), headers = headers)
if (response.status_code < 200 or response.status_code > 299):
raise RESTError(response.status_code, response.json())
return response.json()['access_token']
def main():
token = authenticate_mde()
print(token)
if (__name__ == '__main__'):
main()
When I run this code I receive a 400 error back from the authentication service complaining about a missing body parameter 'grant_type'. However, as you can see in the code, I clearly have that included in the same fashion as the code snippet from MSFT.
Traceback (most recent call last):
File "C:\Users\24724\Documents\code\python\scripts\mde-executor.py", line 42, in <module>
main()
File "C:\Users\24724\Documents\code\python\scripts\mde-executor.py", line 38, in main
token = authenticate_mde()
File "C:\Users\24724\Documents\code\python\scripts\mde-executor.py", line 32, in authenticate_mde
raise RESTError(response.status_code, response.json())
__main__.RESTError: 400 {"error": "invalid_request", "error_description": "AADSTS900144: The request body must contain the following parameter: 'grant_type'.\r\nTrace ID: e4d0d06e-aae6-4b6d-80e2-2b3997f74302\r\nCorrelation ID: 5788089d-f94e-4e9a-8667-d6e36c183af8\r\nTimestamp: 2023-01-06 17:00:23Z", "error_codes": [900144], "timestamp": "2023-01-06 17:00:23Z", "trace_id": "e4d0d06e-aae6-4b6d-80e2-2b3997f74302", "correlation_id": "5788089d-f94e-4e9a-8667-d6e36c183af8", "error_uri": "https://login.microsoftonline.com/error?code=900144"}
I also tried copying MSFT's code snippet exactly and inserting my own global var info but receive the same error. I have tried moving the body to url parameters, headers, splitting it up between body, params, and headers. No luck. I have tried different content-types in the header as well and tried without any headers. None seems to work and I am stumped at this point.
I resolved the issue. Passing 'resource' into the body was apparently screwing it up, even though their python example here shows that:
import json
import urllib.request
import urllib.parse
tenantId = '00000000-0000-0000-0000-000000000000' # Paste your own tenant ID here
appId = '11111111-1111-1111-1111-111111111111' # Paste your own app ID here
appSecret = '22222222-2222-2222-2222-222222222222' # Paste your own app secret here
url = "https://login.microsoftonline.com/%s/oauth2/token" % (tenantId)
resourceAppIdUri = 'https://api.securitycenter.microsoft.com'
body = {
'resource' : resourceAppIdUri,
'client_id' : appId,
'client_secret' : appSecret,
'grant_type' : 'client_credentials'
}
data = urllib.parse.urlencode(body).encode("utf-8")
req = urllib.request.Request(url, data)
response = urllib.request.urlopen(req)
jsonResponse = json.loads(response.read())
aadToken = jsonResponse["access_token"]
https://learn.microsoft.com/en-us/microsoft-365/security/defender-endpoint/run-advanced-query-sample-python?view=o365-worldwide#get-token
Following the example they give for cURL here and using the 'scope' parameter instead fixed it.
curl -i -X POST -H "Content-Type:application/x-www-form-urlencoded" -d "grant_type=client_credentials" -d "client_id=%CLIENT_ID%" -d "scope=https://securitycenter.onmicrosoft.com/windowsatpservice/.default" -d "client_secret=%CLIENT_SECRET%" "https://login.microsoftonline.com/%TENANT_ID%/oauth2/v2.0/token" -k
https://learn.microsoft.com/en-us/microsoft-365/security/defender-endpoint/exposed-apis-create-app-webapp?view=o365-worldwide#use-curl

RESTful API post requests

I am making a request to an API, I'm using basic authorization, yet for some reason the API is unable to decode the authorization string
Here is the code I'm using:
import base64,requests
from base64 import b64encode
url = 'api.sample/test'
APIuser = b'generic_user'
APIpass = b'generic_pass'
myobj = {"data1_field":"data1"}
data_string = APIuser + b":" + APIpass
data_bytes = b64encode(data_string).decode('ascii')
head = {'Content-Type':'application/json', 'Accept':'*/*','Authorization':'Basic ' + data_bytes}
x = requests.post(url, headers=head,
data = myobj)
print(x.text)
this is the error I'm getting:
{
"error": {
"detail": "Cannot decode: java.io.StringReader#45fab9",
"message": "Exception while reading request"
},
"status": "failure"
}
Any ideas of what am I doing wrong?
B64 is read as a byte data on python, so the string will be represented as b'x', so the way of doing it is sending the encryption type on the response, also i was using ascii encoding, and the required one is utf8, important not to mistake it with utf-8 (apparently not the same for the compiler)
url = "api.sample/test"
payload = "{\"Data1\": \"Data1_field\"}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Basic get the string'
}
response = requests.request("POST", url, headers=headers, data = payload)
print(response.text.encode('utf8'))

TypeError: POST data should be bytes, an iterable of bytes, or a file object. It cannot be of type str while trying to pass PUT request in python

I am trying to pass a list of dictionaries(strings) to a for a put request. I am getting this error:
TypeError: POST data should be bytes, an iterable of bytes.
Is this the right way to make a put request with list of dictionaries(strings) in python.
list looks like the following:
list1 = ['{"id" : "","email" : "John#fullcontact.com","fullName": "John Lorang"}', '{"id" : "","email" : "Lola#fullcontact.com","fullName": "Lola Dsilva"}']
myData = json.dumps(list1)
myRestRequestObj = urllib.request.Request(url,myData)
myRestRequestObj.add_header('Content-Type','application/json')
myRestRequestObj.add_header('Authorization','Basic %s')
myRestRequestObj.get_method = lambda : 'PUT'
try:
myRestRequestResponse = urllib.request.urlopen(myRestRequestObj)
except urllib.error.URLError as e:
print(e.reason)
As you said in a comment, you cannot use requests (that's pretty sad to hear!), so I did another snippet using urllib (the short answer: you must .encode('utf-8') json.dumps and decode('utf-8') response.read()):
import urllib.request
import urllib.error
import json
url = 'http://httpbin.org/put'
token = 'jwtToken'
list1 = ['{"id" : "","email" : "John#fullcontact.com","fullName": "John Lorang"}', '{"id" : "","email" : "Lola#fullcontact.com","fullName": "Lola Dsilva"}']
# Request needs bytes, so we have to encode it
params = json.dumps(list1).encode('utf-8')
headers = {
'Content-Type': 'application/json',
'Authorization': 'Basic {token}'.format(token=token)
}
# Let's try to create our request with data, headers and method
try:
request = urllib.request.Request(url, data=params, headers=headers, method='PUT')
except urllib.error.URLError as e:
# Unable to create our request, here the reason
print("Unable to create youro request: {error}".format(error=str(e)))
else:
# We did create our request, let's try to use it
try:
response = urllib.request.urlopen(request)
except urllib.error.HTTPError as e:
# An HTTP error occured, here the reason
print("HTTP Error: {error}".format(error=str(e)))
except Exception as e:
# We got another reason, here the reason
print("An error occured while trying to put {url}: {error}".format(
url=url,
error=str(e)
))
else:
# We are printing the result
# We must decode it because response.read() returns a bytes string
print(response.read().decode('utf-8'))
I did try to add some comments. I hope this solution help you!
To help you learn a better way to learn python, you should read the Style Guide for Python Code
I will suppose you can use the requests module (pip install requests).
requests is a simple yet powerful HTTP libraby for Python.
import json
import requests
my_data = json.dumps(list1)
headers = {
'Authorization': 'Basic {token}'.format(token=your_token)
}
response = requests.put(url, headers=headers, json=my_data)
print("Status code: {status}".format(status=response.status_code))
print("raw response: {raw_response}".format(
raw_response=response.text
)
print("json response: {json_response}".format(
json_response=response.json()
)

"Bad Gateway" error using Python requests module with multipart encoded file POST

I am getting the error message "Bad Gateway
The proxy server received an invalid
response from an upstream server" with the following code:
import requests
url = "https://apis.company.com/v3/media"
attachments = 'media': ('x.mp3', open('x.mp3', 'r'))}
headers = {'content-type': "multipart/form-data",'cache-control': "no-cache"
'Authorization':"Bearer zzz" }
response = requests.post(url, files=attachments, headers = headers)
print response.text
I'm following the example in the requests Quickstart documentation, where it says "You can also pass a list of tuples to the data argument": http://docs.python-requests.org/en/master/user/quickstart/#post-a-multipart-encoded-file
What is causing this error and how can I fix it?
The main problem was that I set the content-type in the header. This code works:
import requests
url = 'https://apis.company.com/v3/media'
token = 'token-goes-here'
headers = { 'Authorization' : 'Bearer ' + token }
filename = 'x.mp3'
with open(filename, 'rb') as media_file:
attachments = {
'media': (filename, media_file, 'application/octet-stream')
}
response = requests.post(url, files = attachments, headers = headers)
print response.text

Google Places Checkin POST request in Python

I'm trying POST a check-in request in Google Places API. The way they described it, I have to request this -
POST https://maps.googleapis.com/maps/api/place/check-in/json?sensor=true_or_false&key=AddYourOwnKeyHere HTTP/1.1
Host: maps.googleapis.com
{
"reference": "place_reference"
}
My Current code looks like this -
def checkin(self, reference="", sensor="true"):
"""
"""
base_url = "https://maps.googleapis.com/maps/api/place/check-in/json"
params = urllib.urlencode(
{
'key': self.API_KEY,
'sensor': sensor,
}
)
post_url = base_url + "?" + params
headers = { 'Host': "maps.googleapis.com" }
data = urllib.urlencode({ 'reference': reference })
req = Request(post_url, data, headers)
response = urllib2.urlopen(req)
resp = response.read()
But I keep getting the error -
urllib2.HTTPError: HTTP Error 400: Bad Request
What am I doing wrong?
Your problem is that the API is expecting JSON when you are sending it the literal reference: xyz
You need to send it the JSON representation.
Try:
data = json.dumps({'reference': reference})

Categories

Resources