Skip to content

Commit

Permalink
[RSPEED-388] Add exception handling for SSL certificates (#87)
Browse files Browse the repository at this point in the history
* Add exception handling for SSL certificates

Adding two exception handling for the SSLAdapter class. One for the certificate not being valid, and the second one for the certificate missing on the system.

Without that, the user would receive a nasty error in the client and a not that helpful error in the journald logs.

* Add unit tests
  • Loading branch information
r0x0d authored Jan 6, 2025
1 parent 192bed8 commit 525235f
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 4 deletions.
20 changes: 16 additions & 4 deletions command_line_assistant/daemon/http/session.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
"""Handle the http sessions that the daemon issues to the backend."""

import logging
from ssl import SSLError

import urllib3
from requests.sessions import Session

from command_line_assistant.config import Config
from command_line_assistant.constants import VERSION
from command_line_assistant.daemon.http.adapters import RetryAdapter, SSLAdapter
from command_line_assistant.dbus.exceptions import RequestFailedError

USER_AGENT = f"clad/{VERSION}"
#: Define the custom user agent for clad
Expand Down Expand Up @@ -46,10 +48,20 @@ def get_session(config: Config) -> Session:
session.verify = False
return session

ssl_adapter = SSLAdapter(
cert_file=config.backend.auth.cert_file, # type: ignore
key_file=config.backend.auth.key_file, # type: ignore
)
try:
ssl_adapter = SSLAdapter(
cert_file=config.backend.auth.cert_file, # type: ignore
key_file=config.backend.auth.key_file, # type: ignore
)
except SSLError as e:
raise RequestFailedError(
"Failed to load certificate in cert chain. If needed, regenerate the certificate with subscription-manager and try again."
) from e
except FileNotFoundError as e:
raise RequestFailedError(
f"Couldn't find certificate files at '{config.backend.auth.cert_file.parent}' folder." # pyright: ignore[reportAttributeAccessIssue]
) from e

# Mount the adapter for the given endpoint.
session.mount(config.backend.endpoint, ssl_adapter)

Expand Down
24 changes: 24 additions & 0 deletions tests/daemon/http/test_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from command_line_assistant.constants import VERSION
from command_line_assistant.daemon.http.session import get_session
from command_line_assistant.dbus.exceptions import RequestFailedError


def test_session_headers(mock_config):
Expand Down Expand Up @@ -73,3 +74,26 @@ def test_various_endpoints(mock_config, endpoint):

# Verify that the endpoint is used for mounting adapters
assert any(pattern == endpoint for pattern, _ in session.adapters.items())


def test_session_with_corrupted_ssl_certificate(mock_config):
mock_config.backend.auth.cert_file.write_text("whatever pem")
mock_config.backend.auth.key_file.write_text("whatever secret")
mock_config.backend.auth.verify_ssl = True

with pytest.raises(
RequestFailedError, match="Failed to load certificate in cert chain."
):
get_session(mock_config)


def test_session_with_missing_ssl_certificate(tmp_path, mock_config):
cert_file = tmp_path / "missing" / "cert.pem"
key_file = tmp_path / "missing" / "key.pem"

mock_config.backend.auth.cert_file = cert_file
mock_config.backend.auth.key_file = key_file
mock_config.backend.auth.verify_ssl = True

with pytest.raises(RequestFailedError, match="Couldn't find certificate files at"):
get_session(mock_config)

0 comments on commit 525235f

Please sign in to comment.