Skip to content

Commit ab37078

Browse files
committed
Test the SSL connection (#441)
1 parent 9fca4e0 commit ab37078

File tree

8 files changed

+244
-8
lines changed

8 files changed

+244
-8
lines changed

.github/workflows/run-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
fail-fast: false
1616
matrix:
1717
database-image: ["mariadb:10.6", "mariadb:10.11", "mariadb:latest", "mysql:5.7", "mysql:latest"]
18-
configuration: ["default", "one-host", "one-socket-host", "config-mount-dir", "fs-import-export", "different-apache-port", "run-as-www-data"]
18+
configuration: ["default", "one-host", "one-socket-host", "config-mount-dir", "fs-import-export", "different-apache-port", "run-as-www-data", "one-ssl-host"]
1919

2020
steps:
2121
- uses: actions/checkout@v4

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ testing-%:
2222
docker compose -p "phpmyadmin_$@" -f ./testing/docker-compose/docker-compose.$@.yml up --build --abort-on-container-exit --exit-code-from=sut
2323
docker compose -p "phpmyadmin_$@" -f ./testing/docker-compose/docker-compose.$@.yml down
2424

25-
run-tests: testing-default testing-one-host testing-one-socket-host testing-config-mount-dir testing-fs-import-export testing-different-apache-port testing-run-as-www-data
25+
run-tests: testing-default testing-one-host testing-one-socket-host testing-config-mount-dir testing-fs-import-export testing-different-apache-port testing-run-as-www-data testing-one-ssl-host
2626

2727
logs:
2828
docker compose -f ./testing/docker-compose/docker-compose.testing-default.yml logs

testing/conftest.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ def pytest_addoption(parser):
44
parser.addoption("--url")
55
parser.addoption("--username")
66
parser.addoption("--password")
7+
parser.addoption("--root-password")
78
parser.addoption("--server")
89
parser.addoption("--sqlfile")
910

@@ -19,6 +20,10 @@ def username(request):
1920
def password(request):
2021
return request.config.getoption("--password")
2122

23+
@pytest.fixture
24+
def root_password(request):
25+
return request.config.getoption("--root-password")
26+
2227
@pytest.fixture
2328
def server(request):
2429
return request.config.getoption("--server")
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
version: "3.1"
2+
3+
services:
4+
db_server:
5+
image: ${DB:-mariadb:11}
6+
command:
7+
- "--plugin_load_add=server_audit"
8+
- "--server_audit=FORCE_PLUS_PERMANENT"
9+
- "--server_audit_events=connect"
10+
- "--server_audit_logging"
11+
#- "--server_audit_file_path=/var/log/mariadb-audit/audit.log"
12+
- "--ssl-ca=/etc/phpmyadmin/ssl/ca-cert.pem"
13+
- "--ssl-cert=/etc/phpmyadmin/ssl/server-cert.pem"
14+
- "--ssl-key=/etc/phpmyadmin/ssl/server-key.pem"
15+
- "--require-secure-transport=ON"
16+
- "--server-audit-logging=ON"
17+
environment:
18+
MARIADB_USER: secure-user
19+
MARIADB_PASSWORD: "${TESTSUITE_PASSWORD:-my-secret-pw}"
20+
MARIADB_ROOT_PASSWORD: "${TESTSUITE_ROOT_PASSWORD:-random-pass}"
21+
# The database name used in the import test
22+
MARIADB_DATABASE: World
23+
healthcheck:
24+
test: ["CMD", "mariadb-admin", "ping", "-uroot", "-prandom-pass"]
25+
start_period: 10s
26+
interval: 5s
27+
timeout: 60s
28+
retries: 10
29+
networks:
30+
testing:
31+
aliases:
32+
- mariadb.phpmyadmin.local
33+
tmpfs:
34+
- /var/lib/mysql:rw,noexec,nosuid,size=300m
35+
volumes:
36+
#- ../secure-user.sql:/docker-entrypoint-initdb.d/secure-user.sql:ro
37+
- ../ca-cert.pem:/etc/phpmyadmin/ssl/ca-cert.pem:ro
38+
- ../ca-key.pem:/etc/phpmyadmin/ssl/ca-key.pem:ro
39+
- ../server-cert.pem:/etc/phpmyadmin/ssl/server-cert.pem:ro
40+
- ../server-key.pem:/etc/phpmyadmin/ssl/server-key.pem:ro
41+
#- ../mariadb-audit:/var/log/mariadb-audit
42+
43+
phpmyadmin:
44+
build:
45+
context: ../../apache
46+
environment:
47+
PMA_HOST: mariadb.phpmyadmin.local
48+
PMA_SSL: 1
49+
PMA_SSL_VERIFY: 1
50+
PMA_SSL_CA: /etc/phpmyadmin/ssl/ca-cert.pem
51+
PMA_SSL_CERT: /etc/phpmyadmin/ssl/client-cert.pem
52+
PMA_SSL_KEY: /etc/phpmyadmin/ssl/client-key.pem
53+
UPLOAD_LIMIT: 123M
54+
MAX_EXECUTION_TIME: 125
55+
HIDE_PHP_VERSION: 1
56+
volumes:
57+
- ../config.user.inc.php:/etc/phpmyadmin/config.user.inc.php:ro
58+
- ../ca-cert.pem:/etc/phpmyadmin/ssl/ca-cert.pem:ro
59+
- ../client-cert.pem:/etc/phpmyadmin/ssl/client-cert.pem:ro
60+
- ../client-key.pem:/etc/phpmyadmin/ssl/client-key.pem:ro
61+
healthcheck:
62+
test: ["CMD", "curl", "-Ss", "http://localhost/robots.txt"]
63+
start_period: 5s
64+
interval: 3s
65+
timeout: 60s
66+
retries: 10
67+
networks:
68+
testing:
69+
aliases:
70+
- phpmyadmin_testing_apache
71+
depends_on:
72+
db_server:
73+
condition: service_healthy
74+
75+
sut:
76+
depends_on:
77+
phpmyadmin:
78+
condition: service_healthy
79+
db_server:
80+
condition: service_healthy
81+
build:
82+
context: ../
83+
command: "/tests/testing/test-docker.sh"
84+
networks:
85+
testing:
86+
environment:
87+
TESTSUITE_HOSTNAME: phpmyadmin_testing_apache
88+
TESTSUITE_PORT: 80
89+
TESTSUITE_USER: secure-user
90+
TESTSUITE_PASSWORD: "${TESTSUITE_PASSWORD:-my-secret-pw}"
91+
TESTSUITE_ROOT_PASSWORD: "${TESTSUITE_ROOT_PASSWORD:-random-pass}"
92+
PMA_HOST: mariadb.phpmyadmin.local
93+
PMA_PORT: 3306
94+
IS_USING_SSL: true
95+
volumes:
96+
- ../ca-cert.pem:/etc/phpmyadmin/ssl/ca-cert.pem:ro
97+
- ../server-cert.pem:/etc/phpmyadmin/ssl/server-cert.pem:ro
98+
- ../client-cert.pem:/etc/phpmyadmin/ssl/client-cert.pem:ro
99+
- ../client-key.pem:/etc/phpmyadmin/ssl/client-key.pem:ro
100+
- ../../:/tests:ro
101+
working_dir: /tests
102+
103+
networks:
104+
testing:
105+
driver: bridge

testing/generate-keys.sh

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#!/bin/sh
2+
3+
set -eu
4+
5+
# Source: https://github.com/chio-nzgft/docker-MariaDB-with-SSL
6+
# See: https://dev.mysql.com/doc/refman/5.7/en/creating-ssl-files-using-openssl.html
7+
8+
9+
ROOT_DIR="$(realpath $(dirname $0))"
10+
echo "Using root dir: $ROOT_DIR"
11+
12+
cd "$ROOT_DIR"
13+
14+
rm -f *.pem
15+
16+
SUBJECT_CA="/C=US/O=phpMyAdmin testing/OU=Docker/CN=ssl-ca.phpmyadmin.local/[email protected]"
17+
SUBJECT_CLIENT="/C=US/O=phpMyAdmin testing/OU=Docker/CN=client.phpmyadmin.local/[email protected]"
18+
SUBJECT_SERVER="/C=US/O=phpMyAdmin testing/OU=Docker/CN=mariadb.phpmyadmin.local"
19+
20+
echo "CA key"
21+
22+
openssl genrsa 2048 > ca-key.pem
23+
openssl req -new -x509 -nodes -days 3600 -subj "${SUBJECT_CA}" -key ca-key.pem -out ca-cert.pem
24+
echo "server key"
25+
26+
openssl req -subj "${SUBJECT_SERVER}" -newkey rsa:2048 -days 3600 -nodes -keyout server-key.pem -out server-req.pem
27+
openssl rsa -in server-key.pem -out server-key.pem
28+
openssl x509 -req -in server-req.pem -days 3600 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem
29+
echo "client key"
30+
31+
openssl req -subj "${SUBJECT_CLIENT}" -newkey rsa:2048 -days 3600 -nodes -keyout client-key.pem -out client-req.pem
32+
openssl rsa -in client-key.pem -out client-key.pem
33+
openssl x509 -req -in client-req.pem -days 3600 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 -out client-cert.pem
34+
echo "check key ok"
35+
36+
openssl verify -CAfile ca-cert.pem server-cert.pem client-cert.pem
37+
chmod 666 *.pem

testing/phpmyadmin_test.py

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ def test_import(url, username, password, server, sqlfile):
5858
br.select_form('import')
5959
br.form.add_file(open(sqlfile), 'text/plain', sqlfile)
6060
response = br.submit()
61-
assert(b'5326 queries executed' in response.read())
61+
response = response.read()
62+
63+
assert(b'5326 queries executed' in response)
6264

6365

6466
def docker_secret(env_name):
@@ -89,14 +91,46 @@ def test_phpmyadmin_secrets():
8991
docker_secret('PMA_CONTROLUSER')
9092
docker_secret('PMA_CONTROLPASS')
9193

94+
def test_is_using_ssl(url, username, password, server):
95+
is_using_ssl = os.environ.get('IS_USING_SSL');
96+
97+
br = create_browser()
98+
response = do_login(br, url, username, password, server)
99+
response = response.read()
100+
101+
assert(b'Server connection' in response)
102+
103+
if is_using_ssl:
104+
assert(b'SSL is used' in response)
105+
assert(b'SSL is not being used' not in response)
106+
else:
107+
assert(b'SSL is used' not in response)
108+
assert(b'SSL is not being used' in response)
109+
110+
def test_is_using_ssl_client_cert(url, server):
111+
is_using_ssl = os.environ.get('IS_USING_SSL');
112+
if not is_using_ssl:
113+
pytest.skip("Missing IS_USING_SSL ENV", allow_module_level=True)
114+
115+
br = create_browser()
116+
password = ""
117+
response = do_login(br, url, "ssl-specific-user", password, server)
118+
response = response.read()
119+
120+
assert(b'Server connection' in response)
121+
assert(b'ssl-specific-user@' in response)
122+
123+
assert(b'SSL is used' in response)
124+
assert(b'SSL is not being used' not in response)
92125

93126
def test_php_ini(url, username, password, server):
94127
skip_expose_php_test = os.environ.get('SKIP_EXPOSE_PHP_TEST');
95128

96129
br = create_browser()
97130
response = do_login(br, url, username, password, server)
131+
response = response.read()
98132

99-
assert(b'Show PHP information' in response.read())
133+
assert(b'Show PHP information' in response)
100134

101135
# Open Show PHP information
102136
response = br.follow_link(text_regex=re.compile('Show PHP information'))

testing/secure-user.sql

Whitespace-only changes.

testing/test-docker.sh

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#!/bin/sh
22

3+
set -eu
4+
35
# Set phpMyAdmin environment
46
PHPMYADMIN_HOSTNAME=${TESTSUITE_HOSTNAME:=localhost}
57
PHPMYADMIN_PORT=${TESTSUITE_PORT:=80}
@@ -8,9 +10,24 @@ PHPMYADMIN_URL=http://${PHPMYADMIN_HOSTNAME}:${PHPMYADMIN_PORT}/
810
# Set database environment
911
PHPMYADMIN_DB_HOSTNAME=${PMA_HOST:=localhost}
1012
PHPMYADMIN_DB_PORT=${PMA_PORT:=3306}
13+
TESTSUITE_USER=${TESTSUITE_USER:=root}
14+
TESTSUITE_ROOT_PASSWORD=${TESTSUITE_ROOT_PASSWORD:-}
15+
16+
SUBJECT_CA="/C=US/O=phpMyAdmin testing/OU=Docker/CN=ssl-ca.phpmyadmin.local/[email protected]"
17+
SUBJECT_CLIENT="/C=US/O=phpMyAdmin testing/OU=Docker/CN=client.phpmyadmin.local/[email protected]"
18+
19+
if [ "${TESTSUITE_USER}" = "root" ] && [ -n "${TESTSUITE_ROOT_PASSWORD}" ]; then
20+
echo "Do not use TESTSUITE_ROOT_PASSWORD with TESTSUITE_USER=root"
21+
exit 1
22+
fi
1123

12-
if [ ! -z "${TESTSUITE_HOSTNAME_ARBITRARY}" ]; then
13-
SERVER="--server ${PHPMYADMIN_DB_HOSTNAME}"
24+
TEST_CLI_ARGS=""
25+
if [ -n "${TESTSUITE_HOSTNAME_ARBITRARY:-}" ]; then
26+
TEST_CLI_ARGS="$TEST_CLI_ARGS --server ${PHPMYADMIN_DB_HOSTNAME}"
27+
fi
28+
29+
if [ -n "${TESTSUITE_ROOT_PASSWORD}" ]; then
30+
TEST_CLI_ARGS="$TEST_CLI_ARGS --root-password ${TESTSUITE_ROOT_PASSWORD}"
1431
fi
1532

1633
# Find test script
@@ -20,7 +37,45 @@ else
2037
FILENAME=./testing/phpmyadmin_test.py
2138
fi
2239

23-
mariadb -h "${PHPMYADMIN_DB_HOSTNAME}" -P"${PHPMYADMIN_DB_PORT}" -u"${TESTSUITE_USER:=root}" -p"${TESTSUITE_PASSWORD}" --skip-ssl -e "SELECT @@version;" > /dev/null
40+
SSL_FLAG="--skip-ssl"
41+
42+
if [ -n "${IS_USING_SSL:-}" ]; then
43+
SSL_FLAG="--ssl --ssl-verify-server-cert --ssl-ca=/etc/phpmyadmin/ssl/ca-cert.pem"
44+
fi
45+
46+
mariadb $SSL_FLAG -h "${PHPMYADMIN_DB_HOSTNAME}" -P"${PHPMYADMIN_DB_PORT}" -u"$TESTSUITE_USER" -p"${TESTSUITE_PASSWORD}" -e "SELECT @@version;SHOW VARIABLES LIKE 'require_secure_transport';SHOW VARIABLES LIKE '%ssl%';"
47+
48+
if [ -n "${IS_USING_SSL:-}" ]; then
49+
set +e
50+
mariadb --skip-ssl -h "${PHPMYADMIN_DB_HOSTNAME}" -P"${PHPMYADMIN_DB_PORT}" -u"$TESTSUITE_USER" -p"${TESTSUITE_PASSWORD}" -e "SELECT @@version;SHOW VARIABLES LIKE 'require_secure_transport';" 1> /dev/null 2> /dev/null
51+
if [ $? != 1 ]; then
52+
echo "The server does not enforce SSL connections, stopping the test."
53+
exit 1
54+
fi
55+
set -e
56+
fi
57+
58+
if [ -n "${IS_USING_SSL:-}" ] && [ -n "${TESTSUITE_ROOT_PASSWORD}" ]; then
59+
mariadb $SSL_FLAG -h "${PHPMYADMIN_DB_HOSTNAME}" -P"${PHPMYADMIN_DB_PORT}" -u"root" -p"${TESTSUITE_ROOT_PASSWORD}" \
60+
-e "CREATE USER 'ssl-specific-user'@'%' REQUIRE SUBJECT '$SUBJECT_CLIENT' AND ISSUER '$SUBJECT_CA';"
61+
62+
set +e
63+
mariadb $SSL_FLAG --ssl-cert=/etc/phpmyadmin/ssl/client-cert.pem --ssl-key=/etc/phpmyadmin/ssl/client-key.pem -h "${PHPMYADMIN_DB_HOSTNAME}" -P"${PHPMYADMIN_DB_PORT}" -u"ssl-specific-user" -e "SELECT @@version;SHOW VARIABLES LIKE 'require_secure_transport';" 1> /dev/null 2> /dev/null
64+
if [ $? != 0 ]; then
65+
echo "The server should accept the SSL client cert login, stopping the test."
66+
exit 1
67+
fi
68+
set -e
69+
70+
set +e
71+
mariadb $SSL_FLAG -h "${PHPMYADMIN_DB_HOSTNAME}" -P"${PHPMYADMIN_DB_PORT}" -u"ssl-specific-user" -e "SELECT @@version;SHOW VARIABLES LIKE 'require_secure_transport';" 1> /dev/null 2> /dev/null
72+
if [ $? != 1 ]; then
73+
echo "The server should refuse the login without a client cert, stopping the test."
74+
exit 1
75+
fi
76+
set -e
77+
fi
78+
2479
ret=$?
2580

2681
if [ $ret -ne 0 ] ; then
@@ -38,7 +93,7 @@ fi
3893

3994
# Perform tests
4095
ret=0
41-
pytest -p no:cacheprovider -q --url "$PHPMYADMIN_URL" --username ${TESTSUITE_USER:=root} --password "$TESTSUITE_PASSWORD" $SERVER $FILENAME
96+
pytest -p no:cacheprovider -q --url "$PHPMYADMIN_URL" --username $TESTSUITE_USER --password "$TESTSUITE_PASSWORD" $TEST_CLI_ARGS $FILENAME
4297
ret=$?
4398

4499
# Show debug output in case of failure

0 commit comments

Comments
 (0)