From d9a2c95cd5ed93245a7c2fd34cc8b1e0b5949a2d Mon Sep 17 00:00:00 2001 From: Luciano Lo Giudice Date: Fri, 29 Apr 2022 18:00:18 -0300 Subject: [PATCH 1/5] Fix ceph-dashboard SAML tests This PR ensures that the SAML tests are using a fully valid IDP metadata (Ceph's dashboard doesn't report its validity until SAML features are used), as well as using TLS in the requests, in addition to some cleanups here and there. --- .../charm_tests/ceph/dashboard/tests.py | 119 ++++++++++++------ 1 file changed, 84 insertions(+), 35 deletions(-) diff --git a/zaza/openstack/charm_tests/ceph/dashboard/tests.py b/zaza/openstack/charm_tests/ceph/dashboard/tests.py index 4e0e5c2..66309d0 100644 --- a/zaza/openstack/charm_tests/ceph/dashboard/tests.py +++ b/zaza/openstack/charm_tests/ceph/dashboard/tests.py @@ -27,14 +27,63 @@ import zaza.openstack.charm_tests.test_utils as test_utils import zaza.openstack.utilities.openstack as openstack_utils +X509_CERT = ''' +MIICZDCCAg6gAwIBAgICBr8wDQYJKoZIhvcNAQEEBQAwgZIxCzAJBgNVBAYTAlVTMRMwEQYDVQQI +EwpDYWxpZm9ybmlhMRQwEgYDVQQHEwtTYW50YSBDbGFyYTEeMBwGA1UEChMVU3VuIE1pY3Jvc3lz +dGVtcyBJbmMuMRowGAYDVQQLExFJZGVudGl0eSBTZXJ2aWNlczEcMBoGA1UEAxMTQ2VydGlmaWNh +dGUgTWFuYWdlcjAeFw0wNzAzMDcyMTUwMDVaFw0xMDEyMDEyMTUwMDVaMDsxFDASBgNVBAoTC2V4 +YW1wbGUuY29tMSMwIQYDVQQDExpMb2FkQmFsYW5jZXItMy5leGFtcGxlLmNvbTCBnzANBgkqhkiG +9w0BAQEFAAOBjQAwgYkCgYEAlOhN9HddLMpE3kCjkPSOFpCkDxTNuhMhcgBkYmSEF/iJcQsLX/ga +pO+W1SIpwqfsjzR5ZvEdtc/8hGumRHqcX3r6XrU0dESM6MW5AbNNJsBnwIV6xZ5QozB4wL4zREhw +zwwYejDVQ/x+8NRESI3ym17tDLEuAKyQBueubgjfic0CAwEAAaNgMF4wEQYJYIZIAYb4QgEBBAQD +AgZAMA4GA1UdDwEB/wQEAwIE8DAfBgNVHSMEGDAWgBQ7oCE35Uwn7FsjS01w5e3DA1CrrjAYBgNV +HREEETAPgQ1tYWxsYUBzdW4uY29tMA0GCSqGSIb3DQEBBAUAA0EAGhJhep7X2hqWJWQoXFcdU7eQ +''' + +X509_DATA = ''' +EwpDYWxpZm9ybmlhMRQwEgYDVQQHEwtTYW50YSBDbGFyYTEeMBwGA1UEChMVU3VuIE1pY3Jvc3lz +dGVtcyBJbmMuMRowGAYDVQQLExFJZGVudGl0eSBTZXJ2aWNlczEcMBoGA1UEAxMTQ2VydGlmaWNh +dGUgTWFuYWdlcjAeFw0wNzAzMDcyMjAxMTVaFw0xMDEyMDEyMjAxMTVaMDsxFDASBgNVBAoTC2V4 +YW1wbGUuY29tMSMwIQYDVQQDExpMb2FkQmFsYW5jZXItMy5leGFtcGxlLmNvbTCBnzANBgkqhkiG +HREEETAPgQ1tYWxsYUBzdW4uY29tMA0GCSqGSIb3DQEBBAUAA0EAEgbmnOz2Rvpj9bludb9lEeVa +OA46zRiyt4BPlbgIaFyG6P7GWSddMi/14EimQjjDbr4ZfvlEdPJmimHExZY3KQ== +''' + SAML_IDP_METADATA = ''' - - - - {} - - - + + + + + + + {cert} + + + + + + + + {data} + + + + + + urn:oasis:names:tc:SAML:2.0:nameid-format:persistent + + + urn:oasis:names:tc:SAML:2.0:nameid-format:transient + + + + ''' @@ -112,16 +161,10 @@ class CephDashboardTest(test_utils.BaseCharmTest): :returns: URL of dashboard on unit :rtype: Union[str, None] """ - units = zaza.model.get_units(self.application_name) - for unit in units: - r = self._run_request_get( - 'https://{}:8443'.format( - zaza.model.get_unit_public_address(unit)), - verify=self.local_ca_cert, - allow_redirects=False) - if r.status_code == requests.codes.ok: - return 'https://{}:8443'.format( - zaza.model.get_unit_public_address(unit)) + output = zaza.model.run_on_leader( + 'ceph-mon', + 'ceph mgr services')['Stdout'] + return json.loads(output)['dashboard'] def test_dashboard_units(self): """Check dashboard units are configured correctly.""" @@ -187,7 +230,7 @@ class CephDashboardTest(test_utils.BaseCharmTest): path = "api/auth" headers = { 'Content-type': 'application/json', - 'Accept': 'application/vnd.ceph.api.v1.0'} + 'Accept': 'application/vnd.ceph.api.v1.0+json'} payload = {"username": user, "password": password} verify = self.local_ca_cert r = self._run_request_post( @@ -232,22 +275,28 @@ class CephDashboardTest(test_utils.BaseCharmTest): return url = self.get_master_dashboard_url() - with tempfile.NamedTemporaryFile(mode='w') as tmp, \ - open(self.local_ca_cert) as cert: - tmp.write(SAML_IDP_METADATA.format(cert.read())) - tmp.flush() - zaza.model.set_application_config( - 'ceph-dashboard', - { - 'saml-base-url': url, - 'saml-idp-metadata': 'file://{}'.format(tmp.name), - } - ) + idp_meta = SAML_IDP_METADATA.format( + cert=X509_CERT, + data=X509_DATA, + host=url) - # Login must be redirected. - resp = requests.get(url + '/auth/saml2/login') - self.assertTrue(resp.is_redirect) + zaza.model.set_application_config( + 'ceph-dashboard', + { + 'saml-base-url': url, + 'saml-idp-metadata': idp_meta, + } + ) - # Check that metadata is present. - resp = requests.get(url + '/auth/saml2/metadata') - self.assertEqual(resp.status_code, requests.code.ok) + # Check that both login and metadata are accesible. + resp = self._run_request_get( + url + '/auth/saml2/login', + verify=self.local_ca_cert, + allow_redirects=False) + self.assertTrue(resp.status_code, requests.codes.ok) + + resp = self._run_request_get( + url + '/auth/saml2/metadata', + verify=self.local_ca_cert, + allow_redirects=False) + self.assertEqual(resp.status_code, requests.codes.ok) From 7d70b22846a5edd182a957f13f5772d83bc882a1 Mon Sep 17 00:00:00 2001 From: Luciano Lo Giudice Date: Fri, 29 Apr 2022 18:04:15 -0300 Subject: [PATCH 2/5] PEP8 style fixes --- zaza/openstack/charm_tests/ceph/dashboard/tests.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/zaza/openstack/charm_tests/ceph/dashboard/tests.py b/zaza/openstack/charm_tests/ceph/dashboard/tests.py index 66309d0..3e1ddc4 100644 --- a/zaza/openstack/charm_tests/ceph/dashboard/tests.py +++ b/zaza/openstack/charm_tests/ceph/dashboard/tests.py @@ -18,7 +18,6 @@ import collections import json import logging import requests -import tempfile import tenacity import uuid @@ -79,7 +78,7 @@ SAML_IDP_METADATA = ''' urn:oasis:names:tc:SAML:2.0:nameid-format:transient - @@ -281,11 +280,8 @@ class CephDashboardTest(test_utils.BaseCharmTest): host=url) zaza.model.set_application_config( - 'ceph-dashboard', - { - 'saml-base-url': url, - 'saml-idp-metadata': idp_meta, - } + 'ceph-dashboard', + {'saml-base-url': url, 'saml-idp-metadata': idp_meta} ) # Check that both login and metadata are accesible. From a6846dd161b547ea75444047d5106bb8ce1aba04 Mon Sep 17 00:00:00 2001 From: Luciano Lo Giudice Date: Mon, 2 May 2022 14:37:54 -0300 Subject: [PATCH 3/5] Add a few retries to avoid race conditions --- .../charm_tests/ceph/dashboard/tests.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/zaza/openstack/charm_tests/ceph/dashboard/tests.py b/zaza/openstack/charm_tests/ceph/dashboard/tests.py index 3e1ddc4..112eaa1 100644 --- a/zaza/openstack/charm_tests/ceph/dashboard/tests.py +++ b/zaza/openstack/charm_tests/ceph/dashboard/tests.py @@ -151,6 +151,8 @@ class CephDashboardTest(test_utils.BaseCharmTest): headers=headers, verify=verify) + @tenacity.retry(wait=tenacity.wait_fixed(2), reraise=True, + stop=tenacity.stop_after_attempt(90)) def get_master_dashboard_url(self): """Get the url of the dashboard servicing requests. @@ -163,7 +165,10 @@ class CephDashboardTest(test_utils.BaseCharmTest): output = zaza.model.run_on_leader( 'ceph-mon', 'ceph mgr services')['Stdout'] - return json.loads(output)['dashboard'] + url = json.loads(output).get('dashboard') + if url is None: + raise tenacity.RetryError(None) + return url def test_dashboard_units(self): """Check dashboard units are configured correctly.""" @@ -266,6 +271,16 @@ class CephDashboardTest(test_utils.BaseCharmTest): 'ceph config-key exists {}'.format(key)) self.assertEqual(check_out['Code'], '0') + @tenacity.retry(wait=tenacity.wait_fixed(2), reraise=True, + stop=tenacity.stop_after_attempt(20)) + def wait_for_saml_dashboard(self): + output = zaza.model.run_on_leader( + 'ceph-mon', + 'ceph dashboard sso status')['Stdout'] + if 'enabled' in output: + return + raise tenacity.RetryError(None) + def test_saml(self): """Check that the dashboard is accessible with SAML enabled.""" get_os_release = openstack_utils.get_os_release From eaf33ab2bd10f2fb3e011ec20d41b0c078030bb8 Mon Sep 17 00:00:00 2001 From: Luciano Lo Giudice Date: Mon, 2 May 2022 14:43:36 -0300 Subject: [PATCH 4/5] Add docstring to public method --- zaza/openstack/charm_tests/ceph/dashboard/tests.py | 1 + 1 file changed, 1 insertion(+) diff --git a/zaza/openstack/charm_tests/ceph/dashboard/tests.py b/zaza/openstack/charm_tests/ceph/dashboard/tests.py index 112eaa1..e66a4b2 100644 --- a/zaza/openstack/charm_tests/ceph/dashboard/tests.py +++ b/zaza/openstack/charm_tests/ceph/dashboard/tests.py @@ -274,6 +274,7 @@ class CephDashboardTest(test_utils.BaseCharmTest): @tenacity.retry(wait=tenacity.wait_fixed(2), reraise=True, stop=tenacity.stop_after_attempt(20)) def wait_for_saml_dashboard(self): + """Wait until the Ceph dashboard is enabled.""" output = zaza.model.run_on_leader( 'ceph-mon', 'ceph dashboard sso status')['Stdout'] From 1a5b3f61522572763e2af353eb68bcad640096f2 Mon Sep 17 00:00:00 2001 From: Luciano Lo Giudice Date: Mon, 2 May 2022 17:31:27 -0300 Subject: [PATCH 5/5] Also wait for the SAML 'enabled' message --- zaza/openstack/charm_tests/ceph/dashboard/tests.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zaza/openstack/charm_tests/ceph/dashboard/tests.py b/zaza/openstack/charm_tests/ceph/dashboard/tests.py index e66a4b2..adc2123 100644 --- a/zaza/openstack/charm_tests/ceph/dashboard/tests.py +++ b/zaza/openstack/charm_tests/ceph/dashboard/tests.py @@ -300,6 +300,8 @@ class CephDashboardTest(test_utils.BaseCharmTest): {'saml-base-url': url, 'saml-idp-metadata': idp_meta} ) + self.wait_for_saml_dashboard() + # Check that both login and metadata are accesible. resp = self._run_request_get( url + '/auth/saml2/login',