Closed makuser closed 5 years ago
Does the same error occur when using the IP address instead of the host name?
For some reason I did not get a notification from github. Please mention @finish06 me next time.
Does the same error occur when using the IP address instead of the host name?
Yes, why wouldn't it happen when using an IP address? UBNT changed the API in UniFi v5 vs v4.
>>> c = Controller('1.3.3.7', 'username', 'password', 8443, version='v5', site_id='site')
Traceback (most recent call last):
File "/home/marc/.local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 600, in urlopen
chunked=chunked)
File "/home/marc/.local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 343, in _make_request
self._validate_conn(conn)
File "/home/marc/.local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 839, in _validate_conn
conn.connect()
File "/home/marc/.local/lib/python3.6/site-packages/urllib3/connection.py", line 364, in connect
_match_hostname(cert, self.assert_hostname or server_hostname)
File "/home/marc/.local/lib/python3.6/site-packages/urllib3/connection.py", line 374, in _match_hostname
match_hostname(cert, asserted_hostname)
File "/usr/lib/python3.6/ssl.py", line 331, in match_hostname
% (hostname, dnsnames[0]))
ssl.CertificateError: hostname '1.3.3.7' doesn't match 'myhostname.tld'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/marc/.local/lib/python3.6/site-packages/requests/adapters.py", line 449, in send
timeout=timeout
File "/home/marc/.local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 638, in urlopen
_stacktrace=sys.exc_info()[2])
File "/home/marc/.local/lib/python3.6/site-packages/urllib3/util/retry.py", line 398, in increment
raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='1.3.3.7', port=8443): Max retries exceeded with url: /api/login (Caused by SSLError(CertificateError("hostname '1.3.3.7' doesn't match 'myhostname.tld'",),))
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/marc/.local/lib/python3.6/site-packages/pyunifi/controller.py", line 89, in __init__
self._login()
File "/home/marc/.local/lib/python3.6/site-packages/pyunifi/controller.py", line 137, in _login
r = self.session.post(login_url, params)
File "/home/marc/.local/lib/python3.6/site-packages/requests/sessions.py", line 581, in post
return self.request('POST', url, data=data, json=json, **kwargs)
File "/home/marc/.local/lib/python3.6/site-packages/requests/sessions.py", line 533, in request
resp = self.send(prep, **send_kwargs)
File "/home/marc/.local/lib/python3.6/site-packages/requests/sessions.py", line 646, in send
r = adapter.send(request, **kwargs)
File "/home/marc/.local/lib/python3.6/site-packages/requests/adapters.py", line 514, in send
raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='1.3.3.7', port=8443): Max retries exceeded with url: /api/login (Caused by SSLError(CertificateError("hostname '1.3.3.7' doesn't match 'myhostname.tld'",),))
>>> c = Controller('1.3.3.7', 'username', 'password', 8443, version='v5', site_id='site', ssl_verify=False)
/home/marc/.local/lib/python3.6/site-packages/urllib3/connectionpool.py:847: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
InsecureRequestWarning)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/marc/.local/lib/python3.6/site-packages/pyunifi/controller.py", line 89, in __init__
self._login()
File "/home/marc/.local/lib/python3.6/site-packages/pyunifi/controller.py", line 139, in _login
raise APIError("Login failed - status code: %i" % r.status_code)
pyunifi.controller.APIError: Login failed - status code: 400
>>>
Unfortunately I currently don't really have a lot of time to implement the necessary adjustments myself, but I'll gladly join you to test things, etc.
Let me know if you'd like access to a v5 controller.
@finish06 Please merge #31, as it should fix it. The solution was way simpler than I thought.
I hope this will fix the home assistant unifi device_tracker component, as there are several threads open, complaining it does not work, when it's actually this library that doesn't work.
@makuser I am on controller version 5.9 and everything works fine. Did you test the code change with your controller? When I test my 5.9.29 controller against the current code, it works. When I test my controller against your pull request, it also works.
@makuser I am on controller version 5.9 and everything works fine. Did you test the code change with your controller? When I test my 5.29 controller against the current code, it works. When I test my controller against your pull request, it also works.
Yes, I have tested it.
The reason why your code did not work is because you weren't sending valid json (at least in my environments that was the case) and more recent versions parse it differently. Previously a single quote might have worked, now only double quoted strings are allowed. This has always been the case for the JSON standard, but only now the UniFi controller actually checks this.
Test this yourself:
### Change it to your env
export username=ubnt
export password=ubnt
export baseurl=https://controller:8443
### Don't change from here on
cookie=$(mktemp)
curl_cmd="curl --tlsv1 --silent --cookie ${cookie} --cookie-jar ${cookie} --insecure "
echo "Double quoted:"
${curl_cmd} --data "{\"username\":\"$username\", \"password\":\"$password\"}" $baseurl/api/login
echo ""
echo "Single quoted:"
${curl_cmd} --data "{'username':'$username', 'password':'$password'}" $baseurl/api/login
echo ""
You've used the request.post / request.put with keyword argument json=value virtually everywhere else, but the login function does not use it, and instead uses the raw python dict (that you then converted to a string).
This (at least in with my python version) will convert the python dict to a single quoted JSON-similar string.
The right way would have been to json.dump(value) it first and send it then, OR simply use the keyword argument json=value directly, which is what my patch does.
Can confirm that I have the same issue with homeassistant (relying on this library) and have had it over multiple 5.9 controller versions. The issue might not show up if you don't have any special characters in your password (though I did not test that).
The issue automatically closed once the pull was merged. If you referenced the pull request, it was stated the pypi package would be updated soon.
Logging in always returns "Login failed - status code: 400".
Trace: