diff --git a/src/server/server_family.cc b/src/server/server_family.cc index bbd9d09b7..2157b955c 100644 --- a/src/server/server_family.cc +++ b/src/server/server_family.cc @@ -141,6 +141,7 @@ ABSL_DECLARE_FLAG(string, tls_ca_cert_file); ABSL_DECLARE_FLAG(string, tls_ca_cert_dir); ABSL_DECLARE_FLAG(int, replica_priority); ABSL_DECLARE_FLAG(double, rss_oom_deny_ratio); +ABSL_DECLARE_FLAG(uint32_t, memcached_port); bool AbslParseFlag(std::string_view in, ReplicaOfFlag* flag, std::string* err) { #define RETURN_ON_ERROR(cond, m) \ @@ -299,6 +300,12 @@ bool ValidateServerTlsFlags() { has_auth = true; } + // Allow TLS without authentication for memcached protocol + // We check if memcached_port is enabled, as this is a static check during startup + if (GetFlag(FLAGS_memcached_port) > 0) { + has_auth = true; + } + if (!has_auth) { LOG(ERROR) << "TLS configured but no authentication method is used!"; return false; diff --git a/tests/dragonfly/memcached_tls_test.py b/tests/dragonfly/memcached_tls_test.py new file mode 100644 index 000000000..e3d683f5d --- /dev/null +++ b/tests/dragonfly/memcached_tls_test.py @@ -0,0 +1,49 @@ +from .instance import DflyInstance +from . import dfly_args +import pymemcache.client.base +from pymemcache.client.base import Client as MCClient +import ssl +import pytest +import time +import socket + +# Basic arguments for enabling memcached and TLS +DEFAULT_ARGS = {"memcached_port": 11211, "proactor_threads": 4} + + +@dfly_args(DEFAULT_ARGS) +def test_memcached_tls_no_requirepass(df_factory, with_tls_server_args, with_tls_ca_cert_args): + """ + Test for issue #5084: ability to use TLS for Memcached without requirepass. + + Dragonfly required a password to be set when using TLS, but the Memcached protocol + does not support password authentication. This test verifies that we can start + the server with TLS enabled but without specifying requirepass and with the Memcached port. + """ + # Create arguments for TLS without specifying requirepass + server_args = {**DEFAULT_ARGS, **with_tls_server_args} + + # Create and start the server - it should not crash + server = df_factory.create(**server_args) + server.start() + + # Give the server time to start + time.sleep(1) + + # Create SSL context for client + ssl_context = ssl.create_default_context() + ssl_context.load_verify_locations(with_tls_ca_cert_args["ca_cert"]) + ssl_context.check_hostname = False + + # Disable certificate verification (since we don't provide a client certificate) + ssl_context.verify_mode = ssl.CERT_NONE + + # Output port information for diagnostics + print(f"Connecting to memcached port: {server.mc_port} on host: 127.0.0.1") + + # Connect to Memcached over TLS + client = MCClient(("127.0.0.1", server.mc_port), tls_context=ssl_context) + + # Test basic operations + assert client.set("foo", "bar") + assert client.get("foo") == b"bar"