Fix phpMyAdmin SSO login and harden SSO/security posture
phpMyAdmin login was broken because phpmyadmin_install.sh never wired the private phpMyAdmin copy into the web server: no Apache Alias was registered via DirectAdmin CustomBuild, so the SSO redirect target was unreachable. Add configure_apache_alias()/apply_apache_alias() (Alias + Directory blocks, ./build rewrite_confs, httpd reload), detect the real Apache group instead of hardcoding diradmin:diradmin, stop silently swallowing chown/chmod failures, and verify an optional SHA256 for the downloaded phpMyAdmin tarball. Extend phpmyadmin_health_check.sh to detect a missing/incorrect Apache alias and to probe HTTP reachability. Security hardening: scope temporary phpMyAdmin SSO MySQL roles to 127.0.0.1 instead of '%', tighten SSO ticket file permissions to 0640 (they contain a plaintext MySQL password), and log MySQL connection failures for diagnosis instead of swallowing them silently. Bump version to 1.2.12 and rebuild the release archive.
This commit is contained in:
@@ -58,6 +58,17 @@ return static function (AppContext $ctx): void {
|
|||||||
$ensurePhpMyAdminReady();
|
$ensurePhpMyAdminReady();
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
$message = 'Nie można przygotować phpMyAdmin: ' . $e->getMessage();
|
$message = 'Nie można przygotować phpMyAdmin: ' . $e->getMessage();
|
||||||
|
@error_log(
|
||||||
|
sprintf(
|
||||||
|
"[%s] PHPMYADMIN_PROVISION_FAIL user=%s remote=%s message=%s\n",
|
||||||
|
date('c'),
|
||||||
|
$ctx->daUser->username(),
|
||||||
|
Http::server('REMOTE_ADDR'),
|
||||||
|
$e->getMessage()
|
||||||
|
),
|
||||||
|
3,
|
||||||
|
PLUGIN_ROOT . '/error.log'
|
||||||
|
);
|
||||||
if ($rawMode) {
|
if ($rawMode) {
|
||||||
echo "HTTP/1.1 500 Internal Server Error\r\n";
|
echo "HTTP/1.1 500 Internal Server Error\r\n";
|
||||||
echo "Content-Type: text/plain; charset=UTF-8\r\n\r\n";
|
echo "Content-Type: text/plain; charset=UTF-8\r\n\r\n";
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
final class MySQLService
|
final class MySQLService
|
||||||
{
|
{
|
||||||
private const TMP_ROLE_PREFIX = 'da_tmp_phpmyadmin_';
|
private const TMP_ROLE_PREFIX = 'da_tmp_phpmyadmin_';
|
||||||
|
public const TMP_ROLE_HOST = '127.0.0.1';
|
||||||
|
|
||||||
/** @var array{host:string,port:int,database:string,user:string,password:string,socket:string} */
|
/** @var array{host:string,port:int,database:string,user:string,password:string,socket:string} */
|
||||||
private array $credentials;
|
private array $credentials;
|
||||||
@@ -703,13 +704,14 @@ final class MySQLService
|
|||||||
public function createTemporaryRole(string $role, string $password, int $expiresAt): void
|
public function createTemporaryRole(string $role, string $password, int $expiresAt): void
|
||||||
{
|
{
|
||||||
$this->query(
|
$this->query(
|
||||||
'CREATE USER ' . $this->quoteLiteral($role) . '@\'%\' IDENTIFIED BY ' . $this->quoteLiteral($password)
|
'CREATE USER ' . $this->quoteLiteral($role) . '@' . $this->quoteLiteral(self::TMP_ROLE_HOST) .
|
||||||
|
' IDENTIFIED BY ' . $this->quoteLiteral($password)
|
||||||
);
|
);
|
||||||
$this->query(
|
$this->query(
|
||||||
'INSERT INTO da_plugin_sso_accounts (role_name, host_pattern, expires_at)
|
'INSERT INTO da_plugin_sso_accounts (role_name, host_pattern, expires_at)
|
||||||
VALUES (?, \'%\', ?)
|
VALUES (?, ?, ?)
|
||||||
ON DUPLICATE KEY UPDATE expires_at = VALUES(expires_at)',
|
ON DUPLICATE KEY UPDATE expires_at = VALUES(expires_at)',
|
||||||
[$role, (string)$expiresAt]
|
[$role, self::TMP_ROLE_HOST, (string)$expiresAt]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -717,13 +719,13 @@ final class MySQLService
|
|||||||
{
|
{
|
||||||
$this->query(
|
$this->query(
|
||||||
'GRANT ALL PRIVILEGES ON ' . $this->quoteIdentifier($dbName) . '.* TO ' .
|
'GRANT ALL PRIVILEGES ON ' . $this->quoteIdentifier($dbName) . '.* TO ' .
|
||||||
$this->quoteLiteral($role) . '@\'%\''
|
$this->quoteLiteral($role) . '@' . $this->quoteLiteral(self::TMP_ROLE_HOST)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function dropTemporaryRole(string $role): void
|
public function dropTemporaryRole(string $role): void
|
||||||
{
|
{
|
||||||
$this->tryQuery('DROP USER IF EXISTS ' . $this->quoteLiteral($role) . '@\'%\'');
|
$this->tryQuery('DROP USER IF EXISTS ' . $this->quoteLiteral($role) . '@' . $this->quoteLiteral(self::TMP_ROLE_HOST));
|
||||||
$this->query('DELETE FROM da_plugin_sso_accounts WHERE role_name = ?', [$role]);
|
$this->query('DELETE FROM da_plugin_sso_accounts WHERE role_name = ?', [$role]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1155,6 +1157,14 @@ final class MySQLService
|
|||||||
);
|
);
|
||||||
|
|
||||||
if ($ok !== true) {
|
if ($ok !== true) {
|
||||||
|
error_log(sprintf(
|
||||||
|
'[%s] MYSQL_CONNECT_FAIL host=%s port=%d database=%s error=%s',
|
||||||
|
date('c'),
|
||||||
|
$this->credentials['host'],
|
||||||
|
$this->credentials['port'],
|
||||||
|
$targetDb,
|
||||||
|
$conn->connect_error ?? 'unknown'
|
||||||
|
));
|
||||||
throw new RuntimeException('Nie udało się połączyć z MySQL.');
|
throw new RuntimeException('Nie udało się połączyć z MySQL.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ final class PhpMyAdminSso
|
|||||||
if (@file_put_contents($tmpPath, $encoded, LOCK_EX) === false) {
|
if (@file_put_contents($tmpPath, $encoded, LOCK_EX) === false) {
|
||||||
throw new RuntimeException('Nie udało się zapisać ticketu phpMyAdmin.');
|
throw new RuntimeException('Nie udało się zapisać ticketu phpMyAdmin.');
|
||||||
}
|
}
|
||||||
@chmod($tmpPath, 0644);
|
@chmod($tmpPath, 0640);
|
||||||
if (!@rename($tmpPath, $path)) {
|
if (!@rename($tmpPath, $path)) {
|
||||||
@unlink($tmpPath);
|
@unlink($tmpPath);
|
||||||
throw new RuntimeException('Nie udało się aktywować ticketu phpMyAdmin.');
|
throw new RuntimeException('Nie udało się aktywować ticketu phpMyAdmin.');
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@ name=alt-mysql
|
|||||||
id=alt-mysql
|
id=alt-mysql
|
||||||
type=user
|
type=user
|
||||||
author=HITME.PL
|
author=HITME.PL
|
||||||
version=1.2.11
|
version=1.2.12
|
||||||
active=no
|
active=no
|
||||||
installed=no
|
installed=no
|
||||||
user_run_as=root
|
user_run_as=root
|
||||||
|
|||||||
Regular → Executable
Regular → Executable
Regular → Executable
@@ -2,16 +2,23 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
PHPMYADMIN_DIR="${PHPMYADMIN_PRIVATE_DIR:-${PHPMYADMIN_DIR:-/var/www/html/alt-mysql-phpmyadmin}}"
|
PHPMYADMIN_DIR="${PHPMYADMIN_PRIVATE_DIR:-${PHPMYADMIN_DIR:-/var/www/html/alt-mysql-phpmyadmin}}"
|
||||||
|
PHPMYADMIN_URL_PATH="${PHPMYADMIN_URL_PATH:-/alt-mysql-phpmyadmin}"
|
||||||
CONFIG_INC="${PHPMYADMIN_DIR}/config.inc.php"
|
CONFIG_INC="${PHPMYADMIN_DIR}/config.inc.php"
|
||||||
SIGNON_SCRIPT="${PHPMYADMIN_DIR}/da_signon.php"
|
SIGNON_SCRIPT="${PHPMYADMIN_DIR}/da_signon.php"
|
||||||
SIGNON_URL_PAGE="${PHPMYADMIN_DIR}/da_login.php"
|
SIGNON_URL_PAGE="${PHPMYADMIN_DIR}/da_login.php"
|
||||||
RUNTIME_CONFIG="${PHPMYADMIN_DIR}/runtime/config.json"
|
RUNTIME_CONFIG="${PHPMYADMIN_DIR}/runtime/config.json"
|
||||||
|
CUSTOMBUILD_DIR="${CUSTOMBUILD_DIR:-/usr/local/directadmin/custombuild}"
|
||||||
|
APACHE_ALIAS_CUSTOM="${CUSTOMBUILD_DIR}/custom/ap2/conf/extra/httpd-alias.conf"
|
||||||
|
|
||||||
fail() {
|
fail() {
|
||||||
printf 'phpMyAdmin alt-mysql health: %s\n' "$*" >&2
|
printf 'phpMyAdmin alt-mysql health: %s\n' "$*" >&2
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
warn() {
|
||||||
|
printf 'phpMyAdmin alt-mysql health: WARNING: %s\n' "$*" >&2
|
||||||
|
}
|
||||||
|
|
||||||
[ -d "$PHPMYADMIN_DIR" ] || fail "phpMyAdmin directory not found: $PHPMYADMIN_DIR"
|
[ -d "$PHPMYADMIN_DIR" ] || fail "phpMyAdmin directory not found: $PHPMYADMIN_DIR"
|
||||||
[ -r "$PHPMYADMIN_DIR/index.php" ] || fail "phpMyAdmin index.php is not readable: $PHPMYADMIN_DIR/index.php"
|
[ -r "$PHPMYADMIN_DIR/index.php" ] || fail "phpMyAdmin index.php is not readable: $PHPMYADMIN_DIR/index.php"
|
||||||
[ -r "$CONFIG_INC" ] || fail "config.inc.php is not readable: $CONFIG_INC"
|
[ -r "$CONFIG_INC" ] || fail "config.inc.php is not readable: $CONFIG_INC"
|
||||||
@@ -24,6 +31,13 @@ grep -Fq "da_mysql_login_consume_ticket" "$SIGNON_URL_PAGE" || fail "da_login.ph
|
|||||||
grep -Fq "DA_MYSQL_DEFAULT_CONF = '/usr/local/directadmin/conf/alt-mysql.conf'" "$SIGNON_SCRIPT" \
|
grep -Fq "DA_MYSQL_DEFAULT_CONF = '/usr/local/directadmin/conf/alt-mysql.conf'" "$SIGNON_SCRIPT" \
|
||||||
|| fail "signon script does not default to alt-mysql.conf"
|
|| fail "signon script does not default to alt-mysql.conf"
|
||||||
|
|
||||||
|
[ -r "$APACHE_ALIAS_CUSTOM" ] \
|
||||||
|
|| fail "Apache alias config not found: $APACHE_ALIAS_CUSTOM - phpMyAdmin is not reachable over HTTP, run phpmyadmin_install.sh"
|
||||||
|
grep -Fq "# BEGIN ALT_MYSQL_PHPMYADMIN" "$APACHE_ALIAS_CUSTOM" \
|
||||||
|
|| fail "Apache alias block missing in $APACHE_ALIAS_CUSTOM - phpMyAdmin is not reachable over HTTP, run phpmyadmin_install.sh"
|
||||||
|
grep -Fq "Alias ${PHPMYADMIN_URL_PATH} ${PHPMYADMIN_DIR}" "$APACHE_ALIAS_CUSTOM" \
|
||||||
|
|| fail "Apache alias in $APACHE_ALIAS_CUSTOM does not point at $PHPMYADMIN_DIR"
|
||||||
|
|
||||||
if [ -r "$RUNTIME_CONFIG" ] && command -v php >/dev/null 2>&1; then
|
if [ -r "$RUNTIME_CONFIG" ] && command -v php >/dev/null 2>&1; then
|
||||||
php -r '
|
php -r '
|
||||||
$path = $argv[1];
|
$path = $argv[1];
|
||||||
@@ -39,4 +53,25 @@ if [ -r "$RUNTIME_CONFIG" ] && command -v php >/dev/null 2>&1; then
|
|||||||
' "$RUNTIME_CONFIG" || fail "runtime config validation failed"
|
' "$RUNTIME_CONFIG" || fail "runtime config validation failed"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -r "$RUNTIME_CONFIG" ] && command -v php >/dev/null 2>&1 && command -v curl >/dev/null 2>&1; then
|
||||||
|
PROBE_URL="$(php -r '
|
||||||
|
$data = json_decode(file_get_contents($argv[1]), true);
|
||||||
|
$base = trim((string)($data["phpmyadmin_public_base_url"] ?? ""));
|
||||||
|
$path = trim((string)($data["phpmyadmin_url_path"] ?? ""));
|
||||||
|
if ($base === "" || $path === "") {
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
echo rtrim($base, "/") . $path . "/da_login.php";
|
||||||
|
' "$RUNTIME_CONFIG" 2>/dev/null || true)"
|
||||||
|
|
||||||
|
if [ -n "$PROBE_URL" ]; then
|
||||||
|
HTTP_CODE="$(curl -s -o /dev/null -m 5 -w '%{http_code}' "$PROBE_URL" 2>/dev/null || true)"
|
||||||
|
if [ -z "$HTTP_CODE" ] || [ "$HTTP_CODE" = "000" ]; then
|
||||||
|
warn "could not reach $PROBE_URL over HTTP (no response) - verify the webserver serves the Apache alias"
|
||||||
|
elif [ "$HTTP_CODE" = "404" ]; then
|
||||||
|
warn "$PROBE_URL returned HTTP 404 - the Apache alias may not be applied yet, run: cd ${CUSTOMBUILD_DIR} && ./build rewrite_confs && systemctl reload httpd"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
echo "phpMyAdmin alt-mysql health: OK"
|
echo "phpMyAdmin alt-mysql health: OK"
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
PHPMYADMIN_PRIVATE_DIR="${PHPMYADMIN_PRIVATE_DIR:-${PHPMYADMIN_DIR:-/var/www/html/alt-mysql-phpmyadmin}}"
|
PHPMYADMIN_PRIVATE_DIR="${PHPMYADMIN_PRIVATE_DIR:-${PHPMYADMIN_DIR:-/var/www/html/alt-mysql-phpmyadmin}}"
|
||||||
|
PHPMYADMIN_URL_PATH="${PHPMYADMIN_URL_PATH:-/alt-mysql-phpmyadmin}"
|
||||||
PHPMYADMIN_VERSION="${PHPMYADMIN_VERSION:-5.2.3}"
|
PHPMYADMIN_VERSION="${PHPMYADMIN_VERSION:-5.2.3}"
|
||||||
PHPMYADMIN_TARBALL_URL="${PHPMYADMIN_TARBALL_URL:-https://files.phpmyadmin.net/phpMyAdmin/5.2.3/phpMyAdmin-5.2.3-all-languages.tar.gz}"
|
PHPMYADMIN_TARBALL_URL="${PHPMYADMIN_TARBALL_URL:-https://files.phpmyadmin.net/phpMyAdmin/5.2.3/phpMyAdmin-5.2.3-all-languages.tar.gz}"
|
||||||
|
PHPMYADMIN_TARBALL_SHA256="${PHPMYADMIN_TARBALL_SHA256:-}"
|
||||||
PHPMYADMIN_DOWNLOAD_DIR="${PHPMYADMIN_DOWNLOAD_DIR:-/usr/local/src}"
|
PHPMYADMIN_DOWNLOAD_DIR="${PHPMYADMIN_DOWNLOAD_DIR:-/usr/local/src}"
|
||||||
PHPMYADMIN_SOURCE_DIR="${PHPMYADMIN_SOURCE_DIR:-}"
|
PHPMYADMIN_SOURCE_DIR="${PHPMYADMIN_SOURCE_DIR:-}"
|
||||||
RUNTIME_DIR="${PHPMYADMIN_PRIVATE_DIR}/runtime"
|
RUNTIME_DIR="${PHPMYADMIN_PRIVATE_DIR}/runtime"
|
||||||
@@ -12,6 +14,11 @@ CONFIG_INC="${PHPMYADMIN_PRIVATE_DIR}/config.inc.php"
|
|||||||
SIGNON_SCRIPT="${PHPMYADMIN_PRIVATE_DIR}/da_signon.php"
|
SIGNON_SCRIPT="${PHPMYADMIN_PRIVATE_DIR}/da_signon.php"
|
||||||
SIGNON_URL_PAGE="${PHPMYADMIN_PRIVATE_DIR}/da_login.php"
|
SIGNON_URL_PAGE="${PHPMYADMIN_PRIVATE_DIR}/da_login.php"
|
||||||
BLOWFISH_SECRET_FILE="${RUNTIME_DIR}/blowfish_secret"
|
BLOWFISH_SECRET_FILE="${RUNTIME_DIR}/blowfish_secret"
|
||||||
|
CUSTOMBUILD_DIR="${CUSTOMBUILD_DIR:-/usr/local/directadmin/custombuild}"
|
||||||
|
CB_BUILD="${CUSTOMBUILD_DIR}/build"
|
||||||
|
APACHE_ALIAS_CUSTOM="${CUSTOMBUILD_DIR}/custom/ap2/conf/extra/httpd-alias.conf"
|
||||||
|
APACHE_ALIAS_SOURCE="/etc/httpd/conf/extra/httpd-alias.conf"
|
||||||
|
APACHE_ALIAS_CONFIGURE="${CUSTOMBUILD_DIR}/configure/ap2/conf/extra/httpd-alias.conf"
|
||||||
|
|
||||||
if [ "${PHPMYADMIN_INSTALL_ASSUME_ROOT:-0}" != "1" ] && [ "${EUID:-$(id -u)}" -ne 0 ]; then
|
if [ "${PHPMYADMIN_INSTALL_ASSUME_ROOT:-0}" != "1" ] && [ "${EUID:-$(id -u)}" -ne 0 ]; then
|
||||||
echo "Skrypt musi być uruchomiony jako root." >&2
|
echo "Skrypt musi być uruchomiony jako root." >&2
|
||||||
@@ -22,11 +29,54 @@ log() {
|
|||||||
printf 'phpMyAdmin alt-mysql: %s\n' "$*"
|
printf 'phpMyAdmin alt-mysql: %s\n' "$*"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
warn() {
|
||||||
|
printf 'phpMyAdmin alt-mysql: WARNING: %s\n' "$*" >&2
|
||||||
|
}
|
||||||
|
|
||||||
die() {
|
die() {
|
||||||
printf 'phpMyAdmin alt-mysql: %s\n' "$*" >&2
|
printf 'phpMyAdmin alt-mysql: %s\n' "$*" >&2
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chown_or_warn() {
|
||||||
|
local owner="$1" errfile
|
||||||
|
shift
|
||||||
|
errfile="$(mktemp)"
|
||||||
|
chown "$owner" "$@" 2>"$errfile" || warn "chown $owner $* failed: $(cat "$errfile")"
|
||||||
|
rm -f "$errfile"
|
||||||
|
}
|
||||||
|
|
||||||
|
chmod_or_warn() {
|
||||||
|
local mode="$1" errfile
|
||||||
|
shift
|
||||||
|
errfile="$(mktemp)"
|
||||||
|
chmod "$mode" "$@" 2>"$errfile" || warn "chmod $mode $* failed: $(cat "$errfile")"
|
||||||
|
rm -f "$errfile"
|
||||||
|
}
|
||||||
|
|
||||||
|
detect_apache_group() {
|
||||||
|
local group_name=""
|
||||||
|
|
||||||
|
if [ -f /etc/httpd/conf/httpd.conf ]; then
|
||||||
|
group_name="$(awk 'tolower($1)=="group" {print $2; exit}' /etc/httpd/conf/httpd.conf | tr -d '[:space:]')"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$group_name" ] && [ -f /etc/apache2/apache2.conf ]; then
|
||||||
|
group_name="$(awk 'tolower($1)=="group" {print $2; exit}' /etc/apache2/apache2.conf | tr -d '[:space:]')"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$group_name" ]; then
|
||||||
|
for candidate in apache www-data nobody; do
|
||||||
|
if getent group "$candidate" >/dev/null 2>&1; then
|
||||||
|
group_name="$candidate"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '%s\n' "${group_name:-diradmin}"
|
||||||
|
}
|
||||||
|
|
||||||
install_private_copy_from_source() {
|
install_private_copy_from_source() {
|
||||||
local source_dir="$1"
|
local source_dir="$1"
|
||||||
[ -d "$source_dir" ] || die "Katalog źródłowy phpMyAdmin nie istnieje: $source_dir"
|
[ -d "$source_dir" ] || die "Katalog źródłowy phpMyAdmin nie istnieje: $source_dir"
|
||||||
@@ -49,6 +99,16 @@ download_private_copy() {
|
|||||||
curl -fL --retry 3 --connect-timeout 20 -o "$tarball" "$PHPMYADMIN_TARBALL_URL"
|
curl -fL --retry 3 --connect-timeout 20 -o "$tarball" "$PHPMYADMIN_TARBALL_URL"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -n "$PHPMYADMIN_TARBALL_SHA256" ]; then
|
||||||
|
command -v sha256sum >/dev/null 2>&1 || die "Brak sha256sum do weryfikacji archiwum phpMyAdmin."
|
||||||
|
local actual_sum
|
||||||
|
actual_sum="$(sha256sum "$tarball" | awk '{print $1}')"
|
||||||
|
[ "$actual_sum" = "$PHPMYADMIN_TARBALL_SHA256" ] || {
|
||||||
|
rm -f "$tarball"
|
||||||
|
die "Niezgodna suma SHA256 archiwum phpMyAdmin. Oczekiwano: ${PHPMYADMIN_TARBALL_SHA256}, otrzymano: ${actual_sum}"
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
|
||||||
tmp_dir="$(mktemp -d)"
|
tmp_dir="$(mktemp -d)"
|
||||||
tar -xzf "$tarball" -C "$tmp_dir"
|
tar -xzf "$tarball" -C "$tmp_dir"
|
||||||
extracted="$(find "$tmp_dir" -mindepth 1 -maxdepth 1 -type d -name 'phpMyAdmin-*' -print -quit)"
|
extracted="$(find "$tmp_dir" -mindepth 1 -maxdepth 1 -type d -name 'phpMyAdmin-*' -print -quit)"
|
||||||
@@ -474,13 +534,86 @@ function get_login_credentials($user = ''): array
|
|||||||
}
|
}
|
||||||
PHP
|
PHP
|
||||||
|
|
||||||
|
local apache_group
|
||||||
|
apache_group="$(detect_apache_group)"
|
||||||
|
|
||||||
mkdir -p "$RUNTIME_DIR/tmp"
|
mkdir -p "$RUNTIME_DIR/tmp"
|
||||||
chown -R diradmin:diradmin "$RUNTIME_DIR" "$CONFIG_INC" "$SIGNON_SCRIPT" "$SIGNON_URL_PAGE" 2>/dev/null || true
|
chown_or_warn root:root "$PHPMYADMIN_PRIVATE_DIR"
|
||||||
chmod 755 "$RUNTIME_DIR" "$TICKETS_DIR" "$RUNTIME_DIR/tmp" 2>/dev/null || true
|
chmod_or_warn 755 "$PHPMYADMIN_PRIVATE_DIR"
|
||||||
chmod 644 "$CONFIG_INC" "$SIGNON_SCRIPT" "$SIGNON_URL_PAGE" "$RUNTIME_DIR/.htaccess" "$TICKETS_DIR/.htaccess" "$RUNTIME_DIR/index.html" "$TICKETS_DIR/index.html" 2>/dev/null || true
|
chown_or_warn "diradmin:${apache_group}" "$RUNTIME_DIR" "$TICKETS_DIR" "$RUNTIME_DIR/tmp" "$CONFIG_INC" "$SIGNON_SCRIPT" "$SIGNON_URL_PAGE"
|
||||||
|
chmod_or_warn 711 "$RUNTIME_DIR" "$RUNTIME_DIR/tmp"
|
||||||
|
chmod_or_warn 2733 "$TICKETS_DIR"
|
||||||
|
chmod_or_warn 644 "$CONFIG_INC" "$SIGNON_SCRIPT" "$SIGNON_URL_PAGE" "$RUNTIME_DIR/.htaccess" "$TICKETS_DIR/.htaccess" "$RUNTIME_DIR/index.html" "$TICKETS_DIR/index.html"
|
||||||
|
}
|
||||||
|
|
||||||
|
configure_apache_alias() {
|
||||||
|
if [ ! -d "$CUSTOMBUILD_DIR" ]; then
|
||||||
|
warn "Brak katalogu CustomBuild: ${CUSTOMBUILD_DIR} - pomijam konfigurację aliasu Apache. Skonfiguruj go ręcznie: Alias ${PHPMYADMIN_URL_PATH} ${PHPMYADMIN_PRIVATE_DIR}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$(dirname "$APACHE_ALIAS_CUSTOM")"
|
||||||
|
|
||||||
|
if [ ! -f "$APACHE_ALIAS_CUSTOM" ]; then
|
||||||
|
if [ -f "$APACHE_ALIAS_SOURCE" ]; then
|
||||||
|
cp -p "$APACHE_ALIAS_SOURCE" "$APACHE_ALIAS_CUSTOM"
|
||||||
|
elif [ -f "$APACHE_ALIAS_CONFIGURE" ]; then
|
||||||
|
cp -p "$APACHE_ALIAS_CONFIGURE" "$APACHE_ALIAS_CUSTOM"
|
||||||
|
else
|
||||||
|
warn "Nie znaleziono źródłowego httpd-alias.conf - tworzę pusty szablon custom."
|
||||||
|
: > "$APACHE_ALIAS_CUSTOM"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
local tmp_file
|
||||||
|
tmp_file="$(mktemp)"
|
||||||
|
awk '
|
||||||
|
BEGIN { skip = 0 }
|
||||||
|
/^# BEGIN ALT_MYSQL_PHPMYADMIN$/ { skip = 1; next }
|
||||||
|
/^# END ALT_MYSQL_PHPMYADMIN$/ { skip = 0; next }
|
||||||
|
skip == 0 { print }
|
||||||
|
' "$APACHE_ALIAS_CUSTOM" > "$tmp_file"
|
||||||
|
|
||||||
|
cat >> "$tmp_file" <<EOF
|
||||||
|
|
||||||
|
# BEGIN ALT_MYSQL_PHPMYADMIN
|
||||||
|
Alias ${PHPMYADMIN_URL_PATH} ${PHPMYADMIN_PRIVATE_DIR}
|
||||||
|
|
||||||
|
<Directory "${PHPMYADMIN_PRIVATE_DIR}">
|
||||||
|
AllowOverride None
|
||||||
|
Options -Indexes
|
||||||
|
Require all granted
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
<Directory "${RUNTIME_DIR}">
|
||||||
|
AllowOverride None
|
||||||
|
Options -Indexes
|
||||||
|
Require all denied
|
||||||
|
</Directory>
|
||||||
|
# END ALT_MYSQL_PHPMYADMIN
|
||||||
|
EOF
|
||||||
|
|
||||||
|
mv "$tmp_file" "$APACHE_ALIAS_CUSTOM"
|
||||||
|
chmod_or_warn 644 "$APACHE_ALIAS_CUSTOM"
|
||||||
|
}
|
||||||
|
|
||||||
|
apply_apache_alias() {
|
||||||
|
if [ -x "$CB_BUILD" ]; then
|
||||||
|
(cd "$CUSTOMBUILD_DIR" && ./build rewrite_confs) || warn "rewrite_confs zakończyło się błędem - uruchom ręcznie: cd ${CUSTOMBUILD_DIR} && ./build rewrite_confs"
|
||||||
|
else
|
||||||
|
warn "Brak ${CB_BUILD} - uruchom ręcznie: cd ${CUSTOMBUILD_DIR} && ./build rewrite_confs"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v systemctl >/dev/null 2>&1 && systemctl is-active --quiet httpd 2>/dev/null; then
|
||||||
|
systemctl reload httpd || warn "Nie udało się przeładować httpd."
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
ensure_private_copy
|
ensure_private_copy
|
||||||
write_private_config
|
write_private_config
|
||||||
|
configure_apache_alias
|
||||||
|
if [ "${PHPMYADMIN_SKIP_APACHE_RELOAD:-0}" != "1" ]; then
|
||||||
|
apply_apache_alias
|
||||||
|
fi
|
||||||
|
|
||||||
log "Prywatna kopia phpMyAdmin dla alt-mysql jest gotowa w ${PHPMYADMIN_PRIVATE_DIR}."
|
log "Prywatna kopia phpMyAdmin dla alt-mysql jest gotowa w ${PHPMYADMIN_PRIVATE_DIR}."
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
$pluginDir = dirname(__DIR__);
|
||||||
|
require_once $pluginDir . '/exec/lib/Settings.php';
|
||||||
|
require_once $pluginDir . '/exec/lib/MySQLService.php';
|
||||||
|
|
||||||
|
function fail(string $message): void
|
||||||
|
{
|
||||||
|
fwrite(STDERR, "FAIL: {$message}\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function assert_true(bool $condition, string $message): void
|
||||||
|
{
|
||||||
|
if (!$condition) {
|
||||||
|
fail($message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$logPath = tempnam(sys_get_temp_dir(), 'altmysql-error-log-');
|
||||||
|
if ($logPath === false) {
|
||||||
|
fail('cannot create temp log file');
|
||||||
|
}
|
||||||
|
ini_set('log_errors', '1');
|
||||||
|
ini_set('error_log', $logPath);
|
||||||
|
|
||||||
|
$settingsPath = tempnam(sys_get_temp_dir(), 'altmysql-settings-');
|
||||||
|
file_put_contents($settingsPath, '');
|
||||||
|
$settings = Settings::load($settingsPath);
|
||||||
|
unlink($settingsPath);
|
||||||
|
|
||||||
|
$mysql = new MySQLService([
|
||||||
|
'host' => '127.0.0.1',
|
||||||
|
'port' => 1,
|
||||||
|
'database' => 'mysql',
|
||||||
|
'user' => 'nobody',
|
||||||
|
'password' => 'nopassword',
|
||||||
|
'socket' => '',
|
||||||
|
], $settings);
|
||||||
|
|
||||||
|
$threw = false;
|
||||||
|
try {
|
||||||
|
$mysql->serverVersion();
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
$threw = true;
|
||||||
|
}
|
||||||
|
assert_true($threw, 'connecting to a closed port must still raise an exception');
|
||||||
|
|
||||||
|
$logContents = (string)file_get_contents($logPath);
|
||||||
|
assert_true(
|
||||||
|
str_contains($logContents, 'MYSQL_CONNECT_FAIL'),
|
||||||
|
'a failed MySQL connection must be logged for diagnosis (expected MYSQL_CONNECT_FAIL marker in error log, got: ' . $logContents . ')'
|
||||||
|
);
|
||||||
|
assert_true(
|
||||||
|
str_contains($logContents, '127.0.0.1'),
|
||||||
|
'the connect-failure log line must include the target host for diagnosis'
|
||||||
|
);
|
||||||
|
|
||||||
|
unlink($logPath);
|
||||||
|
|
||||||
|
echo "mysql_connect_failure_test: OK\n";
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
PLUGIN_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
PLUGIN_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
ARCHIVE="${1:-$(cd "$PLUGIN_DIR/.." && pwd)/archives/1.2.11/alt-mysql.tar.gz}"
|
ARCHIVE="${1:-$(cd "$PLUGIN_DIR/.." && pwd)/archives/1.2.12/alt-mysql.tar.gz}"
|
||||||
|
|
||||||
fail() {
|
fail() {
|
||||||
echo "FAIL: $*" >&2
|
echo "FAIL: $*" >&2
|
||||||
@@ -37,7 +37,7 @@ fi
|
|||||||
CONF="$(tar -xOzf "$ARCHIVE" ./plugin.conf 2>/dev/null || tar -xOzf "$ARCHIVE" plugin.conf)"
|
CONF="$(tar -xOzf "$ARCHIVE" ./plugin.conf 2>/dev/null || tar -xOzf "$ARCHIVE" plugin.conf)"
|
||||||
printf '%s\n' "$CONF" | grep -Fxq "name=alt-mysql" || fail "archive plugin name is not alt-mysql"
|
printf '%s\n' "$CONF" | grep -Fxq "name=alt-mysql" || fail "archive plugin name is not alt-mysql"
|
||||||
printf '%s\n' "$CONF" | grep -Fxq "id=alt-mysql" || fail "archive plugin id is not alt-mysql"
|
printf '%s\n' "$CONF" | grep -Fxq "id=alt-mysql" || fail "archive plugin id is not alt-mysql"
|
||||||
printf '%s\n' "$CONF" | grep -Fxq "version=1.2.11" || fail "archive plugin version is not 1.2.11"
|
printf '%s\n' "$CONF" | grep -Fxq "version=1.2.12" || fail "archive plugin version is not 1.2.12"
|
||||||
|
|
||||||
SETTINGS="$(tar -xOzf "$ARCHIVE" ./plugin-settings.conf 2>/dev/null || tar -xOzf "$ARCHIVE" plugin-settings.conf)"
|
SETTINGS="$(tar -xOzf "$ARCHIVE" ./plugin-settings.conf 2>/dev/null || tar -xOzf "$ARCHIVE" plugin-settings.conf)"
|
||||||
printf '%s\n' "$SETTINGS" | grep -Fxq "PHPMYADMIN_INSTALL_DIR=/var/www/html/alt-mysql-phpmyadmin" \
|
printf '%s\n' "$SETTINGS" | grep -Fxq "PHPMYADMIN_INSTALL_DIR=/var/www/html/alt-mysql-phpmyadmin" \
|
||||||
|
|||||||
@@ -16,21 +16,19 @@ grep -Fq 'PHPMYADMIN_VERSION="${PHPMYADMIN_VERSION:-5.2.3}"' "$SCRIPT" \
|
|||||||
grep -Fq 'PHPMYADMIN_TARBALL_URL="${PHPMYADMIN_TARBALL_URL:-https://files.phpmyadmin.net/phpMyAdmin/5.2.3/phpMyAdmin-5.2.3-all-languages.tar.gz}"' "$SCRIPT" \
|
grep -Fq 'PHPMYADMIN_TARBALL_URL="${PHPMYADMIN_TARBALL_URL:-https://files.phpmyadmin.net/phpMyAdmin/5.2.3/phpMyAdmin-5.2.3-all-languages.tar.gz}"' "$SCRIPT" \
|
||||||
|| fail "phpMyAdmin tarball URL is not the explicit 5.2.3 URL"
|
|| fail "phpMyAdmin tarball URL is not the explicit 5.2.3 URL"
|
||||||
|
|
||||||
mkdir -p "$TMP_DIR/phpMyAdmin"
|
|
||||||
cat > "$TMP_DIR/phpMyAdmin/config.inc.php" <<'PHP'
|
|
||||||
<?php
|
|
||||||
$cfg = [];
|
|
||||||
PHP
|
|
||||||
mkdir -p "$TMP_DIR/phpMyAdmin-source"
|
mkdir -p "$TMP_DIR/phpMyAdmin-source"
|
||||||
cat > "$TMP_DIR/phpMyAdmin-source/index.php" <<'PHP'
|
cat > "$TMP_DIR/phpMyAdmin-source/index.php" <<'PHP'
|
||||||
<?php
|
<?php
|
||||||
echo 'private phpMyAdmin';
|
echo 'private phpMyAdmin';
|
||||||
PHP
|
PHP
|
||||||
|
|
||||||
PHPMYADMIN_EXISTING_DIR="$TMP_DIR/phpMyAdmin" \
|
CUSTOMBUILD_DIR="$TMP_DIR/custombuild"
|
||||||
|
mkdir -p "$CUSTOMBUILD_DIR"
|
||||||
|
|
||||||
PHPMYADMIN_PRIVATE_DIR="$TMP_DIR/alt-mysql-phpmyadmin" \
|
PHPMYADMIN_PRIVATE_DIR="$TMP_DIR/alt-mysql-phpmyadmin" \
|
||||||
PHPMYADMIN_SOURCE_DIR="$TMP_DIR/phpMyAdmin-source" \
|
PHPMYADMIN_SOURCE_DIR="$TMP_DIR/phpMyAdmin-source" \
|
||||||
PHPMYADMIN_INSTALL_ASSUME_ROOT=1 \
|
PHPMYADMIN_INSTALL_ASSUME_ROOT=1 \
|
||||||
|
CUSTOMBUILD_DIR="$CUSTOMBUILD_DIR" \
|
||||||
bash "$SCRIPT" >/dev/null
|
bash "$SCRIPT" >/dev/null
|
||||||
|
|
||||||
PRIVATE_DIR="$TMP_DIR/alt-mysql-phpmyadmin"
|
PRIVATE_DIR="$TMP_DIR/alt-mysql-phpmyadmin"
|
||||||
@@ -39,15 +37,27 @@ SIGNON_SCRIPT="$PRIVATE_DIR/da_signon.php"
|
|||||||
SIGNON_URL_PAGE="$PRIVATE_DIR/da_login.php"
|
SIGNON_URL_PAGE="$PRIVATE_DIR/da_login.php"
|
||||||
TICKET_DIR="$PRIVATE_DIR/runtime/tickets"
|
TICKET_DIR="$PRIVATE_DIR/runtime/tickets"
|
||||||
SESSION_DIR="$TMP_DIR/sessions"
|
SESSION_DIR="$TMP_DIR/sessions"
|
||||||
|
ALIAS_CONF="$CUSTOMBUILD_DIR/custom/ap2/conf/extra/httpd-alias.conf"
|
||||||
|
|
||||||
[ -r "$PRIVATE_DIR/index.php" ] || fail "private phpMyAdmin copy was not installed"
|
[ -r "$PRIVATE_DIR/index.php" ] || fail "private phpMyAdmin copy was not installed"
|
||||||
[ -r "$CONFIG_INC" ] || fail "private phpMyAdmin config was not created"
|
[ -r "$CONFIG_INC" ] || fail "private phpMyAdmin config was not created"
|
||||||
[ -r "$SIGNON_SCRIPT" ] || fail "signon script was not created"
|
[ -r "$SIGNON_SCRIPT" ] || fail "signon script was not created"
|
||||||
[ -r "$SIGNON_URL_PAGE" ] || fail "phpMyAdmin SignonURL page was not created"
|
[ -r "$SIGNON_URL_PAGE" ] || fail "phpMyAdmin SignonURL page was not created"
|
||||||
[ -d "$TICKET_DIR" ] || fail "phpMyAdmin ticket directory was not created"
|
[ -d "$TICKET_DIR" ] || fail "phpMyAdmin ticket directory was not created"
|
||||||
if grep -Fq "config.mysql.inc.php" "$TMP_DIR/phpMyAdmin/config.inc.php"; then
|
|
||||||
fail "installer modified existing CustomBuild phpMyAdmin config"
|
[ -r "$ALIAS_CONF" ] || fail "Apache alias config was not created"
|
||||||
fi
|
grep -Fq "# BEGIN ALT_MYSQL_PHPMYADMIN" "$ALIAS_CONF" || fail "Apache alias block marker missing"
|
||||||
|
grep -Fq "Alias /alt-mysql-phpmyadmin ${PRIVATE_DIR}" "$ALIAS_CONF" || fail "Apache alias does not point at private phpMyAdmin dir"
|
||||||
|
grep -Fq "# END ALT_MYSQL_PHPMYADMIN" "$ALIAS_CONF" || fail "Apache alias end marker missing"
|
||||||
|
|
||||||
|
PHPMYADMIN_PRIVATE_DIR="$TMP_DIR/alt-mysql-phpmyadmin" \
|
||||||
|
PHPMYADMIN_SOURCE_DIR="$TMP_DIR/phpMyAdmin-source" \
|
||||||
|
PHPMYADMIN_INSTALL_ASSUME_ROOT=1 \
|
||||||
|
CUSTOMBUILD_DIR="$CUSTOMBUILD_DIR" \
|
||||||
|
bash "$SCRIPT" >/dev/null
|
||||||
|
|
||||||
|
BEGIN_COUNT="$(grep -Fc "# BEGIN ALT_MYSQL_PHPMYADMIN" "$ALIAS_CONF" || true)"
|
||||||
|
[ "$BEGIN_COUNT" -eq 1 ] || fail "Apache alias block was duplicated on re-run (found $BEGIN_COUNT times)"
|
||||||
|
|
||||||
SERVER_JSON="$(php -r '
|
SERVER_JSON="$(php -r '
|
||||||
$_SERVER["HTTPS"] = "on";
|
$_SERVER["HTTPS"] = "on";
|
||||||
@@ -143,7 +153,16 @@ php -d session.save_path="$SESSION_DIR" -r '
|
|||||||
exit(3);
|
exit(3);
|
||||||
}
|
}
|
||||||
' "$SIGNON_SCRIPT" || fail "signon script cannot read SSO session while phpMyAdmin session is active"
|
' "$SIGNON_SCRIPT" || fail "signon script cannot read SSO session while phpMyAdmin session is active"
|
||||||
PHPMYADMIN_PRIVATE_DIR="$PRIVATE_DIR" bash "$PLUGIN_DIR/scripts/setup/phpmyadmin_health_check.sh" >/dev/null \
|
PHPMYADMIN_PRIVATE_DIR="$PRIVATE_DIR" CUSTOMBUILD_DIR="$CUSTOMBUILD_DIR" \
|
||||||
|| fail "phpMyAdmin health check should pass for SignonURL-capable config"
|
bash "$PLUGIN_DIR/scripts/setup/phpmyadmin_health_check.sh" >/dev/null \
|
||||||
|
|| fail "phpMyAdmin health check should pass for SignonURL-capable config with Apache alias present"
|
||||||
|
|
||||||
|
EMPTY_CUSTOMBUILD_DIR="$TMP_DIR/custombuild-empty"
|
||||||
|
mkdir -p "$EMPTY_CUSTOMBUILD_DIR"
|
||||||
|
HEALTH_OUTPUT="$(PHPMYADMIN_PRIVATE_DIR="$PRIVATE_DIR" CUSTOMBUILD_DIR="$EMPTY_CUSTOMBUILD_DIR" \
|
||||||
|
bash "$PLUGIN_DIR/scripts/setup/phpmyadmin_health_check.sh" 2>&1)" \
|
||||||
|
&& fail "phpMyAdmin health check should fail when the Apache alias is missing"
|
||||||
|
echo "$HEALTH_OUTPUT" | grep -Fqi "alias" \
|
||||||
|
|| fail "phpMyAdmin health check failure message should mention the missing Apache alias (got: $HEALTH_OUTPUT)"
|
||||||
|
|
||||||
echo "phpmyadmin_install_test: OK"
|
echo "phpmyadmin_install_test: OK"
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
$pluginDir = dirname(__DIR__);
|
||||||
|
require_once $pluginDir . '/exec/lib/Settings.php';
|
||||||
|
require_once $pluginDir . '/exec/lib/MySQLService.php';
|
||||||
|
require_once $pluginDir . '/exec/lib/PhpMyAdminSso.php';
|
||||||
|
|
||||||
|
function fail(string $message): void
|
||||||
|
{
|
||||||
|
fwrite(STDERR, "FAIL: {$message}\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function assert_true(bool $condition, string $message): void
|
||||||
|
{
|
||||||
|
if (!$condition) {
|
||||||
|
fail($message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function assert_same($expected, $actual, string $message): void
|
||||||
|
{
|
||||||
|
if ($expected !== $actual) {
|
||||||
|
fail($message . ' expected=' . var_export($expected, true) . ' actual=' . var_export($actual, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function load_settings(string $contents): Settings
|
||||||
|
{
|
||||||
|
$path = tempnam(sys_get_temp_dir(), 'altmysql-settings-');
|
||||||
|
if ($path === false) {
|
||||||
|
fail('cannot create temp settings file');
|
||||||
|
}
|
||||||
|
file_put_contents($path, $contents);
|
||||||
|
$settings = Settings::load($path);
|
||||||
|
unlink($path);
|
||||||
|
return $settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Temporary SSO role must be host-scoped, not wildcard '%' ---
|
||||||
|
|
||||||
|
$mysqlServiceSource = (string)file_get_contents($pluginDir . '/exec/lib/MySQLService.php');
|
||||||
|
assert_true(
|
||||||
|
!str_contains($mysqlServiceSource, "@\\'%\\'"),
|
||||||
|
'MySQLService must not create/grant/drop temporary phpMyAdmin SSO roles on the wildcard host (%)'
|
||||||
|
);
|
||||||
|
|
||||||
|
$mysqlServiceClass = new ReflectionClass(MySQLService::class);
|
||||||
|
assert_true($mysqlServiceClass->hasConstant('TMP_ROLE_HOST'), 'MySQLService must define a TMP_ROLE_HOST constant');
|
||||||
|
assert_same('127.0.0.1', $mysqlServiceClass->getConstant('TMP_ROLE_HOST'), 'TMP_ROLE_HOST must scope the temporary SSO role to the phpMyAdmin app host');
|
||||||
|
|
||||||
|
// --- phpMyAdmin login ticket files must not be world-readable ---
|
||||||
|
|
||||||
|
$ssoDir = sys_get_temp_dir() . '/altmysql-pma-sso-' . bin2hex(random_bytes(4));
|
||||||
|
mkdir($ssoDir, 0755, true);
|
||||||
|
|
||||||
|
$settings = load_settings("PHPMYADMIN_SSO_DIR={$ssoDir}\nPHPMYADMIN_TICKET_TTL=60\n");
|
||||||
|
|
||||||
|
$ssoClass = new ReflectionClass(PhpMyAdminSso::class);
|
||||||
|
/** @var PhpMyAdminSso $sso */
|
||||||
|
$sso = $ssoClass->newInstanceWithoutConstructor();
|
||||||
|
$settingsProp = $ssoClass->getProperty('settings');
|
||||||
|
$settingsProp->setAccessible(true);
|
||||||
|
$settingsProp->setValue($sso, $settings);
|
||||||
|
|
||||||
|
$writeTicket = $ssoClass->getMethod('writeLoginTicket');
|
||||||
|
$writeTicket->setAccessible(true);
|
||||||
|
$auth = [
|
||||||
|
'user' => 'da_tmp_phpmyadmin_demo_test',
|
||||||
|
'password' => 'secret-password',
|
||||||
|
'host' => '127.0.0.1',
|
||||||
|
'port' => 33033,
|
||||||
|
'db' => 'demo_db',
|
||||||
|
];
|
||||||
|
$token = $writeTicket->invoke($sso, $auth, 'demo_db');
|
||||||
|
|
||||||
|
assert_true(preg_match('/\A[a-f0-9]{64}\z/', $token) === 1, 'ticket token must be a 64 char lowercase hex string');
|
||||||
|
|
||||||
|
$ticketPath = $ssoDir . '/tickets/' . $token . '.json';
|
||||||
|
assert_true(is_file($ticketPath), 'ticket file must be written to <sso_dir>/tickets/<token>.json');
|
||||||
|
|
||||||
|
$mode = fileperms($ticketPath) & 0777;
|
||||||
|
assert_same(0640, $mode, 'ticket files contain a plaintext MySQL password and must not be world-readable (expected 0640)');
|
||||||
|
|
||||||
|
$decoded = json_decode((string)file_get_contents($ticketPath), true);
|
||||||
|
assert_true(is_array($decoded), 'ticket file must contain valid JSON');
|
||||||
|
assert_same('demo_db', $decoded['db'] ?? null, 'ticket must record the target database');
|
||||||
|
assert_same('da_tmp_phpmyadmin_demo_test', $decoded['auth']['user'] ?? null, 'ticket must record the temporary role name');
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
array_map('unlink', glob($ssoDir . '/tickets/*') ?: []);
|
||||||
|
@rmdir($ssoDir . '/tickets');
|
||||||
|
@rmdir($ssoDir);
|
||||||
|
|
||||||
|
echo "phpmyadmin_sso_test: OK\n";
|
||||||
@@ -14,7 +14,7 @@ case "$(basename "$PLUGIN_DIR")" in
|
|||||||
esac
|
esac
|
||||||
grep -Fxq "name=alt-mysql" "$PLUGIN_DIR/plugin.conf" || fail "plugin.conf name is not alt-mysql"
|
grep -Fxq "name=alt-mysql" "$PLUGIN_DIR/plugin.conf" || fail "plugin.conf name is not alt-mysql"
|
||||||
grep -Fxq "id=alt-mysql" "$PLUGIN_DIR/plugin.conf" || fail "plugin.conf id is not alt-mysql"
|
grep -Fxq "id=alt-mysql" "$PLUGIN_DIR/plugin.conf" || fail "plugin.conf id is not alt-mysql"
|
||||||
grep -Fxq "version=1.2.11" "$PLUGIN_DIR/plugin.conf" || fail "plugin.conf version is not 1.2.11"
|
grep -Fxq "version=1.2.12" "$PLUGIN_DIR/plugin.conf" || fail "plugin.conf version is not 1.2.12"
|
||||||
grep -Fq "return '/CMD_PLUGINS/alt-mysql';" "$PLUGIN_DIR/exec/lib/AppContext.php" \
|
grep -Fq "return '/CMD_PLUGINS/alt-mysql';" "$PLUGIN_DIR/exec/lib/AppContext.php" \
|
||||||
|| fail "AppContext base URL is not alt-mysql"
|
|| fail "AppContext base URL is not alt-mysql"
|
||||||
grep -Fq "\$pluginId = 'alt-mysql';" "$PLUGIN_DIR/exec/lib/DirectAdminUser.php" \
|
grep -Fq "\$pluginId = 'alt-mysql';" "$PLUGIN_DIR/exec/lib/DirectAdminUser.php" \
|
||||||
|
|||||||
Reference in New Issue
Block a user