BadParametersError: Invalid signature when using OVH Python wrapper - python

I'm using OVH API along with python wrapper:
https://pypi.python.org/pypi/ovh
When trying to execute this code:
import ovh
client = ovh.Client()
# Print nice welcome message
print "Welcome", client.get('/me')['firstname']
I get this error:
Traceback (most recent call last):
File "index.py", line 6, in <module>
print "Welcome", client.get('/me')['firstname']
File "/home/rubinhozzz/.local/lib/python2.7/site-packages/ovh/client.py", line 290, in get
return self.call('GET', _target, None, _need_auth)
File "/home/rubinhozzz/.local/lib/python2.7/site-packages/ovh/client.py", line 419, in call
raise BadParametersError(json_result.get('message'))
ovh.exceptions.BadParametersError: Invalid signature
My info is saved in the ovh.conf as the documentation suggests.
[default]
; general configuration: default endpoint
endpoint=ovh-eu
[ovh-eu]
application_key=XXXlVy5SE7dY7Gc5
application_secret=XXXdTEBKHweS5F0P0tb0lfOa8GoQPy4l
consumer_key=pscg79fXXX8ESMIXXX7dR9ckpDR7Pful
It looks that I can connect but when trying to use the services like for instance "/me", the error raises!

It is difficult to reproduce the issue because it requires an application key and it seems that it is only granted to existing customers of OVH. I couldn't even see a link to an account registration page on their site.
By looking at the code of the call() method in /ovh/client.py, it seems that their server doesn't recognise the format or the content off the signature sent by your script. According to the inline documentation the signature is generated from these parameters:
application_secret
consumer_key
METHOD
full request url
body
server current time (takes time delta into account)
Since your call is identical to the example code provided on the OVH Python package web page, the last four parameters should be valid. In that case it looks like either the application secret or the customer key (or both) in your config file are not correct.
See also the documentation on OVH site under the 'Signing requests' heading. They explain how the signature is made and what it should look like.
Perhaps try to re-create a new application API to obtain new key and secret and make sure you copy them without any additional character.

Related

Accessing Office 365 ProPlus OneDrive folder using the official Python SDK

We are currently trying to access a folder of an Office 365 ProPlus tenant using the official OneDrive SDK for Python (https://github.com/OneDrive/onedrive-sdk-python). One of our clients would like to use a OneDrive folder as a way of storing and sharing programmatically generated files, therefore, we would like to provide basic file operations.
We have a working solution for a personal OneDrive account, however, when we try to apply the same approach for their OneDrive, we face an issue during the authentication process.
We asked them to register the application in the Azure AD following the steps in the official documentation. Next, they sent us the redirect URI, client ID and client secret that we included in our script. We are trying to use the following code:
redirect_uri = 'REDIRECT_URI'
client_secret = 'CLIENT_SECRET'
client_id='CLIENT_ID'
discovery_uri = 'https://api.office.com/discovery/'
auth_server_url='https://login.microsoftonline.com/common/oauth2/authorize'
auth_token_url='https://login.microsoftonline.com/common/oauth2/token'
http_provider = onedrivesdk.HttpProvider()
auth_provider = onedrivesdk.AuthProvider(http_provider,
client_id,
auth_server_url=auth_server_url,
auth_token_url=auth_token_url)
auth_url = auth_provider.get_auth_url(redirect_uri)
code = GetAuthCodeServer.get_auth_code(auth_url, redirect_uri)
However, we get the following error message when executing the last line:
Traceback (most recent call last):
File "onedrive-test.py", line 25, in
code = GetAuthCodeServer.get_auth_code(auth_url, redirect_uri)
File "/home/username/.local/lib/python3.6/site-packages/onedrivesdk/helpers/GetAuthCodeServer.py",
line 60, in get_auth_code
s = GetAuthCodeServer((host_address, port), code_acquired, GetAuthCodeRequestHandler)
File "/home/username/.local/lib/python3.6/site-packages/onedrivesdk/helpers/GetAuthCodeServer.py",
line 76, in init
HTTPServer.init(self, server_address, RequestHandlerClass)
File "/usr/lib/python3.6/socketserver.py", line 453, in init
self.server_bind()
File "/usr/lib/python3.6/http/server.py", line 136, in server_bind
socketserver.TCPServer.server_bind(self)
File "/usr/lib/python3.6/socketserver.py", line 467, in server_bind
self.socket.bind(self.server_address)
socket.gaierror: [Errno -2] Name or service not known
We also tried opening the auth_url manually, which took us one step further, but still could not authenticate the application with the following error:
AADSTS50020: User account 'USER ACCOUNT' from identity provider
'live.com' does not exist in tenant 'TENANT NAME' and cannot access
the application 'CLIENT ID' in that tenant. The account needs to be
added as an external user in the tenant first. Sign out and sign in
again with a different Azure Active Directory user account.
We have two questions:
What might casue the first error? This is the comment (see below) that can be found in the readme of the SDK about using the GetAuthCodeServer class. It seems to us that the server cannot be run. Are there any not explicitly defined dependencies that we should be aware of before trying to run the webserver? (We are running the script on Ubuntu 18.10)
If you want to remove some of that manual work, you can
use the helper class GetAuthCodeServer. That helper class spins up a
webserver, so this method cannot be used on all environments.
With respect to the second issue, can you recommend proper material for configuring OneDrive for Business for our use-case? We went through a lot of documentation, but after long hours of research, we still could not find the correct way to fix that issue, especially since we do not have direct acces to the tenant and we cannot easily experiment with things. We would need to give a step-by-step cookbook to our client to set up everything on their side.
Any help would be much appreciated! :)

