/
Al
/
TESamples
Обзор
Документация
Войти
/
Al
/
TESamples
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
scripts/te-curl.sh
110 строк
5 KB
Александр Седых
added guide-not-framework.md, fixed problem
13 май 2026, 14:04
13 май 2026, 14:04
fdd9cf0
Код
Авторство
О чём код?
#!/usr/bin/env bash # ============================================================= # TokenExchange — ручная проверка TE-flow с хоста (PLAN.md §3.5) # # Запускает ту же последовательность, что smoke.sh, но обращается # к Keycloak по адресу с хоста (по умолчанию http://localhost:8080) # и подробно печатает запросы/ответы для развёрнутого знакомства. # # Использование: # ./scripts/te-curl.sh # alice + scope=orders:read # SYNTETIC_USER=bob ./scripts/te-curl.sh # сменить пользователя # SCOPE='orders:read orders:write' ./scripts/te-curl.sh # AUDIENCE=service-a ./scripts/te-curl.sh # явный audience # ============================================================= set -euo pipefail KC_BASE="${KC_BASE:-http://localhost:8080}" REALM="${REALM:-realm-primary}" BFF_CLIENT_ID="${BFF_CLIENT_ID:-bff-agent}" BFF_SECRET="${BFF_SECRET:-bff-agent-dev-secret}" AGENT_CLIENT_ID="${AGENT_CLIENT_ID:-agent-runtime}" AGENT_SECRET="${AGENT_SECRET:-agent-runtime-dev-secret}" SYNTETIC_USER="${SYNTETIC_USER:-alice}" PASSWORD="${PASSWORD:-${SYNTETIC_USER}-dev}" AUDIENCE="${AUDIENCE:-internal-services}" SCOPE="${SCOPE:-orders:read}" SCOPE_ROPC="${SCOPE_ROPC:-openid orders:read orders:write payments:write}" TOKEN_URL="${KC_BASE}/realms/${REALM}/protocol/openid-connect/token" C='\033[36m'; G='\033[32m'; R='\033[31m'; N='\033[0m' section() { printf "\n${C}==> %s${N}\n" "$*"; } fail() { printf "${R}[FAIL]${N} %s\n" "$*" >&2; exit 1; } # Декодируем JWT-payload (только payload, без подписи!). jwt_payload() { local jwt="$1" payload payload="$(printf '%s' "$jwt" | cut -d'.' -f2 | tr '_-' '/+')" case $(( ${#payload} % 4 )) in 2) payload="${payload}==" ;; 3) payload="${payload}=" ;; esac printf '%s' "$payload" | base64 -d 2>/dev/null } command -v jq >/dev/null || fail "Требуется jq" command -v curl >/dev/null || fail "Требуется curl" # ---------- 1. user_at ---------- section "1. ROPC: user_at для '${SYNTETIC_USER}' через клиента '${BFF_CLIENT_ID}'" USER_RESP="$(curl -fsS -X POST "${TOKEN_URL}" \ -H 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode "grant_type=password" \ --data-urlencode "client_id=${BFF_CLIENT_ID}" \ --data-urlencode "client_secret=${BFF_SECRET}" \ --data-urlencode "username=${SYNTETIC_USER}" \ --data-urlencode "password=${PASSWORD}" \ --data-urlencode "scope=${SCOPE_ROPC}")" USER_AT="$(printf '%s' "$USER_RESP" | jq -er '.access_token')" printf "${G}user_at${N}.scope = %s\n" "$(jwt_payload "$USER_AT" | jq -r '.scope')" printf "${G}user_at${N}.aud = %s\n" "$(jwt_payload "$USER_AT" | jq -c '.aud')" printf "${G}user_at${N}.sub = %s (preferred_username=%s)\n" \ "$(jwt_payload "$USER_AT" | jq -r '.sub')" \ "$(jwt_payload "$USER_AT" | jq -r '.preferred_username')" # ---------- 2. actor_token ---------- section "2. client_credentials: actor_token для '${AGENT_CLIENT_ID}'" AGENT_RESP="$(curl -fsS -X POST "${TOKEN_URL}" \ -H 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode "grant_type=client_credentials" \ --data-urlencode "client_id=${AGENT_CLIENT_ID}" \ --data-urlencode "client_secret=${AGENT_SECRET}")" ACTOR_TOKEN="$(printf '%s' "$AGENT_RESP" | jq -er '.access_token')" printf "${G}actor_token${N}.azp/clientHost claims:\n" jwt_payload "$ACTOR_TOKEN" | jq '{iss,sub,clientId,azp,client_id,agent_name,agent_version,agent_type}' # ---------- 3. TE ---------- section "3. Token Exchange: scope='${SCOPE}', audience='${AUDIENCE}'" TE_RESP="$(curl -sS -X POST "${TOKEN_URL}" \ -H 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \ --data-urlencode "client_id=${BFF_CLIENT_ID}" \ --data-urlencode "client_secret=${BFF_SECRET}" \ --data-urlencode "subject_token=${USER_AT}" \ --data-urlencode "subject_token_type=urn:ietf:params:oauth:token-type:access_token" \ --data-urlencode "actor_token=${ACTOR_TOKEN}" \ --data-urlencode "actor_token_type=urn:ietf:params:oauth:token-type:access_token" \ --data-urlencode "requested_token_type=urn:ietf:params:oauth:token-type:access_token" \ --data-urlencode "audience=${AUDIENCE}" \ --data-urlencode "scope=${SCOPE}")" ERR="$(printf '%s' "$TE_RESP" | jq -r '.error // empty')" if [ -n "$ERR" ]; then printf "${R}TE error:${N}\n%s\n" "$(printf '%s' "$TE_RESP" | jq .)" exit 1 fi DELEGATED_AT="$(printf '%s' "$TE_RESP" | jq -er '.access_token')" section "4. delegated_at — payload" jwt_payload "$DELEGATED_AT" | jq '{iss,sub,preferred_username,aud,scope,act,azp,exp}' section "Done. Дальше — посмотреть полный payload через:" B64URL="$(printf '%s' "$DELEGATED_AT" | cut -d'.' -f2)" B64STD="$(printf '%s' "$B64URL" | tr '_-' '/+')" case $(( ${#B64STD} % 4 )) in 2) B64STD="${B64STD}==" ;; 3) B64STD="${B64STD}=" ;; esac printf " echo '%s' | base64 -d | jq .\n\n" "$B64STD" section "Полученный delegated_at можно передать руками в любой из chain-сервисов, чтобы пройти цепочку, к примеру:" printf "curl -s -H 'Authorization: Bearer $DELEGATED_AT' http://localhost:8082/api/echo | jq .\n\n"