Skip to content

Commit

Permalink
Test the SSL connection (#441)
Browse files Browse the repository at this point in the history
  • Loading branch information
williamdes committed Jan 14, 2025
1 parent 9fca4e0 commit ab37078
Show file tree
Hide file tree
Showing 8 changed files with 244 additions and 8 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
fail-fast: false
matrix:
database-image: ["mariadb:10.6", "mariadb:10.11", "mariadb:latest", "mysql:5.7", "mysql:latest"]
configuration: ["default", "one-host", "one-socket-host", "config-mount-dir", "fs-import-export", "different-apache-port", "run-as-www-data"]
configuration: ["default", "one-host", "one-socket-host", "config-mount-dir", "fs-import-export", "different-apache-port", "run-as-www-data", "one-ssl-host"]

steps:
- uses: actions/checkout@v4
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ testing-%:
docker compose -p "phpmyadmin_$@" -f ./testing/docker-compose/docker-compose.$@.yml up --build --abort-on-container-exit --exit-code-from=sut
docker compose -p "phpmyadmin_$@" -f ./testing/docker-compose/docker-compose.$@.yml down

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
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

logs:
docker compose -f ./testing/docker-compose/docker-compose.testing-default.yml logs
Expand Down
5 changes: 5 additions & 0 deletions testing/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ def pytest_addoption(parser):
parser.addoption("--url")
parser.addoption("--username")
parser.addoption("--password")
parser.addoption("--root-password")
parser.addoption("--server")
parser.addoption("--sqlfile")

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

@pytest.fixture
def root_password(request):
return request.config.getoption("--root-password")

@pytest.fixture
def server(request):
return request.config.getoption("--server")
Expand Down
105 changes: 105 additions & 0 deletions testing/docker-compose/docker-compose.testing-one-ssl-host.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
version: "3.1"

services:
db_server:
image: ${DB:-mariadb:11}
command:
- "--plugin_load_add=server_audit"
- "--server_audit=FORCE_PLUS_PERMANENT"
- "--server_audit_events=connect"
- "--server_audit_logging"
#- "--server_audit_file_path=/var/log/mariadb-audit/audit.log"
- "--ssl-ca=/etc/phpmyadmin/ssl/ca-cert.pem"
- "--ssl-cert=/etc/phpmyadmin/ssl/server-cert.pem"
- "--ssl-key=/etc/phpmyadmin/ssl/server-key.pem"
- "--require-secure-transport=ON"
- "--server-audit-logging=ON"
environment:
MARIADB_USER: secure-user
MARIADB_PASSWORD: "${TESTSUITE_PASSWORD:-my-secret-pw}"
MARIADB_ROOT_PASSWORD: "${TESTSUITE_ROOT_PASSWORD:-random-pass}"
# The database name used in the import test
MARIADB_DATABASE: World
healthcheck:
test: ["CMD", "mariadb-admin", "ping", "-uroot", "-prandom-pass"]
start_period: 10s
interval: 5s
timeout: 60s
retries: 10
networks:
testing:
aliases:
- mariadb.phpmyadmin.local
tmpfs:
- /var/lib/mysql:rw,noexec,nosuid,size=300m
volumes:
#- ../secure-user.sql:/docker-entrypoint-initdb.d/secure-user.sql:ro
- ../ca-cert.pem:/etc/phpmyadmin/ssl/ca-cert.pem:ro
- ../ca-key.pem:/etc/phpmyadmin/ssl/ca-key.pem:ro
- ../server-cert.pem:/etc/phpmyadmin/ssl/server-cert.pem:ro
- ../server-key.pem:/etc/phpmyadmin/ssl/server-key.pem:ro
#- ../mariadb-audit:/var/log/mariadb-audit

phpmyadmin:
build:
context: ../../apache
environment:
PMA_HOST: mariadb.phpmyadmin.local
PMA_SSL: 1
PMA_SSL_VERIFY: 1
PMA_SSL_CA: /etc/phpmyadmin/ssl/ca-cert.pem
PMA_SSL_CERT: /etc/phpmyadmin/ssl/client-cert.pem
PMA_SSL_KEY: /etc/phpmyadmin/ssl/client-key.pem
UPLOAD_LIMIT: 123M
MAX_EXECUTION_TIME: 125
HIDE_PHP_VERSION: 1
volumes:
- ../config.user.inc.php:/etc/phpmyadmin/config.user.inc.php:ro
- ../ca-cert.pem:/etc/phpmyadmin/ssl/ca-cert.pem:ro
- ../client-cert.pem:/etc/phpmyadmin/ssl/client-cert.pem:ro
- ../client-key.pem:/etc/phpmyadmin/ssl/client-key.pem:ro
healthcheck:
test: ["CMD", "curl", "-Ss", "http://localhost/robots.txt"]
start_period: 5s
interval: 3s
timeout: 60s
retries: 10
networks:
testing:
aliases:
- phpmyadmin_testing_apache
depends_on:
db_server:
condition: service_healthy

sut:
depends_on:
phpmyadmin:
condition: service_healthy
db_server:
condition: service_healthy
build:
context: ../
command: "/tests/testing/test-docker.sh"
networks:
testing:
environment:
TESTSUITE_HOSTNAME: phpmyadmin_testing_apache
TESTSUITE_PORT: 80
TESTSUITE_USER: secure-user
TESTSUITE_PASSWORD: "${TESTSUITE_PASSWORD:-my-secret-pw}"
TESTSUITE_ROOT_PASSWORD: "${TESTSUITE_ROOT_PASSWORD:-random-pass}"
PMA_HOST: mariadb.phpmyadmin.local
PMA_PORT: 3306
IS_USING_SSL: true
volumes:
- ../ca-cert.pem:/etc/phpmyadmin/ssl/ca-cert.pem:ro
- ../server-cert.pem:/etc/phpmyadmin/ssl/server-cert.pem:ro
- ../client-cert.pem:/etc/phpmyadmin/ssl/client-cert.pem:ro
- ../client-key.pem:/etc/phpmyadmin/ssl/client-key.pem:ro
- ../../:/tests:ro
working_dir: /tests

networks:
testing:
driver: bridge
37 changes: 37 additions & 0 deletions testing/generate-keys.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/bin/sh

set -eu

# Source: https://github.com/chio-nzgft/docker-MariaDB-with-SSL
# See: https://dev.mysql.com/doc/refman/5.7/en/creating-ssl-files-using-openssl.html


ROOT_DIR="$(realpath $(dirname $0))"
echo "Using root dir: $ROOT_DIR"

cd "$ROOT_DIR"

rm -f *.pem

SUBJECT_CA="/C=US/O=phpMyAdmin testing/OU=Docker/CN=ssl-ca.phpmyadmin.local/[email protected]"
SUBJECT_CLIENT="/C=US/O=phpMyAdmin testing/OU=Docker/CN=client.phpmyadmin.local/[email protected]"
SUBJECT_SERVER="/C=US/O=phpMyAdmin testing/OU=Docker/CN=mariadb.phpmyadmin.local"

echo "CA key"

openssl genrsa 2048 > ca-key.pem
openssl req -new -x509 -nodes -days 3600 -subj "${SUBJECT_CA}" -key ca-key.pem -out ca-cert.pem
echo "server key"

openssl req -subj "${SUBJECT_SERVER}" -newkey rsa:2048 -days 3600 -nodes -keyout server-key.pem -out server-req.pem
openssl rsa -in server-key.pem -out server-key.pem
openssl x509 -req -in server-req.pem -days 3600 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem
echo "client key"

openssl req -subj "${SUBJECT_CLIENT}" -newkey rsa:2048 -days 3600 -nodes -keyout client-key.pem -out client-req.pem
openssl rsa -in client-key.pem -out client-key.pem
openssl x509 -req -in client-req.pem -days 3600 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 -out client-cert.pem
echo "check key ok"

openssl verify -CAfile ca-cert.pem server-cert.pem client-cert.pem
chmod 666 *.pem
38 changes: 36 additions & 2 deletions testing/phpmyadmin_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ def test_import(url, username, password, server, sqlfile):
br.select_form('import')
br.form.add_file(open(sqlfile), 'text/plain', sqlfile)
response = br.submit()
assert(b'5326 queries executed' in response.read())
response = response.read()

assert(b'5326 queries executed' in response)


def docker_secret(env_name):
Expand Down Expand Up @@ -89,14 +91,46 @@ def test_phpmyadmin_secrets():
docker_secret('PMA_CONTROLUSER')
docker_secret('PMA_CONTROLPASS')

def test_is_using_ssl(url, username, password, server):
is_using_ssl = os.environ.get('IS_USING_SSL');

br = create_browser()
response = do_login(br, url, username, password, server)
response = response.read()

assert(b'Server connection' in response)

if is_using_ssl:
assert(b'SSL is used' in response)
assert(b'SSL is not being used' not in response)
else:
assert(b'SSL is used' not in response)
assert(b'SSL is not being used' in response)

def test_is_using_ssl_client_cert(url, server):
is_using_ssl = os.environ.get('IS_USING_SSL');
if not is_using_ssl:
pytest.skip("Missing IS_USING_SSL ENV", allow_module_level=True)

br = create_browser()
password = ""
response = do_login(br, url, "ssl-specific-user", password, server)
response = response.read()

assert(b'Server connection' in response)
assert(b'ssl-specific-user@' in response)

assert(b'SSL is used' in response)
assert(b'SSL is not being used' not in response)

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

br = create_browser()
response = do_login(br, url, username, password, server)
response = response.read()

assert(b'Show PHP information' in response.read())
assert(b'Show PHP information' in response)

# Open Show PHP information
response = br.follow_link(text_regex=re.compile('Show PHP information'))
Expand Down
Empty file added testing/secure-user.sql
Empty file.
63 changes: 59 additions & 4 deletions testing/test-docker.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#!/bin/sh

set -eu

# Set phpMyAdmin environment
PHPMYADMIN_HOSTNAME=${TESTSUITE_HOSTNAME:=localhost}
PHPMYADMIN_PORT=${TESTSUITE_PORT:=80}
Expand All @@ -8,9 +10,24 @@ PHPMYADMIN_URL=http://${PHPMYADMIN_HOSTNAME}:${PHPMYADMIN_PORT}/
# Set database environment
PHPMYADMIN_DB_HOSTNAME=${PMA_HOST:=localhost}
PHPMYADMIN_DB_PORT=${PMA_PORT:=3306}
TESTSUITE_USER=${TESTSUITE_USER:=root}
TESTSUITE_ROOT_PASSWORD=${TESTSUITE_ROOT_PASSWORD:-}

SUBJECT_CA="/C=US/O=phpMyAdmin testing/OU=Docker/CN=ssl-ca.phpmyadmin.local/[email protected]"
SUBJECT_CLIENT="/C=US/O=phpMyAdmin testing/OU=Docker/CN=client.phpmyadmin.local/[email protected]"

if [ "${TESTSUITE_USER}" = "root" ] && [ -n "${TESTSUITE_ROOT_PASSWORD}" ]; then
echo "Do not use TESTSUITE_ROOT_PASSWORD with TESTSUITE_USER=root"
exit 1
fi

if [ ! -z "${TESTSUITE_HOSTNAME_ARBITRARY}" ]; then
SERVER="--server ${PHPMYADMIN_DB_HOSTNAME}"
TEST_CLI_ARGS=""
if [ -n "${TESTSUITE_HOSTNAME_ARBITRARY:-}" ]; then
TEST_CLI_ARGS="$TEST_CLI_ARGS --server ${PHPMYADMIN_DB_HOSTNAME}"
fi

if [ -n "${TESTSUITE_ROOT_PASSWORD}" ]; then
TEST_CLI_ARGS="$TEST_CLI_ARGS --root-password ${TESTSUITE_ROOT_PASSWORD}"
fi

# Find test script
Expand All @@ -20,7 +37,45 @@ else
FILENAME=./testing/phpmyadmin_test.py
fi

mariadb -h "${PHPMYADMIN_DB_HOSTNAME}" -P"${PHPMYADMIN_DB_PORT}" -u"${TESTSUITE_USER:=root}" -p"${TESTSUITE_PASSWORD}" --skip-ssl -e "SELECT @@version;" > /dev/null
SSL_FLAG="--skip-ssl"

if [ -n "${IS_USING_SSL:-}" ]; then
SSL_FLAG="--ssl --ssl-verify-server-cert --ssl-ca=/etc/phpmyadmin/ssl/ca-cert.pem"
fi

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%';"

if [ -n "${IS_USING_SSL:-}" ]; then
set +e
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
if [ $? != 1 ]; then
echo "The server does not enforce SSL connections, stopping the test."
exit 1
fi
set -e
fi

if [ -n "${IS_USING_SSL:-}" ] && [ -n "${TESTSUITE_ROOT_PASSWORD}" ]; then
mariadb $SSL_FLAG -h "${PHPMYADMIN_DB_HOSTNAME}" -P"${PHPMYADMIN_DB_PORT}" -u"root" -p"${TESTSUITE_ROOT_PASSWORD}" \
-e "CREATE USER 'ssl-specific-user'@'%' REQUIRE SUBJECT '$SUBJECT_CLIENT' AND ISSUER '$SUBJECT_CA';"

set +e
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
if [ $? != 0 ]; then
echo "The server should accept the SSL client cert login, stopping the test."
exit 1
fi
set -e

set +e
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
if [ $? != 1 ]; then
echo "The server should refuse the login without a client cert, stopping the test."
exit 1
fi
set -e
fi

ret=$?

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

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

# Show debug output in case of failure
Expand Down

0 comments on commit ab37078

Please sign in to comment.