API GET request returns 404

I'm currently developing a Django web application which is supposed to add some functionality to online shops based on InSales (a popular Russian web platform). I use the official InSales lib for Python called pyinsales to get objects like orders and products from registered shops.
The InSales API is based on REST requests with XML. I use the code below to get information about orders in the Django shell:
from install.models import Shop
from insales import InSalesApi
shop = Shop.objects.get(shop_url='shop-url.myinsales.ru')
api = InSalesApi(shop.shop_url, 'trackpost', shop.password)
orders = api.get_orders()
Here shop.shop_url is the shop URL ("oh, really?"), trackpost is the name of my app and shop.password is the password needed to connect. Password is generated by MD5 (that's an InSales rule). And here I get an error:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/local/lib/python3.5/site-packages/insales/api.py", line 32, in get_orders
return self._get('/admin/orders.xml', {'per_page': per_page, 'page': page}) or []
File "/usr/local/lib/python3.5/site-packages/insales/api.py", line 291, in _get
return self._req('get', endpoint, qargs)
File "/usr/local/lib/python3.5/site-packages/insales/api.py", line 307, in _req
response = getattr(self.connection, method)(*args, **kwargs)
File "/usr/local/lib/python3.5/site-packages/insales/connection.py", line 85, in get
return self.request('GET', path, qargs=qargs)
File "/usr/local/lib/python3.5/site-packages/insales/connection.py", line 70, in request
(method, path, resp.status, body), resp.status)
insales.connection.ApiError: GET request to /admin/orders.xml?page=1&per_page=25 returned: 404
b'<?xml version="1.0" encoding="UTF-8"?>\n<errors>\n <error></error>\n</errors>\n'
I've already checked everything for mistakes. Password is generated properly (according to official documentation), shop URL is correct and all the methods from the lib are used correctly. InSales tech support doesn't response, so now I have no idea about what is happening.
I don't want you to debug this issue, but I'd like to know what can cause the 404 error (except obvious things, like incorrect URL or password). Thanks everybody who tries to answer.
404 mean that the server couldn't find what you requested.
https://en.wikipedia.org/wiki/HTTP_404
So it's not an authentication issue, it seems like there are no orders at that particular endpoint.
Have you tried using the python "requests" package instead of using the "pyinsales" module to request data from the endpoint directly? That way you can customize your own headers, etc.
You might also try testing the endpoints in a program like postman to ensure that the endpoints are valid before you try to hit them programmatically.
Analysing the pyinsales code on github, I realised that url should be a subdomain name on myinsales domain, so if the full url is http://shop.myinsales.ru/ then the first argument in pyinsales should be shop. That's a pity no one working on the module pointed that in readme, but such things happen

