POST Request in Python 'requests' module not working properly - python

POST https://maxcvservices.dnb.com/rest/Authentication
x-dnb-user: MyUsername
x-dnb-pwd: MyPassword
is the documentation of the D&B API and hence I am trying to send a POST request using python requests module using the following line of code:
r = requests.post('https://maxcvservices.dnb.com/rest/Authentication',params={'x-dnb-user':userid,'x-dnb-pwd':pass})
the response I am getting is Response [500]
and the content of the response is : error processing request\r\n
My question is whether I am doing something wrong while passing the post request and the parameters or is it a problem with my username and password being invalid?
I feel the problem lies in the way I am passing the POST request as the API responds with a separate error 401 for incorrect userid, pass.
{'connection': 'Keep-Alive',
'content-encoding': 'gzip',
'content-length': '46',
'content-type': 'text/plain',
'date': 'Sat, 26 Oct 2013 17:43:22 GMT',
'server': '',
'vary': 'Accept-Encoding',
'x-correlationid': 'Id-d4c07ad3526bff3a03fb742e 0'}
my response header when I use:
r = requests.post('https://maxcvservices.dnb.com/rest/Authentication', headers={'x-dnb-user': 'userid', 'x-dnb-pwd': 'password'})
A random user-id and password.
But according to the API I am supposed to receive <Response [401]> .
I receive <Response [500]> instead.

