Skip to content

Commit f10a07a

Browse files
authored
Added testing with TLS-based authentication (#3931)
* Added testing with TLS-based authentication * Revert changes * Revert changes * Codestyle changes * Change hardcoded value to constant
1 parent 3da93d7 commit f10a07a

File tree

4 files changed

+98
-5
lines changed

4 files changed

+98
-5
lines changed

docker-compose.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ services:
1313
container_name: redis-standalone
1414
environment:
1515
- TLS_ENABLED=yes
16+
- TLS_CLIENT_CNS=test_user
1617
- REDIS_CLUSTER=no
1718
- PORT=6379
1819
- TLS_PORT=6666
@@ -56,6 +57,7 @@ services:
5657
- NODES=6
5758
- REPLICAS=1
5859
- TLS_ENABLED=yes
60+
- TLS_CLIENT_CNS=test_user
5961
- PORT=16379
6062
- TLS_PORT=27379
6163
command: ${REDIS_EXTRA_ARGS:---enable-debug-command yes --enable-module-command yes --tls-auth-clients optional --save "" --tls-cluster yes}

tests/ssl_utils.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22
import os
33
from collections import namedtuple
44

5+
CN_USERNAME = "test_user"
56
CLIENT_CERT_NAME = "client.crt"
7+
CLIENT_CN_CERT_NAME = f"{CN_USERNAME}.crt"
68
CLIENT_KEY_NAME = "client.key"
9+
CLIENT_CN_KEY_NAME = f"{CN_USERNAME}.key"
710
SERVER_CERT_NAME = "redis.crt"
811
SERVER_KEY_NAME = "redis.key"
912
CA_CERT_NAME = "ca.crt"
@@ -12,6 +15,7 @@
1215
class CertificateType(str, enum.Enum):
1316
client = "client"
1417
server = "server"
18+
client_cn = "client-cn"
1519

1620

1721
TLSFiles = namedtuple("TLSFiles", ["certfile", "keyfile", "ca_certfile"])
@@ -41,3 +45,9 @@ def get_tls_certificates(
4145
os.path.join(cert_dir, SERVER_KEY_NAME),
4246
os.path.join(cert_dir, CA_CERT_NAME),
4347
)
48+
elif cert_type == CertificateType.client_cn:
49+
return TLSFiles(
50+
os.path.join(cert_dir, CLIENT_CN_CERT_NAME),
51+
os.path.join(cert_dir, CLIENT_CN_KEY_NAME),
52+
os.path.join(cert_dir, CA_CERT_NAME),
53+
)

tests/test_asyncio/test_ssl.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import pytest
55
import pytest_asyncio
66
import redis.asyncio as redis
7+
from tests.conftest import skip_if_server_version_lt
8+
from tests.ssl_utils import get_tls_certificates, CertificateType, CN_USERNAME
79

810
# Skip test or not based on cryptography installation
911
try:
@@ -193,3 +195,41 @@ async def test_ssl_password_parameter(self, request):
193195
assert conn.ssl_context.password == test_password
194196
finally:
195197
await r.aclose()
198+
199+
@skip_if_server_version_lt("8.5.0")
200+
async def test_ssl_authenticate_with_client_cert(self, request, r):
201+
"""Test that when client certificate is used for authentication,
202+
the connection is created successfully"""
203+
204+
try:
205+
# Non SSL client, to setup ACL
206+
assert await r.acl_setuser(
207+
CN_USERNAME,
208+
enabled=True,
209+
reset=True,
210+
passwords=["+clientpass"],
211+
keys=["*"],
212+
commands=["+acl"],
213+
)
214+
finally:
215+
await r.close()
216+
217+
ssl_url = request.config.option.redis_ssl_url
218+
p = urlparse(ssl_url)[1].split(":")
219+
client_cn_cert, client_cn_key, ca_cert = get_tls_certificates(
220+
request.session.config.REDIS_INFO["tls_cert_subdir"],
221+
CertificateType.client_cn,
222+
)
223+
r = redis.Redis(
224+
host=p[0],
225+
port=p[1],
226+
ssl=True,
227+
ssl_certfile=client_cn_cert,
228+
ssl_keyfile=client_cn_key,
229+
ssl_cert_reqs="required",
230+
ssl_ca_certs=ca_cert,
231+
)
232+
try:
233+
assert await r.acl_whoami() == CN_USERNAME
234+
finally:
235+
await r.close()

tests/test_ssl.py

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@
66
import redis
77
from redis.exceptions import ConnectionError, RedisError
88

9-
from .conftest import skip_if_cryptography, skip_if_nocryptography
10-
from .ssl_utils import CertificateType, get_tls_certificates
9+
from .conftest import (
10+
skip_if_cryptography,
11+
skip_if_nocryptography,
12+
skip_if_server_version_lt,
13+
)
14+
from .ssl_utils import CertificateType, get_tls_certificates, CN_USERNAME
1115

1216

1317
@pytest.mark.ssl
@@ -20,10 +24,10 @@ class TestSSL:
2024

2125
@pytest.fixture(autouse=True)
2226
def _set_ssl_certs(self, request):
23-
tls_cert_subdir = request.session.config.REDIS_INFO["tls_cert_subdir"]
24-
self.client_certs = get_tls_certificates(tls_cert_subdir)
27+
self.tls_cert_subdir = request.session.config.REDIS_INFO["tls_cert_subdir"]
28+
self.client_certs = get_tls_certificates(self.tls_cert_subdir)
2529
self.server_certs = get_tls_certificates(
26-
tls_cert_subdir, cert_type=CertificateType.server
30+
self.tls_cert_subdir, cert_type=CertificateType.server
2731
)
2832

2933
def test_ssl_with_invalid_cert(self, request):
@@ -425,3 +429,40 @@ def capture_context_wrap_socket(context_self, sock, **_kwargs):
425429

426430
finally:
427431
r.close()
432+
433+
@skip_if_server_version_lt("8.5.0")
434+
def test_ssl_authenticate_with_client_cert(self, request, r):
435+
"""Test that when client certificate is used for authentication,
436+
the connection is created successfully"""
437+
438+
try:
439+
# Non SSL client, to setup ACL
440+
assert r.acl_setuser(
441+
CN_USERNAME,
442+
enabled=True,
443+
reset=True,
444+
passwords=["+clientpass"],
445+
keys=["*"],
446+
commands=["+acl"],
447+
)
448+
finally:
449+
r.close()
450+
451+
ssl_url = request.config.option.redis_ssl_url
452+
p = urlparse(ssl_url)[1].split(":")
453+
client_cn_cert, client_cn_key, ca_cert = get_tls_certificates(
454+
self.tls_cert_subdir, CertificateType.client_cn
455+
)
456+
r = redis.Redis(
457+
host=p[0],
458+
port=p[1],
459+
ssl=True,
460+
ssl_certfile=client_cn_cert,
461+
ssl_keyfile=client_cn_key,
462+
ssl_cert_reqs="required",
463+
ssl_ca_certs=ca_cert,
464+
)
465+
try:
466+
assert r.acl_whoami() == CN_USERNAME
467+
finally:
468+
r.close()

0 commit comments

Comments
 (0)