authentification for Google Storage using Python

I want to build an app which has easy interactions with google storage, i.e., list files in bucket, download a file, and upload a file.
Following this tutorial, I decided to use a service account (not a user one) for authentification and followed the procedure. I created a public/private key on my console and download the key on my machine. Then I created the .boto file which points to this private key, and finally launched this program and it worked:
import boto
import gcs_oauth2_boto_plugin
uri = boto.storage_uri('txxxxxxxxxxxxxx9.appspot.com', 'gs')
for obj in uri.get_bucket():
print '%s://%s/%s' % (uri.scheme, uri.bucket_name, obj.name)
As you can see, the package gcs_oauth2_boto_plugin is not used in the code, so I decided to get rid of it. But magically, when I comment the import gcs_oauth2_boto_plugin line and run the program again, I get this error:
C:\Users\...\Anaconda3\envs\snakes\python.exe C:/Users/.../Dropbox/Prog/s3_manifest_builder/test.py
Traceback (most recent call last):
File "C:/Users/.../Dropbox/Prog/s3_manifest_builder/test.py", line 10, in <module>
for obj in uri.get_bucket():
File "C:\Users\...\Anaconda3\envs\snakes\lib\site-packages\boto\storage_uri.py", line 181, in get_bucket
conn = self.connect()
File "C:\Users\...\Anaconda3\envs\snakes\lib\site-packages\boto\storage_uri.py", line 140, in connect
**connection_args)
File "C:\Users\...\Anaconda3\envs\snakes\lib\site-packages\boto\gs\connection.py", line 47, in __init__
suppress_consec_slashes=suppress_consec_slashes)
File "C:\Users\...\Anaconda3\envs\snakes\lib\site-packages\boto\s3\connection.py", line 190, in __init__
validate_certs=validate_certs, profile_name=profile_name)
File "C:\Users\...\Anaconda3\envs\snakes\lib\site-packages\boto\connection.py", line 569, in __init__
host, config, self.provider, self._required_auth_capability())
File "C:\Users\...\Anaconda3\envs\snakes\lib\site-packages\boto\auth.py", line 987, in get_auth_handler
'Check your credentials' % (len(names), str(names)))
boto.exception.NoAuthHandlerFound: No handler was ready to authenticate. 1 handlers were checked. ['HmacAuthV1Handler'] Check your credentials
So my questions are:
1- how can you explain that deleting an import which IS NOT USED in the code makes it fail?
2- more generally, to be sure to understand the authentification process, if I want to run my app on a machine, I must be sure to have the .boto file (which points to my service account private key) generated previously? Or is there a cleaner/easier way to give access to my application to Google Storage for in/out interactions?
For instance, I only have to provide public and private key as strings to my program when I want to connect to a S3 bucket with boto. I don't needto generate a .boto file, importing packages etc..., which makes it so much easier to use, isn't it?
1- how can you explain that deleting an import which IS NOT USED in the code makes it fail?
The first hint is that the module is named a "plugin", although exactly how that's implemented isn't clear on the surface. It intuitively makes some sense that not importing a module would lead to an exception of this kind, though. Initially, I thought it was a bad practice of doing stateful activity on a global during the init of importing that module. In some ways, that is what it was, but only because class hierarchies are "state" in the meta-programmable python.
It turns out (as in many cases) that inspecting the location that stacktrace was thrown from (boto.auth.get_auth_handler()) provides the key to understanding the issue.
(see the linked source for commented version)
def get_auth_handler(host, config, provider, requested_capability=None):
ready_handlers = []
auth_handlers = boto.plugin.get_plugin(AuthHandler, requested_capability)
for handler in auth_handlers:
try:
ready_handlers.append(handler(host, config, provider))
except boto.auth_handler.NotReadyToAuthenticate:
pass
if not ready_handlers:
checked_handlers = auth_handlers
names = [handler.__name__ for handler in checked_handlers]
raise boto.exception.NoAuthHandlerFound(
'No handler was ready to authenticate. %d handlers were checked.'
' %s '
'Check your credentials' % (len(names), str(names)))
Note the reference to the class AuthHandler, which is defined in boto.auth_handler.
So, you can see that we need to look at the contents of boto.plugin.get_plugin(AuthHandler, requested_capability):
def get_plugin(cls, requested_capability=None):
if not requested_capability:
requested_capability = []
result = []
for handler in cls.__subclasses__():
if handler.is_capable(requested_capability):
result.append(handler)
return result
So, it becomes clear, at last finally when we see that the class definition of the class OAuth2Auth in gcs_oauth2_boto_plugin.oauth2_plugin, in which it is declared as a subclass of boto.auth_handler.AuthHandler, signaling its auth capabilities to the boto framework via the following member variable:
capability = ['google-oauth2', 's3']
2- more generally, to be sure to understand the authentification process, if I want to run my app on a machine, I must be sure to have the .boto file (which points to my service account private key) generated previously? Or is there a cleaner/easier way to give access to my application to Google Storage for in/out interactions?
This has a more generalized answer: You can use a .boto file, although you can also use service account credentials, and you could even use the REST API and go through an oauth2 flow to get the tokens needed to send in the Authorization header. The various methods of auth to cloud storage are in the documentation. The tutorial/doc you linked shows some methods, you've used .boto for another method. You can read about the Cloud Storage REST API (JSON) here and you can read about python oauth2 flows of various kinds here.

Dropbox API request token not working with Python 3?

I'm maintaining a Python application using the official Dropbox API. To ask the users to let my application use their Dropbox account, I use a small script using the DropboxSession class, which is clearly the same as the one we can find on this blog post :
# Include the Dropbox SDK libraries
from dropbox import client, rest, session
# Get your app key and secret from the Dropbox developer website
APP_KEY = '******'
APP_SECRET = '******'
# ACCESS_TYPE should be 'dropbox' or 'app_folder' as configured for your app
ACCESS_TYPE = 'app_folder'
sess = session.DropboxSession(APP_KEY, APP_SECRET, ACCESS_TYPE)
request_token = sess.obtain_request_token()
url = sess.build_authorize_url(request_token)
# Make the user sign in and authorize this token
print "url:", url
print "Please visit this website and press the 'Allow' button, then hit 'Enter' here."
# Python 2/3 compatibility
try:
raw_input()
except NameError:
input()
# This will fail if the user didn't visit the above URL
access_token = sess.obtain_access_token(request_token)
#Print the token for future reference
print access_token
While it's perfectly working with Python 2.7.6, it seems to fail because of Dropbox code in Python 3.4 (the raw_input problem having been dealt with). I get this error :
Traceback (most recent call last):
File "/home/scylardor/.virtualenvs/onitu3/lib/python3.4/site-packages/dropbox/session.py", line 285, in _parse_token
key = params['oauth_token'][0]
KeyError: 'oauth_token'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "get_access_token.py", line 12, in <module>
request_token = sess.obtain_request_token()
File "/home/scylardor/.virtualenvs/onitu3/lib/python3.4/site-packages/dropbox/session.py", line 185, in obtain_request_token
self.request_token = self._parse_token(response.read())
File "/home/scylardor/.virtualenvs/onitu3/lib/python3.4/site-packages/dropbox/session.py", line 287, in _parse_token
raise ValueError("'oauth_token' not found in OAuth request.")
ValueError: 'oauth_token' not found in OAuth request.
Long story short, after having studied the faulty code, it seems that the Dropbox code searches for a string dictionary key, despite the fact that in Python 3, those keys become bytestrings (i.e. it lookups 'oauth_token', which isn't here, instead of b'oauth_token', which is here).
However, even after having fixed the code to see if that's the only issue, no luck, I get another error further in the procedure:
Traceback (most recent call last):
File "get_access_token.py", line 25, in <module>
access_token = sess.obtain_access_token(request_token)
File "/home/scylardor/.virtualenvs/onitu3/lib/python3.4/site-packages/dropbox/session.py", line 214, in obtain_access_token
response = self.rest_client.POST(url, headers=headers, params=params, raw_response=True)
File "/home/scylardor/.virtualenvs/onitu3/lib/python3.4/site-packages/dropbox/rest.py", line 316, in POST
return cls.IMPL.POST(*n, **kw)
File "/home/scylardor/.virtualenvs/onitu3/lib/python3.4/site-packages/dropbox/rest.py", line 254, in POST
post_params=params, headers=headers, raw_response=raw_response)
File "/home/scylardor/.virtualenvs/onitu3/lib/python3.4/site-packages/dropbox/rest.py", line 227, in request
raise ErrorResponse(r, r.read())
dropbox.rest.ErrorResponse: [401] 'Unauthorized'
So the faulty functions are sess.obtain_request_token() and sess.obtain_access_token(request_token). And the Python 2.7 version works fine, but I'd like to keep Python 3 compatibility.
So, does anyone know how one's supposed to make it work in Python 3 ? Could it be deliberately broken in order to make people move on to new procedures ? I could have sworn it was working with Python 3, some time ago.
Thank you for your time if you have an idea :)
edit: It seems the Dropbox SDK just isn't fully Python 3-compatible yet. So, I guess there's nothing else to do than to wait for them to update the SDK.
Try to use version 1.6
$ pip install dropbox==1.6
Better than waiting for the SDK to be compatible, you can use (or contribute to and use) the "community" fork, dropbox-py3 (here on github).
(Those quotes are big quotes. For now it's just me coding this, and just the part I need, but everyone's welcome to help. I think it's mainly identifying the few parts that are missing a ".encode" because it's mixing bytes and strings.)

