141 lines
5.2 KiB
Bash
Executable File
141 lines
5.2 KiB
Bash
Executable File
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
# Get the directory where this script is located
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
|
|
USERNAME=$(pass_mgr get-username --key git)
|
|
KC_PASS=$(pass_mgr get-secret --key keycloak)
|
|
GITEA_PASS=$(pass_mgr get-secret --key git)
|
|
|
|
if [[ -z "$USERNAME" || -z "$KC_PASS" || -z "$GITEA_PASS" ]]; then
|
|
echo "[ERROR] Missing required credentials in pass_mgr" >&2
|
|
exit 1
|
|
fi
|
|
|
|
sql_escape() {
|
|
printf '%s' "$1" | sed "s/'/''/g"
|
|
}
|
|
|
|
WORKDIR="/tmp"
|
|
COOKIES_FILE="$WORKDIR/${USERNAME}_oidc_cookies.txt"
|
|
KC_LOGIN_HTML="$WORKDIR/${USERNAME}_kc_login.html"
|
|
KC_POST_LOGIN_HTML="$WORKDIR/${USERNAME}_kc_post_login.html"
|
|
KC_POST_LOGIN_LOG="$WORKDIR/${USERNAME}_kc_post_login.log"
|
|
GITEA_CALLBACK_HTML="$WORKDIR/${USERNAME}_gitea_after_callback.html"
|
|
GITEA_LINK_HTML="$WORKDIR/${USERNAME}_gitea_link_account.html"
|
|
GITEA_LINK_RESP_HTML="$WORKDIR/${USERNAME}_gitea_link_signin.html"
|
|
GITEA_LINK_RESP_LOG="$WORKDIR/${USERNAME}_gitea_link_signin.log"
|
|
|
|
OIDC_URL="https://git.hangman-lab.top/user/oauth2/hangman-lab"
|
|
ESCAPED_USERNAME=$(sql_escape "$USERNAME")
|
|
|
|
cleanup() {
|
|
"$SCRIPT_DIR/external-login-ctrl" --disable >/dev/null 2>&1 || true
|
|
if [[ -n "${ORIG_LOGIN_TYPE:-}" && -n "${ORIG_LOGIN_SOURCE:-}" ]]; then
|
|
ssh root@vps.git "
|
|
set -euo pipefail
|
|
. /root/git-kc/.env
|
|
docker exec -i git-kc-mysql mysql -uroot -p\"\$MYSQL_ROOT_PASSWORD\" giteadb -e \"UPDATE user SET login_type=${ORIG_LOGIN_TYPE}, login_source=${ORIG_LOGIN_SOURCE}, login_name=${ORIG_LOGIN_NAME_SQL:-NULL} WHERE name='${ESCAPED_USERNAME}';\"
|
|
" >/dev/null 2>&1 || true
|
|
fi
|
|
rm -f "$COOKIES_FILE" "$KC_LOGIN_HTML" "$KC_POST_LOGIN_HTML" "$KC_POST_LOGIN_LOG" \
|
|
"$GITEA_CALLBACK_HTML" "$GITEA_LINK_HTML" "$GITEA_LINK_RESP_HTML" "$GITEA_LINK_RESP_LOG"
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
rm -f "$COOKIES_FILE" "$KC_LOGIN_HTML" "$KC_POST_LOGIN_HTML" "$KC_POST_LOGIN_LOG" \
|
|
"$GITEA_CALLBACK_HTML" "$GITEA_LINK_HTML" "$GITEA_LINK_RESP_HTML" "$GITEA_LINK_RESP_LOG"
|
|
|
|
# Capture original login fields so we can restore them exactly.
|
|
ORIG_STATE=$(ssh root@vps.git "
|
|
set -euo pipefail
|
|
. /root/git-kc/.env
|
|
docker exec -i git-kc-mysql mysql -N -B -uroot -p\"\$MYSQL_ROOT_PASSWORD\" giteadb -e \"SELECT login_type, login_source, COALESCE(login_name, '__NULL__') FROM user WHERE name='${ESCAPED_USERNAME}' LIMIT 1;\"
|
|
")
|
|
|
|
if [[ -z "$ORIG_STATE" ]]; then
|
|
echo "[ERROR] User not found in Gitea DB: $USERNAME" >&2
|
|
exit 1
|
|
fi
|
|
|
|
IFS=$'\t' read -r ORIG_LOGIN_TYPE ORIG_LOGIN_SOURCE ORIG_LOGIN_NAME <<< "$ORIG_STATE"
|
|
if [[ "$ORIG_LOGIN_NAME" == "__NULL__" ]]; then
|
|
ORIG_LOGIN_NAME_SQL="NULL"
|
|
else
|
|
ORIG_LOGIN_NAME_SQL="'$(sql_escape "$ORIG_LOGIN_NAME")'"
|
|
fi
|
|
|
|
"$SCRIPT_DIR/external-login-ctrl" --enable
|
|
|
|
echo "[INFO] 通过 OIDC 入口触发跳转,获取 Keycloak 登录页..."
|
|
curl -s -L -c "$COOKIES_FILE" "$OIDC_URL" -o "$KC_LOGIN_HTML"
|
|
|
|
KC_LOGIN_URL=$(perl -ne '
|
|
if(/<form id="kc-form-login"/ .. /<\/form>/){
|
|
if(/action="([^"]+)"/){
|
|
my $u=$1; $u=~s/&/&/g; print $u; exit
|
|
}
|
|
}
|
|
' "$KC_LOGIN_HTML")
|
|
|
|
if [[ -z "${KC_LOGIN_URL:-}" ]]; then
|
|
echo "[ERROR] 未找到 kc-form-login 表单的 action URL" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "[INFO] 登录 Keycloak..."
|
|
curl -v "$KC_LOGIN_URL" \
|
|
-b "$COOKIES_FILE" -c "$COOKIES_FILE" \
|
|
--data-urlencode "username=$USERNAME" \
|
|
--data-urlencode "password=$KC_PASS" \
|
|
-d "credentialId=" \
|
|
-o "$KC_POST_LOGIN_HTML" \
|
|
2>"$KC_POST_LOGIN_LOG" || true
|
|
|
|
GITEA_CALLBACK_URL=$(grep -i "location: https://git.hangman-lab.top" "$KC_POST_LOGIN_LOG" | sed -E 's/.*location: (https:[^\r]+).*/\1/i' | tail -n1)
|
|
|
|
if [[ -z "${GITEA_CALLBACK_URL:-}" ]]; then
|
|
echo "[ERROR] 登录后未发现返回 Gitea 的 callback URL" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "[INFO] 调用 Gitea 回调..."
|
|
curl -s -L -b "$COOKIES_FILE" -c "$COOKIES_FILE" "$GITEA_CALLBACK_URL" -o "$GITEA_CALLBACK_HTML"
|
|
|
|
echo "[INFO] 访问 Gitea Link Account 页面..."
|
|
curl -s -b "$COOKIES_FILE" "https://git.hangman-lab.top/user/link_account" -o "$GITEA_LINK_HTML"
|
|
|
|
CSRF_TOKEN=$(perl -ne 'if(/name="_csrf" value="([^"]+)"/){print $1; exit}' "$GITEA_LINK_HTML" || true)
|
|
|
|
if [[ -z "${CSRF_TOKEN:-}" ]]; then
|
|
echo "[ERROR] 未能从 Link Account 页面解析出 _csrf" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "[INFO] 临时将 login_type 改为本地登录..."
|
|
ssh root@vps.git "
|
|
set -euo pipefail
|
|
. /root/git-kc/.env
|
|
docker exec -i git-kc-mysql mysql -uroot -p\"\$MYSQL_ROOT_PASSWORD\" giteadb -e \"UPDATE user SET login_type=0, login_source=0, login_name=NULL WHERE name='${ESCAPED_USERNAME}';\"
|
|
"
|
|
|
|
echo "[INFO] 提交 link_account_signin..."
|
|
curl -v "https://git.hangman-lab.top/user/link_account_signin" \
|
|
-b "$COOKIES_FILE" -c "$COOKIES_FILE" \
|
|
--data-urlencode "_csrf=$CSRF_TOKEN" \
|
|
--data-urlencode "user_name=$USERNAME" \
|
|
--data-urlencode "password=$GITEA_PASS" \
|
|
-o "$GITEA_LINK_RESP_HTML" \
|
|
2>"$GITEA_LINK_RESP_LOG" || true
|
|
|
|
echo "[INFO] 恢复原始登录方式..."
|
|
ssh root@vps.git "
|
|
set -euo pipefail
|
|
. /root/git-kc/.env
|
|
docker exec -i git-kc-mysql mysql -uroot -p\"\$MYSQL_ROOT_PASSWORD\" giteadb -e \"UPDATE user SET login_type=${ORIG_LOGIN_TYPE}, login_source=${ORIG_LOGIN_SOURCE}, login_name=${ORIG_LOGIN_NAME_SQL} WHERE name='${ESCAPED_USERNAME}';\"
|
|
"
|
|
unset ORIG_LOGIN_TYPE ORIG_LOGIN_SOURCE ORIG_LOGIN_NAME ORIG_LOGIN_NAME_SQL
|
|
|
|
echo "[DONE] Keycloak 账号关联完成"
|