{ "info": { "author": "Nicko van Someren", "author_email": "nicko@nicko.org", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", "Programming Language :: Python :: 3" ], "description": "# A high-level Python interface to the Unifi controller software\n\nunificontrol aims to be a rich and full-featured Python interface to the\nUbiquiti Unifi software defined network controller. Goals of this package\ninclude:\n* A clean interface that supports introspection and self-documentation.\n* Proper handling of SSL connections to allow secure access to the controller even if it uses a self-signed certificate.\n* A concise, readable internal representation of the Unifi API so that new API calls can easily be added as new features are added to the controller.\n* Python 3 only, since it's the way of the future.\n\n## Installation\n\nTo install the most recent release use:\n```\npip install unificontrol\n```\n\nTo install the latest version of the code from GitHub use:\n\n```\npip install -e git+https://github.com/nickovs/unificontrol.git@master#egg=unificontrol\n```\n\n## Usage\n\nThe simplest way to use this client is simply to create an instance with the necessary parameters and log in.\n\n```python\nclient = UnifiClient(host=\"unifi.localdomain\",\n username=UNIFI_USER, password=UNIFI_PASSWORD, site=UNIFI_SITE)\n```\n\nThe host name (and the host port, if you are using something other than the default 8443) must be specificed when you create the client. The username and password can be passed to the login method instead of the contstructor if you prefer. If you supply then username and password in the constructor then the client will automatically log in when needed and re-authenticate if your session expires.\n\nSince the Unifi controller uses a [self-signed certifcate](#ssl-security-with-self-signed-certificates) the default behaviour of the client is to fetch the SSL certificate from the server when you create the client instance and pin all future SSL connections to require the same certificate. This works OK but if you are building some tool that will talk to the controller and you have place to store configuration then a better solution is to store a copy of the correct certificate in a safe place and supply it to the constructor using the `cert` keyword argument. A server's certifcate can be fetched using the python ssl library:\n\n```python\nimport ssl\ncert = ssl.get_server_certificate((\"unifi.localdomain\", 8443))\n# Store the cert in a safe place\n...\n# Fetch the cert from a safe place\nclient = UnifiClient(host=\"unifi.localdomain\",\n username=UNIFI_USER, password=UNIFI_PASSWORD, site=UNIFI_SITE,\n cert=cert)\n```\n\nIf you have a proper certificate for the controller, issued by a known authority and with a subject name matching the host name used to access the server then you can switch off the certificate pinning by passing `cert=None`.\n\n\n## SSL Security with self-signed certificates\n\nThe Unifi controller is accessed using the `https:` protocol in order protect the session. Unfortunately the way that they do this does not protect against _Man-In-The-Middle_ attacks due to the use of a _self-signed certificate_. To understand why this is an issue and how to fix it it is necessary to understand a bit about what SSL certificates do and how they do it.\n\nThe SSL protocol (and its more modern successor, the TLS protocol) make use of _digital certificates_. These are essentially messages that are a digitally _signed_ message that is _signed_ by some party to state that a particular identity is connected to a particular _public key_. A _public key_ is a value that can be used to verify a _digital signature_ such as the ones on these certificates. Each certificate has an _issuer_, the party signing the message, and a _subject_, the party that is having its identity/key relationship asserted in this certificate. In order to validate a certificate you need to have a copy of the _public key_ associated with the _issuer_. The _public key_ belonging to the _subject_ of a certificate sent in the course of starting an SSL session is used to validate _digital signatures_ in the SSL handshake messages and this is used as evidence that the server with which you are communicating belongs to the _subject_ of the certificate.\n\nWhen you make an SSL connection on the internet it is typical for the server at the other end to have a _certificate_ issued by some well know authority. Your web browser has the public keys of many well know authorities built in to it. In these sorts of certificate the identity of the _subject_ includes the domain name of the server to which you are connecting and these authorities are supposed to only issue certificate to the owners of the domains. This way you can have confidence that you are connecting to the right server and not to some system that is trying to eavesdrop on your conversation.\n\nThe Unifi controller (and many other local servers and appliances) typically does not have a public, externally accessible domain name and even if it did, getting a certificate for that domain name is often time consuming and expensive. As a result what Ubiquiti (along with most appliance vendors) does is create a _self-signed certificate_. This is a certificate for which the _issuer_ is not some well known authority but is instead the same identity as the _subject_. The first time you fire up the Unifi controller it spots that it doesn't have a certificate and creates a new one, signed by itself, and identifying the server with the host name `unifi`.\n\nThere are two problems with this approach. Firstly, since the _issuer_ of the certificate is not a well known authority many systems will complain that the certificate is issued by an unknown party. Secondly, unless you access your Unifi controller using the unqualified domain name `unifi` the host name in the certificate will not match the host name used to access the server, and again the system will complain about a mismatched domain name. Furthermore, since the certificate was just created out of thin air, if you anticipate and ignore these two warnings then there is nothing to stop an eavesdropper from simply creating a new _self-signed certificate_ and fooling you into sending your credentials to a bogus server instead of the Unifi controller.\n\nFortunately there is a solution to these problems. The solution is known as _certificate pinning_. This basically just means that you expect to see the same certificate every time you access the same server. This won't help if the eavesdropper is already intercepting your connections the first time you access a service but it will protect you for all subsequent accesses.\n\nThis library implements certificate pinning.\n\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/nickovs/unificontrol", "keywords": "unifi,wifi,network,mamangement", "license": "", "maintainer": "", "maintainer_email": "", "name": "unificontrol", "package_url": "https://pypi.org/project/unificontrol/", "platform": "", "project_url": "https://pypi.org/project/unificontrol/", "project_urls": { "Homepage": "https://github.com/nickovs/unificontrol" }, "release_url": "https://pypi.org/project/unificontrol/0.2.1/", "requires_dist": [ "requests" ], "requires_python": ">=3.4", "summary": "Secure access to Ubiquiti Unifi network controllers", "version": "0.2.1" }, "last_serial": 4122496, "releases": { "0.2.0": [ { "comment_text": "", "digests": { "md5": "745127d0424ccd745a56b9d0566c3fda", "sha256": "54f14c7ce163d2b93f6a1873fdecd9722e9aaf1e1f0dfa93cd79ee3b4e01089b" }, "downloads": -1, "filename": "unificontrol-0.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "745127d0424ccd745a56b9d0566c3fda", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.4", "size": 15596, "upload_time": "2018-07-27T21:28:27", "url": "https://files.pythonhosted.org/packages/d3/a5/c4e7f762820ce5d3ea00bd92288bedd3223faea8ee9444e9a3c1bedd391d/unificontrol-0.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7477482a58ef3f47dbcbc9c3424cf220", "sha256": "df0dcd8a352d485b1302a75fbc84cd2cfdbe0e55675d73e8d293beb22df9597b" }, "downloads": -1, "filename": "unificontrol-0.2.0.tar.gz", "has_sig": false, "md5_digest": "7477482a58ef3f47dbcbc9c3424cf220", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.4", "size": 15718, "upload_time": "2018-07-27T21:28:28", "url": "https://files.pythonhosted.org/packages/de/c1/a811c7642768d478138564b4fae01addd5a6bf3a7159ea9460a51435cf89/unificontrol-0.2.0.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "3d9877a51c1a0f2a83e583b72993e517", "sha256": "4d67647f03aa5ae387276fe1a6033cfac74749a4a9701395392323241431cbfd" }, "downloads": -1, "filename": "unificontrol-0.2.1-py3-none-any.whl", "has_sig": false, "md5_digest": "3d9877a51c1a0f2a83e583b72993e517", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.4", "size": 15628, "upload_time": "2018-08-01T00:38:36", "url": "https://files.pythonhosted.org/packages/59/29/1aa5a2171f2318768a56f4663375f11a4a465a93173ad280461c661d9489/unificontrol-0.2.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "5fc5efafa6e2a59f3f3c3c26c8c20db7", "sha256": "39c55a6d90e64536d4c1732e9479ae499de61be9e88a56683d6fed3c16f83444" }, "downloads": -1, "filename": "unificontrol-0.2.1.tar.gz", "has_sig": false, "md5_digest": "5fc5efafa6e2a59f3f3c3c26c8c20db7", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.4", "size": 15803, "upload_time": "2018-08-01T00:38:37", "url": "https://files.pythonhosted.org/packages/8b/5e/f460812bb650d588f8bf6a8659de718d76aea744ad51e0b16bdacb79c96b/unificontrol-0.2.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "3d9877a51c1a0f2a83e583b72993e517", "sha256": "4d67647f03aa5ae387276fe1a6033cfac74749a4a9701395392323241431cbfd" }, "downloads": -1, "filename": "unificontrol-0.2.1-py3-none-any.whl", "has_sig": false, "md5_digest": "3d9877a51c1a0f2a83e583b72993e517", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.4", "size": 15628, "upload_time": "2018-08-01T00:38:36", "url": "https://files.pythonhosted.org/packages/59/29/1aa5a2171f2318768a56f4663375f11a4a465a93173ad280461c661d9489/unificontrol-0.2.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "5fc5efafa6e2a59f3f3c3c26c8c20db7", "sha256": "39c55a6d90e64536d4c1732e9479ae499de61be9e88a56683d6fed3c16f83444" }, "downloads": -1, "filename": "unificontrol-0.2.1.tar.gz", "has_sig": false, "md5_digest": "5fc5efafa6e2a59f3f3c3c26c8c20db7", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.4", "size": 15803, "upload_time": "2018-08-01T00:38:37", "url": "https://files.pythonhosted.org/packages/8b/5e/f460812bb650d588f8bf6a8659de718d76aea744ad51e0b16bdacb79c96b/unificontrol-0.2.1.tar.gz" } ] }