131 lines
6.4 KiB
Bash
Executable File
131 lines
6.4 KiB
Bash
Executable File
#!/bin/bash
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# L99 SSO + AUTHENTIK NON-REGRESSION v4.0 — EXHAUSTIF
|
|
# Tests: auth redirect, rd= param, SSO script injection,
|
|
# WebSocket, Authentik health, Docker status, flow API
|
|
# Cron: */6h | Alerte: Telegram
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
LOG_DIR="/var/log/wevia-director"
|
|
LOG_FILE="$LOG_DIR/l99-sso.log"
|
|
RESULT_FILE="$LOG_DIR/l99-sso-latest.json"
|
|
mkdir -p "$LOG_DIR"
|
|
|
|
DATE=$(date "+%Y-%m-%d %H:%M")
|
|
PASS=0; FAIL=0; TOTAL=0; FAILS=""
|
|
|
|
# ═══ SECTION 1: AUTHENTIK INFRASTRUCTURE ═══
|
|
echo "[$DATE] === SECTION 1: AUTHENTIK INFRA ===" >> "$LOG_FILE"
|
|
|
|
# 1.1 Docker containers
|
|
for c in authentik-server authentik-worker authentik-db authentik-redis; do
|
|
TOTAL=$((TOTAL+1))
|
|
ST=$(docker ps --format "{{.Status}}" --filter "name=^${c}$" 2>/dev/null)
|
|
if echo "$ST" | grep -q "Up"; then
|
|
PASS=$((PASS+1))
|
|
else
|
|
FAIL=$((FAIL+1)); FAILS="$FAILS\n• docker:$c DOWN"
|
|
fi
|
|
done
|
|
|
|
# 1.2 Authentik API health
|
|
TOTAL=$((TOTAL+1))
|
|
API_CODE=$(curl -s --max-time 5 -o /dev/null -w "%{http_code}" "http://127.0.0.1:9090/api/v3/root/config/" 2>/dev/null)
|
|
if [ "$API_CODE" = "200" ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); FAILS="$FAILS\n• authentik-api HTTP:$API_CODE"; fi
|
|
|
|
# 1.3 Flow executor API
|
|
TOTAL=$((TOTAL+1))
|
|
FLOW_CODE=$(curl -s --max-time 5 -o /dev/null -w "%{http_code}" "http://127.0.0.1:9090/api/v3/flows/executor/default-authentication-flow/" -H "Host: weval-consulting.com" 2>/dev/null)
|
|
if [ "$FLOW_CODE" = "200" ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); FAILS="$FAILS\n• flow-executor HTTP:$FLOW_CODE"; fi
|
|
|
|
# 1.4 WebSocket endpoint
|
|
TOTAL=$((TOTAL+1))
|
|
WS_CODE=$(curl -s --max-time 5 -o /dev/null -w "%{http_code}" "http://127.0.0.1:9090/ws/client/" 2>/dev/null)
|
|
if [ "$WS_CODE" = "200" ] || [ "$WS_CODE" = "101" ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); FAILS="$FAILS\n• websocket HTTP:$WS_CODE"; fi
|
|
|
|
# 1.5 Flow HTML loads FlowInterface JS
|
|
TOTAL=$((TOTAL+1))
|
|
HAS_FLOW=$(curl -s --max-time 5 "http://127.0.0.1:9090/if/flow/default-authentication-flow/" -H "Host: weval-consulting.com" 2>/dev/null | grep -c "FlowInterface")
|
|
if [ "$HAS_FLOW" -ge 1 ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); FAILS="$FAILS\n• flow-html no FlowInterface JS"; fi
|
|
|
|
# 1.6 Version pinned (not :latest)
|
|
TOTAL=$((TOTAL+1))
|
|
IMG=$(docker inspect authentik-server --format "{{.Config.Image}}" 2>/dev/null)
|
|
if echo "$IMG" | grep -q ":latest"; then FAIL=$((FAIL+1)); FAILS="$FAILS\n• version NOT pinned ($IMG)"; else PASS=$((PASS+1)); fi
|
|
|
|
# 1.7 Nginx WebSocket config
|
|
TOTAL=$((TOTAL+1))
|
|
WS_NGINX=$(grep -c "proxy_set_header Upgrade" /etc/nginx/sites-enabled/weval-consulting 2>/dev/null)
|
|
if [ "$WS_NGINX" -ge 3 ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); FAILS="$FAILS\n• nginx missing WebSocket headers ($WS_NGINX found)"; fi
|
|
|
|
# 1.8 Nginx immutable flag
|
|
TOTAL=$((TOTAL+1))
|
|
IMMUTABLE=$(lsattr /etc/nginx/sites-enabled/weval-consulting 2>/dev/null | grep -c "i")
|
|
if [ "$IMMUTABLE" -ge 1 ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); FAILS="$FAILS\n• nginx NOT immutable"; fi
|
|
|
|
# ═══ SECTION 2: SSO REDIRECT — ALL PROTECTED PAGES ═══
|
|
echo "[$DATE] === SECTION 2: SSO REDIRECT ===" >> "$LOG_FILE"
|
|
|
|
PAGES=$(grep -B1 "auth_request /outpost" /etc/nginx/sites-enabled/weval-consulting 2>/dev/null | grep "location" | sed "s/.*location[= ]*//" | sed "s/ {.*//" | grep -v "^~" | grep -v "^/api/" | sort -u)
|
|
|
|
for page in $PAGES; do
|
|
TOTAL=$((TOTAL+1))
|
|
CODE=$(curl -s -o /tmp/sso_wb -w "%{http_code}" --max-time 5 -k "https://127.0.0.1$page" -H "Host: weval-consulting.com" 2>/dev/null)
|
|
RD=$(curl -s -o /dev/null -w "%{redirect_url}" --max-time 5 -k "https://127.0.0.1$page" -H "Host: weval-consulting.com" 2>/dev/null)
|
|
HAS_SCRIPT=$(grep -c "weval_sso_target" /tmp/sso_wb 2>/dev/null)
|
|
|
|
OK=0
|
|
if [ "$CODE" = "302" ] && echo "$RD" | grep -q "rd="; then OK=1;
|
|
elif [ "$CODE" = "200" ] && [ "$HAS_SCRIPT" -ge 1 ]; then OK=1; fi
|
|
|
|
if [ "$OK" = "1" ]; then PASS=$((PASS+1));
|
|
else FAIL=$((FAIL+1)); FAILS="$FAILS\n• $page (HTTP:$CODE)"; fi
|
|
done
|
|
rm -f /tmp/sso_wb
|
|
|
|
# ═══ SECTION 3: SSO SCRIPT INJECTION ═══
|
|
echo "[$DATE] === SECTION 3: SSO SCRIPT INJECTION ===" >> "$LOG_FILE"
|
|
|
|
# Test sub_filter on homepage (always accessible)
|
|
TOTAL=$((TOTAL+1))
|
|
HOME_SCRIPT=$(curl -s --max-time 5 -k "https://127.0.0.1/" -H "Host: weval-consulting.com" 2>/dev/null | grep -c "weval_sso_target")
|
|
if [ "$HOME_SCRIPT" -ge 1 ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); FAILS="$FAILS\n• homepage missing sso_script"; fi
|
|
|
|
# ═══ RESULTS ═══
|
|
[ "$TOTAL" = "0" ] && TOTAL=1
|
|
SCORE=$((PASS*100/TOTAL))
|
|
|
|
cat > "$RESULT_FILE" << JSONEOF
|
|
{"date":"$DATE","total":$TOTAL,"pass":$PASS,"fail":$FAIL,"score":$SCORE,"failures":"$(echo -e "$FAILS" | tr '\n' '|')","version":"v4.0","sections":{"infra":8,"pages":$(echo "$PAGES" | wc -w),"injection":1}}
|
|
JSONEOF
|
|
|
|
echo "[$DATE] L99-SSO-v4: $PASS/$TOTAL ($SCORE%)" >> "$LOG_FILE"
|
|
|
|
# Telegram alert if failures
|
|
if [ $FAIL -gt 0 ]; then
|
|
GROQ_KEY=$(grep "^GROQ_KEY" /etc/weval/secrets.env 2>/dev/null | cut -d= -f2)
|
|
DIAG=""
|
|
if [ -n "$GROQ_KEY" ]; then
|
|
PROMPT="SSO test failed: $PASS/$TOTAL. Failures:$FAILS. Diagnose in 2 lines."
|
|
PROMPT_ESC=$(echo "$PROMPT" | python3 -c "import sys,json;print(json.dumps(sys.stdin.read()))")
|
|
DIAG=$(curl -s --max-time 15 "https://api.groq.com/openai/v1/chat/completions" \
|
|
-H "Authorization: Bearer $GROQ_KEY" -H "Content-Type: application/json" \
|
|
-d "{\"model\":\"llama-3.3-70b-versatile\",\"messages\":[{\"role\":\"user\",\"content\":$PROMPT_ESC}],\"max_tokens\":150}" 2>/dev/null \
|
|
| python3 -c "import sys,json;print(json.load(sys.stdin).get('choices',[{}])[0].get('message',{}).get('content',''))" 2>/dev/null)
|
|
echo "[$DATE] IA: $DIAG" >> "$LOG_FILE"
|
|
fi
|
|
|
|
TG_TOKEN=$(cat /etc/weval/tg_bot_token 2>/dev/null)
|
|
if [ -n "$TG_TOKEN" ]; then
|
|
MSG="⚠️ L99 SSO v4 REGRESSION\n📊 $PASS/$TOTAL ($SCORE%)\n❌$FAILS"
|
|
[ -n "$DIAG" ] && MSG="$MSG\n\n🧠 $DIAG"
|
|
curl -s "https://api.telegram.org/bot${TG_TOKEN}/sendMessage" \
|
|
-d "chat_id=7605775322" --data-urlencode "text=$MSG" > /dev/null 2>&1
|
|
fi
|
|
echo "L99-SSO-v4: $PASS/$TOTAL ($SCORE%) ❌"
|
|
echo -e "FAILURES:$FAILS"
|
|
else
|
|
echo "L99-SSO-v4: $PASS/$TOTAL ($SCORE%) ✅"
|
|
fi
|
|
exit $FAIL
|