I am trying to use a WooCommerce Python client to make a POST request but
I get "Provided Signature does not match"
The client I use is from:
WooCommerce API OAuth in python
This is my client:
#!/usr/bin/env python
import requests
import random
import string
import time
from hashlib import sha1
import hmac
import binascii
import re
import collections
from urllib import quote, urlencode
def uksort(dictionary):
return collections.OrderedDict(sorted(dictionary.items(), cmp = cmp))
class WooCommerce(object):
def __init__(self, consumer_key, consumer_secret, endpoint):
self.consumer_key = consumer_key
self.consumer_secret = consumer_secret
self.endpoint = endpoint
def _make_request(self, resource, params, method = "GET"):
oauth_params = {
"oauth_consumer_key": self.consumer_key,
"oauth_nonce": self._gen_nonce(),
"oauth_timestamp": self._gen_timestamp(),
"oauth_signature_method": "HMAC-SHA1",
}
oauth_params["oauth_signature"] = self._gen_signature(resource, dict(params.items() + oauth_params.items()), method)
params = dict(params.items() + oauth_params.items())
if method == "GET":
print self.endpoint + resource + "?" + urlencode(params)
elif method == "POST":
print self.endpoint + resource + "?" + urlencode(params)
req = urllib.request.Request(self.endpoint + resource + "?" + urlencode(params))
open = urllib.request.urlopen(req)
requestContent = open.read()
#print(open)
def _gen_nonce(self):
ran_string = ''.join(random.choice(string.ascii_uppercase + string.digits) for i in range(32)).encode("base64")
alnum_hash = re.sub(r'[^a-zA-Z0-9]', "", ran_string)
return alnum_hash
def _gen_timestamp(self):
return int(time.time())
def _gen_signature(self, resource, params, method):
base_request_uri = quote(self.endpoint + resource, safe = "")
normalized_params = self._normalize_params(params)
sorted_params = uksort(normalized_params)
query_string = "%26".join([key + "%3D" + value for key, value in sorted_params.iteritems()])
raw_string = method + "&" + base_request_uri + "&" + query_string
hashed = hmac.new(self.consumer_secret, raw_string, sha1)
return binascii.b2a_base64(hashed.digest()).rstrip("\n")
def _normalize_params(self, params):
normalized = {}
for key, value in params.iteritems():
key = quote(str(key), safe = "")
value = quote(str(value), safe = "")
normalized[key] = value
return normalized
And I use it like this from another class:
woo_client = WooCommerce('ck_7bb1951bee7454b2e29bf5eef9205e0e', 'cs_155cd9420201c0a7e140bebd6a9794c7', 'http://dima.bg/wc-api/v2')
data = {
"product": {
"title": "testname",
}
}
result = self.woo_client._make_request("/products/", data, 'POST')
Can you see something wrong with my URL ? Thanks for your time.
http://xxxxxxxxx.xx/wc-api/v2/products/?product=%7B%27title%27%3A+%27testname%27%7D&oauth_nonce=NThWODczRFIyWkxRNFZOVkUxNFdRSVo0QjFSNllIVFk&oauth_timestamp=1423647865&oauth_consumer_key=ck_7bb1951bee7454b2e29bf5eef9205e0e&oauth_signature_method=HMAC-SHA1&oauth_signature=3PSnEEf08gFthIRAr8AUKQiDjco%3D
I used your code as a starting point for my own solution to this problem and had some success! Here's what I did:
import requests
import random
import string
import time
from hashlib import sha1
import hmac
import binascii
import re
from urllib import quote, urlencode
import httplib2
from collections import OrderedDict
def key_compare(a, b):
return cmp(a[0], b[0])
class Restful_Client(object):
"""docstring for Restful_Client"""
def __init__(self, endpoint, consumer_key, consumer_secret):
super(Restful_Client, self).__init__()
self.consumer_key = consumer_key
self.consumer_secret = consumer_secret
self.endpoint = endpoint
def make_request(self, resource, params, method='GET' ):
oauth_params = {
'oauth_consumer_key': self.consumer_key,
'oauth_nonce': self.gen_nonce(),
'oauth_timestamp': self.gen_timestamp(),
'oauth_signature_method': 'HMAC-SHA1',
# 'oauth_version':'1.0'
}
oauth_params['oauth_signature'] = self.gen_signature(
resource,
OrderedDict( params.items() + oauth_params.items() ),
method
)
params = OrderedDict( params.items() + oauth_params.items() )
clean_params = self.sort_params(self.normalize_params(params))
uri = endpoint + resource
p_string = urlencode(clean_params)
print 'p string:'
print '\n'.join(p_string.split('&'))
return httplib2.Http().request(uri + '?' + p_string)
def gen_signature(self, resource, params, method):
base_request_uri = quote(self.endpoint + resource, safe = "")
clean_params = self.sort_params(
self.normalize_params(
self.normalize_params(
params
)
)
)
query_string = '%26'.join([
key + '%3D' + value\
for key, value in clean_params.iteritems()
])
raw_string = '&'.join([method, base_request_uri, query_string])
print "raw string: "
print '\n'.join(raw_string.split('%26'))
hashed = hmac.new(self.consumer_secret, raw_string, sha1)
return binascii.b2a_base64( hashed.digest() )[:-1]
def normalize_string(self, string):
return quote(str(string), safe="")
def normalize_params(self, params):
return OrderedDict( [
(self.normalize_string(key), self.normalize_string(value))\
for key, value \
in params.iteritems()
])
def sort_params(self, params):
return OrderedDict(sorted(
params.iteritems(),
cmp=key_compare
))
def gen_timestamp(self):
return int(time.time())
# return 1429451603
def gen_nonce(self):
return hex(self.gen_timestamp())
#todo: make this more secure
if __name__ == "__main__":
store_url = '<STORE URL HERE>'
api_base = 'wc-api'
api_ver = 'v2'
endpoint = "%s/%s/%s/" % (store_url, api_base, api_ver)
consumer_key = '<CK HERE>'
consumer_secret = '<CS HERE>'
resource = 'customers'
parameters = {
# 'fields':'id,first_name'
}
rc = Restful_Client(endpoint, consumer_key, consumer_secret)
r, c = rc.make_request(resource, parameters, 'GET')
print r
print c
What I would suggest is ensuring that the parameters are encoded the correct number of times, I found that the parameters needed to be "double encoded" to work. It looks like in this case your parameters (the key and value strings) are not "double encoded" as suggested in the API doc http://woothemes.github.io/woocommerce-rest-api-docs/#authentication
You can test this hypothesis by trying a simple GET request without any parameters like the one in my code. if that works then that might be your problem. Good luck!
Related
According to official documentation https://bybit-exchange.github.io/docs/derivativesV3/unified_margin/#t-constructingtherequest I try to get account balance endpoint: GET /unified/v3/private/account/wallet/balance. But anyway I get this response: {"retCode":10004,"retMsg":"error sign!","result":null,"retExtInfo":null,"time":1665751778451}
from urllib.parse import urlencode
import requests
import hashlib
import time
import hmac
import uuid
api_key = 'xxxxxxxxxxxx'
secret_key = 'xxxxxxxxxxxxxxxxxxxx'
httpClient = requests.Session()
recv_window = "5000"
url = "https://api.bybit.com"
def HTTP_Request(endPoint, method, payload):
time_stamp = requests.get(url + "/v3/public/time").json()
time_stamp = str(time_stamp["time"])
signature = genSignature(params, time_stamp)
headers = {
'X-BAPI-SIGN-TYPE': '2',
'X-BAPI-SIGN': signature,
'X-BAPI-API-KEY': api_key,
'X-BAPI-TIMESTAMP': time_stamp,
'X-BAPI-RECV-WINDOW': recv_window
}
response = httpClient.request(method, url+endpoint+"?"+payload, headers=headers)
print(response.text)
def genSignature(payload, time_stamp):
# encoding list obj to url format str
peyload_url_enc = urlencode(
sorted(payload.items(), key=lambda tup: tup[0])
)
param_str = str(time_stamp) + api_key + recv_window + peyload_url_enc
hash = hmac.new(
key=bytes(secret_key, "utf-8"),
msg=param_str.encode("utf-8"),
digestmod="sha256"
)
signature = hash.hexdigest()
return signature
endpoint = "/unified/v3/private/account/wallet/balance"
method = "GET"
params = {"coin": "USDT"}
HTTP_Request(endpoint, method, str(params))
The problem seems to be in genSignature, but no matter how I change the function, the error remains the same
Thanks to this repository I found another method of connecting to the Bybit. So if you faced with similar problem, open the link, there are also some examples of creating different post/get queries
My working variant:
def bybit_spot_balance(AccessKey: str, SecretKey: str) -> dict:
params = {
"api_key": AccessKey,
"timestamp": round(time.time() * 1000),
"recv_window": 10000
}
# Create the param str
param_str = urlencode(
sorted(params.items(), key=lambda tup: tup[0])
)
# Generate the signature
hash = hmac.new(
bytes(SecretKey, "utf-8"),
param_str.encode("utf-8"),
hashlib.sha256
)
signature = hash.hexdigest()
sign_real = {
"sign": signature
}
param_str = quote_plus(param_str, safe="=&")
full_param_str = f"{param_str}&sign={sign_real['sign']}"
# Request information
url = "https://api.bybit.com/spot/v3/private/account"
headers = {"Content-Type": "application/json"}
body = dict(params, **sign_real)
urllib3.disable_warnings()
response = requests.get(f"{url}?{full_param_str}", headers=headers, verify=False).json()
return response
i am trying to make a function that uses multiple aws services in a lambda function :
import os
import boto3
import hmac, hashlib, base64, copy
def lambda_handler(event, context):
secretsmanager = boto3.client('secretsmanager')
secret_response = secretsmanager.get_secret_value(SecretId = os.environ.get('cognitoSecretID'))
cognito = boto3.client('cognito-idp')
cognito_pool_id = os.environ.get('cognitoPoolID')
event_body = event['body']
username = event_body['email']
secret = secret_response['SecretString']
raw_message = username + cognito_pool_id
message = bytes(raw_message, 'utf-8')
secret = bytes(secret,'utf-8')
secret_hash = base64.b64encode(hmac.new(secret, message, digestmod=hashlib.sha256).digest()).decode()
authParameters = {
'USERNAME': username,
'PASSWORD': event_body['password'],
'SECRET_HASH': secret_hash
}
cognito.admin_initiate_auth(UserPoolId = cognito_pool_id, ClientId = os.environ.get('cognitoClientID'), AuthFlow = "ADMIN_USER_PASSWORD_AUTH", AuthParameters = authParameters )
return True
i am testing git with pytest as follows :
import os
import pytest
from unittest.mock import call
import boto3
import hmac, hashlib, base64
from src.DacAdminsLogin import lambda_handler
from __mocks__.SecretsManagerMock import SecretsManagerMock
MockLambdaHandlerEvent = {
'body' : {
'email': "abdelouahedelhariri#gmail.com",
'password': "test"
}
}
#pytest.fixture
def dummy_secret(monkeypatch):
dummySecret = 'adummytest'
monkeypatch.setenv('cognitoSecretID', dummySecret, prepend=False)
return dummySecret
#pytest.fixture
def dummy_cognito_id(monkeypatch):
dummyCognitoID = 'adummycognitoid'
monkeypatch.setenv('cognitoClientID', dummyCognitoID, prepend=False)
return 'adummycognitoid'
#pytest.fixture
def dummy_cognito_pool_id(monkeypatch):
dummyCognitoPoolID = 'adummycognitopoolid'
monkeypatch.setenv('cognitoPoolID', dummyCognitoPoolID, prepend=False)
return 'adummycognitopoolid'
#pytest.fixture
def secret_manager(mocker, dummy_secret):
mock = mocker.patch('__mocks__.SecretsManagerMock.SecretsManagerMock')
mock.get_secret_value.return_value = {'SecretString' : dummy_secret}
return mock
#pytest.fixture
def cognito(mocker):
return mocker.patch('__mocks__.CognitoMock.CognitoMock', return_value= "Test secret")
#pytest.fixture
def client(mocker, secret_manager, cognito):
return mocker.patch('boto3.client', side_effect= [secret_manager, cognito])
def test_create_secrets_manager_client(client):
lambda_handler(MockLambdaHandlerEvent,1)
client.assert_has_calls([call('secretsmanager')])
def test_get_secret_value_call(client ,secret_manager, dummy_secret):
lambda_handler(MockLambdaHandlerEvent,1)
secret_manager.get_secret_value.assert_called_once_with(SecretId= dummy_secret)
def test_create_cognito_client(client ,secret_manager, dummy_secret):
lambda_handler(MockLambdaHandlerEvent,1)
client.assert_has_calls([call('secretsmanager'), call('cognito')])
def test_admin_initiate_auth_call(client, monkeypatch , cognito, dummy_secret, dummy_cognito_id, dummy_cognito_pool_id):
MockLambdaHandlerEventBody = MockLambdaHandlerEvent['body']
username = MockLambdaHandlerEventBody['email']
app_client_id = dummy_cognito_pool_id
key = dummy_secret
message = bytes(username+app_client_id,'utf-8')
key = bytes(dummy_secret,'utf-8')
secret_hash = base64.b64encode(hmac.new(key, message, digestmod=hashlib.sha256).digest()).decode()
authParameters = {
'USERNAME': username,
'PASSWORD': MockLambdaHandlerEventBody['password'],
'SECRET_HASH': secret_hash
}
lambda_handler(MockLambdaHandlerEvent,1)
cognito.admin_initiate_auth.assert_called_once_with(UserPoolId = dummy_cognito_pool_id, ClientId = dummy_cognito_id, AuthFlow = "ADMIN_USER_PASSWORD_AUTH", AuthParameters = authParameters )
I am new to python and i don't know why i keep getting the following error : TypeError: can only concatenate str (not "NoneType") to str, coming from the raw_message concatenation.
When i comment out the cognito.admin_initiate_auth.assert_called_once_with(UserPoolId = dummy_cognito_pool_id, ClientId = dummy_cognito_id, AuthFlow = "ADMIN_USER_PASSWORD_AUTH", AuthParameters = authParameters )
or change for example the UserPoolId to another value the error disappears.
I tried to connect to the Riot api to access the summoner info. I wrote 3 files:
"RiotConsts": a file setting some constants such as "URL", "api_version", "region"
"RiotAPI": the main functions
"riot_main": to call the info I want.
I am receiving an error: "RiotAPI' object has no attribute '_request'".
class RiotAPI(object):
def __init__(self,api_key,region=Consts.REGIONS['europe_nordic_and_east']):
self.api_key = api_key
self.region = region
def request(self, api_key, params={}):
args = {'api_key': self.api_key}
for k,v in params.items():
if k not in args:
args[k] = v
response = requests.get(
Consts.URL['base'].format(
proxy = self.region,
region = self.region,
url = api_url
),
params=args
)
print (response.url)
return response.json()
def get_summoner_by_name(self, name):
api_url = Consts.URL['summoner_by_name'].format(
version=Consts.API_VERSIONS['summoner'],
summonerName=name
)
return self._request(api_url)
I expect to receive the summoner info but I got:
'RiotAPI' object has no attribute '_request'
Simpler code to connect Riot API and to have summoner infos :
class RiotApi(object):
def __init__(self, api_key: str, region="euw1"):
self.__RIOT_API_KEY = api_key
self.__HEADER = {'X-Riot-Token': self.__RIOT_API_KEY}
self.__REGION = region
self.__BASE_URL = ".api.riotgames.com/lol/"
self.__API_URL_SUMMONER_V4 = "https://" + self.__REGION + self.__BASE_URL + "summoner/v4/summoners/"
def get_summoner_by_name(self, summoner_name: str) -> dict:
"""Summoner Infos and Ids
#param summoner_name: LoL summoner name
#return json object of infos and ids
"""
url = self.__API_URL_SUMMONER_V4 + "by-name/" + summoner_name
request = requests.get(url, headers=self.__HEADER)
return request.json()
As mentioned in comment, object has no attribute error is caused by invocation of undefined attribute (or method) -- in this case _request() method. So, assuming the rest of the code are correct, you can try this code:
# class RiotAPI(object):
class RiotAPI:
def __init__(self,api_key,region=Consts.REGIONS['europe_nordic_and_east']):
self.api_key = api_key
self.region = region
# def request(self, api_key, params={}):
def request(self, api_url, params={}):
args = {'api_key': self.api_key}
for k,v in params.items():
if k not in args:
args[k] = v
response = requests.get(
Consts.URL['base'].format(
proxy = self.region,
region = self.region,
url = api_url
),
params=args
)
print (response.url)
return response.json()
def get_summoner_by_name(self, name):
api_url = Consts.URL['summoner_by_name'].format(
version=Consts.API_VERSIONS['summoner'],
summonerName=name
)
#return self._request(api_url)
return self.request(api_url)
This is my code for testing Trello API:
import string
import random
import requests
from settings import *
nonce = lambda x: ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(10 if not x else x))
def get_board_detals(board_id):
url = "https://trello.com/1/boards/" + board_id
params = {"key":key,
"token":token}
return requests.get(url=url, params=params)
def post_board_name(board_name):
url = "https://api.trello.com/1/boards"
params = {"key": key,
"token": token,
"name": board_name}
return requests.post(url=url, params=params)
def put_new_board_name(board_id):
url = "https://api.trello.com/1/boards" + board_id
params = {"key": key,
"token": token}
return requests.put(url=url, params=params)
and code for unittest:
import unittest
from board_details import *
class BoardDetails(unittest.TestCase):
def setUp(self):
self.name = nonce(10)
def test_put_new_name(self):
result_post = post_board_name(self.name)
board_id = result_post.json()['id']
result_put = put_new_board_name(board_id)
self.assertEqual(result_put.status_code, 200)
self.assertIn(result_put.json()['name'], self.name)
if __name__ == '__main__':
unittest.main()
When I run the code, I receive an error: AssertionError: 404 != 200.
I don't know why it is like that, can someone point out what's the reason for my error?
I did it like this and it seems to work fine:
function:
def put_new_board_name(board_id, board_name):
url = "https://api.trello.com/1/boards/" + board_id +"/name"
params = {"key": key,
"token": token,
"value" : board_name}
return requests.put(url=url, params=params)
and method:
def test_put_new_name(self):
result_post = post_board_name(self.name)
board_id = result_post.json()['id']
result_put = put_new_board_name(board_id, board_name=self.name)
self.assertEqual(result_put.status_code, 200)
self.assertIn(result_put.json()['name'], self.name)
I'm having an awfully hard time with Yahoo's authentication/authorization. I've enabled BOSS in my account, set up a payment method, and now I'm trying to run a search using some python code:
import urllib2
import oauth2 as oauth
import time
OAUTH_CONSUMER_KEY = "blahblahblah"
OAUTH_CONSUMER_SECRET = "blah"
def oauth_request(url, params, method="GET"):
params['oauth_version'] = "1.0",
params['oauth_nonce'] = oauth.generate_nonce(),
params['oauth_timestamp'] = int(time.time())
consumer = oauth.Consumer(key=OAUTH_CONSUMER_KEY,
secret=OAUTH_CONSUMER_SECRET)
params['oauth_consumer_key'] = consumer.key
req = oauth.Request(method=method, url=url, parameters=params)
req.sign_request(oauth.SignatureMethod_HMAC_SHA1(), consumer, None)
return req
if __name__ == "__main__":
url = "http://yboss.yahooapis.com/ysearch/web"
req = oauth_request(url, params={"q": "cats dogs"})
req_url = req.to_url()
print req_url
result = urllib2.urlopen(req_url)
I keep getting a urllib2.HTTPError: HTTP Error 401: Unauthorized exception. I can't figure out whether there's something wrong with my key, or the method of signing, or if I'm somehow tampering with my data after signing, or what the deal is. Anyone have suggestions?
I made some small changes to make your example work. See code for comments.
import urllib2
import oauth2 as oauth
import time
OAUTH_CONSUMER_KEY = "blahblahblah"
OAUTH_CONSUMER_SECRET = "blah"
def oauth_request(url, params, method="GET"):
# Removed trailing commas here - they make a difference.
params['oauth_version'] = "1.0" #,
params['oauth_nonce'] = oauth.generate_nonce() #,
params['oauth_timestamp'] = int(time.time())
consumer = oauth.Consumer(key=OAUTH_CONSUMER_KEY,
secret=OAUTH_CONSUMER_SECRET)
params['oauth_consumer_key'] = consumer.key
req = oauth.Request(method=method, url=url, parameters=params)
req.sign_request(oauth.SignatureMethod_HMAC_SHA1(), consumer, None)
return req
if __name__ == "__main__":
url = "http://yboss.yahooapis.com/ysearch/web"
req = oauth_request(url, params={"q": "cats dogs"})
# This one is a bit nasty. Apparently the BOSS API does not like
# "+" in its URLs so you have to replace "%20" manually.
# Not sure if the API should be expected to accept either.
# Not sure why to_url does not just return %20 instead...
# Also, oauth2.Request seems to store parameters as unicode and forget
# to encode to utf8 prior to percentage encoding them in its to_url
# method. However, it's handled correctly for generating signatures.
# to_url fails when query parameters contain non-ASCII characters. To
# work around, manually utf8 encode the request parameters.
req['q'] = req['q'].encode('utf8')
req_url = req.to_url().replace('+', '%20')
print req_url
result = urllib2.urlopen(req_url)
Here is a Python code snippet that works for me against Yahoo! BOSS:
import httplib2
import oauth2
import time
OAUTH_CONSUMER_KEY = "Blah"
OAUTH_CONSUMER_SECRET = "Blah"
if __name__ == "__main__":
url = "http://yboss.yahooapis.com/ysearch/web?q=cats%20dogs"
consumer = oauth2.Consumer(key=OAUTH_CONSUMER_KEY,secret=OAUTH_CONSUMER_SECRET)
params = {
'oauth_version': '1.0',
'oauth_nonce': oauth2.generate_nonce(),
'oauth_timestamp': int(time.time()),
}
oauth_request = oauth2.Request(method='GET', url=url, parameters=params)
oauth_request.sign_request(oauth2.SignatureMethod_HMAC_SHA1(), consumer, None)
oauth_header=oauth_request.to_header(realm='yahooapis.com')
# Get search results
http = httplib2.Http()
resp, content = http.request(url, 'GET', headers=oauth_header)
print resp
print content
Im using an Authenticate Header to submit the OAuth signature.
So I decided to ditch Python and try Perl, and it Just Worked. Here's a minimal code sample:
use strict;
use Net::OAuth;
use LWP::UserAgent;
my $CC_KEY = "blahblahblah";
my $CC_SECRET = "blah";
my $url = 'http://yboss.yahooapis.com/ysearch/web';
print make_request($url, {q => "cat dog", format => "xml", count => 5});
sub make_request {
my ($url, $args) = #_;
my $request = Net::OAuth->request("request token")
->new(
consumer_key => $CC_KEY,
consumer_secret => $CC_SECRET,
request_url => $url,
request_method => 'GET',
signature_method => 'HMAC-SHA1',
timestamp => time,
nonce => int(rand 10**6),
callback => 'oob',
extra_params => $args,
protocol_version => Net::OAuth::PROTOCOL_VERSION_1_0A,
);
$request->sign;
my $res = LWP::UserAgent->new(env_proxy=>1)->get($request->to_url);
return $res->content if $res->is_success;
die $res->status_line;
}
Here's another solution, this time back in python-land. This was put together by Tom De Smedt, author of the Pattern web-mining kit.
I'll communicate with the author of python-oauth2 to see if it can be fixed.
OAUTH_CONSUMER_KEY = "blahblahblah"
OAUTH_CONSUMER_SECRET = "blah"
import urllib
import hmac
import time
import random
import base64
try:
from hashlib import sha1
from hashlib import md5
except:
import sha as sha1
import md5; md5=md5.new
def hmac_sha1(key, text):
return hmac.new(key, text, sha1).digest()
def oauth_nonce(length=40):
h = "".join([str(random.randint(0, 9)) for i in range(length)])
h = md5(str(time.time()) + h).hexdigest()
return h
def oauth_timestamp():
return str(int(time.time()))
def oauth_encode(s):
return urllib.quote(s, "~")
def oauth_signature(url, data={}, method="get", secret="", token=""):
# Signature base string: http://tools.ietf.org/html/rfc5849#section-3.4.1
base = oauth_encode(method.upper()) + "&"
base += oauth_encode(url.rstrip("?")) + "&"
base += oauth_encode("&".join(["%s=%s" % (k, v) for k, v in sorted(data.items())]))
# HMAC-SHA1 signature algorithm: http://tools.ietf.org/html/rfc5849#section-3.4.2
signature = hmac_sha1(oauth_encode(secret) + "&" + token, base)
signature = base64.b64encode(signature)
return signature
q = "cat"
url = "http://yboss.yahooapis.com/ysearch/" + "web" # web | images | news
data = {
"q": q,
"start": 0,
"count": 50, # 35 for images
"format": "xml",
"oauth_version": "1.0",
"oauth_nonce" : oauth_nonce(),
"oauth_timestamp" : oauth_timestamp(),
"oauth_consumer_key" : OAUTH_CONSUMER_KEY,
"oauth_signature_method" : "HMAC-SHA1",
}
data["oauth_signature"] = oauth_signature(url, data, secret=OAUTH_CONSUMER_SECRET)
complete_url = url + "?" + urllib.urlencode(data)
response = urllib.urlopen(complete_url)
print response.read()
Here is sample code to access Yahoo! BOSS API v2 using with python-oauth as oauth liberary.
OAUTH_CONSUMER_KEY = "<oauth consumer key>"
OAUTH_CONSUMER_SECRET = "<oauth consumer secret>"
URL = "http://yboss.yahooapis.com/ysearch/web"
import urllib
import oauth.oauth as oauth
data = {
"q": "yahoo boss search",
"start":0,
"count":2,
"format":"json"
}
consumer = oauth.OAuthConsumer(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET)
signature_method_plaintext = oauth.OAuthSignatureMethod_PLAINTEXT()
signature_method_hmac_sha1 = oauth.OAuthSignatureMethod_HMAC_SHA1()
oauth_request = oauth.OAuthRequest.from_consumer_and_token(consumer, token=None, http_method='GET', http_url=URL, parameters=data)
oauth_request.sign_request(signature_method_hmac_sha1, consumer, "")
complete_url = oauth_request.to_url()
response = urllib.urlopen(complete_url)
print "REQUEST URL => %s" % complete_url
print ""
print "RESPONSE =>"
print response.read()
I stepped into the urllib2.open code using the debugger, and found that the response has this header:
WWW-Authenticate: OAuth oauth_problem="version_rejected", realm="yahooapis.com"
So I guess I'm having some kind of version mismatch of OAuth.