nickovs / unificontrol

A high-level Python interface to the Unifi controller software
Apache License 2.0
96 stars 41 forks source link

No way to use the library at all with self-signed certificate on the UDM Pro #25

Open desrod opened 3 years ago

desrod commented 3 years ago

Despite what the `ssl_self_signed.rst document states, pinning does not work at all for the initial login. You can create the client object, but you can't use it to query the API of the UDMP at all.

This includes port 443 and 8443. The self-signed certificate is queried correctly and passed back in the request, but since the Python 'requests' library can't validate the SSL certificate, it fails with the below (common) SSL verify error:

Traceback (most recent call last):
  File "./test.py", line 14, in <module>
    client.login()
  File "/tmp/env/src/unificontrol/unificontrol/unifi.py", line 155, in login
    self._login(username=username if username else self._user,
  File "/tmp/env/src/unificontrol/unificontrol/metaprogram.py", line 125, in wrapper
    return instance(client, *a, **kw)
  File "/tmp/env/src/unificontrol/unificontrol/metaprogram.py", line 103, in __call__
    return client._execute(url, self._method, rest_dict, need_login=self._need_login)
  File "/tmp/env/src/unificontrol/unificontrol/unifi.py", line 96, in _execute
    resp = ses.send(ses.prepare_request(request))
  File "/tmp/env/lib/python3.8/site-packages/requests/sessions.py", line 655, in send
    r = adapter.send(request, **kwargs)
  File "/tmp/env/lib/python3.8/site-packages/requests/adapters.py", line 514, in send
    raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='192.168.x.x', port=443): Max retries exceeded with url: /api/login (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate (_ssl.c:1123)')))

Other than procuring an officially-signed, upstream SSL certificate that the standard host certificate chain will trust, this will not work. I did add the certificate directly from the controller to /usr/local/share/ca-certificates/ and refreshed the cert chain, still no success.

Is there a plan to support verify=False in the constructor, so this will work for those of us without an upstream SSL cert configured on our controllers?

nickovs commented 3 years ago

@desrod Thanks for the report. Can you provide a little information as to your environment (what OS, Python version and unificontrol version)? If you can provide info about the version of software on your UDM Pro that would also be helpful; Ubiquiti have been making a lot of changes recently so it's a bit of a moving target.

desrod commented 3 years ago

Sure can! I've been chasing down some very weird issues with my UDMP, which is what led me to find this project.

The entire test script is:

#!/usr/bin/env python3 

import logging
logging.basicConfig(level=logging.DEBUG)
import unificontrol
import ssl

cert = ssl.get_server_certificate(("unifi.local", 8443))

client = unificontrol.UnifiClient(host="unifi.local", 
                                  port='443', 
                                  username='me', 
                                  password="SuperSecretPassword", 
                                  site='default', 
                                  cert=cert)

client.login()

I started with the IP statically defined, that didn't work, so I added an entry to /etc/hosts to match the name in the self-signed cert itself. Same results either way.

rfroom commented 3 years ago

Hello, I am running into same problem. Did anyone else find a solution or work-around?

kpanchen commented 3 years ago

Hello, same here, tried different things and nothing worked. I have my own CA, root and unifi certs both generated by CA, whatever I tried to provide root or unifi cert I have the same error: '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1129)')))

caco3 commented 3 years ago

For me this failed because the certificate is expired. According to the web browser, it is signed by Ubiquiti Networks Inc. but expired already in 2011! Because of this I always got this error: ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: certificate has expired (_ssl.c:1129).

The only workaround I found was to patch unifi.py and add a verify=False on resp = ses.send(ses.prepare_request(request), verify=False).

To suppress the warnings I also added following to my main script:

import requests
from urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)