From c4fa0355be7688a3c814a108335a3ff91f4708fd Mon Sep 17 00:00:00 2001 From: Dan Lavu Date: Fri, 5 Feb 2016 08:51:07 -0500 Subject: [PATCH] Adding SSL encryption to integration tests. --- src/tests/intg/ca.py | 163 ++++++++++++++++++++++++++++++++++++++++++ src/tests/intg/config.py.m4 | 1 + src/tests/intg/ds_openldap.py | 19 ++++- 3 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 src/tests/intg/ca.py diff --git a/src/tests/intg/ca.py b/src/tests/intg/ca.py new file mode 100644 index 0000000000000000000000000000000000000000..c7adb7a2f0c2ea7f342c9df1d6ad41dcb2fcc28e --- /dev/null +++ b/src/tests/intg/ca.py @@ -0,0 +1,163 @@ +# +# SSSD LOCAL domain tests +# +# Copyright (c) 2016 Red Hat, Inc. +# Author: Dan Lavu +# +# This is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 only +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +from OpenSSL import crypto +from os.path import exists, join + +import socket +import os +import shutil +import config + + +class CA(): + """CA Class""" + + def __init__(self, subject=None, country='US', state='NC', + city='Raleigh', organization='Red Hat Inc.', unit='SSSD', config_dir=config.SSL_PATH): + if subject is None: + self.subject = socket.gethostname() + self.country = country + self.state = state + self.city = city + self.organization = organization + self.unit = unit + self.hostname = socket.gethostname() + if config.SSL_PATH is not '/tmp': + self.config_dir = config_dir + else: + self.config_dir = config_dir + '/ssl' + self.csr_dir = self.config_dir + '/newcerts' + self.key_dir = self.config_dir + '/private' + self.cert_dir = self.config_dir + '/certs' + + self.index = int(1000) + + + def setup(self): + """Setup CA using OpenSSL""" + cacert = self.hostname + '-ca.crt' + cakey = self.hostname + '-ca.key' + + if not exists(join(self.cert_dir, cacert)) or not exists(join(self.key_dir, cakey)): + key = crypto.PKey() + key.generate_key(crypto.TYPE_RSA, 2048) + + ca = crypto.X509() + ca.get_subject().C = self.country + ca.get_subject().ST = self.state + ca.get_subject().L = self.city + ca.get_subject().O = self.organization + ca.get_subject().OU = self.unit + ca.get_subject().CN = self.subject + ca.set_serial_number(self.index) + ca.gmtime_adj_notBefore(0) + ca.gmtime_adj_notAfter(10 * 365 * 24 * 60 * 60) + ca.set_issuer(ca.get_subject()) + ca.set_pubkey(key) + ca.sign(key, 'sha1') + + if not os.path.exists(self.csr_dir): + os.makedirs(self.csr_dir) + if not os.path.exists(self.key_dir): + os.makedirs(self.key_dir) + if not os.path.exists(self.cert_dir): + os.makedirs(self.cert_dir) + + open(os.path.join(self.cert_dir, cacert), 'wt').write \ + (crypto.dump_certificate(crypto.FILETYPE_PEM, ca)) + open(os.path.join(self.key_dir, cakey), 'wt').write \ + (crypto.dump_privatekey(crypto.FILETYPE_PEM, key)) + + + def teardown(self): + """Teardown CA certificate files""" + if os.path.exists(self.config_dir) and not '/tmp': + shutil.rmtree(self.config_dir) + + + def get_ca(self): + """Returns CA certificate in ASCII PEM encoding""" + ca = crypto.load_certificate(crypto.FILETYPE_PEM, open\ + (os.path.join(self.cert_dir, socket.gethostname() + '-ca.crt'), 'rt').read()) + ca_crt = crypto.dump_certificate(crypto.FILETYPE_PEM, ca) + + return ca_crt + + + def get_cert(self, csr, text=False): + """Retrieves certificate + required: csr -csr_type + optional: text + False - will return a pem object type (Default) + True - will return the certificate as ASCII + """ + cacert = self.hostname + '-ca.crt' + cakey = self.hostname + '-ca.key' + ca_crt = crypto.load_certificate(crypto.FILETYPE_PEM, open(os.path.join(self.cert_dir, cacert), 'rt').read()) + ca_key = crypto.load_privatekey(crypto.FILETYPE_PEM, open(os.path.join(self.key_dir, cakey), 'rt').read()) + + cert = crypto.X509() + cert.set_subject(csr.get_subject()) + cert.set_serial_number(self.index+1) + cert.gmtime_adj_notBefore(0) + cert.gmtime_adj_notAfter(10 * 365 * 24 * 60 * 60) + cert.set_issuer(ca_crt.get_subject()) + cert.set_pubkey(csr.get_pubkey()) + cert.sign(ca_key, 'sha1') + + open(os.path.join(self.cert_dir, socket.gethostname() + '.crt'), 'wt')\ + .write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert)) + server_crt = crypto.dump_certificate(crypto.FILETYPE_PEM, cert) + + if text is True: + return server_crt + else: + return cert + + + def request_cert(self, fqdn=None, text=False): + """Generates CSR + optional: fqdn, socket.gethostname() (Default) + optional: text + False - will return a pem object type (Default) + True - will return the certificate as ASCII + """ + if fqdn is None: + fqdn = socket.getfqdn() + + hostname = socket.gethostname() + key = crypto.PKey() + key.generate_key(crypto.TYPE_RSA, 2048) + csr = crypto.X509Req() + csr.get_subject().CN = fqdn + csr.set_pubkey(key) + csr.sign(key, 'sha1') + + open(os.path.join(self.key_dir, hostname + '.key'), 'wt').\ + write(crypto.dump_privatekey(crypto.FILETYPE_PEM, key)) + open(os.path.join(self.csr_dir, hostname + '.csr'), 'wt').\ + write(crypto.dump_certificate_request(crypto.FILETYPE_PEM, csr)) + + server_csr = crypto.dump_certificate_request(crypto.FILETYPE_PEM, csr) + + if text is True: + return server_csr + else: + return csr \ No newline at end of file diff --git a/src/tests/intg/config.py.m4 b/src/tests/intg/config.py.m4 index 563127c6ea895508308a4f94689cc4e26ca4cbde..141813fa7a7a5bc9c06e48dfc938885f4eb1d539 100644 --- a/src/tests/intg/config.py.m4 +++ b/src/tests/intg/config.py.m4 @@ -11,3 +11,4 @@ PID_PATH = "pidpath" PIDFILE_PATH = PID_PATH + "/sssd.pid" LOG_PATH = "logpath" MCACHE_PATH = "mcpath" +SSL_PATH = "/tmp/ssl" diff --git a/src/tests/intg/ds_openldap.py b/src/tests/intg/ds_openldap.py index fb230a081b58bd4e135585daa5a6ddf8f494861c..dbbbfea660d3c4e0f7c7546663cc8560522ffa37 100644 --- a/src/tests/intg/ds_openldap.py +++ b/src/tests/intg/ds_openldap.py @@ -27,8 +27,10 @@ import errno import signal import shutil import sys +import socket from util import * from ds import DS +from ca import CA def hash_password(password): @@ -39,7 +41,7 @@ def hash_password(password): return "{SSHA}" + base64.standard_b64encode(hash.digest() + salt) -class DSOpenLDAP(DS): +class DSOpenLDAP(DS, CA): """OpenLDAP directory server instance.""" def __init__(self, dir, port, base_dn, admin_rdn, admin_pw): @@ -60,6 +62,9 @@ class DSOpenLDAP(DS): self.conf_dir = self.dir + "/etc/ldap" self.conf_slapd_d_dir = self.conf_dir + "/slapd.d" self.data_dir = self.dir + "/var/lib/ldap" + self.ca_inst = CA() + + def _setup_config(self): """Setup the instance initial configuration.""" @@ -73,6 +78,13 @@ class DSOpenLDAP(DS): uid = os.geteuid() gid = os.getegid() + self.ca_inst.setup() + self.ca_inst.get_cert(self.ca_inst.request_cert()) + fqdn = socket.gethostname() + cert = os.path.join(self.ca_inst.cert_dir, fqdn + '.crt') + ca_cert = os.path.join(self.ca_inst.cert_dir, fqdn + '-ca.crt') + key = os.path.join(self.ca_inst.key_dir, fqdn + '.key') + # # Add configuration # @@ -82,6 +94,9 @@ class DSOpenLDAP(DS): cn: config olcPidFile: {self.pid_path} olcArgsFile: {args_file} + olcTLSCertificateKeyFile: {key} + olcTLSCertificateFile: {cert} + olcTLSCACertificatePath: {ca_cert} # Read slapd.conf(5) for possible values olcLogLevel: none @@ -282,3 +297,5 @@ class DSOpenLDAP(DS): for path in (self.conf_slapd_d_dir, self.run_dir, self.data_dir): shutil.rmtree(path, True) + + self.ca_inst.teardown() -- 1.8.3.1