Actually validate door controller SSL certificates
This commit is contained in:
parent
4d38ac5840
commit
0528686903
12
README.md
12
README.md
@ -33,3 +33,15 @@ Retrieves events from the HID Evo Solo door controllers, and pushes them to a SQ
|
||||
## Systemd
|
||||
|
||||
There are systemd units in the [`systemd`](./systemd/) folder, which can be used to run the various scripts regularly.
|
||||
|
||||
## SSL Certificates
|
||||
|
||||
The HID Evo Solo door controllers we use have a self-signed certificate, which is included in this repo as [`hidglobal.com.pem`](./hidglobal.com.pem).
|
||||
|
||||
If you need to use a different certificate, you can either download it with your browser or the following command (replacing `SERVER` by the address of the door):
|
||||
|
||||
```sh
|
||||
openssl s_client -connect SERVER:443 </dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > example.pem
|
||||
```
|
||||
|
||||
Then set `doorControllerCA_BUNDLE` in `config.yaml` to the path to the created pem file. If your doors have different certificates, (which ours annoyingly don't), you will need to concatenate the certificates together into a single file.
|
||||
|
@ -6,6 +6,8 @@ doorControllers:
|
||||
Wood Shop Rear: {ip: 172.18.51.15, access: Wood Shop}
|
||||
Storage Closet: {ip: 172.18.51.16, access: Storage Closet}
|
||||
|
||||
doorControllerCA_BUNDLE: "hidglobal.com.pem"
|
||||
|
||||
# {member type: door schedule}
|
||||
memberLevels:
|
||||
CMS Staff: 7x24
|
||||
|
24
hidglobal.com.pem
Normal file
24
hidglobal.com.pem
Normal file
@ -0,0 +1,24 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID9TCCAt2gAwIBAgIJAPBotjnyfGu6MA0GCSqGSIb3DQEBCwUAMIGQMQswCQYD
|
||||
VQQGEwJVUzERMA8GA1UECAwIQ29sb3JhZG8xFDASBgNVBAcMC1dlc3RtaW5zdGVy
|
||||
MQwwCgYDVQQKDANISUQxDDAKBgNVBAsMA05BUzEWMBQGA1UEAwwNaGlkZ2xvYmFs
|
||||
LmNvbTEkMCIGCSqGSIb3DQEJARYVc3VwcG9ydEBoaWRnbG9iYWwuY29tMB4XDTE5
|
||||
MDcyMjEwMTQxMFoXDTI5MDcxOTEwMTQxMFowgZAxCzAJBgNVBAYTAlVTMREwDwYD
|
||||
VQQIDAhDb2xvcmFkbzEUMBIGA1UEBwwLV2VzdG1pbnN0ZXIxDDAKBgNVBAoMA0hJ
|
||||
RDEMMAoGA1UECwwDTkFTMRYwFAYDVQQDDA1oaWRnbG9iYWwuY29tMSQwIgYJKoZI
|
||||
hvcNAQkBFhVzdXBwb3J0QGhpZGdsb2JhbC5jb20wggEiMA0GCSqGSIb3DQEBAQUA
|
||||
A4IBDwAwggEKAoIBAQDSibuXB9Tn0EdwL2jDig26s/b1D9SX5B4xnZM+xZ4/mE6U
|
||||
Meg5xbiTSMiWqtoSMVxG1WJDxogJWxCgZis2qk3AG89PBarg17pBmxPLYyCLricx
|
||||
alyNvTJBxYgA/zKagPof6h6UqKOkhsW9qvulEmPe+TKk47pmlZXe+v+1A6PQDY5B
|
||||
Y3MtqE23cnZ5nBTVanFAc1vbokMXUCCtRvE1Y/KhvuaJr2VjOSJ/KV3vcdTSCLGc
|
||||
W9/n/Fv8udvI/eIkoPNpCUwngm8j3Aa7qN/OSg3SvVvBcl/Ykc08STSyZPMJGBaR
|
||||
EuUcAraEBZbUDOCinDS488jKVHAXhrnvzzi7RMlhAgMBAAGjUDBOMB0GA1UdDgQW
|
||||
BBSvOzxCjQi86ZUsuW0o4aa7GNAeSTAfBgNVHSMEGDAWgBSvOzxCjQi86ZUsuW0o
|
||||
4aa7GNAeSTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQA/8FCv6x8v
|
||||
PHm2Ya/hbZ/S3amdl7/E1illeApNRZodTGCn/rlVSGanCfWYzEY2naHiDC2ImhZq
|
||||
NkHK9uvUtxaVQFq5VN6WQMo351J78LLfcoqpKOLGX3b9byFvrw7WporZx3C7yL1U
|
||||
LS3oxI/pgavxy1KbOIw/yl+QgV50vlfvQ7sKZ1E5YOrgWLP5nJ9OeEKRdsASJyZS
|
||||
Jjl0k/eGaZreSvAZPmx4kaePfbi7DNDA+mNhSFygwt6AakjjVoF2xUZ1F+qwBtER
|
||||
GPxdZWldywUYsdBRG1PPvBsMo9ME46HpPdXRIjMge8P01fsaMr/6H86ojWg9uJmH
|
||||
cCKtiouo08hL
|
||||
-----END CERTIFICATE-----
|
@ -22,6 +22,7 @@ class Config:
|
||||
self.DOOR_PASSWORD,
|
||||
name=doorName,
|
||||
access=doorData["access"],
|
||||
cert=self.doorControllerCA_BUNDLE
|
||||
)
|
||||
for doorName, doorData in self.doorControllers.items()
|
||||
}
|
||||
|
@ -3,9 +3,10 @@ from datetime import datetime
|
||||
from io import StringIO
|
||||
|
||||
import requests
|
||||
import urllib3
|
||||
from lxml import etree
|
||||
from lxml.builder import ElementMaker
|
||||
from requests import Session
|
||||
from requests.adapters import HTTPAdapter
|
||||
|
||||
E_plain = ElementMaker(nsmap={"hid": "http://www.hidglobal.com/VertX"})
|
||||
E = ElementMaker(
|
||||
@ -22,9 +23,10 @@ fieldnames = "CardNumber,CardFormat,PinRequired,PinCode,ExtendedAccess,ExpiryDat
|
||||
","
|
||||
)
|
||||
|
||||
# TODO: where should this live?
|
||||
# it's fine, ssl certs are for losers anyway
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
class HostNameIgnoringAdapter(HTTPAdapter):
|
||||
def init_poolmanager(self, *args, **kwargs):
|
||||
super().init_poolmanager(*args, **kwargs, assert_hostname=False)
|
||||
|
||||
|
||||
class RemoteError(Exception):
|
||||
@ -33,12 +35,16 @@ class RemoteError(Exception):
|
||||
|
||||
|
||||
class DoorController:
|
||||
def __init__(self, ip, username, password, name="", access=""):
|
||||
def __init__(self, ip, username, password, name="", access="", cert=None):
|
||||
self.ip = ip
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.name = name
|
||||
self.access = access
|
||||
self.session = Session()
|
||||
if cert is not None:
|
||||
self.session.mount("https://", HostNameIgnoringAdapter())
|
||||
self.session.verify = cert
|
||||
|
||||
# lazy evaluated, hopefully won't change for the lifetime of this object
|
||||
@property
|
||||
@ -55,13 +61,12 @@ class DoorController:
|
||||
|
||||
def doImport(self, params=None, files=None):
|
||||
"""Send a request to the door control import script"""
|
||||
r = requests.post(
|
||||
r = self.session.post(
|
||||
"https://" + self.ip + "/cgi-bin/import.cgi",
|
||||
params=params,
|
||||
files=files,
|
||||
auth=requests.auth.HTTPDigestAuth(self.username, self.password),
|
||||
timeout=60,
|
||||
verify=False,
|
||||
) # ignore insecure SSL
|
||||
xml = etree.XML(r.content)
|
||||
if (
|
||||
@ -82,11 +87,10 @@ class DoorController:
|
||||
def doXMLRequest(self, xml, prefix=b'<?xml version="1.0" encoding="UTF-8"?>'):
|
||||
if not isinstance(xml, bytes):
|
||||
xml = etree.tostring(xml)
|
||||
r = requests.get(
|
||||
r = self.session.get(
|
||||
"https://" + self.ip + "/cgi-bin/vertx_xml.cgi",
|
||||
params={"XML": prefix + xml},
|
||||
auth=requests.auth.HTTPDigestAuth(self.username, self.password),
|
||||
verify=False,
|
||||
)
|
||||
resp_xml = etree.XML(r.content)
|
||||
# probably meed to be more sane about this
|
||||
|
Reference in New Issue
Block a user