Commit 7b64b12c authored by Jérome Perrin's avatar Jérome Perrin

fixup! erp5 with dependent services

parent a0522e54
from . import ERP5InstanceTestCase from . import ERP5InstanceTestCase
from . import setUpModule from . import setUpModule
from slapos.testing.utils import findFreeTCPPort from slapos.testing.utils import findFreeTCPPort
from slapos.testing.testcase import ManagedService from slapos.testing.testcase import ManagedResource
from slapos.testing.utils import ManagedHTTPServer from slapos.testing.utils import ManagedHTTPServer
from slapos.testing.utils import CrontabMixin from slapos.testing.utils import CrontabMixin
...@@ -53,12 +53,12 @@ class EchoHTTPServer(ManagedHTTPServer): ...@@ -53,12 +53,12 @@ class EchoHTTPServer(ManagedHTTPServer):
log_message = logging.getLogger(__name__ + '.HeaderEchoHandler').info log_message = logging.getLogger(__name__ + '.HeaderEchoHandler').info
class CaucaseService(ManagedService): class CaucaseService(ManagedResource):
url = None # type: str url = None # type: str
directory = None # type: str directory = None # type: str
_caucased_process = None # type: subprocess.Popen _caucased_process = None # type: subprocess.Popen
def start(self): def open(self):
# type: () -> None # type: () -> None
# start a caucased and server certificate. # start a caucased and server certificate.
software_release_root_path = os.path.join( software_release_root_path = os.path.join(
...@@ -96,7 +96,7 @@ class CaucaseService(ManagedService): ...@@ -96,7 +96,7 @@ class CaucaseService(ManagedService):
else: else:
raise RuntimeError('caucased failed to start.') raise RuntimeError('caucased failed to start.')
def stop(self): def close(self):
# type: () -> None # type: () -> None
self._caucased_process.terminate() self._caucased_process.terminate()
self._caucased_process.wait() self._caucased_process.wait()
...@@ -129,13 +129,13 @@ class BalancerTestCase(ERP5InstanceTestCase): ...@@ -129,13 +129,13 @@ class BalancerTestCase(ERP5InstanceTestCase):
'zope-family-dict': { 'zope-family-dict': {
'default': ['dummy_http_server'], # TODO: dummy_http_server is bad name 'default': ['dummy_http_server'], # TODO: dummy_http_server is bad name
}, },
'dummy_http_server': [[cls.getManagedService("backend_web_server", EchoHTTPServer).netloc, 1, False]], 'dummy_http_server': [[cls.getManagedResource("backend_web_server", EchoHTTPServer).netloc, 1, False]],
'backend-path-dict': { 'backend-path-dict': {
'default': '/', 'default': '/',
}, },
'ssl-authentication-dict': {}, 'ssl-authentication-dict': {},
'ssl': { 'ssl': {
'caucase-url': cls.getManagedService("caucase", CaucaseService).url, 'caucase-url': cls.getManagedResource("caucase", CaucaseService).url,
} }
} }
...@@ -167,7 +167,7 @@ class TestAccessLog(BalancerTestCase, CrontabMixin): ...@@ -167,7 +167,7 @@ class TestAccessLog(BalancerTestCase, CrontabMixin):
# type: () -> Dict # type: () -> Dict
parameter_dict = super(TestAccessLog, cls)._getInstanceParameterDict() parameter_dict = super(TestAccessLog, cls)._getInstanceParameterDict()
# use a slow server instead # use a slow server instead
parameter_dict['dummy_http_server'] = [[cls.getManagedService("slow_web_server", SlowHTTPServer).netloc, 1, False]] parameter_dict['dummy_http_server'] = [[cls.getManagedResource("slow_web_server", SlowHTTPServer).netloc, 1, False]]
return parameter_dict return parameter_dict
def test_access_log(self): def test_access_log(self):
...@@ -195,28 +195,25 @@ class TestAccessLog(BalancerTestCase, CrontabMixin): ...@@ -195,28 +195,25 @@ class TestAccessLog(BalancerTestCase, CrontabMixin):
import pdb; pdb.set_trace() import pdb; pdb.set_trace()
class CaucaseClientCertificate(ManagedService): class CaucaseClientCertificate(ManagedResource):
ca_crt_file = None # type: str ca_crt_file = None # type: str
crl_file = None # type: str crl_file = None # type: str
csr_file = None # type: str csr_file = None # type: str
cert_file = None # type: str cert_file = None # type: str
key_file = None # type: str key_file = None # type: str
def start(self): def open(self):
# type: () -> None # type: () -> None
self.ca_crt_file = tempfile.NamedTemporaryFile(delete=False, suffix='ca-crt.pem').name self.tmpdir = tempfile.mkdtemp()
self.crl_file = tempfile.NamedTemporaryFile(delete=False, suffix='ca-crl.pem').name self.ca_crt_file = os.path.join(self.tmpdir, 'ca-crt.pem')
self.csr_file = tempfile.NamedTemporaryFile(delete=False, suffix='csr.pem').name self.crl_file = os.path.join(self.tmpdir, 'ca-crl.pem')
# self.cert_file = tempfile.NamedTemporaryFile(delete=False, suffix='crt.pem').name self.csr_file = os.path.join(self.tmpdir, 'csr.pem')
self.cert_file = self.key_file = tempfile.NamedTemporaryFile(delete=False, suffix='key.pem').name self.cert_file = os.path.join(self.tmpdir, 'crt.pem')
self.key_file = os.path.join(self.tmpdir, 'key.pem')
def stop(self):
def close(self):
# type: () -> None # type: () -> None
os.unlink(self.ca_crt_file) shutil.rmtree(self.tmpdir)
os.unlink(self.crl_file)
os.unlink(self.csr_file)
# os.unlink(self.cert_file)
os.unlink(self.key_file)
def request(self, common_name, caucase): def request(self, common_name, caucase):
# type: (str, CaucaseCertificate) -> None # type: (str, CaucaseCertificate) -> None
...@@ -229,13 +226,8 @@ class CaucaseClientCertificate(ManagedService): ...@@ -229,13 +226,8 @@ class CaucaseClientCertificate(ManagedService):
cas_args = [ cas_args = [
caucase_path, caucase_path,
'--ca-url', caucase.url, '--ca-url', caucase.url,
'--ca-crt', self.ca_crt_file, # must not exist '--ca-crt', self.ca_crt_file,
'--crl', self.crl_file, '--crl', self.crl_file,
# XXX 'service
# '--ca-crt', os.path.join(caucase.directory, 'service', 'service-ca-crt.pem'),
# '--crl', os.path.join(caucase.directory, 'service', 'service.crl'),
# '--user-ca-crt', os.path.join(caucase.directory, 'service', 'user-ca-crt.pem'),
# '--user-crl', os.path.join(caucase.directory, 'service', 'user.crl'),
] ]
key = rsa.generate_private_key( key = rsa.generate_private_key(
...@@ -244,27 +236,33 @@ class CaucaseClientCertificate(ManagedService): ...@@ -244,27 +236,33 @@ class CaucaseClientCertificate(ManagedService):
backend=default_backend() backend=default_backend()
) )
with open(self.key_file, 'wb') as f: with open(self.key_file, 'wb') as f:
f.write(key.private_bytes( f.write(
key.private_bytes(
encoding=serialization.Encoding.PEM, encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL, format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption(), encryption_algorithm=serialization.NoEncryption(),
)) ))
csr = x509.CertificateSigningRequestBuilder().subject_name(x509.Name([ csr = x509.CertificateSigningRequestBuilder().subject_name(
x509.NameAttribute(NameOID.COMMON_NAME, common_name), x509.Name([
])).sign(key, hashes.SHA256(), default_backend()) x509.NameAttribute(
NameOID.COMMON_NAME,
common_name,
),
])).sign(
key,
hashes.SHA256(),
default_backend(),
)
with open(self.csr_file, 'wb') as f: with open(self.csr_file, 'wb') as f:
f.write(csr.public_bytes(serialization.Encoding.PEM)) f.write(csr.public_bytes(serialization.Encoding.PEM))
caucase_process = subprocess.Popen( csr_id = subprocess.check_output(
cas_args + [ cas_args + [
'--send-csr', self.csr_file, '--send-csr', self.csr_file,
], ],
stdout=subprocess.PIPE, ).split()[0]
stderr=subprocess.STDOUT, assert csr_id
)
result = caucase_process.communicate()
csr_id = result[0].split()[0]
for _ in range(10): for _ in range(10):
if not subprocess.call( if not subprocess.call(
...@@ -277,169 +275,19 @@ class CaucaseClientCertificate(ManagedService): ...@@ -277,169 +275,19 @@ class CaucaseClientCertificate(ManagedService):
time.sleep(1) time.sleep(1)
else: else:
raise RuntimeError('getting service certificate failed.') raise RuntimeError('getting service certificate failed.')
with open(self.cert_file) as f:
assert 'BEGIN CERTIFICATE' in f.read()
class TestFrontendXForwardedFor(BalancerTestCase): class TestFrontendXForwardedFor(BalancerTestCase):
__partition_reference__ = 'xff' __partition_reference__ = 'xff'
frontend_caucase_dir = None
frontend_caucased_process = None
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
# type: () -> None # type: () -> None
frontend_caucase = cls.getManagedService('frontend_caucase', CaucaseService) frontend_caucase = cls.getManagedResource('frontend_caucase', CaucaseService)
certificate = cls.getManagedService('client_certificate', CaucaseClientCertificate) certificate = cls.getManagedResource('client_certificate', CaucaseClientCertificate)
certificate.request(u'shared frontend', frontend_caucase) certificate.request(u'shared frontend', frontend_caucase)
cls.client_certificate = certificate.key_file
super(TestFrontendXForwardedFor, cls).setUpClass()
# TODO: ManagedService
@classmethod
def setUpClassOld(cls):
# type: () -> None
# start a caucased and generate a valid client certificate.
cls.computer_partition_root_path = os.path.abspath(os.curdir)
cls.frontend_caucase_dir = tempfile.mkdtemp()
frontend_caucased_dir = os.path.join(cls.frontend_caucase_dir, 'caucased')
os.mkdir(frontend_caucased_dir)
frontend_user_dir = os.path.join(cls.frontend_caucase_dir, 'user')
os.mkdir(frontend_user_dir)
frontend_service_dir = os.path.join(cls.frontend_caucase_dir, 'service')
os.mkdir(frontend_service_dir)
frontend_caucased_netloc = '%s:%s' % (cls._ipv4_address, findFreeTCPPort(cls._ipv4_address))
cls.frontend_caucased_url = 'http://' + frontend_caucased_netloc
if 0:
cls.user_certificate = frontend_user_key = os.path.join(frontend_user_dir, 'client.key.pem')
frontend_user_csr = os.path.join(frontend_user_dir, 'client.csr.pem')
key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
backend=default_backend()
)
with open(frontend_user_key, 'wb') as f:
f.write(key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption(),
))
csr = x509.CertificateSigningRequestBuilder().subject_name(x509.Name([
x509.NameAttribute(NameOID.COMMON_NAME, u'user'),
])).sign(key, hashes.SHA256(), default_backend())
with open(frontend_user_csr, 'wb') as f:
f.write(csr.public_bytes(serialization.Encoding.PEM))
cls.software_release_root_path = os.path.join(
cls.slap._software_root,
hashlib.md5(cls.getSoftwareURL()).hexdigest(),
)
caucased_path = os.path.join(cls.software_release_root_path, 'bin', 'caucased')
caucase_path = os.path.join(cls.software_release_root_path, 'bin', 'caucase')
cls.frontend_caucased_process = subprocess.Popen(
[
caucased_path,
'--db', os.path.join(frontend_caucased_dir, 'caucase.sqlite'),
'--server-key', os.path.join(frontend_caucased_dir, 'server.key.pem'),
'--netloc', frontend_caucased_netloc,
'--service-auto-approve-count', '1',
],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
for _ in range(10):
try:
if requests.get(cls.frontend_caucased_url).status_code == 200:
break
except Exception:
pass
time.sleep(1)
else:
raise RuntimeError('caucased failed to start.')
cau_args = [
caucase_path,
'--ca-url', cls.frontend_caucased_url,
'--ca-crt', os.path.join(frontend_user_dir, 'service-ca-crt.pem'),
'--crl', os.path.join(frontend_user_dir, 'service.crl'),
'--user-ca-crt', os.path.join(frontend_user_dir, 'user-ca-crt.pem'),
'--user-crl', os.path.join(frontend_user_dir, 'user.crl'),
]
cas_args = [
caucase_path,
'--ca-url', cls.frontend_caucased_url,
'--ca-crt', os.path.join(frontend_service_dir, 'service-ca-crt.pem'),
'--crl', os.path.join(frontend_service_dir, 'service.crl'),
'--user-ca-crt', os.path.join(frontend_service_dir, 'user-ca-crt.pem'),
'--user-crl', os.path.join(frontend_service_dir, 'user.crl'),
]
if 0:
caucase_process = subprocess.Popen(
cau_args + [
'--mode', 'user',
'--send-csr', frontend_user_csr,
],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
result = caucase_process.communicate()
csr_id = result[0].split()[0]
subprocess.check_call(
cau_args + [
'--mode', 'user',
'--get-crt', csr_id, frontend_user_key,
],
)
cls.client_certificate = frontend_service_key = os.path.join(frontend_service_dir, 'crt.pem')
frontend_service_csr = os.path.join(frontend_service_dir, 'csr.pem')
key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
backend=default_backend()
)
with open(frontend_service_key, 'wb') as f:
f.write(key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption(),
))
csr = x509.CertificateSigningRequestBuilder().subject_name(x509.Name([
x509.NameAttribute(NameOID.COMMON_NAME, u'service'),
])).sign(key, hashes.SHA256(), default_backend())
with open(frontend_service_csr, 'wb') as f:
f.write(csr.public_bytes(serialization.Encoding.PEM))
caucase_process = subprocess.Popen(
cas_args + [
'--send-csr', frontend_service_csr,
],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
result = caucase_process.communicate()
csr_id = result[0].split()[0]
for _ in range(10):
if not subprocess.call(
cas_args + [
'--get-crt', csr_id, frontend_service_key,
],
) == 0:
break
else:
time.sleep(1)
else:
raise RuntimeError('getting service certificate failed.')
super(TestFrontendXForwardedFor, cls).setUpClass() super(TestFrontendXForwardedFor, cls).setUpClass()
@classmethod @classmethod
...@@ -453,26 +301,19 @@ class TestFrontendXForwardedFor(BalancerTestCase): ...@@ -453,26 +301,19 @@ class TestFrontendXForwardedFor(BalancerTestCase):
'default': False, 'default': False,
'default-auth': True, 'default-auth': True,
} }
parameter_dict['ssl']['frontend-caucase-url-list'] = [cls.getManagedService('frontend_caucase', CaucaseService).url] parameter_dict['ssl']['frontend-caucase-url-list'] = [cls.getManagedResource('frontend_caucase', CaucaseService).url]
return parameter_dict return parameter_dict
@classmethod
def _cleanup(cls, snapshot_name):
if cls.frontend_caucased_process:
cls.frontend_caucased_process.terminate()
cls.frontend_caucased_process.wait()
if cls.frontend_caucase_dir:
shutil.rmtree(cls.frontend_caucase_dir)
super(TestFrontendXForwardedFor, cls)._cleanup(snapshot_name)
def test_x_forwarded_for_added_when_verified_connection(self): def test_x_forwarded_for_added_when_verified_connection(self):
# type: () -> None # type: () -> None
client_certificate = self.getManagedResource('client_certificate', CaucaseClientCertificate)
for backend in ('default', 'default-auth'): for backend in ('default', 'default-auth'):
balancer_url = json.loads(self.computer_partition.getConnectionParameterDict()['_'])[backend] balancer_url = json.loads(self.computer_partition.getConnectionParameterDict()['_'])[backend]
result = requests.get( result = requests.get(
balancer_url, balancer_url,
headers={'X-Forwarded-For': '1.2.3.4'}, headers={'X-Forwarded-For': '1.2.3.4'},
cert=self.client_certificate, cert=(client_certificate.cert_file, client_certificate.key_file),
verify=False, verify=False,
).json() ).json()
self.assertEqual(result['Incoming Headers'].get('x-forwarded-for').split(', ')[0], '1.2.3.4') self.assertEqual(result['Incoming Headers'].get('x-forwarded-for').split(', ')[0], '1.2.3.4')
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment