Skip to content

Commit

Permalink
Add https support for version 3 of the controller, and moved dev to v…
Browse files Browse the repository at this point in the history
…scode
  • Loading branch information
dingusdk committed Jun 6, 2020
1 parent 79cb37e commit 4eb08ac
Show file tree
Hide file tree
Showing 18 changed files with 138 additions and 219 deletions.
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/dist
/build
/ihcsdk.egg-info
/build.bat
/upload.bat
/nppBackup
/.venv
__pycache__/
.parameters
15 changes: 15 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: Example file",
"type": "python",
"request": "launch",
"program": "example.py",
"console": "integratedTerminal"
}
]
}
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"python.pythonPath": "g:\\Dev\\python\\ihcsdk\\.venv\\Scripts\\python.exe"
}
3 changes: 3 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include readme.md
include license.txt
include ihcsdk/certs/*.crt
4 changes: 3 additions & 1 deletion build.bat
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
rm -R dist
python setup.py sdist
rm -R build
rm -R ihcsdk.egg-info
python setup.py sdist bdist_wheel
50 changes: 26 additions & 24 deletions Examples/ihctest.py → example.py
Original file line number Diff line number Diff line change
@@ -1,43 +1,45 @@
"""
Test example showing how to use the ihcsdk to connect to the ihc controller
To run the example create a file '.parameters' in this folder and add:
ihcurl username password resourceid
The resourceid is an ihc resource id of any boolean resource in you controller.
The resource will be toggled when the test starts, and after this you can set it
using '1' and '2'. 'q' to quit
"""
from sys import argv
from datetime import datetime
from ihcsdk.ihccontroller import IHCController
# from ihcsdk.ihccurlconnection import IHCCurlConnection

t = datetime.now()
from ihcsdk.ihccontroller import IHCController


def on_ihc_change(ihcid, value):
"""Callback when ihc resource changes"""
print("Resource change " + str(ihcid) + "->" + str(value) +
" time: " + gettime())
def main():
"""Do the test"""

starttime = datetime.now()

def gettime():
dif = datetime.now() - t
return str(dif)
def on_ihc_change(ihcid, value):
"""Callback when ihc resource changes"""
print("Resource change " + str(ihcid) + "->" + str(value) +
" time: " + gettime())

def gettime():
dif = datetime.now() - starttime
return str(dif)

def main():
"""Do the test"""
global t
if len(argv) != 5:
print("Syntax: ihctest ihcurl username password resourceid")
cmdline = open(".parameters", "rt").read()
args = cmdline.split(' ')
if len(args) != 4:
print("The '.parameters' file should contain: ihcurl username password resourceid")
exit()
url = argv[1]
resid = int(argv[4])
ihc = IHCController(url, argv[2], argv[3])
# Un-comment the line below to use pycurl connection
# ihc.client.connection = IHCCurlConnection( url)
url = args[0]
resid = int(args[3])
ihc = IHCController(url, args[1], args[2])
if not ihc.authenticate():
print("Authenticate failed")
exit()

print("Authenticate succeeded\r\n")

# read project
# read the ihc project
project = ihc.get_project()
if project is False:
print("Failed to read project")
Expand All @@ -63,11 +65,11 @@ def main():
while True:
i = input()
if i == "1":
t = datetime.now()
starttime = datetime.now()
ihc.set_runtime_value_bool(resid, False)
continue
if i == "2":
t = datetime.now()
starttime = datetime.now()
ihc.set_runtime_value_bool(resid, True)
continue
if i == "q":
Expand Down
File renamed without changes.
23 changes: 23 additions & 0 deletions ihcsdk/certs/ihc3.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIIDyzCCArOgAwIBAgIEapjIFzANBgkqhkiG9w0BAQsFADCBlTELMAkGA1UEBhMC
RlIxDzANBgNVBAgTBkZyYW5jZTEeMBwGA1UEBxMVOTI1MDAgUnVlaWwgTWFsbWFp
c29uMRswGQYDVQQKExJTY2huZWlkZXIgRWxlY3RyaWMxGzAZBgNVBAsTEkdsb2Jh
bCBFbmdpbmVlcmluZzEbMBkGA1UEAxMSU2NobmVpZGVyIEVsZWN0cmljMB4XDTE2
MDMwMjExNTExMFoXDTI2MDEwOTExNTExMFowgZUxCzAJBgNVBAYTAkZSMQ8wDQYD
VQQIEwZGcmFuY2UxHjAcBgNVBAcTFTkyNTAwIFJ1ZWlsIE1hbG1haXNvbjEbMBkG
A1UEChMSU2NobmVpZGVyIEVsZWN0cmljMRswGQYDVQQLExJHbG9iYWwgRW5naW5l
ZXJpbmcxGzAZBgNVBAMTElNjaG5laWRlciBFbGVjdHJpYzCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAKBnGTVIWpV4yld9hFpkRFn0rT/jFMT9JUbMRvBx
La0nZuOPAQh4xCpM6p+upjF91x+SRM+pGt1oMxptxmhK3fXeghinC1qF3EB3e7wE
QUc/35ckVbDR7K/rlqRW/qSjB1mNSX8YWzxCTEbBhYJiQwSxVOjAZ1zyvNUq8Msq
3yi19aER1Rn3Vpdma216ogXWHJe2hVgtnoM+l85vE8dd72wcVdya5qrMOI67gvnh
DjoSbVeP5kUFgt9gU0cNC6HsSw0ayvxYlTb3hlzdO211zCJc1yADFzIb5eNa8LPp
9NCTrG5qAhda+0GY2pJk+XqrpH6VryKLZIvV7CCa2VASlO0CAwEAAaMhMB8wHQYD
VR0OBBYEFI2fPYY01dOInhlJEhJl3mMavE27MA0GCSqGSIb3DQEBCwUAA4IBAQB3
BdnEsqTv/f44b2cKsztQ9+3tq4RfO0FRtcpXGr5uNIRVcTLqaT1TrqEMOmB9v+9j
99hVrm4T0gkchW51jYKNuwTP+4zYk+mx6BVuSWysmBg6meB3J8I7x5q/oWjylHOT
LznoHPhB4kwA/TCh9DfOdcklhYMVesWm3XllYhY8Vy5JaT2g4AWE2PHZP6e/fPHc
Vm4867n8P58ko+2uHb+noFBkNC/3BsSiGkMQZ+GSgkVxQAzvdj8vcndJEe/uvCh+
/OI9DdwFVF00zdP1CTaNI4YvDEfCHjRDyVNY1ygJ/cvNeK/Y1ohYKgGfrsunCZsJ
Jit2KlT6WgvhepiYCrWP
-----END CERTIFICATE-----
6 changes: 5 additions & 1 deletion ihcsdk/ihcclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import zlib
import base64
from ihcsdk.ihcconnection import IHCConnection
from ihcsdk.ihcsslconnection import IHCSSLConnection

IHCSTATE_READY = "text.ctrl.state.ready"

Expand All @@ -22,7 +23,10 @@ def __init__(self, url: str):
self.url = url
self.username = ""
self.password = ""
self.connection = IHCConnection(url)
if url.startswith( "https://"):
self.connection = IHCSSLConnection(url)
else:
self.connection = IHCConnection(url)

def authenticate(self, username: str, password: str) -> bool:
"""Do an Authentricate request and save the cookie returned to be used
Expand Down
8 changes: 6 additions & 2 deletions ihcsdk/ihcconnection.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@


class IHCConnection(object):
"""description of class"""
"""Implements a http connection to the controller"""

soapenvelope = """<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"
Expand All @@ -15,14 +15,17 @@ class IHCConnection(object):
<s:Body>{body}</s:Body></s:Envelope>"""

def __init__(self, url: str):
"""Initialize the IIHCSoapClient with a url for the controller"""
"""Initialize the IHCConnection with a url for the controller"""
self.url = url
self.cookies = ""
self.verify = False
self.last_exception = None
self.last_response = None
self.session = requests.Session()

def cert_verify(self):
return None

def soap_action(self, service, action, payloadbody):
"""Do a soap request."""
payload = self.soapenvelope.format(body=payloadbody).encode('utf-8')
Expand All @@ -36,6 +39,7 @@ def soap_action(self, service, action, payloadbody):
response = self.session.post(url=self.url + service,
headers=headers,
data=payload,
verify=self.cert_verify(),
cookies=self.cookies)
except requests.exceptions.RequestException as exp:
self.last_exception = exp
Expand Down
6 changes: 2 additions & 4 deletions ihcsdk/ihccontroller.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ def authenticate(self) -> bool:
if not self.client.authenticate(self._username, self._password):
return False
if self._ihcevents:
self.client.enable_runtime_notifications(
self._ihcevents.keys())
self.client.enable_runtime_notifications(self._ihcevents.keys())
return True

def disconnect(self):
Expand Down Expand Up @@ -112,8 +111,7 @@ def _notify_fn(self):
with IHCController._mutex:
# Are there are any new ids to be added?
if self._newnotifyids:
self.client.enable_runtime_notifications(
self._newnotifyids)
self.client.enable_runtime_notifications(self._newnotifyids)
self._newnotifyids = []

changes = self.client.wait_for_resource_value_changes()
Expand Down
60 changes: 0 additions & 60 deletions ihcsdk/ihccurlconnection.py

This file was deleted.

77 changes: 29 additions & 48 deletions ihcsdk/ihcsslconnection.py
Original file line number Diff line number Diff line change
@@ -1,65 +1,46 @@
"""Implements soap reqeust using the "requests" module"""
# pylint: disable=too-few-public-methods
import ssl
import xml.etree.ElementTree
import os
import requests
from requests.packages.urllib3.util.ssl_ import create_urllib3_context

from cryptography.x509 import load_pem_x509_certificate
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from requests.adapters import HTTPAdapter

from ihcsdk.ihcconnection import IHCConnection


class IHCSSLConnection(IHCConnection):
"""description of class"""
"""Implements a https connection to the controller"""

def __init__(self, url: str):
"""Initialize the IIHCSoapClient with a url for the controller"""
"""Initialize the IHCSSLConnection with a url for the controller"""
super(IHCSSLConnection, self).__init__(url)
self.session = requests.Session()
self.session.mount('https://', TLSv1Adapter())
self.cert_file = os.path.dirname( __file__) + "/certs/ihc3.crt"
self.session.mount('https://', CertAdapter( self.get_fingerprint_from_cert()))

def soap_action(self, service, action, payloadbody):
"""Do a soap request"""
payload = self.soapenvelope.format(body=payloadbody).encode('utf-8')
headers = {"Host": self.url,
"Content-Type": "text/xml; charset=UTF-8",
"Cache-Control": "no-cache",
"Content-Length": str(len(payload)),
"SOAPAction": action}
try:
response = self.session.post(
url=self.url + service, headers=headers, data=payload)
except Exception as exp:
return False
if response.status_code != 200:
return False
try:
xdoc = xml.etree.ElementTree.fromstring(response.text)
if xdoc is None:
return False
except xml.etree.ElementTree.ParseError:
return False
return xdoc
def get_fingerprint_from_cert( self):
"""Get the fingerprint from the certificate"""
pem = open( self.cert_file, "rb").read()
cert = load_pem_x509_certificate(pem, default_backend())
f = cert.fingerprint( hashes.SHA1())
return ''.join('{:02x}'.format(x) for x in f)

def cert_verify(self):
return self.cert_file

class TLSv1Adapter(HTTPAdapter):
"""Force TLSv1"""

CIPHERS = ('AES256-SHA')
class CertAdapter(requests.adapters.HTTPAdapter):
"""A adapter for a specific certificate"""

def init_poolmanager(self, connections, maxsize,
block=requests.adapters.DEFAULT_POOLBLOCK,
**pool_kwargs):
"""Initialize poolmanager with cipher and Tlsv1"""
context = create_urllib3_context(ciphers=self.CIPHERS,
ssl_version=ssl.PROTOCOL_TLSv1)
pool_kwargs['ssl_context'] = context
return super(TLSv1Adapter, self).init_poolmanager(connections, maxsize,
block, **pool_kwargs)
def __init__(self, fingerprint, **kwargs):
"""Constructor. Store the fingerprint for use when creating the poolmanager."""
self.fingerprint = fingerprint
super(CertAdapter, self).__init__(**kwargs)

def proxy_manager_for(self, proxy, **proxy_kwargs):
"""Ensure cipher and Tlsv1"""
context = create_urllib3_context(ciphers=self.CIPHERS,
ssl_version=ssl.PROTOCOL_TLSv1)
proxy_kwargs['ssl_context'] = context
return super(TLSv1Adapter, self).proxy_manager_for(proxy,
**proxy_kwargs)
def init_poolmanager(self, connections, maxsize, block=False, **pool_kwargs):
"""Create a custom poolmanager"""
pool_kwargs['assert_fingerprint'] = self.fingerprint
return super(CertAdapter, self).init_poolmanager(connections, maxsize,
block, **pool_kwargs)
Loading

0 comments on commit 4eb08ac

Please sign in to comment.