You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
calculate-utils-3-console/pym/console/application/client_class.py

627 lines
25 KiB

8 years ago
# -*- coding: utf-8 -*-
# Copyright 2012-2016 Mir Calculate. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
3 years ago
import urllib.request as u2
8 years ago
if hasattr(u2, "ssl"):
u2.ssl._create_default_https_context = u2.ssl._create_unverified_context
8 years ago
import os
import sys
import socket
import ssl
import OpenSSL
import hashlib
import M2Crypto
3 years ago
import calculate.contrib
from calculate.core.datavars import DataVarsCore
from calculate.lib.datavars import DataVars
import calculate.contrib
from suds.client import Client
3 years ago
from .cert_verify import verify, get_CRL
import http.client as httplib
from suds.transport.http import HttpTransport
3 years ago
from .pyopenssl_wrapper import PyOpenSSLSocket
from suds.transport import Transport
from suds.properties import Unskin
3 years ago
from http.cookiejar import CookieJar, DefaultCookiePolicy
from logging import getLogger
from ..datavars import DataVarsConsole
from calculate.lib.cl_lang import setLocalTranslate
from .sid_func import SessionId
from calculate.lib.utils.files import readFile
8 years ago
_ = lambda x: x
setLocalTranslate('cl_console3', sys.modules[__name__])
log = getLogger(__name__)
flag = 0
class SUDSHTTPRedirectHandler(u2.HTTPRedirectHandler):
def redirect_request(self, req, fp, code, msg, headers, newurl):
"""Return a Request or None in response to a redirect.
This is called by the http_error_30x methods,
it was taken from the original Python version and modified
to use POST when redirection takes place.
This allows a SOAP message to be redirected without a loss
of content.
"""
m = req.get_method()
if (code in (301, 302, 303, 307) and m in ("GET", "HEAD")
or code in (301, 302, 303) and m == "POST"):
newurl = newurl.replace(' ', '%20')
newheaders = dict((k,v) for k,v in req.headers.items()
if k.lower() not in ("content-length", "content-type")
)
log.debug("Redirecting to %s", newurl)
return u2.Request(newurl,
data=req.data, # here we pass the original data
headers=newheaders,
origin_req_host=req.get_origin_req_host(),
unverifiable=True,
)
else:
raise u2.HTTPError(req.get_full_url(), code, msg, headers, fp)
3 years ago
# class CheckingHTTPSConnection(httplib.HTTPSConnection):
# """based on httplib.HTTPSConnection code - extended to support
# server certificate verification and client certificate authorization"""
# response_class = MyHTTPResponse
# FORCE_SSL_VERSION = None
# SERVER_CERT_CHECK = True # might be turned off when a workaround is needed
# def __init__(self, host, ca_certs=None, cert_verifier=None,
# keyobj=None, certobj=None, **kw):
# """cert_verifier is a function returning either True or False
# based on whether the certificate was found to be OK,
# keyobj and certobj represent internal PyOpenSSL structures holding
# the key and certificate respectively.
# """
# httplib.HTTPSConnection.__init__(self, host, **kw)
# self.ca_certs = ca_certs
# self.cert_verifier = cert_verifier
# self.keyobj = keyobj
# self.certobj = certobj
# def connect(self):
# sock = socket.create_connection((self.host, self.port), self.timeout)
# if hasattr(self, '_tunnel_host') and self._tunnel_host:
# self.sock = sock
# self._tunnel()
# if self.FORCE_SSL_VERSION:
# add = {'ssl_version': self.FORCE_SSL_VERSION}
# else:
# add = {}
# if self.SERVER_CERT_CHECK and self.ca_certs:
# add['cert_reqs'] = ssl.CERT_REQUIRED
# else:
# add['cert_reqs'] = ssl.CERT_NONE
# # try to use PyOpenSSL by default
# if PYOPENSSL_AVAILABLE:
# wrap_class = PyOpenSSLSocket
# add['keyobj'] = self.keyobj
# add['certobj'] = self.certobj
# add['keyfile'] = self.key_file
# add['certfile'] = self.cert_file
# else:
# wrap_class = ssl.SSLSocket
# self.sock = wrap_class(sock, ca_certs=self.ca_certs, **add)
# #if self.cert_verifier and self.SERVER_CERT_CHECK:
# # if not self.cert_verifier(self.sock.getpeercert()):
# # raise Exception("Server certificate did not pass security check.",
# # self.sock.getpeercert())
8 years ago
class Client_suds(SessionId, Client):
def set_parameters(self, path_to_cert, CERT_FILE, PKEY_FILE, HOST):
self.path_to_cert = path_to_cert
if not CERT_FILE:
CERT_FILE = ''
self.CERT_FILE = CERT_FILE
8 years ago
self.REQ_FILE = path_to_cert + 'client.csr'
self.PKEY_FILE = PKEY_FILE
self.SID_FILE = path_to_cert + 'sids'
self.SID_LOCK = path_to_cert + 'sids.lock'
self.CRL_PATH = path_to_cert + 'ca/crl/'
self.HOST = HOST
if not os.path.exists(self.CRL_PATH):
os.makedirs(self.CRL_PATH)
8 years ago
3 years ago
class CheckingClientHTTPSConnection(httplib.HTTPSConnection):
"""based on httplib.HTTPSConnection code"""
response_class = httplib.HTTPResponse
FORCE_SSL_VERSION = None
SERVER_CERT_CHECK = True # might be turned off when a workaround is needed
def __init__(self, cert_path, host, ca_certs=None, cert_verifier=None,
keyobj=None, certobj=None, wait_thread=None, **kw):
"""cert_verifier is a function returning either True or False
based on whether the certificate was found to be OK,
keyobj and certobj represent internal PyOpenSSL structures holding
the key and certificate respectively.
"""
3 years ago
httplib.HTTPSConnection.__init__(self, host, **kw)
self.ca_certs = ca_certs
3 years ago
self.cert_verifier = cert_verifier
self.keyobj = keyobj
self.certobj = certobj
self.cert_path = cert_path
self.CRL_PATH = os.path.join(cert_path, 'ca/crl/')
self.wait_thread = wait_thread
# get filename store cert server
8 years ago
def cert_list(self, host, ca_certs, server_cert):
if host == '127.0.0.1':
host = 'localhost'
if not os.path.exists(self.trusted_path):
try:
os.makedirs(self.trusted_path)
except OSError:
pass
if not os.path.exists(ca_certs):
8 years ago
fc = open(ca_certs, "w")
fc.close()
filename = None
try:
with open(ca_certs) as fd:
t = fd.read()
# for each line
for line in t.splitlines():
# Split string into a words list
words = line.split()
if len(words) > 1:
# if first word...
if words[0] == host:
filename = words[1]
if not filename:
return None
except:
3 years ago
print(_("Certificate not found on the client`s side"))
return None
try:
fd = open(self.trusted_path + filename, 'r')
store_cert = fd.read()
fd.close()
if store_cert == server_cert:
return filename
except:
3 years ago
print(_("Failed to open the file"), self.trusted_path, filename)
return None
8 years ago
def add_all_ca_cert(self, list_ca_certs):
# so root cert be first, ca after
clVarsCore = DataVarsCore()
clVarsCore.importCore()
clVarsCore.flIniFile()
8 years ago
list_ca_certs.reverse()
system_ca_db = clVarsCore.Get('core.cl_glob_root_cert')
clVars = DataVars()
clVars.flIniFile()
homePath = clVars.Get('ur_home_path')
cl_client_cert_dir = clVarsCore.Get('core.cl_client_cert_dir')
8 years ago
cl_client_cert_dir = cl_client_cert_dir.replace("~", homePath)
12 years ago
root_cert_md5 = os.path.join(cl_client_cert_dir, "ca/cert_list")
user_root_cert = clVarsCore.Get('core.cl_user_root_cert')
8 years ago
user_root_cert = user_root_cert.replace("~", homePath)
for cert in list_ca_certs:
if os.path.exists(system_ca_db):
if cert in readFile(system_ca_db):
continue
if os.path.exists(user_root_cert):
if cert in readFile(user_root_cert):
continue
md5 = hashlib.md5()
3 years ago
md5.update(cert.encode("UTF-8"))
md5sum = md5.hexdigest()
3 years ago
print("\n=================================================")
print("md5sum = ", md5sum)
8 years ago
if not os.path.exists(root_cert_md5):
8 years ago
fc = open(root_cert_md5, "w")
fc.close()
8 years ago
filename = None
with open(root_cert_md5) as fd:
t = fd.read()
# for each line
for line in t.splitlines():
# Split string into a words list
8 years ago
words = line.split(' ', 1)
if words[0] == md5sum:
filename = words[1]
if not filename:
8 years ago
certobj = OpenSSL.crypto.load_certificate(
OpenSSL.SSL.FILETYPE_PEM, cert)
Issuer = certobj.get_issuer().get_components()
for item in Issuer:
if item[0] == b'CN':
filename = item[1].decode("UTF-8")
8 years ago
fc = open(root_cert_md5, "a")
fc.write('%s %s\n' % (md5sum, filename))
fc.close()
8 years ago
if not filename:
3 years ago
print(_('Field "CN" not found in the certificate!'))
return 1
8 years ago
fd = open(os.path.join(cl_client_cert_dir, 'ca/', filename),
'w')
fd.write(cert)
fd.close()
8 years ago
fa = open(user_root_cert, 'a')
fa.write(cert)
fa.close()
3 years ago
print(_("filename = "), filename)
print(_("Certificate added"))
else:
3 years ago
print(_("The file containing the CA certificate now exists"))
get_CRL(cl_client_cert_dir)
def add_ca_cert(self, cert, list_ca_certs):
8 years ago
url = 'https://%s:%s/?wsdl' % (self.host, self.port)
client = Client_suds(
url, transport=HTTPSClientCertTransport(None, None, self.cert_path))
client.wsdl.services[0].setlocation(url)
cert = client.service.get_ca()
if cert == '1':
3 years ago
print(_("Invalid server certificate!"))
12 years ago
raise Exception(1)
if cert == '2':
3 years ago
print(_("CA certificate not found on the server"))
12 years ago
raise Exception(1)
8 years ago
try:
8 years ago
certobj = OpenSSL.crypto.load_certificate(
OpenSSL.SSL.FILETYPE_PEM, cert)
except:
3 years ago
print(_("Error. Certificate not added to trusted"))
12 years ago
raise Exception(1)
3 years ago
print('\n', _("Fingerprint = %s") % certobj.digest('SHA1'))
print(_("Serial Number = "), certobj.get_serial_number())
Issuer = certobj.get_issuer().get_components()
3 years ago
print('\n', _("Issuer"))
for i in Issuer:
3 years ago
print("%s : %s" % (i[0], i[1]))
Subject = certobj.get_subject().get_components()
3 years ago
print('\n', _("Subject"))
for subj in Subject:
3 years ago
print("%s : %s" % (subj[0], subj[1]))
ans = input(_("Add the CA certificate to trusted? y/[n]:"))
8 years ago
if ans.lower() in ['y', 'yes']:
list_ca_certs.append(cert)
self.add_all_ca_cert(list_ca_certs)
else:
3 years ago
print(_("Certificate not added to trusted"))
# add certificate server in trusted
def add_server_cert(self, cert):
self.wait_thread.stop()
3 years ago
print(_("Untrusted server certificate!"))
8 years ago
certobj = OpenSSL.crypto.load_certificate(
OpenSSL.SSL.FILETYPE_PEM, cert)
3 years ago
print('\n' + _("Fingerprint = %s") % certobj.digest('SHA1'))
print(_("Serial Number = "), certobj.get_serial_number())
Issuer = certobj.get_issuer().get_components()
3 years ago
print('\n' + _("Issuer"))
for i in Issuer:
3 years ago
print("%s : %s" % (i[0], i[1]))
Subject = certobj.get_subject().get_components()
3 years ago
print('\n' + _("Subject"))
for item in Subject:
3 years ago
print("%s : %s" % (item[0], item[1]))
8 years ago
3 years ago
print('\n' + _('Add this server certificate to trusted (s) or'))
print(_('Try to add the CA and root certificates to trusted (c) or'))
choice = input(_("Quit (q)? s/c/[q]: "))
if choice.lower() in ['s', 'c']:
8 years ago
# self.sock = ssl.wrap_socket(sock)
ca_certs = os.path.join(self.trusted_path, "cert.list")
8 years ago
if not os.path.exists(ca_certs):
8 years ago
fc = open(ca_certs, "w")
fc.close()
8 years ago
if self.host == '127.0.0.1':
host = 'localhost'
8 years ago
else:
host = self.host
filename = host
8 years ago
fc = open(self.trusted_path + filename, "w")
fc.write(cert)
fc.close()
with open(ca_certs) as fd:
t = fd.read()
# for each line
for line in t.splitlines():
# Split string into a words list
words = line.split()
if len(words) > 1:
# if first word...
if words[0] == host:
return 0
# Open file with compliance server certificates and server hostname
8 years ago
fcl = open(ca_certs, "a")
fcl.write(host + ' ' + filename + '\n')
fcl.close()
if choice.lower() != 'c':
return 3
if choice.lower() == 'c':
clVars = DataVarsCore()
clVars.importCore()
clVars.flIniFile()
cl_client_cert_dir = clVars.Get('core.cl_client_cert_dir')
homePath = clVars.Get('ur_home_path')
8 years ago
cl_client_cert_dir = cl_client_cert_dir.replace("~", homePath)
12 years ago
root_cert_dir = os.path.join(cl_client_cert_dir, "ca")
8 years ago
if not os.path.exists(root_cert_dir):
try:
os.makedirs(root_cert_dir)
except OSError:
3 years ago
print(_("Failed to create directory %s") % root_cert_dir)
12 years ago
raise Exception(1)
8 years ago
3 years ago
print('\n' + _("Add the CA and root certificates"))
self.list_ca_certs = []
self.add_ca_cert(cert, self.list_ca_certs)
return 3
8 years ago
elif not choice.lower() in ['c', 's']:
return 4
def connect_trusted_root(self, sock, root_cert, crl_certs):
self.ca_path = self.cert_path + "ca/"
8 years ago
server_cert = ssl.get_server_certificate(addr=(self.host, self.port))
global flag
if self.cert_file:
f = verify(server_cert, crl_certs, flag)
if not f:
flag = 1
elif f == 1:
12 years ago
raise Exception(1)
else:
import time
8 years ago
time.sleep(0.1)
try:
if self.FORCE_SSL_VERSION:
add = {'ssl_version': self.FORCE_SSL_VERSION}
else:
add = {}
add['cert_reqs'] = ssl.CERT_REQUIRED
3 years ago
add['keyobj'] = self.keyobj
add['certobj'] = self.certobj
add['keyfile'] = self.key_file
add['certfile'] = self.cert_file
self.sock = PyOpenSSLSocket(sock, ca_certs=self.ca_certs, **add)
return 0
except:
return 1
def connect_trusted_server(self, sock, crl_certs):
self.trusted_path = self.cert_path + "trusted/"
ca_cert_list = self.trusted_path + "cert.list"
8 years ago
server_cert = ssl.get_server_certificate(addr=(self.host, self.port))
global flag
if self.cert_file:
f = verify(server_cert, crl_certs, flag)
if not f:
flag = 1
elif f == 1:
12 years ago
raise Exception(1)
8 years ago
# if not hasattr(HTTPSClientCertTransport, 'filename') or \
# HTTPSClientCertTransport.filename == None:
HTTPSClientCertTransport.filename = self.cert_list(
self.host, ca_cert_list, server_cert)
if HTTPSClientCertTransport.filename:
try:
if self.FORCE_SSL_VERSION:
add = {'ssl_version': self.FORCE_SSL_VERSION}
else:
add = {}
add['cert_reqs'] = ssl.CERT_NONE
3 years ago
add['keyobj'] = self.keyobj
add['certobj'] = self.certobj
add['keyfile'] = self.key_file
add['certfile'] = self.cert_file
self.sock = PyOpenSSLSocket(sock, ca_certs=None, **add)
return 0
except Exception:
HTTPSClientCertTransport.filename = None
return 1
else:
return self.add_server_cert(server_cert)
def connect(self):
sock = socket.create_connection((self.host, self.port), self.timeout)
if hasattr(self, '_tunnel_host') and self._tunnel_host:
self.sock = sock
self._tunnel()
self.Vars = DataVarsConsole()
self.Vars.importConsole()
self.Vars.flIniFile()
user_root_cert = self.Vars.Get('core.cl_user_root_cert')
homePath = self.Vars.Get('ur_home_path')
8 years ago
user_root_cert = user_root_cert.replace("~", homePath)
result_user_root = 1
while True:
if os.path.exists(user_root_cert):
8 years ago
result_user_root = self.connect_trusted_root(sock,
user_root_cert,
self.CRL_PATH)
if result_user_root == 1:
glob_root_cert = self.Vars.Get('core.cl_glob_root_cert')
result_root_con = 1
if os.path.exists(glob_root_cert):
sock = socket.create_connection((self.host, self.port),
8 years ago
self.timeout,
self.source_address)
if self._tunnel_host:
self.sock = sock
self._tunnel()
8 years ago
result_root_con = self.connect_trusted_root(sock,
glob_root_cert,
self.CRL_PATH)
if result_root_con == 1:
sock = socket.create_connection((self.host, self.port),
8 years ago
self.timeout,
self.source_address)
if self._tunnel_host:
self.sock = sock
self._tunnel()
8 years ago
result_server_con = self.connect_trusted_server(
sock, self.CRL_PATH)
if result_server_con in [1, 2]:
raise Exception(1)
elif result_server_con == 3:
continue
elif result_server_con == 4:
3 years ago
print(_('This server is not trusted'))
self.wait_thread.stop()
sys.exit(1)
elif result_root_con == 2:
8 years ago
raise Exception(1)
elif result_user_root == 2:
8 years ago
raise Exception(1)
break
8 years ago
3 years ago
class CheckingClientHTTPSHandler(u2.HTTPSHandler):
def __init__(self, cert_path, ca_certs=None, cert_verifier=None,
client_certfile=None, client_keyfile=None,
3 years ago
client_keyobj=None, client_certobj=None,
*args, **kw):
"""cert_verifier is a function returning either True or False
based on whether the certificate was found to be OK"""
3 years ago
u2.HTTPSHandler.__init__(self, *args, **kw)
self.ca_certs = ca_certs
self.cert_verifier = cert_verifier
self.client_keyfile = client_keyfile # filename
self.client_certfile = client_certfile # filename
self.keyobj = client_keyobj
self.certobj = client_certobj
# FOR DEBUG
# self.set_http_debuglevel(100)
self.cert_path = cert_path
def https_open(self, req):
def open(*args, **kw):
new_kw = dict(ca_certs=self.ca_certs,
cert_verifier=self.cert_verifier,
cert_file=self.client_certfile,
key_file=self.client_keyfile,
3 years ago
keyobj=self.keyobj,
certobj=self.certobj)
new_kw.update(kw)
3 years ago
return CheckingClientHTTPSConnection(self.cert_path, *args, **new_kw)
return self.do_open(open, req)
https_request = u2.AbstractHTTPHandler.do_request_
8 years ago
class HTTPSClientCertTransport(HttpTransport):
8 years ago
def __init__(self, key, cert, path_to_cert, password=None,
ca_certs=None, cert_verifier=None,
client_keyfile=None, client_certfile=None,
client_keyobj=None, client_certobj=None,
cookie_callback=None, user_agent_string=None,
wait_thread=None, **kwargs):
Transport.__init__(self)
self.key = key
self.cert = cert
self.cert_path = path_to_cert
if key:
3 years ago
with open(cert) as cert_file:
client_certobj = OpenSSL.crypto.load_certificate \
(OpenSSL.SSL.FILETYPE_PEM, cert_file.read())
if password:
with open(key) as key_file:
client_keyobj = OpenSSL.crypto.load_privatekey \
(OpenSSL.SSL.FILETYPE_PEM, key_file.read(),
password)
else:
import M2Crypto
bio = M2Crypto.BIO.openfile(key)
rsa = M2Crypto.m2.rsa_read_key(bio._ptr(),lambda *unused: b"")
if not rsa:
raise OpenSSL.crypto.Error
with open(key) as key_file:
client_keyobj = OpenSSL.crypto.load_privatekey(OpenSSL.SSL.FILETYPE_PEM,
key_file.read())
Unskin(self.options).update(kwargs)
self.cookiejar = CookieJar(DefaultCookiePolicy())
self.cookie_callback = cookie_callback
self.user_agent_string = user_agent_string
log.debug("Proxy: %s", self.options.proxy)
3 years ago
if ca_certs or (client_keyfile and client_certfile) \
or (client_keyobj and client_certobj):
https_handler = CheckingClientHTTPSHandler(cert_path=path_to_cert,
ca_certs=ca_certs,
cert_verifier=cert_verifier,
client_keyfile=client_keyfile,
client_certfile=client_certfile,
client_keyobj=client_keyobj,
client_certobj=client_certobj)
else:
https_handler = u2.HTTPSHandler()
self.urlopener = u2.build_opener(SUDSHTTPRedirectHandler(),
u2.HTTPCookieProcessor(self.cookiejar),
https_handler)
# relic from old times:
# from dslib.network import ProxyManager
# proxy_handler = ProxyManager.HTTPS_PROXY.create_proxy_handler()
# proxy_auth_handler = ProxyManager.HTTPS_PROXY.create_proxy_auth_handler()
# apparently, dslib simply returned None on create_proxy_auth_handler
# if this is ever needed, probably use urllib2.ProxyBasicAuthHandler
3 years ago
# proxy_auth_handler = None
# and create_proxy_handler SHOULD HAVE eval'd to this:
# proxy_handler = urllib2.ProxyHandler({"https" : "https://hostname"})
# but because no hostname was given, it also just returned None
3 years ago
# proxy_handler = None
#these two literally do nothing right now
# if proxy_handler:
# self.urlopener.add_handler(proxy_handler)
# if proxy_auth_handler:
# self.urlopener.add_handler(proxy_auth_handler)
self.urlopener.addheaders = [('User-agent', str(self.user_agent_string))]