From 1b6370516009eeccd0b9ab3aa69b10823bf147f2 Mon Sep 17 00:00:00 2001 From: Tanner Prestegard Date: Fri, 13 Sep 2019 15:21:35 -0500 Subject: [PATCH] add certificate checking functionality and tests Add the ability to print the certificate's subject and expiration date/time. Add information on using these new functions to the troubleshooting docs. Add unit tests. --- docs/source/troubleshooting.rst | 13 ++++ ligo/gracedb/rest.py | 11 ++++ ligo/gracedb/test/test_certificate.py | 88 +++++++++++++++++++++++++++ 3 files changed, 112 insertions(+) diff --git a/docs/source/troubleshooting.rst b/docs/source/troubleshooting.rst index fb0266f..a6d8678 100644 --- a/docs/source/troubleshooting.rst +++ b/docs/source/troubleshooting.rst @@ -66,6 +66,19 @@ If not, check the description of how authentication credentials can be provided For the command-line client, see :ref:`here `. +Check your certificate +---------------------- +If you are using an X.509 certificate for authentication, you can check the subject by doing:: + + client.print_certificate_subject() + +You can also check the expiration date by doing:: + + client.print_certificate_expiration_date() + +Make sure the subject is what you expect and that your certificate isn't expired. + + Check your user account on the server ------------------------------------- Is the server identifying you with the user account that you expect it to? diff --git a/ligo/gracedb/rest.py b/ligo/gracedb/rest.py index c7dacca..5b888b2 100644 --- a/ligo/gracedb/rest.py +++ b/ligo/gracedb/rest.py @@ -288,6 +288,17 @@ class GsiRest(object): time_to_expire <= datetime.timedelta(seconds=reload_buffer) return expired + def print_certificate_subject(self): + if not hasattr(self, 'certificate'): + raise RuntimeError('No certificate found.') + print(self.certificate.subject.rfc4514_string()) + + def print_certificate_expiration_date(self): + if not hasattr(self, 'certificate'): + raise RuntimeError('No certificate found.') + out_str = '{dt} UTC'.format(dt=self.certificate.not_valid_after) + print(out_str) + def set_up_connector(self, host, port, proxy_host, proxy_port): # Versions of Python earlier than 2.7.9 don't use SSL Context # objects for this purpose, and do not do any server cert verification. diff --git a/ligo/gracedb/test/test_certificate.py b/ligo/gracedb/test/test_certificate.py index b6dbaea..7553e32 100644 --- a/ligo/gracedb/test/test_certificate.py +++ b/ligo/gracedb/test/test_certificate.py @@ -160,3 +160,91 @@ def test_reloading_feature(force_noauth, reload_cert, cert_expired): assert mock_load_cert.call_count == load_cert_call_count assert mock_cert_expire.call_count == check_cert_call_count assert mock_set_up_conn.call_count == set_up_conn_call_count + + +def test_x509_cert_print_subject(x509_cert, capsys): + """Test printing X.509 certificate subject""" + # Set up cert and key files + cert_file = '/tmp/cert_file' + key_file = '/tmp/key_file' + + conn_func = 'ligo.gracedb.rest.GraceDb.set_up_connector' + load_cert_func = 'ligo.gracedb.rest.GraceDb._load_certificate' + with mock.patch(conn_func), \ + mock.patch(load_cert_func): # noqa: E127 + + # Initialize client + client = GraceDb(cred=(cert_file, key_file)) + + # Assign fake certificate + client.certificate = x509_cert + + # Print certificate subject + client.print_certificate_subject() + + # Check output + stdout = capsys.readouterr().out + assert stdout.strip() == client.certificate.subject.rfc4514_string() + + +def test_x509_cert_print_subject_no_cert(): + """Test printing X.509 certificate subject with no cert""" + # Set up cert and key files + cert_file = '/tmp/cert_file' + key_file = '/tmp/key_file' + + conn_func = 'ligo.gracedb.rest.GraceDb.set_up_connector' + load_cert_func = 'ligo.gracedb.rest.GraceDb._load_certificate' + with mock.patch(conn_func), \ + mock.patch(load_cert_func): # noqa: E127 + + # Initialize client + client = GraceDb(cred=(cert_file, key_file)) + + # Try to print certificate subject + with pytest.raises(RuntimeError, match='No certificate found.'): + client.print_certificate_subject() + + +def test_x509_cert_print_expiration(x509_cert, capsys): + """Test printing X.509 certificate expiration""" + # Set up cert and key files + cert_file = '/tmp/cert_file' + key_file = '/tmp/key_file' + + conn_func = 'ligo.gracedb.rest.GraceDb.set_up_connector' + load_cert_func = 'ligo.gracedb.rest.GraceDb._load_certificate' + with mock.patch(conn_func), \ + mock.patch(load_cert_func): # noqa: E127 + + # Initialize client + client = GraceDb(cred=(cert_file, key_file)) + + # Assign fake certificate + client.certificate = x509_cert + + # Print certificate expiration date + client.print_certificate_expiration_date() + + # Check output + stdout = capsys.readouterr().out + assert stdout.strip() == str(client.certificate.not_valid_after) + ' UTC' + + +def test_x509_cert_print_expiration_no_cert(): + """Test printing X.509 certificate expiration date with no cert""" + # Set up cert and key files + cert_file = '/tmp/cert_file' + key_file = '/tmp/key_file' + + conn_func = 'ligo.gracedb.rest.GraceDb.set_up_connector' + load_cert_func = 'ligo.gracedb.rest.GraceDb._load_certificate' + with mock.patch(conn_func), \ + mock.patch(load_cert_func): # noqa: E127 + + # Initialize client + client = GraceDb(cred=(cert_file, key_file)) + + # Try to print certificate subject + with pytest.raises(RuntimeError, match='No certificate found.'): + client.print_certificate_expiration_date() -- GitLab