Skip to content

Support TLS on the xmlrpc server and client - #189

Open
sundaram123krishnan wants to merge 1 commit into
praiskup:mainfrom
sundaram123krishnan:tls-support
Open

Support TLS on the xmlrpc server and client#189
sundaram123krishnan wants to merge 1 commit into
praiskup:mainfrom
sundaram123krishnan:tls-support

Conversation

@sundaram123krishnan

@sundaram123krishnan sundaram123krishnan commented Jul 21, 2026

Copy link
Copy Markdown

Relates #7

Added 3 new options in config/server.yaml:

  • ssl_certfile
  • ssl_keyfile
  • ssl_clients - concatenated certs of all the trusted clients

As per #7 (comment), no config for client is implemented in this PR.

Both sides use ssl.create_default_context (which is the recommended way), more about it here

Summary by CodeRabbit

  • New Features
    • Added optional TLS/SSL support for the XML-RPC server and client.
    • Introduced TLS configuration and certificate/client validation controls.
    • Documented TLS/SSL settings for the server in the configuration template.
  • Bug Fixes
    • Improved handling and reporting of TLS-specific client connection failures.
  • Tests
    • Added TLS-enabled integration coverage, including trusted/untrusted client behavior and non-TLS compatibility.

@sundaram123krishnan
sundaram123krishnan force-pushed the tls-support branch 2 times, most recently from 939b092 to f9bdc3f Compare July 21, 2026 13:40
Comment thread resalloc/client.py Fixed
Comment thread resallocserver/main.py Fixed
Comment thread resallocserver/main.py Fixed
@praiskup

Copy link
Copy Markdown
Owner

@coderabbitai ptal

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

@praiskup I’ll review the TLS implementation and its configuration/error-handling paths.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

TLS support is added to the XML-RPC server and client, including certificate configuration, client authentication, TLS error handling, documentation, and integration tests covering accepted and rejected connections.

XML-RPC TLS

Layer / File(s) Summary
Server TLS configuration and socket wrapping
resallocserver/tls.py, resallocserver/main.py
ServerTLS builds the configured SSL context and wraps the XML-RPC server socket during startup, while preserving plain-socket behavior when TLS is disabled.
Client TLS context and error handling
resalloc/client.py
The client loads CA and optional client certificates, passes the context to ServerProxy, and converts TLS failures into ResallocClientException.
TLS documentation and integration validation
config/server.yaml, shelltests/tests/tls.sh, Makefile
TLS configuration is documented, the TLS shell test is registered, and integration coverage checks certificate authentication, HTTPS enforcement, rejected clients, and invalid configuration warnings.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant ServerProxy
  participant XMLRPCServer
  participant ServerTLS
  Client->>ServerProxy: create with SSL context
  ServerProxy->>XMLRPCServer: send XML-RPC request over TLS
  XMLRPCServer->>ServerTLS: use configured TLS-wrapped socket
  ServerTLS-->>XMLRPCServer: authenticate server and client certificates
  XMLRPCServer-->>ServerProxy: return XML-RPC response
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 58.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding TLS support to the XML-RPC server and client.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
config/server.yaml (1)

23-31: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Document that omitting ssl_clients accepts any client.

With ssl_certfile set but ssl_clients unset, verify_mode stays CERT_NONE, so the connection is encrypted but unauthenticated. Worth stating here since it is the security-relevant default.

📝 Suggested wording
-# Certificate and private key for the xmlrpc server.  When ssl_certfile is not
-# set, the server speaks HTTP. When ssl_keyfile is not
-# set, the private key is expected in the ssl_certfile itself.
+# Certificate and private key for the xmlrpc server.  When ssl_certfile is not
+# set, the server speaks HTTP.  When ssl_keyfile is not set, the private key is
+# expected in the ssl_certfile itself.
 `#ssl_certfile`: '/etc/resallocserver/server.crt'
 `#ssl_keyfile`: '/etc/resallocserver/server.key'
 
 # PEM file with the concatenated certificates of all the clients allowed to
-# connect. Requires ssl_certfile.
+# connect.  Requires ssl_certfile.  When unset, the traffic is encrypted but
+# any client is accepted (no client certificate is requested).
 `#ssl_clients`: '/etc/resallocserver/clients.pem'
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@config/server.yaml` around lines 23 - 31, Update the SSL configuration
comments near ssl_clients to state that leaving ssl_clients unset accepts any
client: connections remain encrypted when ssl_certfile is configured, but client
authentication is disabled because verify_mode remains CERT_NONE.
resallocserver/tls.py (1)

56-73: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

TLS handshake runs on the accept loop, not on the worker threads.

Wrapping the listening socket means accept() performs the handshake inline (do_handshake_on_connect=True), so the serve_forever() thread blocks for the duration of every handshake. A slow or stalled client can therefore delay all other connections even though daemon_threads is set. Handshake errors themselves are fine — ssl.SSLError subclasses OSError and socketserver swallows those in _handle_request_noblock, which matches what shelltests/tests/tls.sh observes.

If you want to keep the accept loop responsive, set a socket timeout / defer the handshake to the request thread; otherwise this is acceptable for the expected client count.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@resallocserver/tls.py` around lines 56 - 73, The build_tls_socket method
currently performs TLS handshakes during accept, blocking the server loop on
slow clients. Configure the wrapped socket to use a finite timeout or defer the
handshake until request handling so serve_forever remains responsive; preserve
the existing plain-socket behavior when TLS is disabled.
resalloc/client.py (1)

43-44: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use exception chaining instead of disabling the lint in both TLS error paths. Both sites re-raise as ResallocClientException while suppressing raise-missing-from, discarding the original ssl.SSLError context that makes TLS failures diagnosable. The project is Python 3 only (TEST_PYTHONS := python3), so raise ... from is available and also clears the Ruff B904 warnings.

  • resalloc/client.py#L43-L44: drop the pylint disable and use raise ResallocClientException(...) from err.
  • resalloc/client.py#L66-L68: drop the pylint disable and use raise ResallocClientException(...) from ssl_err.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@resalloc/client.py` around lines 43 - 44, Update both TLS exception handlers
in resalloc/client.py at lines 43-44 and 66-68: remove the pylint disables and
chain each ResallocClientException with its caught exception using “from err” in
the first path and “from ssl_err” in the second, preserving the existing
messages.

Source: Linters/SAST tools

shelltests/tests/tls.sh (1)

167-169: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Fixed 20s timeout always burns the full 20 seconds.

The misconfigured server never exits on its own, so timeout must fire every time — repeated for each python/database combination in the matrix. The warning is written during startup, so polling the log and killing early is equivalent and much faster.

⏱️ Proposed fix
-CONFIG_DIR=$WORKDIR/bad-etc timeout 20 "$SERVER_BIN" &>/dev/null || :
-grep -q "ssl_clients is set but ssl_certfile is not" "$badlog/main.log" \
-    || fatal "no warning about ssl_clients without ssl_certfile"
+CONFIG_DIR=$WORKDIR/bad-etc "$SERVER_BIN" &>/dev/null &
+bad_server_pid=$!
+cleanup_actions+=( "kill $bad_server_pid 2>/dev/null" )
+counter=20
+while ! grep -q "ssl_clients is set but ssl_certfile is not" \
+        "$badlog/main.log" 2>/dev/null; do
+    counter=$(( counter - 1 ))
+    test $counter -gt 0 || fatal "no warning about ssl_clients without ssl_certfile"
+    sleep 1
+done
+kill "$bad_server_pid" 2>/dev/null || :
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@shelltests/tests/tls.sh` around lines 167 - 169, Replace the fixed 20-second
timeout around the misconfigured SERVER_BIN startup with polling for the
expected warning in badlog/main.log, then terminate the server as soon as the
warning appears. Preserve the existing fatal failure when the warning is not
observed and ensure the background server process is cleaned up after polling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@shelltests/tests/tls.sh`:
- Around line 115-119: Add a short sleep inside the startup retry loop
surrounding maint resource-list, after each failed attempt or counter decrement,
so retries are paced and the full timeout remains available for server startup.

---

Nitpick comments:
In `@config/server.yaml`:
- Around line 23-31: Update the SSL configuration comments near ssl_clients to
state that leaving ssl_clients unset accepts any client: connections remain
encrypted when ssl_certfile is configured, but client authentication is disabled
because verify_mode remains CERT_NONE.

In `@resalloc/client.py`:
- Around line 43-44: Update both TLS exception handlers in resalloc/client.py at
lines 43-44 and 66-68: remove the pylint disables and chain each
ResallocClientException with its caught exception using “from err” in the first
path and “from ssl_err” in the second, preserving the existing messages.

In `@resallocserver/tls.py`:
- Around line 56-73: The build_tls_socket method currently performs TLS
handshakes during accept, blocking the server loop on slow clients. Configure
the wrapped socket to use a finite timeout or defer the handshake until request
handling so serve_forever remains responsive; preserve the existing plain-socket
behavior when TLS is disabled.

In `@shelltests/tests/tls.sh`:
- Around line 167-169: Replace the fixed 20-second timeout around the
misconfigured SERVER_BIN startup with polling for the expected warning in
badlog/main.log, then terminate the server as soon as the warning appears.
Preserve the existing fatal failure when the warning is not observed and ensure
the background server process is cleaned up after polling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 21b7c6f9-380c-4b96-905d-cabc6bdbc172

📥 Commits

Reviewing files that changed from the base of the PR and between 4803c31 and f9bdc3f.

📒 Files selected for processing (6)
  • Makefile
  • config/server.yaml
  • resalloc/client.py
  • resallocserver/main.py
  • resallocserver/tls.py
  • shelltests/tests/tls.sh

Comment thread shelltests/tests/tls.sh
Comment on lines +115 to +119
counter=30
while ! maint resource-list &>/dev/null; do
counter=$(( counter - 1 ))
test $counter -gt 0
done

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# How do the other shelltests wait for the server, and how does maint connect?
fd -t f . shelltests | head -50
rg -n -C3 'maint\s*\(\)|maint resource-list|MAINT_BIN' shelltests

Repository: praiskup/resalloc

Length of output: 10528


🏁 Script executed:

#!/bin/bash
sed -n '1,180p' shelltests/tests/tls.sh
printf '\n--- testlib ---\n'
sed -n '1,120p' shelltests/testlib

Repository: praiskup/resalloc

Length of output: 8442


🏁 Script executed:

#!/bin/bash
rg -n -C2 'resalloc-maint|--connection|ssl_certfile|ssl_clients|CONFIG_DIR|resource-list' -g '!*.o' -g '!*.a' .

Repository: praiskup/resalloc

Length of output: 20744


🏁 Script executed:

#!/bin/bash
sed -n '1,220p' bin/resalloc-maint
printf '\n--- maintainer ---\n'
rg -n -C2 'class Maintainer|def resource_list|def ticket_list|requests|http|xmlrpc|sqlite|sqlalchemy' resallocserver tests bin/resalloc-maint

Repository: praiskup/resalloc

Length of output: 16283


Add a sleep to the startup wait loop.
It retries as fast as possible, so the 30-iteration timeout can expire before the server finishes coming up.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@shelltests/tests/tls.sh` around lines 115 - 119, Add a short sleep inside the
startup retry loop surrounding maint resource-list, after each failed attempt or
counter decrement, so retries are paced and the full timeout remains available
for server startup.

Source: Linters/SAST tools

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
resalloc/client.py (1)

41-44: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Preserve the original TLS exception causes.

Both wrappers suppress exception chaining, making TLS failures harder to diagnose.

  • resalloc/client.py#L41-L44: raise ResallocClientException from err.
  • resalloc/client.py#L64-L68: raise ResallocClientException from ssl_err.
Proposed fix
-        raise ResallocClientException(
-            "Invalid client TLS configuration: {0}".format(err))
+        raise ResallocClientException(
+            "Invalid client TLS configuration: {0}".format(err)) from err
...
-        raise ResallocClientException(
-            "TLS error while talking to the server: {0}".format(
-                ssl_err))
+        raise ResallocClientException(
+            "TLS error while talking to the server: {0}".format(
+                ssl_err)) from ssl_err
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@resalloc/client.py` around lines 41 - 44, Preserve exception chaining in both
TLS error wrappers: update the ResallocClientException raises in
resalloc/client.py lines 41-44 and 64-68 to explicitly raise from the caught
exceptions err and ssl_err respectively, removing the suppression workaround
while keeping the existing messages and exception handling.

Source: Linters/SAST tools

shelltests/tests/tls.sh (1)

167-169: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Avoid the unconditional 20-second wait.

The server is expected to remain running, so timeout 20 delays this test by the full 20 seconds before checking the log. Start it in the background, poll for the warning with a bounded retry loop, then terminate and reap it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@shelltests/tests/tls.sh` around lines 167 - 169, Update the server startup
check around CONFIG_DIR and badlog/main.log to remove the unconditional timeout
wait: launch SERVER_BIN in the background, poll for the expected “ssl_clients is
set but ssl_certfile is not” warning using a bounded retry loop, then terminate
and reap the server before asserting failure if the warning was not observed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@resalloc/client.py`:
- Around line 41-44: Preserve exception chaining in both TLS error wrappers:
update the ResallocClientException raises in resalloc/client.py lines 41-44 and
64-68 to explicitly raise from the caught exceptions err and ssl_err
respectively, removing the suppression workaround while keeping the existing
messages and exception handling.

In `@shelltests/tests/tls.sh`:
- Around line 167-169: Update the server startup check around CONFIG_DIR and
badlog/main.log to remove the unconditional timeout wait: launch SERVER_BIN in
the background, poll for the expected “ssl_clients is set but ssl_certfile is
not” warning using a bounded retry loop, then terminate and reap the server
before asserting failure if the warning was not observed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9b1038a2-584c-4954-a7f0-e5f75a47e463

📥 Commits

Reviewing files that changed from the base of the PR and between f9bdc3f and 5ed9eab.

📒 Files selected for processing (6)
  • Makefile
  • config/server.yaml
  • resalloc/client.py
  • resallocserver/main.py
  • resallocserver/tls.py
  • shelltests/tests/tls.sh
🚧 Files skipped from review as they are similar to previous changes (4)
  • config/server.yaml
  • Makefile
  • resallocserver/tls.py
  • resallocserver/main.py

@sundaram123krishnan

Copy link
Copy Markdown
Author

ptal @praiskup

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants