I have been regularly accessing an API at work using curl. But now i need to do a bit of automation for the same.
Was trying to translate what i do with curl into python using the requests module.
But I keep receiving a 401 error.
My curl requests that i regularly are as below:
Step1: Session Authentication with cookies:
curl -b cookies -c cookies -v -X POST -H "Content-Type: application/json" --data-binary '{"auth":{"username":"aaa","password":"bbb"}}' http://api.xyz.at/auth
Step2: Access API URL for data retrieval
curl -b cookies -c cookies http://api.xyz.at/somepage?per_id=556677
Now using Python Requests, here is what I am doing
Step1: For Authentication
username = 'aaa'
password = 'bbb'
s = requests.Session()
s.post('http://api.xyz.at/auth',auth=('username','pasword'))
This "i think" works fine, and give me the below response
<Response [200]>
Step2: Access API URL for data retrieval
s.get('http://api.xyz.at/somepage?per_id=556677')
but this Step 2 keeps returning an error
<Response [401]>
The code is failing and not sure where.
My Python skills are visibly pedestrian. I have been looking at the Requests website. But unfortunately haven't been able to decipher.
Guidance would be appreciated :)
import urllib2, urllib
url = 'http://api.xyz.at/auth'
pm = urllib2.HTTPPasswordMgrWithDefaultRealm()
pm.add_password(None, url, 'user', 'password')
auth = urllib2.HTTPBasicAuthHandler(pm)
opener = urllib2.build_opener(auth)
urllib2.install_opener(opener)
request = urllib2.Request('http://api.xyz.at/somepage?per_id=556677', None)
handler = urllib2.urlopen(request)
handler.read()
Since you are getting a 401 error I guess you are not passing the authentication token which you get as response from login API. Use the same auth token to perform other options - Get-post-Delete.
Related
I am testing some APIs whose only documentation is the response to the requests for the respective APIs. Basically when I execute I get for all the requests: {"detail":"Authentication credentials were not provided."} except for the login request which is successful, this is because I obviously pass the parameters to it as required I guess.
Below is my code for the requests:
import requests
credential = {'identity' : 'xxxxxxx', 'password': 'xxxxxx'}
#use the 'auth' parameter to send requests with HTTP Basic Auth: auth = ('xxxxxx', 'xxxxxxx')
#url list
api_login = 'https://xxxxxxxx/api/login'
api_channel = 'https://xxxxxxxx/api/channel'
#requests
r_login = requests.post(url=api_login, data = credential)
print(r_login.status_code)
r_channels = requests.get(url=api_channel)
print(r_channels.text)
If it can help, following the info for the API that fail the authentication:
Curl
curl -X 'GET' \
'https://xxxxxxx/api/channels' \
-H 'accept: application/json' \
-H 'X-CSRFToken: xxxxxxxxx'
Request URL
https://xxxxxxx/api/channels
At the moment I've tried using basic authentication in the GET request and passing the headers in the documentation curl but as I'm not a bit practical I might have got it wrong.
I want to use the Bitbucket API to get information of a private repository.
It works fine with curl:
curl -u username:apppassword https://api.bitbucket.org/2.0/repositories/company/repo
But not with Python (Unfortunately I have to use Python 3.4):
#!/usr/bin/env python3
from pybitbucket.auth import BasicAuthenticator
from pybitbucket.bitbucket import Client
from pybitbucket.repository import Repository
from pybitbucket.user import User
client = Client(BasicAuthenticator('username', 'apppassword ', 'usermail'))
print(User.find_current_user(client).display_name)
print(Repository.find_repository_by_full_name("company/repo"))
User name is printed correctly. But Repository.find_repository_by_full_name raises a 403 (forbidden).
Same thing, when I try to do it with urllib:
import urllib.request
base_url = 'https://api.bitbucket.org/2.0/'
password_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
password_mgr.add_password(None, base_url, 'username', 'apppassword ')
handler = urllib.request.HTTPBasicAuthHandler(password_mgr)
opener = urllib.request.build_opener(handler)
with opener.open(base_url + 'user') as f:
print(f.read())
with opener.open(base_url + 'repositories/company/repo') as f:
print(f.read())
Authentication must work, otherwise it could not return my user name correctly. Also, when I enter wrong credentials, I get a 401 (unauthorized) instead of a 403 (forbidden).
On the other hand, it works perfectly fine when I use curl.
Oh, it doesn't work with wget either:
wget --http-user=username --http-passwd=apppassword https://api.bitbucket.org/2.0/repositories/company/repository
What is curl doing different than wget and Python?
The Bitbucket API doesn't answer with 401 Unauthorized when I call https://api.bitbucket.org/2.0/repositories/company/repository. This can easily tested with a browser. It doesn't ask for credentials but shows Access denied. You must have write or admin access. So no authentication will take place.
But when I open https://api.bitbucket.org/2.0/user, Bitbucket responses with 401 Unauthorized and the header www-authenticate: Basic realm="Bitbucket.org HTTP", so the browser knows to show the authentication dialog. That's why getting the user data works on Python.
To solve this, I have to enforce to send the authentication even when the server doesn't ask for it. I haven't found a way to do this with a urllib.request.HTTPBasicAuthHandler but by adding the Authorization header manually:
import base64
import urllib.request
request = urllib.request.Request('https://api.bitbucket.org/2.0/repositories/company/repository')
base64string = base64.b64encode('{}:{}'.format('username', 'apppassword').encode('ascii'))
request.add_header('Authorization', 'Basic {}'.format(base64string.decode('ascii')))
with urllib.request.urlopen(request) as response:
print(response.read())
I'm aware seems a pretty repetitive issue. From bash and curl I make calls to the API Github this way
# curl -u myuser https://api.github.com/repos/myuser/somerepo/pulls?state=all -H "Authorization: token randomtokenhere" -d '{"title":"Pull Request develop to master","base":"master", "head":"develop"}'
and works like a charm. However, from Python 3(3.5.2) with json and requests, I got an error no matter what.
Example:
user = "myuser"
password = "sompassword"
url = "https://api.github.com/repos/myuser/somerepo/pulls?state=all"
token = "randomtokenhere"
title = "Pull Request develop to master"
base = "master"
head = "develop"
headers = {'Authorization': 'token ' + token}
content = {"title":title,"base":base, "head":head}
req = requests.post(url,json=json.dumps(content),auth=(user,password),headers=headers)
print("response posts is {} and status code is {}".format(req.text,req.status_code))
the response of requests is
response posts is {"message":"Must specify two-factor authentication OTP code.","documentation_url":"https://developer.github.com/v3/auth#working-with-two-factor-authentication"} and status code is 401
so it seems the call is just missing the token in some way. But I'm not able to know why. Can I debug this in some way? Or did I miss something very obvious?
Thanks
Well, sorry for bother, my call was not correct. This actually worked:
//req = requests.post(url,json=json.dumps(content),auth=(user,password),headers=headers)
req = requests.post(url,json=content,auth=(user,token))
I've removed the json.dumps function, removed the headers parameter, and instead use password I set up the token with the auth.
Regards
I have a curl command that works perfectly fine and gives me a HTTP 200.
curl -i -H "Authorization: Basic jadkfhjkafDSKJ12DD=" http://<ip>/LoadTest/rest/authentication-point/authenticate
The above API needs the authorization in base64 format and the details have to be passed as Headers. This is a GET request.
When I try to run the same in Python 2.7, I get Response [403]. Code below.
import requests
headers = {'Authorization': 'Basic jadkfhjkafDSKJ12DD='}
authurl = "http://<ip>/LoadTest/rest/authentication-point/authenticate"
r = requests.get(authurl, headers=headers)
print r.status_code
What am I missing here? How should i pass the authorization values exactly like I passed in the curl command? I've tried multiple ways but still end up getting HTTP 403 always. Kindly guide.
Thanks all for your inputs. This is the final solution. I found that there is proxy that is stopping the payload. So added the session to the request.
import requests
session = requests.Session()
session.trust_env = False
headers = {'Authorization': 'Basic jadkfhjkafDSKJ12DD='}
authurl = "http://<ip>/LoadTest/rest/authentication-point/authenticate"
r = session.get(authurl, headers=headers)
print r.status_code
Setting the trust_env=False ignores the following:
Authentication information from .netrc (code)
CA bundles defined in
REQUESTS_CA_BUNDLE or CURL_CA_BUNDLE (code)
I'm new with cURL and Requests and I have a doubt on how I can transform a cURL petition to a Requests command in Python.
Looking at Apache Stratos documentation Doc Page to perform a login against the server, in cURL you use:
curl -X GET -H "Content-Type: application/json" -k -v -u admin:admin https://localhost:9443/api/session
And it works on the terminal. Now, I want to do the same on my Django website and to transform the curl URL to python code and use the module "requests" I don't know how pass the user and pass info on the petition.
The code that I have now it's:
headers = {'Content-Type':'application/json'}
data = {}
req = requests.post('https://localhost:9443/api/session', headers=headers, params=data)
But I don't know how pass the user and password so I tried this (Requests Python Login Tutorial)
data = {"username":"admin","password":"admin"}
But I get a certificate error from server:
File "/usr/lib/python2.7/dist-packages/requests/adapters.py", line 385, in send raise SSLError(e)
requests.exceptions.SSLError: [Errno 1] _ssl.c:510: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
So, I'm sending correctly the user and password? How I can solve the certificate error?
Thanks and regards
You can turn off SSL cert verification with the verify flag, and use basic authentication by specifying auth.
from requests.auth import HTTPBasicAuth
req = requests.post('https://localhost:9443/api/session', headers=headers, auth=HTTPBasicAuth('admin', 'admin'), verify=False)
See the requests docs for more info.
You are using your localhost which almost certainly doesn't have a valid certificate.
For testing purposes disable ssl verification (it is still encrypted just not verifying certificate)
req = requests.post('https://localhost:9443/api/session', headers=headers, params=data, verify=False)
After the #Sam solution and looking on the Requests Auth Doc Page I found the solution:
The Python Resquest code it's:
requests.get('https://localhost:9443/api/session', headers=headers, auth=HTTPBasicAuth('admin', 'admin'), verify=False)
The "params" field it's not needed.
And then:
u'{"Success":{ "sessionId": "547D78FD4966DDBE21AEFDAECE909DEC"}}'
Hope it helps someone!