I'm using the starter kit by #ErikRas
With the following code, I'm having trouble authenticating my python program.
Here's my python:
import requests
URL="http://localhost"
PORT="3030"
Session = requests.Session()
Request = Session.post(URL+':'+PORT+'/login', data={'name':'AuthedUserName'})
# (Password to follow proof of concept obviously)
In my api.js file i just had:
import express from 'express';
import session from 'express-session';
import bodyParser from 'body-parser';
import config from '../src/config';
import * as actions from './actions/index';
import {mapUrl} from 'utils/url.js';
import http from 'http';
const app = express();
const server = new http.Server(app);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(session({
secret: 'react and redux rule!!!!',
resave: false,
saveUninitialized: false,
cookie: { maxAge: 60000 }
}));
app.use((req, res) => {
/* There's heaps here, but all that is relevant is: */
console.log(req.body)
In the console i'm just getting {}
I found this article:
req.body empty on posts
and
Python Post Request Body appears empty in Node server when sent
but as you can see i'm already using bodyparser.json and bodyparser.urlencoded.extended = true
Okay, so i compared my pythons request against my web-app's request by printing the request to the console in node.
I found that the web app had more in its header than the python's requests' request. WebApp:
referer: 'http://localhost:3001/login'
origin: 'http://localhost:3001'
host: 'http://localhost:3001'
connection: 'close'
So I included this in my header, it worked!
I wanted to see which header property was 'necessary', so i gradually pulled everything out to see if this broke the POST request.
Turns out i managed to pull everything out! So what i'm using now is this:
r = Session.post(URL+':'+PORT+'/login',headers = {}, data={'name':'AuthedUserName'})
That's it!! I'd like to understand why headers={} works, but i need to moving forward with my project!!
<<<<<<---- Edit ---->>>>>>
Above is 'half' right, since my web app is using json and i want to use json, what i needed to do was change my header to
headers = {u'content-type': u'application/json'}
Then use json.dumps on the payload only!
r = session.post('http://'+DB_URL+':3030/sinumecUpdate', headers = headers, data = json.dumps(dataObject))
I also needed to pull out
app.use(bodyParser.urlencoded({ extended: true }));
From my node API and stick with only the JSON body parser.
import requests
import json
url = 'http://127.0.0.1'
data={'name':'AuthedUserName'}
headers = {'content-type': 'application/json'}
r = requests.post(url=url, data=json.dumps(data), headers=headers)
Related
Best wishes (first things first!)
I want to enable/disable a PoE port on my UniFi switch. For this I aim using Python 3.9.1 (first time) with the following code:
import requests
import json
import sys
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
gateway = {"ip": "MYSERVER.COM", "port": "8443"}
headers = {"Accept": "application/json", "Content-Type": "application/json"}
login_url = f"https://{gateway['ip']}:{gateway['port']}/api/login"
login_data = {
"username": "MYUSERNAME",
"password": "MYPASSWORD"
}
session = requests.Session()
login_response = session.post(login_url, headers=headers, data=json.dumps(login_data), verify=False)
if (login_response.status_code == 200):
api_url_portoverrides = 'api/s/default/rest/device/MYDEVICEID'
poe_url = f"https://{gateway['ip']}:{gateway['port']}/{api_url_portoverrides}"
# build json for port overrides
json_poe_state_on = '{"port_overrides": [{"port_idx": 6, "portconf_id": "MYPROFILE1"}]}'
json_poe_state_off = '{"port_overrides": [{"port_idx": 6, "portconf_id": "MYPROFILE2"}]}'
post_response = session.put(poe_url, headers=headers, data=json.dumps(json_poe_state_off))
print('Response HTTP Request {request}'.format(request=post_response.request ))
else:
print("Login failed")
The login works (I get the 2 security cookies and tried them in Paw (a macOS REST API client) to see if these were ok)) but the second call, the. PUT, returns OK but noting happens.
Before I've done this in Python, I tried all my calls in Paw first and there it works. I tried everything in bash with curl and there it works too. So I am a bit at a loss here.
Anyone has an idea?
Thank you for your time!
Best regards!
Peter
Solved it! By looking into what was posted with Wireshark I saw that the payload was different. The culprit was the json.dumps function which encoded the string by putting a backslash in front of each double quote.
It works now!
I have a node.js API as below to which I send a POST request from python as below,the issue am facing is if I remove the
headers={"Content-Type": "application/json"} the POST goes thorugh,if not i get a Read timed out. error, can anyone provide guidance on how to fix this timeout error ?
node.js endpoint
app.post("/api/bats_push",(req, res) => {
//console.log("Calling bats_push...")
const d = {
method: req.method,
headers: req.headers,
query: req.query,
body: ''
}
req.on('data', (c) => {
//console.log(c)
d.body = d.body + c
});
req.on('end', () => {
DATA.push(d);
res.end('Saved BATS job details');
//res.status(200).json({
//message: "Saved BATS job details",
//posts: req.body
//});
});
});
Python POST
try:
json"},timeout=10.0)
r = requests.post(webhook_url,data=json_data.encode("utf8"),verify=False,headers={"Content-Type": "application/json"})
print "posted"
print(r.status_code, r.reason)
print r.url
print r.text
except Exception as e:
print (e)
Error:-
InsecureRequestWarning)
HTTPSConnectionPool(host='company.com', port=443): Read timed out. (read timeout=10.0)
I seems that you are using express.js. I believe that your problem is, that body is actually already parsed. You can check it by reading req.body. The situation is caused because express.js already read whole body (due to the content type) and trying to read body again will cause timeout (event data and event end are not emitted).
There are several ways how to fix it.
disable express.js body parser - or reconfigure it to ignore json
remove reading body code and use directly req.body
app.post("/api/bats_push",(req, res) => {
//console.log("Calling bats_push...")
const d = {
method: req.method,
headers: req.headers,
query: req.query,
body: req.body
}
DATA.push(d);
res.end('Saved BATS job details');
});
according to requests why not use this:
#replace this
r = requests.post(webhook_url,data=json_data.encode("utf8"),verify=False,headers={"Content-Type": "application/json"})
#by this...assuming that 'data' is a dict
r = requests.post(webhook, json=data, verify=False)
Looks like it could be something related to your SSL.
Check if you get the same error sending a request to your localhost with the server running.
From your question,the key word is:
if I remove the headers={"Content-Type": "application/json"} the POST goes thorugh.
The reason may clear:it is a wrong way use about the header.
Simpler say: the node.js app check the header before into the logic code.
if do not send the header by ourself,the requests part use the default headers below:
{
'User-Agent': 'python-requests/2.22.0',
'Accept-Encoding': 'gzip, deflate',
'Accept': '*/*',
'Connection': 'keep-alive',
}
through the requests's code can print the default headers when post.
you just use the header
{"Content-Type": "application/json"}
may resulting in the node.js app think the reqeust not legitimate(the word I do not know how to explain in English).
If the node.js app is developed by yourself, you can try to find the frame's check after create a tcp connection and before the logic code,the way is to read the source code.
If the node.js app is not developed by yourself,try to change the header mixing the default header to find which header key checked by the node.js app.
But in my thought,It is import ,about the node.js app's interface description:
we just use by interface description engouth,just need to know the error from the api header's check, which the description should show but not show to us?
Hope to help you.
and thank you for you useful help already.
I am trying to make an API call using python. Sadly, the only documentation of the API is an implementation already existing in C#.
My problem is, that after i acquire an Azure AADTokenCredential object - i simply do not know how to use it in my HTTPS request.
def get_data_from_api(credentials):
serialNumber = "123456789"
fromDate = "01/10/2019 00:00:00" # DD/m/YYYY HH:MM:SS
untilDate = "09/10/2019 00:00:00" # DD/m/YYYY HH:MM:SS
PARAMS = {
serialNumber: serialNumber,
fromDate: fromDate,
untilDate: untilDate
}
url = "https://myapi.azurewebsites.net/api/sensordata/GetBySerialNumber"
r = requests.get(url = url, header={"Authorization": credentials}, params=PARAMS)
print(r)
#data = r.json()
return data
The credentials is an msrestazure.azure_active_directory.AADTokenCredentials retrieved using the adal package.
The above code results in an error as the header object can only be strings.
My question is - How do i pass the authorization object in the correct way?
The C# implementation looks like this:
// Make a request to get the token from AAD
AuthenticationResult result = Task.Run(async () => await authContext.AcquireTokenAsync(resource, cc)).Result;
// Get the auth header which includes the token from the result
string authHeader = result.CreateAuthorizationHeader();
// ...
// Prepare a HTTP request for getting data.
// First create a client
HttpClient client = new HttpClient();
// Create the actual request. It is a GET request so pass the arguments in the url is enough
HttpRequestMessage request = new HttpRequestMessage(
HttpMethod.Get, $"https://api.azurewebsites.net/api/sensordata/GetBySerialNumber?serialNumber={serialNumber}&from={fromDate}&until={untilDate}");
// Add the required authorization header that includes the token. Without it the request will fail as unauthorized
request.Headers.TryAddWithoutValidation("Authorization", authHeader);
// Prepare the response object
HttpResponseMessage response = Task.Run(async () => await client.SendAsync(request)).Result;
So yes! I finally solved it.
My problem was that i was passing on the ADAL object to the requests phase, however what I needed to do was pass on the actual token that is retrieved using: 'credentials = context.acquire_token_with_client_credentials(resource_uri,client_id,client_secret)'.
Here credentials is a dictionary and what the requests needs in the header for authentication was:
header = {
"Authorization": "Bearer "+credentials["accessToken"]
}
r = requests.get(url=url, headers=header, params=PARAMS)
passing this on to the requests.get method worked!
I'm fairly new to Python programming and I don't know all the libraries needed for the following.
I would like to use Python to test some HTTP APIs. Mainly I want to use OAuth and make a few JSON calls. The APIs in question can be found on: https://developers.trustpilot.com/authentication and the generate product review link (I can only use one link)
I want to authenticate myself and then generate a product review link in one step. So far I've been using the Advanced REST client (ARC) to make these calls individually. I could also use .arc files if you think it's easier.
The idea would be make these calls successively in one go. So it would be something along the lines:
1) Make the authentication call.
The HTTP Method looks like this:
https://api.trustpilot.com/v1/oauth/oauth-business-users-for-applications/accesstoken
Method Post:
Header
Authorization: Basic Base64encode(APIkey:Secret)
Content-Type: application/x-www-form-urlencoded
Payload:
grant_type=password&username=user#mail.com&password=SomePass
Translate this bit into Python basically.
1.a) Add a header to the call
Header Authorization: base64encode hash Content-Type: application/x-www-form-urlencoded
1.b) Add a payload to the call
Payload: grant_type=password&username
4) Receive the token from call made in step 1) (Result is format)
"access token": Auth_token
5) Take the token and use it in creating a product review.
5.a) Add the token in the header
Header: Authorization: Bearer Auth_token
6.a) Add a JSON payload to the call made in step 5.
Here's the code I have so far:
Import requests
header = {'Authorization: Basic NnNrQUprTWRHTU5VSXJGYXBVRGxack1oT01oTUFRZHI6QTFvOGJjRUNDdUxBTmVqUQ==}','Content-Type: application/x-www-form-urlencoded'}
payload = {'grant_type=password&username=email#address.com&password=SomePassword'}
r = requests.post('https://api.trustpilot.com/v1/oauth/oauth-business-users-for-applications/accesstoken', headers=header, params=payload )
Ideally I want to create the requests.post(url, header, payload) and then return what the server answers in JSON format. I think that print r.text would do the last part.
So this is the code I have writtent (that works now):
import requests
import getpass
import json
from requests.auth import HTTPBasicAuth
header = {'grant_type':'password' , 'username':'mail#maildomain.com', 'password':'YourPassword'}
username= "YOURAPIKEY" #APIKey
password= "YOURSECRET" #Secret
res = requests.post(
'URL/v1/oauth/oauth-business-users-for-applications/accesstoken',
auth=HTTPBasicAuth(username, password), # basic authentication
data=header)
#print(res.content) #See content of the call result.
data = res.json() # get response as parsed json (will return a dict)
auth_token = data.get('access_token')
requests can do all what you ask without any work from your part.
See the doc for authentication, parameters, json output, json input
Make the authentication call.
import requests
import getpass
from requests.auth import HTTPBasicAuth
username = raw_input('Username: ')
password = getpass.getpass('Password: ')
res = requests.post(
'https://api.trustpilot.com/v1/oauth/oauth-business-users-for-applications/accesstoken',
auth=HTTPBasicAuth(username, password), # basic authentication
params={ # url parameters
'grant_type': 'password',
'username': 'email#address.com',
'password': 'SomePassword'
})
Receive the token from call made in step 1) (Result is format)
# res = requests.post.....
data = res.json() # get response as parsed json (will return a dict)
auth_token = data.get('access token')
Take the token and use it in creating a product review.
request.post(
'.../product_review',
headers={
'Authorization': 'Bearer ' + auth_token
},
json={'my': 'payload'}) # send data as json
I'm working on a simple command-line Pushbullet Python project, and have the following code:
from settings import *
import urllib
import urllib2
def pushSms(number, message):
url = 'https://api.pushbullet.com/v2/ephemerals'
values = {
"type": "push",
"push": {
"type": "messaging_extension_reply",
"package_name": "com.pushbullet.android",
"source_user_iden": settings["PUSHBULLET_USER_IDEN"],
"target_device_iden": settings["PUSHBULLET_SMS_IDEN"],
"conversation_iden": number,
"message": message
}
}
headers = {"Authorization" : "Bearer " + settings["PUSHBULLET_API_KEY"]}
data = urllib.urlencode(values)
req = urllib2.Request(url, data, headers)
response = urllib2.urlopen(req)
return response
Example usage might be pushSms("555 555 5555", "Hi there!").
This takes advantage of the Pushbullet android app access to SMS, as documented here. I've checked my settings variables and they're all valid (in fact, they're currently in use in a JavaScript version of nearly this exact code in another project of mine.
My suspicion is that this is a basic Python syntax/urllib2 misuse or error, but I've been staring/Googling for hours and can't see my error. Thoughts?
I can't tell for certain (the response from the server may contain more information), but because we accept both form encoded and json requests, you probably need to set the header "Content-Type: application/json" on the request.
If that's not the case, could you post the body of the 400 response?