Immer wieder gibt es Software, welche vorschreibt, wie genau ein Passwort auszusehen hat. Der UniFi OS Server ist eine davon und erlaubt es nicht, die Richtlinie anzupassen. Mit folgendem Bash-Skript kann das Passwort über die undokumentierte API beliebig geändert werden.
#!/usr/bin/env bash
set -u
if [[ $# -ne 3 ]]; then
echo "Verwendung: $0 <Server-IP> '<altes-passwort>' '<neues-passwort>'"
exit 1
fi
USER="admin"
BASE_URL="https://$1:11443"
OLD_PASSWORD="$2"
NEW_PASSWORD="$3"
LOGIN_BODY="$(mktemp)"
LOGIN_HEADERS="$(mktemp)"
PASSWORD_BODY="$(mktemp)"
PASSWORD_HEADERS="$(mktemp)"
trap 'rm -f "$LOGIN_BODY" "$LOGIN_HEADERS" "$PASSWORD_BODY" "$PASSWORD_HEADERS"' EXIT
# Login
LOGIN_JSON="$(
jq -n \
--arg username "$USER" \
--arg password "$OLD_PASSWORD" \
'{
username: $username,
password: $password
}'
)"
wget \
--no-check-certificate \
--quiet \
--server-response \
--header="Content-Type: application/json" \
--post-data="$LOGIN_JSON" \
-O "$LOGIN_BODY" \
"$BASE_URL/api/auth/login" \
2>"$LOGIN_HEADERS"
HTTP_STATUS="$(
sed -n 's/^ HTTP\/[^ ]* \([0-9][0-9][0-9]\).*/\1/p' "$LOGIN_HEADERS" | tail -n 1
)"
if [[ "$HTTP_STATUS" != "200" ]]; then
echo "Login fehlgeschlagen (HTTP $HTTP_STATUS)."
if [[ -s "$LOGIN_BODY" ]]; then
cat "$LOGIN_BODY"
else
cat "$LOGIN_HEADERS"
fi
exit 1
fi
USER_UUID="$(jq -r '.id // empty' "$LOGIN_BODY")"
if [[ -z "$USER_UUID" ]]; then
echo "Fehler: Keine User-UUID in der Login-Antwort gefunden."
exit 1
fi
TOKEN="$(sed -n 's/.*Set-Cookie: TOKEN=\([^;]*\).*/\1/p' "$LOGIN_HEADERS" | tail -n 1)"
if [[ -z "$TOKEN" ]]; then
echo "Fehler: Kein TOKEN-Cookie gefunden."
exit 1
fi
JWT_PAYLOAD="$(
printf '%s' "$TOKEN" |
cut -d. -f2 |
tr '_-' '/+' |
awk '{l=length($0)%4; if(l==2) printf "%s==",$0; else if(l==3) printf "%s=",$0; else printf "%s",$0}' |
base64 -d 2>/dev/null
)"
CSRF_TOKEN="$(
printf '%s' "$JWT_PAYLOAD" |
jq -r '.csrfToken // empty'
)"
if [[ -z "$CSRF_TOKEN" ]]; then
echo "Kein csrfToken im JWT gefunden."
exit 1
fi
echo "Login erfolgreich."
echo " User-UUID: $USER_UUID"
echo " JWT: $TOKEN"
echo " csrfToken: $CSRF_TOKEN"
# Passwort ändern
PASSWORD_JSON="$(
jq -n \
--arg password "$NEW_PASSWORD" \
'{
password: $password
}'
)"
wget \
--no-check-certificate \
--quiet \
--server-response \
--header="Content-Type: application/json" \
--header="Cookie: TOKEN=$TOKEN" \
--header="X-CSRF-Token: $CSRF_TOKEN" \
--body-data="$PASSWORD_JSON" \
--method=PUT \
-O "$PASSWORD_BODY" \
"$BASE_URL/proxy/users/api/v2/user/$USER_UUID" \
2>"$PASSWORD_HEADERS"
HTTP_STATUS="$(sed -n 's/.*HTTP\/[^ ]* \([0-9][0-9][0-9]\).*/\1/p' "$PASSWORD_HEADERS" | tail -n 1)"
if [[ "$HTTP_STATUS" != "200" ]]; then
echo "Passwortänderung fehlgeschlagen (HTTP $HTTP_STATUS)."
if [[ -s "$PASSWORD_BODY" ]]; then
cat "$PASSWORD_BODY"
else
cat "$PASSWORD_HEADERS"
fi
exit 1
fi
echo "Passwort erfolgreich geändert."