I am trying to accomplish the Oauth authentication on Identi.ca. Basically, I am trying to use the very same code that works for Twitter, but, of course, changing the urls. I am not even being able to get the request token, because of a HTTP Error 400: Bad Request, as shown bellow. I really would like to know what I am doing wrong, or what differs from the Twitter way of doing it. What I have so far is:
from oauth import oauth
import urllib2
class IdenticaOauth:
def __init__(self):
self.request_token_url = 'https://identi.ca/api/oauth/request_token'
self.access_token_url = 'https://identi.ca/api/oauth/access_token'
self.authorize_url = 'https://identi.ca/api/oauth/authorize'
self.consumer_key = '8024d4db70d9e49d22728f25b4c1458b'
self.consumer_secret = '4eb762cfe3c0a55950375dad795cf20e'
self.consumer = oauth.OAuthConsumer(self.consumer_key, self.consumer_secret)
self.signature_method = oauth.OAuthSignatureMethod_HMAC_SHA1()
def get_unauthorized_request_token(self):
oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer, http_url = self.request_token_url)
oauth_request.sign_request(self.signature_method, self.consumer, None)
url = oauth_request.to_url()
response = self.get(url)
token = oauth.OAuthToken.from_string(response)
return token
def get(self, url):
request = urllib2.Request(url)
# urllib2.HTTPError: HTTP Error 400: Bad Request
response = urllib2.urlopen(request)
return response.read()
identica_oauth = IdenticaOauth()
request_token = identica_oauth.get_unauthorized_request_token()
Related
I have the below requests for GET & POST and the GET's work fine and the post shows a 200 response but when i check the external program it has not received any data from the post.
import requests
import json
class BearerAuth(requests.auth.AuthBase):
def __init__(self, token):
self.token = token
def __call__(self, r):
r.headers["authorization"] = "Bearer " + self.token
return r
class BearerAuth2(requests.auth.AuthBase):
def __init__(self, token):
self.token = token
def __call__(self, s):
s.headers["authorization"] = "api " + self.token
return s
headers={'content-type': 'application/json'}
response = requests.get('https://api', auth=BearerAuth('123'))
response2 = requests.get('https://api2', auth=BearerAuth('123'))
splunktok = requests.post('https://http-inputs', data={response, respons2}, headers=headers, auth=BearerAuth2('456'))
print(response.json(), response2.json())
What i want to do is get all the response body data from response & response 2 and use it in the POST to my external program. im not sure if i need to store the response as raw in variables first?
You are sending the requests.Response objects as a set:
data={response, respons2}
Assuming you intend to send the JSON responses, you can do something like:
data={**response.json(), **respons2.json()}
Ive worked this out. I added the below
after the first request i add
payload=response.json()
and then on the post i added
data=json.dumps(payload)
i created a script that will get the users friend list (GET request) and i was successful. Now i am attempting to make a script that will follow a particular user (POST request) and i've been unsuccessful.
here is my oauth function (where the problem lies):
def augment_POST(url,**kwargs) :
secrets = hidden.oauth()
consumer = oauth2.Consumer(secrets['consumer_key'], secrets['consumer_secret'])
token = oauth2.Token(secrets['token_key'],secrets['token_secret'])
oauth_request = oauth2.Request.from_consumer_and_token(consumer, token= token, http_method='POST', http_url=url, parameters=kwargs)
oauth_request.to_postdata() # this returns post data, where should i put it?
oauth_request.sign_request(oauth2.SignatureMethod_HMAC_SHA1(), consumer, token)
return oauth_request.to_url()
my augment_GET function is the exact same thing except http_mehtod='GET'
for clarity:
def follow_user(id):
seedurl="https://api.twitter.com/1.1/friendships/create.json"
print 'Attempting to follow: %d' % (id,)
url = augment_POST(seedurl,user_id=id)
connection = urllib.urlopen(url)
data = connection.read()
headers = connection.info().dict
any help will be greatly appreciated.
First it seems you need to import urllib2 to make a POST request.
You have to send the POST data that you get from the to_postdata method
using the data argument of urlopen:
def augment_POST(url, **kwargs) :
secrets = hidden.oauth()
consumer = oauth2.Consumer(secrets['consumer_key'],
secrets['consumer_secret'])
token = oauth2.Token(secrets['token_key'],
secrets['token_secret'])
oauth_request = oauth2.Request.from_consumer_and_token(
consumer,
token= token,
http_method='POST',
http_url=url,
parameters=kwargs
)
oauth_request.sign_request(oauth2.SignatureMethod_HMAC_SHA1(),
consumer, token)
# this is the data that must be sent with you POST request
return oauth_request.to_postdata()
def follow_user(id):
url = "https://api.twitter.com/1.1/friendships/create.json"
print 'Attempting to follow: %d' % id
postdata = augment(url, method='GET', user_id=id)
# Send the POST request with the data argument
# The url is the same as the data is sent in the body of the request
connection = urllib2.urlopen(url, data=postdata)
data = connection.read()
headers = connection.info().dict
I would recommend to use the requests_oauthlib module which makes all this really easy:
from requests_oauthlib import OAuth1Session
tokens = hidden.oauth()
client = OAuth1Session(tokens['consumer_key'],
tokens['consumer_secret'],
tokens['token_key'],
tokens['token_secret'])
def follow_user(id):
url = "https://api.twitter.com/1.1/friendships/create.json"
print 'Attempting to follow: %d' % id
# for GET requests use client.get and the `params` argument
# instead of the `data` argument
response = client.post(url, data={'user_id': id})
data = response.text
# or even `data = response.json()` to decode the data
headers = response.headers
I am trying to fetch a pdf stream through python requests from flipkart.
But on running label.status_code i am getting 415.
My code:
class FlipkartAPI:
def __init__(self, token):
self.token = token
self.session = self.get_session()
def get_session(self):
session = requests.Session()
session.headers.update({'Authorization': 'Bearer %s' % self.token,
'Content-type': 'application/json',})
return session
def fetch_labels(self, orderItemIds):
self.session.headers.update({'Content-type':'application/octet-stream'})
url = "https://api.flipkart.net/sellers/orders/labels"
payload = {'orderItemId':','.join(orderItemIds)}
return self.session.get(url, params=payload, stream=True)
Function call:
fk = FlipkartAPI(token)
label = fk.fetch_labels(oiids)
print label.status_code
print label.url
print label.content
I get:
415
https://api.flipkart.net/sellers/orders/labels?orderItemId=230005995
The link for documentation is: Documentation
I searched on internet and it says the error is for unsupported media type.
So what am i doing wrong?
Don't set a Content-Type header, you are sending a GET request, which has no body so has no content to set a type for.
Instead, set an Accept header, as detailed in the documentation. Do not set that header for the whole session, just for this request:
def fetch_labels(self, orderItemIds):
url = "https://api.flipkart.net/sellers/orders/labels"
headers = {'Accept': 'application/octet-stream'}
payload = {'orderItemId':','.join(orderItemIds)}
return self.session.get(url, params=payload, headers=headers, stream=True)
What I want to do is GET from a site and if that request returns a 401, then redo my authentication wiggle (which may be out of date) and try again. But I don't want to try a third time, since that would be my authentication wiggle having the wrong credentials. Does anyone have a nice way of doing this that doesn't involve properly ugly code, ideally in python requests library, but I don't mind changing.
It doesn't get any less ugly than this, I think:
import requests
from requests.auth import HTTPBasicAuth
response = requests.get('http://your_url')
if response.status_code == 401:
response = requests.get('http://your_url', auth=HTTPBasicAuth('user', 'pass'))
if response.status_code != 200:
# Definitely something's wrong
You could have wrapped this in a function and used a decorator to evaluate the response and retry the auth on 401. Then you only need to decorate any function that requires this re-auth logic....
Update:
As requested, a code example. I'm afraid this one is an old piece of code, Python 2 based, but you'll get the idea. This one will retry an http call a number of times as defined in settings.NUM_PLATFORM_RETRIES and will call a refresh_token on auth failures. you can adjust the use case and result to whatever.
You can then use this decorator around methods:
#retry_on_read_error
def some_func():
do_something()
def retry_on_read_error(fn):
"""
Retry Feed reads on failures
If a token refresh is required it is performed before retry.
This decorator relies on the model to have a refresh_token method defined, othewise it will fail
"""
#wraps(fn)
def _wrapper(self, *args, **kwargs):
for i in range(settings.NUM_PLATFORM_RETRIES):
try:
res = fn(self, *args, **kwargs)
try:
_res = json.loads(res)
except ValueError:
# not a json response (could be local file read or non json data)
return res
if 'error' in _res and _res['error']['status'] in (401, 400):
raise AccessRefusedException(_res['error']['message'])
return res
except (urllib2.URLError, IOError, AccessRefusedException) as e:
if isinstance(e, AccessRefusedException):
self.refresh_token()
continue
raise ApiRequestFailed(
"Api failing, after %s retries: %s" % (settings.NUM_PLATFORM_RETRIES, e), args, kwargs
)
return _wrapper
You can use something like this
# 401 retry strategy
import requests
from requests import Request, Session, RequestException
class PreparedRequest:
"""
Class to make Http request with 401 retry
"""
failedRequests = []
defaultBaseUrl = "https://jsonplaceholder.typicode.com"
MAX_RETRY_COUNT = 0
def __init__(self, method, endpoint,
baseurl=defaultBaseUrl, headers=None, data=None, params=None):
"""
Constructor for PreparedRequest class
#param method: Http Request Method
#param endpoint: endpoint of the request
#param headers: headers of the request
#param data: data of request
#param params: params of the request
"""
self.method = method
self.url = baseurl + endpoint
self.headers = headers
self.data = data
self.params = params
self.response = None
def send(self):
"""
To send http request to the server
#return: response of the request
"""
req = Request(method=self.method, url=self.url, data=self.data,
headers=self.headers,params=self.params)
session = Session()
prepared = session.prepare_request(req)
response = session.send(prepared)
if response.status_code == 200:
PreparedRequest.failedRequests.append(self)
PreparedRequest.refresh_token()
elif response.status_code == 502:
raise Exception(response.raise_for_status())
else:
self.response = session.send(prepared)
#staticmethod
def refresh_token():
if PreparedRequest.MAX_RETRY_COUNT > 3:
return
print("Refreshing the token")
# Write your refresh token strategy here
PreparedRequest.MAX_RETRY_COUNT += 1
total_failed = len(PreparedRequest.failedRequests)
for i in range(total_failed):
item = PreparedRequest.failedRequests.pop()
item.send()
r = PreparedRequest(method="GET", endpoint="/todos/")
r.send()
print(r.response.json())
You need to send in the header of the request the authentication param
import requests
from requests.auth import HTTPBasicAuth
auth = HTTPBasicAuth("username", "password")
response = requests.get("http://serverIpOrName/html", auth=auth)
if response.status_code == 401 :
print("Authentication required")
if response.status_code == 200:
print(response.content)
I'm trying to issue a basic UbuntuOne API call.
As explained on https://one.ubuntu.com/developer/account_admin/auth/otherplatforms, I'm getting the OAUTH token and then passing it to the UbuntuOne service.
I get the token and consumer info alright
I'm then trying to issue a /api/file_storage/v1 API call (see: https://one.ubuntu.com/developer/files/store_files/cloud.) The request is signed using the OAUTH token.
The code snippet below is the exact code I'm executing (minus the email.password/description fields.) The token and consumer data is returned properly. I'm getting a '401 UNAUTHORIZED' from the server when issuing the /api/file_storage/v1 request... any idea why?
import base64
import json
import urllib
import urllib2
import oauth2
email = 'bla'
password = 'foo'
description = 'bar'
class Unauthorized(Exception):
"""The provided email address and password were incorrect."""
def acquire_token(email_address, password, description):
"""Aquire an OAuth access token for the given user."""
# Issue a new access token for the user.
request = urllib2.Request(
'https://login.ubuntu.com/api/1.0/authentications?' +
urllib.urlencode({'ws.op': 'authenticate', 'token_name': description}))
request.add_header('Accept', 'application/json')
request.add_header('Authorization', 'Basic %s' % base64.b64encode('%s:%s' % (email_address, password)))
try:
response = urllib2.urlopen(request)
except urllib2.HTTPError, exc:
if exc.code == 401: # Unauthorized
raise Unauthorized("Bad email address or password")
else:
raise
data = json.load(response)
consumer = oauth2.Consumer(data['consumer_key'], data['consumer_secret'])
token = oauth2.Token(data['token'], data['token_secret'])
# Tell Ubuntu One about the new token.
get_tokens_url = ('https://one.ubuntu.com/oauth/sso-finished-so-get-tokens/')
oauth_request = oauth2.Request.from_consumer_and_token(consumer, token, 'GET', get_tokens_url)
oauth_request.sign_request(oauth2.SignatureMethod_PLAINTEXT(), consumer, token)
request = urllib2.Request(get_tokens_url)
for header, value in oauth_request.to_header().items():
request.add_header(header, value)
response = urllib2.urlopen(request)
return consumer, token
if __name__ == '__main__':
consumer, token = acquire_token(email, password, description)
print 'Consumer:', consumer
print 'Token:', token
url = 'https://one.ubuntu.com/api/file_storage/v1'
oauth_request = oauth2.Request.from_consumer_and_token(consumer, token, 'GET', url)
oauth_request.sign_request(oauth2.SignatureMethod_PLAINTEXT(), consumer, token)
request = urllib2.Request(url)
request.add_header('Accept', 'application/json')
for header, value in oauth_request.to_header().items():
request.add_header(header, value)
response = urllib2.urlopen(request)
The issue was with the 'description' field. It must be in the following format:
Ubuntu One # $hostname [$application]
Else, the UbuntuOne service returns a "ok 0/1" and does not register the token.