PyGithub BadCredentialsException when calling Github.get_organization()

I'm using PyGithub v1.25 to create a little webapp where members of my organization can create private repositories in our github organization. Right now, I'm getting a BadCredentialsException when trying to call the get_organization() method of the Github base class.
Here is the relevant portion of my code:
from github import Github
import settings
GIT_OBJECT = Github(login_or_token=settings.AUTH_TOKEN)
ORG_OBJECT = GIT_OBJECT.get_organization('My-Organization-Name')
The auth token I am using was generated from my github user account, which has sufficient privileges to create private repositories in this organization when using the github web interface. I created the token with "user", "repo", and "admin:org" scopes selected. I am getting an error at the creation of ORG_OBJECT.
The stack trace:
File "/local/path/to/my/code/github_console/console/org_manage.py", line 10, in <module>
ORG_OBJECT = GIT_OBJECT.get_organization(‘My-Organization-Name’)
File "/local/path/to/my/code/github_console/lib/github/MainClass.py", line 187, in get_organization
"/orgs/" + login
File "/local/path/to/my/code/github_console/lib/github/Requester.py", line 169, in requestJsonAndCheck
return self.__check(*self.requestJson(verb, url, parameters, headers, input, cnx))
File "/local/path/to/my/code/github_console/lib/github/Requester.py", line 177, in __check
raise self.__createException(status, responseHeaders, output)
BadCredentialsException: 401 {u'documentation_url': u'https://developer.github.com/v3', u'message': u'Bad credentials'}
If anyone who has used either PyGithub or the github API before (or someone who is better than me at reading docs) has any insights, I appreciate the help!
Here's the PyGithub source code, in case anyone wants a look at that.
Doh!
Apparently, the above displayed code works great, and I just effed up importing local settings into my settings module, so a dummy AUTH_TOKEN was being used, and of course, resulting in a BadCredentialsException.
On the plus side, I guess the above is a demonstration of correct PyGithub usage.

Categories