cloudant / python-cloudant

A Python library for Cloudant and CouchDB
Apache License 2.0
163 stars 55 forks source link

requests.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed #381

Closed Megidd closed 6 years ago

Megidd commented 6 years ago

Cloudant (python-cloudant) version(s) that are affected by this issue.

$ pip show cloudant
Name: cloudant
Version: 2.8.1
Summary: Cloudant / CouchDB Client Library
Home-page: https://github.com/cloudant/python-cloudant
Author: IBM
Author-email: alfinkel@us.ibm.com
License: UNKNOWN
Location: /home/uconn/.local/lib/python2.7/site-packages
Requires: requests
Required-by: 

Python version

$ python2.7
Python 2.7.12 (default, Dec  4 2017, 14:50:18) 
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>

A small code sample that demonstrates the issue: I have the following code in script.py file:

# Use CouchDB to create a CouchDB client
from cloudant.client import CouchDB
client = CouchDB('admin', '****', url='https://192.168.1.106:6984')

client.connect()

# Perform client tasks...
session = client.session()
print('Username: {0}'.format(session['userCtx']['name']))
print('Databases: {0}'.format(client.all_dbs()))

db = client['sample']

# Disconnect from the server
client.disconnect()

Error

I'm using CouchDB with a self-signed SSL certificate, but I receive the following error:

$ python2.7 script.py 
Traceback (most recent call last):
  File "script.py", line 5, in <module>
    client.connect()
  File "/home/uconn/.local/lib/python2.7/site-packages/cloudant/client.py", line 142, in connect
    self.session_login()
  File "/home/uconn/.local/lib/python2.7/site-packages/cloudant/client.py", line 183, in session_login
    self.change_credentials(user=user, auth_token=passwd)
  File "/home/uconn/.local/lib/python2.7/site-packages/cloudant/client.py", line 193, in change_credentials
    self.r_session.login()
  File "/home/uconn/.local/lib/python2.7/site-packages/cloudant/_client_session.py", line 150, in login
    data={'name': self._username, 'password': self._password},
  File "/home/uconn/.local/lib/python2.7/site-packages/cloudant/_client_session.py", line 65, in request
    method, url, timeout=self._timeout, **kwargs)
  File "/usr/lib/python2.7/dist-packages/requests/sessions.py", line 468, in request
    resp = self.send(prep, **send_kwargs)
  File "/usr/lib/python2.7/dist-packages/requests/sessions.py", line 576, in send
    r = adapter.send(request, **kwargs)
  File "/usr/lib/python2.7/dist-packages/requests/adapters.py", line 447, in send
    raise SSLError(e, request=request)
requests.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:590)

Tried so far:

I have tried solutions like this one: How to get Python requests to trust a self signed SSL certificate?, but they are not helpful.

tomblench commented 6 years ago

@Megidd you can use the stackoverflow answer in conjuction with our documentation here to pass in the verify argument to your certificate.

Or you could install your self-signed certificate as a root certificate system-wide (the exact location will depend on your SSL library and operating system), so that it is trusted by all applications. After all, you want curl, your web browser, etc, to trust this certificate - don't you?

ricellis commented 6 years ago

Since all the HTTP requests python-cloudant makes go through Requests you should also be able to use the REQUESTS_CA_BUNDLE environment variable to point to a CA certificate file that will allow Requests to validate your certificate without needing to pass the verify argument to each request.

andreapiso commented 6 years ago

Setting the environment variable works - but really the whole r_session handling could be better.

For one, the r_session is None until you use client.connect(), which since we want to set the SSL path to prevent connect from failing, kind of defeats the purpose...

Furthermore, if we use a bogus connect() call to create r_session, it still does not work well, for example, it will still give an SSL error even setting verify to False.

I think the r_session object should be created together with the Cloudant or CouchDB object, so that we could chance the r_session before actually connecting.

emlaver commented 6 years ago

@AndreaPisoni Thanks for providing these details. We have no plans to implement this but you are welcome to raise a PR and our team will review it.