Those are HTTP headers; quoting the API documentation:
Secure access to D&B Direct services is managed through the use of an Authentication Token, which can be obtained by sending an HTTP POST request to Authentication Service URL, passing a valid username and password in the HTTP header.
Add them as such:
r = requests.post(
'https://maxcvservices.dnb.com/rest/Authentication',
headers={'x-dnb-user': userid, 'x-dnb-pwd': password})
This works for me, albeit that I get a 401 response (as I don't have any valid credentials):
>>> import requests
>>> requests.__version__
'2.0.0'
>>> r = requests.post('https://maxcvservices.dnb.com/rest/Authentication',
... headers={'x-dnb-user': 'userid', 'x-dnb-pwd': 'password'})
>>> r
<Response [401]>
>>> r.headers['authorization']
'INVALID CREDENTIALS'
entirely as documented.

Related

Upload Multipart/Form Data to WordPress REST API with Python

I have an API I am building out that will allow me to upload media to my WordPress website using their new API. I have searched all over the internet and SO for a solution to this problem, but all of the answers seem to be using an older WordPress API so I have not had much success in finding an answer.
I have the following code written out in a function to send a multipart/form-data request to the API:
img = open(image_path, 'rb')
file_name = os.path.basename(image)
print('Compressing and sending data...')
NEW_HEADER = {
'Authorization': f'BEARER {WORDPRESS_ACCESS_TOKEN}',
'Content-Disposition': f'attachment; filename={file_name}',
'Content-Type': 'multipart/form-data'
}
response = requests.post(
url=WORDPRESS_MEDIA_URL,
files={'media': img.read()},
headers=NEW_HEADER
)
print(response.request)
print(response.text)
return response
Which returns me:
{"media":[],"errors":[]}
<Response [200]>
OK
So, it sends something to the endpoint, but it's return an empty array and empty error box. Again, I can't seem to find any solution for the new WP, so forgive me if the Python seems a little hacky and put-together, I've just been putting together what appears to work.
Further Reading Since Original Posting
I pinged the API with Postman and it returns data as expected:
{"media":[{"id":"xxxx","date":"2022-11-03T20:06:54-05:00","parent":0,"link":"https:mywebsite","title":"mypicture","caption":"","description":"",...}
So, Since the post request seems to not be the issue, I tried to debug my request in Postman and my local console to see what was being sent:
{'User-Agent': 'python-requests/2.28.1', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Authorization': 'BEARER QnkXS43KhiqO7Oa!9G!zN2gnz90hHhZEribF2ddZu0h8&5V0p5M69^OwDb9E6H%B', 'Content-Type': 'multipart/form-data', 'Content-Length': '6'}
media=
And I see that the media returns empty from my local console. In Postman, the media is returned as undefined (though I'm not sure if that's just Postman being unable to parse the image in a JSON format in the console/debugger.
This leads me to believe that either the way I am accessing/calling the directory with the image is wrong, or the way I am trying to encode it to the request.
Even Further Reading Since Posting
I have since circumnavigated any concerns about directory issues by copying the photos from an external directory to that of one inside the project folder.
Since then, it appears that the current way I am sending the data returns the same response as if I am sending nothing at all:
response = requests.post(
url=WORDPRESS_MEDIA_URL, # there is no data sent in this request.
headers=NEW_HEADER
)
Which still returns me:
{"media":[],"errors":[]}
<Response [200]>
OK
This leads me to believe that the way I am sending the data is incorrect, as WordPress is receiving my request, but is not getting the information that it needs.
So, doing some further reading and research, I come across requests-toolbelt, which is to help sending multipart/form-data:
data = MultipartEncoder(fields={'media': (file_name, img, 'image/jpeg')})
new_header = {
'Authorization': f'BEARER {WORDPRESS_ACCESS_TOKEN}',
'Content-Type': data.content_type,
'Content-Disposition': 'form-data; name="media"; filename="%s"' % name_img,
}
response = requests.post(WORDPRESS_MEDIA_URL, data=data, headers=new_header)
Now, when I send a request with this data, I get this response:
{"error":"unsupported_mime_type","message":"File type unknown"}
<Response [400]>
Bad Request
So sending the request with the MultipartEncoder returns an error of an unsupported MIME type. So while it isn't a blank 200 response, it gives me reason to think that perhaps I am using the MultipartEncoder wrong, or I am not making the proper adjustments to the picture I am trying to upload.
Any insight into this would be greatly appreciated.

POST build to TeamCity queue

I am trying to use the TeamCity REST API to add a build to the queue but am running into some difficulty with authorization.
I have the url to our teamcity server defined, and have generated an authorization token through the admin page
TEAMCITY_URL = 'http://teamcity.somedomain.com'
BEARER_TOKEN = 'SOMELONGTOKEN'
With this URL and token I can successfully make GET requests
import json
import requests
session = requests.Session()
session.headers.update({
'Accept': 'application/json',
'Authorization': f'Bearer {BEARER_TOKEN}',
})
response = session.get(f'{TEAMCITY_URL}/app/rest/projects/example/buildTypes')
assert(response.status_code == requests.codes.ok) # this succeeds, can parse response fine later
but then if I try to POST a build to the queue I get a 403
payload = {
'branchName': 'master',
'buildType': {
'id': buildID # assume this was already defined
}
}
response = session.post(f'{TEAMCITY_URL}/app/rest/buildQueue', json=payload)
assert(response.status_code == requests.codes.ok) # fails with 403
the latter response.text is
'403 Forbidden: Responding with 403 status code due to failed CSRF check: authenticated POST request is made, but neither tc-csrf-token parameter nor X-TC-CSRF-Token header are provided.. For a temporary workaround, you can set internal property teamcity.csrf.paranoid=false and provide valid Origin={teamcity_url} header with your request\n'
How can I correctly use this bearer token to perform a POST request?
The fix for this was I needed to first make a GET request for a CSRF token. I could then use this token to update the session headers with a 'X-TC-CSRF-Token' as follows
response = session.get(f'{TEAMCITY_URL}/authenticationTest.html?csrf')
assert(response.status_code == requests.codes.ok)
csrf_token = response.text
session.headers.update({
'X-TC-CSRF-Token': csrf_token
})
then the subsequent POST would succeed. More details in official docs.

Bad request when calling DocuSign API for JWT user token. Consent?

I'm using the DocuSign API to request a JWT user token:
with open('docusign.pem', mode='rb') as privatefile:
private_key_bytes = privatefile.read()
api_client = ApiClient()
oauth_host_name = 'account-d.docusign.com'
# not real, random:
client_id = 'dff16ff1-de93-477d-a73d-3774ac9932dc'
user_id = '7401f22e-ff2c-4777-9117-5932ace2e71a'
expires_in = 3600
result = api_client.request_jwt_user_token(client_id, user_id,
oauth_host_name,
private_key_bytes,
expires_in,
scopes=(OAuth.SCOPE_SIGNATURE,))
This returns:
(400)
Reason: Bad Request
HTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache', 'Pragma': 'no-cache',
'Content-Type': 'application/json; charset=utf-8', 'Expires': '-1', 'Server':
'Microsoft-IIS/10.0', 'X-AspNetMvc-Version': '5.2', 'X-DocuSign-TraceToken':
'c1d090b7-cefd-4881-80c6-3f1c55ccc5b4', 'X-Content-Type-Options': 'nosniff',
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload,
max-age=15768000', 'X-Frame-Options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block;
report=/client-errors/xss', 'X-DocuSign-Node': 'DA2DFE179', 'Date':
'Sun, 23 Aug 2020 15:18:46 GMT', 'Content-Length': '28'})
HTTP response body: b'{"error":"consent_required"}'
So how to obtain "consent". This page has two sections "Admin consent for internal applications" and "Admin consent for external applications":
DocuSign obtaining consent
I'm not sure how to get consent in the sandbox. It already say "DS Admin" under "permission profile" for the user in DocuSign.
Update
I used the second technique "Admin consent for internal applications" to obtain consent with the settings:
admin_consent_scope=impersonation
response_type=code
scope=openid
And instead of the login I got the message at the DocuSign website:
"You are not an organization admin. Please contact your DocuSign Administrator."
How do I ask DocuSign to enable this feature on my developer account?
See this blog post on granting consent.
Note that the user being impersonated needs to consent to both the signature scope (if you're using the eSignature features), and the impersonation scope.
For individual consent, the two scopes are separated by a space which should be entered as %20, the encoded value.
Example:
https://account-d.docusign.com/oauth/auth?
response_type=code
&scope=signature%20impersonation
&client_id=YOUR_INTEGRATION_KEY
To use admin consent you must have an organization. This requires you to register a domain name and confirm it with DNS records.
While this is the recommended approach, it's a bit more complex.
I would consider using individual consent to get you unblocked for now.
To do that, you just construct a URL like this one:
https://account-d.docusign.com/oauth/auth?
response_type=code
&scope=YOUR_REQUESTED_SCOPES
&client_id=YOUR_INTEGRATION_KEY
&redirect_uri=YOUR_REDIRECT_URI
And proceed to agree and just ignore the code you get back. After that you can use JWT to obtain a token.
&redirect_uri=YOUR_REDIRECT_URI

Received Authentication Denied as Response while trying to get the access token (for Cloudhub.io) with requests library

I'm tying to get the data from the Cloudhub API which resides on Mulesoft.
I tried to access through postman (With the same Client Credentials - Bearer Authorization) and it's working fine (I can able to get the result with proper get requests).
But when I tried to do the same with Python requests library I ran into issues. Here is my piece of code:
import requests
import json, os
CLIENT_ID = os.environ['CLIENT_ID']
CLIENT_SECRET = os.environ['CLIENT_SECRET']
grant_type = 'client_credentials'
body_params = {'grant_type' : grant_type}
headers = {'Accept': '*/*',
'Cache-Control':'no-cache',
'Accept-Encoding': 'gzip, deflate',
'Content-Type':'application/json, application/x-www-form-urlencoded',
'Connection': 'keep-alive'}
url='https://<domain-name>-api.us-w2.cloudhub.io/api/token'
response = requests.post(url, data=body_params, auth = (CLIENT_ID, CLIENT_SECRET), headers= headers)
token_raw = json.loads(response.text)
print(token_raw)
Result: {'error': 'Authentication denied.'}
All I need to know is
How it's working fine with Postman but why I'm not able to connect with python code?
Is there anything I've to change in my code or any additional information needed for this request? or am I passing the correct endpoint in receiving the access token for Cloudhub API?
Please post your suggestions or any documentation that I need to refer.
Hope the information that I gave is clear and Thanks in Advance !!
I found the answer of my own question. I can get it from the postman itself.
Here is my code for API Call with Python.
import http.client
import os
conn = http.client.HTTPSConnection("<domain-name>-api.us-w2.cloudhub.io")
payload = ''
headers = {
'client_id': os.environ['CLIENT_ID'],
'client_secret': os.environ['CLIENT_SECRET']
}
conn.request("GET", "/api/<Query that you want to pass - endpoint>", payload, headers)
response = conn.getresponse()
resp_data = response.read()
print(resp_data.decode("utf-8"))
The URL is incorrect. To call CloudHub REST API you need to obtain a bearer token from Anypoint Platform REST API. The URL mentioned looks to for some application deployed in CloudHub, not from the platform APIs. This is the same method than to get the bearer token to use in Anypoint MQ Admin API. It looks like you are trying to use the Anypoint MQ Broker API, which is an Anypoint MQ specific token.
Example in Curl to get an Anypoint Platform token:
$ curl -H "Content-Type: application/json" -X POST -d '{"username":"joe.blogs","password":"sample.password"}' https://anypoint.mulesoft.com/accounts/login
{
"access_token": "f648eea2-3704-4560-bb46-bfff79712652",
"token_type": "bearer",
"redirectUrl": "/home/"
}
Additionally the Content-type of your example seems incorrect because it has 2 values.
I'm sure the Postman request is different for it to work, or maybe it works only for the Anypoint MQ Broker API.

How to use Python to retrieve xml page that requires http login?

When I access a page on an IIS server to retrieve xml, using a query parameter through the browser (using the http in the below example) I get a pop-up login dialog for username and password (appears to be a system standard dialog/form). and once submitted the data arrives. as an xml page.
How do I handle this with urllib? when I do the following, I never get prompted for a uid/psw.. I just get a traceback indicating the server (correctly ) id's me as not authorized. Using python 2.7 in Ipython notebook
f = urllib.urlopen("http://www.nalmls.com/SERetsHuntsville/Search.aspx?SearchType=Property&Class=RES&StandardNames=0&Format=COMPACT&Query=(DATE_MODIFIED=2012-09-28T00:00:00%2B)&Limit=10")
s = f.read()
f.close()
Pointers to doc also appreciated! did not find this exact use case.
I plan to parse the xml to csv if that makes a difference.
You are dealing with http authentication. I've always found it tricky to get working quickly with the urllib library. The requests python package makes it super simple.
url = "http://www.nalmls.com/SERetsHuntsville/Search.aspx?SearchType=Property&Class=RES&StandardNames=0&Format=COMPACT&Query=(DATE_MODIFIED=2012-09-28T00:00:00%2B)&Limit=10"
r = requests.get(url, auth=('user', 'pass'))
page = r.text
If you look at the headers for that url you can see that it is using digest authentication:
{'content-length': '1893', 'x-powered-by': 'ASP.NET',
'x-aspnet-version': '4.0.30319', 'server': 'Microsoft-IIS/7.5',
'cache-control': 'private', 'date': 'Fri, 05 Oct 2012 18:20:54 GMT',
'content-type': 'text/html; charset=utf-8', 'www-authenticate':
'Digest realm="Solid Earth", nonce="MTAvNS8yMDEyIDE6MjE6MjUgUE0",
opaque="0000000000000000", stale=false, algorithm=MD5, qop="auth"'}
So you will need:
from requests.auth import HTTPDigestAuth
r = requests.get(url, auth=HTTPDigestAuth('user', 'pass'))
There are many ways to do it but i suggest you start with urllib2 and it's batteries included.
import urllib2, base64
req = urllib2.Request("http://webpage.com//user")
b64str = base64.encodestring('%s:%s' % (username, password)).replace('\n', '')
request.add_header("Authorization", "Basic %s" % b64str)
result = urllib2.urlopen(req)
You can use requests, beautifulsoup,mechanize or selenium if your task gets harder. Googling will give you enough examples for each one of these,
This can be done in a couple of ways:
Use urllib/urllib2 and requests as others have suggested
Use Mechanize to simulate manual form-filling and get back the response

Categories

Resources