You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
6.2 KiB
190 lines
6.2 KiB
#!/bin/bash
|
|
|
|
# SSO (Casdoor) 单点登录 E2E 测试
|
|
#
|
|
# 测试账号:
|
|
# Casdoor 地址: https://cas.gxxhygroup.com
|
|
# 用户名: testuser
|
|
# 密码: Test@1234
|
|
# 组织: XhyGroup
|
|
# 应用: xhy-base
|
|
#
|
|
# 前置条件:
|
|
# 1. 后端服务运行在 localhost:8888
|
|
# 2. Casdoor 服务可访问
|
|
# 3. base-api.yaml 中 Casdoor 配置正确
|
|
|
|
BASE_URL="${BASE_URL:-http://localhost:8888/api/v1}"
|
|
CASDOOR_URL="${CASDOOR_URL:-https://cas.gxxhygroup.com}"
|
|
CASDOOR_USER="${CASDOOR_USER:-testuser}"
|
|
CASDOOR_PASS="${CASDOOR_PASS:-Test@1234}"
|
|
|
|
# 颜色输出
|
|
log_info() { echo "[INFO] $1"; }
|
|
log_success() { echo "[PASS] $1"; }
|
|
log_error() { echo "[FAIL] $1"; }
|
|
|
|
PASS=0
|
|
FAIL=0
|
|
|
|
assert_ok() {
|
|
local desc="$1"
|
|
local result="$2"
|
|
if [ "$result" = "0" ]; then
|
|
log_success "$desc"
|
|
PASS=$((PASS + 1))
|
|
else
|
|
log_error "$desc"
|
|
FAIL=$((FAIL + 1))
|
|
fi
|
|
}
|
|
|
|
echo ""
|
|
echo "========================================="
|
|
echo " SSO (Casdoor) 单点登录 E2E 测试"
|
|
echo "========================================="
|
|
echo ""
|
|
|
|
# ========== 测试 1: 获取 SSO 登录链接 ==========
|
|
log_info "测试 1: 获取 SSO 登录链接"
|
|
LOGIN_URL_RESP=$(curl -s "$BASE_URL/auth/sso/login-url")
|
|
echo " 响应: $LOGIN_URL_RESP"
|
|
|
|
# 用 python 或简单方式提取 login_url
|
|
LOGIN_URL=""
|
|
if echo "$LOGIN_URL_RESP" | grep -q "login_url"; then
|
|
LOGIN_URL=$(echo "$LOGIN_URL_RESP" | sed 's/.*"login_url":"\([^"]*\)".*/\1/')
|
|
fi
|
|
|
|
if [ -n "$LOGIN_URL" ]; then
|
|
assert_ok "GET /auth/sso/login-url 返回有效的登录链接" "0"
|
|
echo " 链接: ${LOGIN_URL:0:100}..."
|
|
else
|
|
assert_ok "GET /auth/sso/login-url 返回有效的登录链接" "1"
|
|
fi
|
|
|
|
# 验证链接包含必要参数
|
|
HAS_PARAMS="0"
|
|
echo "$LOGIN_URL" | grep -q "client_id=" || HAS_PARAMS="1"
|
|
echo "$LOGIN_URL" | grep -q "redirect_uri=" || HAS_PARAMS="1"
|
|
echo "$LOGIN_URL" | grep -q "response_type=code" || HAS_PARAMS="1"
|
|
echo "$LOGIN_URL" | grep -q "state=" || HAS_PARAMS="1"
|
|
assert_ok "登录链接包含 client_id, redirect_uri, response_type, state" "$HAS_PARAMS"
|
|
|
|
# ========== 测试 2: Casdoor 服务可达性 ==========
|
|
log_info "测试 2: Casdoor 服务可达性"
|
|
CASDOOR_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$CASDOOR_URL/.well-known/openid-configuration" 2>/dev/null || echo "000")
|
|
echo " OIDC 发现端点状态码: $CASDOOR_STATUS"
|
|
|
|
if [ "$CASDOOR_STATUS" = "200" ]; then
|
|
assert_ok "Casdoor OIDC 发现端点可访问" "0"
|
|
else
|
|
assert_ok "Casdoor OIDC 发现端点可访问 [HTTP $CASDOOR_STATUS]" "1"
|
|
fi
|
|
|
|
# ========== 测试 3: Casdoor API 登录获取授权码 ==========
|
|
log_info "测试 3: Casdoor API 登录"
|
|
LOGIN_API_RESP=$(curl -s -X POST "$CASDOOR_URL/api/login" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{
|
|
\"application\": \"xhy-base\",
|
|
\"organization\": \"XhyGroup\",
|
|
\"username\": \"$CASDOOR_USER\",
|
|
\"password\": \"$CASDOOR_PASS\",
|
|
\"type\": \"code\"
|
|
}" 2>/dev/null || echo '{"status":"error"}')
|
|
|
|
echo " Casdoor 响应: ${LOGIN_API_RESP:0:200}"
|
|
|
|
if echo "$LOGIN_API_RESP" | grep -q '"status":"ok"'; then
|
|
assert_ok "Casdoor API 登录成功" "0"
|
|
elif echo "$LOGIN_API_RESP" | grep -q "not supported"; then
|
|
log_info " Casdoor 应用不支持 API 直接登录(需浏览器),跳过"
|
|
assert_ok "Casdoor API 可达(需浏览器完成授权)" "0"
|
|
else
|
|
assert_ok "Casdoor API 登录成功" "1"
|
|
fi
|
|
|
|
# ========== 测试 4: 后端回调处理 (用 Casdoor 授权码) ==========
|
|
log_info "测试 4: 后端 SSO 回调"
|
|
|
|
# 从 Casdoor 响应中提取授权码(data 或 data2 字段)
|
|
AUTH_CODE=""
|
|
if echo "$LOGIN_API_RESP" | grep -q '"code"'; then
|
|
# 提取第一个非 status 的 code 字段
|
|
AUTH_CODE=$(echo "$LOGIN_API_RESP" | sed 's/.*"data":"\([^"]*\)".*/\1/' 2>/dev/null)
|
|
if [ "$AUTH_CODE" = "$LOGIN_API_RESP" ]; then
|
|
AUTH_CODE=$(echo "$LOGIN_API_RESP" | sed 's/.*"data2":"\([^"]*\)".*/\1/' 2>/dev/null)
|
|
fi
|
|
if [ "$AUTH_CODE" = "$LOGIN_API_RESP" ]; then
|
|
AUTH_CODE=""
|
|
fi
|
|
fi
|
|
|
|
if [ -n "$AUTH_CODE" ] && [ ${#AUTH_CODE} -gt 5 ]; then
|
|
echo " 授权码: ${AUTH_CODE:0:20}..."
|
|
|
|
# 调用后端回调
|
|
CALLBACK_HEADERS=$(curl -s -D - -o /dev/null \
|
|
"$BASE_URL/auth/sso/callback?code=$AUTH_CODE&state=test" 2>/dev/null)
|
|
|
|
HTTP_CODE=$(echo "$CALLBACK_HEADERS" | head -1 | grep -o '[0-9]\{3\}')
|
|
LOCATION=$(echo "$CALLBACK_HEADERS" | grep -i "^Location:" | tr -d '\r' | cut -d' ' -f2-)
|
|
|
|
echo " 回调状态码: $HTTP_CODE"
|
|
echo " 重定向到: ${LOCATION:0:100}"
|
|
|
|
if [ "$HTTP_CODE" = "302" ]; then
|
|
assert_ok "后端回调返回 302 重定向" "0"
|
|
else
|
|
assert_ok "后端回调返回 302 重定向 [实际: $HTTP_CODE]" "1"
|
|
fi
|
|
|
|
if echo "$LOCATION" | grep -q "token="; then
|
|
assert_ok "重定向 URL 包含 JWT token" "0"
|
|
else
|
|
assert_ok "重定向 URL 包含 JWT token" "1"
|
|
fi
|
|
else
|
|
log_info " 无法从 Casdoor API 获取授权码,跳过回调测试"
|
|
log_info " (Casdoor 可能需要浏览器交互完成登录)"
|
|
fi
|
|
|
|
# ========== 测试 5: SSO 用户不能密码登录 ==========
|
|
log_info "测试 5: SSO 用户密码登录限制"
|
|
PASSWORD_LOGIN_RESP=$(curl -s -X POST "$BASE_URL/login" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"email":"test@example.com","password":"anypassword"}')
|
|
|
|
echo " 密码登录响应: $PASSWORD_LOGIN_RESP"
|
|
|
|
if echo "$PASSWORD_LOGIN_RESP" | grep -q "SSO"; then
|
|
assert_ok "SSO 用户密码登录被拒绝,提示使用 SSO" "0"
|
|
elif echo "$PASSWORD_LOGIN_RESP" | grep -q "不存在"; then
|
|
log_info " SSO 用户尚未创建(需先完成一次浏览器 SSO 登录)"
|
|
assert_ok "密码登录未暴露 SSO 用户信息" "0"
|
|
elif echo "$PASSWORD_LOGIN_RESP" | grep -q "密码错误"; then
|
|
log_info " 存在同邮箱的本地用户(SSO 用户通过 casdoor_id 区分)"
|
|
assert_ok "密码登录未暴露 SSO 用户信息" "0"
|
|
else
|
|
assert_ok "SSO 用户密码登录被拒绝" "1"
|
|
fi
|
|
|
|
# ========== 测试报告 ==========
|
|
echo ""
|
|
echo "========================================="
|
|
echo " SSO 测试报告"
|
|
echo "========================================="
|
|
echo ""
|
|
echo "通过: $PASS"
|
|
echo "失败: $FAIL"
|
|
echo "总计: $((PASS + FAIL))"
|
|
echo ""
|
|
|
|
if [ $FAIL -eq 0 ]; then
|
|
echo "所有 SSO 测试通过!"
|
|
exit 0
|
|
else
|
|
echo "存在失败的测试项"
|
|
exit 1
|
|
fi
|
|
|