test: reproduce and block unsafe broker auto-link
This commit is contained in:
Executable
+178
@@ -0,0 +1,178 @@
|
||||
#!/usr/bin/env sh
|
||||
set -eu
|
||||
|
||||
mode="${1:-}"
|
||||
case "$mode" in
|
||||
vulnerable|secure) ;;
|
||||
*)
|
||||
echo "usage: $0 vulnerable|secure" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ ! -f .env ]; then
|
||||
echo "missing .env" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -a
|
||||
. ./.env
|
||||
set +a
|
||||
|
||||
keycloak_url="${KEYCLOAK_URL:-http://localhost:8080}"
|
||||
realm="${KEYCLOAK_REALM:-keycloak-patterns}"
|
||||
admin_base="$keycloak_url/admin/realms/$realm"
|
||||
vulnerable_flow="vulnerable first broker login"
|
||||
idp_url="$admin_base/identity-provider/instances/mock-google"
|
||||
|
||||
admin_token="$(
|
||||
curl -fsS \
|
||||
-d client_id=admin-cli \
|
||||
-d grant_type=password \
|
||||
-d "username=$KC_BOOTSTRAP_ADMIN_USERNAME" \
|
||||
-d "password=$KC_BOOTSTRAP_ADMIN_PASSWORD" \
|
||||
"$keycloak_url/realms/master/protocol/openid-connect/token" |
|
||||
jq -er .access_token
|
||||
)"
|
||||
|
||||
auth_header="Authorization: Bearer $admin_token"
|
||||
encode() {
|
||||
jq -rn --arg value "$1" '$value | @uri'
|
||||
}
|
||||
|
||||
flows="$(curl -fsS -H "$auth_header" "$admin_base/authentication/flows")"
|
||||
flow_id="$(
|
||||
printf '%s' "$flows" |
|
||||
jq -r --arg alias "$vulnerable_flow" '
|
||||
.[] | select(.alias == $alias) | .id
|
||||
' |
|
||||
head -1
|
||||
)"
|
||||
|
||||
if [ -n "$flow_id" ]; then
|
||||
existing_executions="$(
|
||||
curl -fsS -H "$auth_header" \
|
||||
"$admin_base/authentication/flows/$(encode "$vulnerable_flow")/executions"
|
||||
)"
|
||||
if printf '%s' "$existing_executions" | jq -e '
|
||||
any(.[]; .authenticationFlow == true)
|
||||
' >/dev/null; then
|
||||
idp_before_delete="$(curl -fsS -H "$auth_header" "$idp_url")"
|
||||
printf '%s' "$idp_before_delete" |
|
||||
jq '.firstBrokerLoginFlowAlias = "first broker login"' |
|
||||
curl -fsS -X PUT \
|
||||
-H "$auth_header" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data @- \
|
||||
"$idp_url"
|
||||
curl -fsS -X DELETE \
|
||||
-H "$auth_header" \
|
||||
"$admin_base/authentication/flows/$flow_id"
|
||||
flow_id=""
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$flow_id" ]; then
|
||||
curl -fsS -X POST \
|
||||
-H "$auth_header" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data "$(
|
||||
jq -n --arg alias "$vulnerable_flow" '{
|
||||
alias: $alias,
|
||||
description: "INSECURE LEARNING FLOW - automatic email linking",
|
||||
providerId: "basic-flow",
|
||||
topLevel: true,
|
||||
builtIn: false
|
||||
}'
|
||||
)" \
|
||||
"$admin_base/authentication/flows"
|
||||
fi
|
||||
|
||||
executions_url="$admin_base/authentication/flows/$(encode "$vulnerable_flow")/executions"
|
||||
executions="$(curl -fsS -H "$auth_header" "$executions_url")"
|
||||
create_user_id="$(
|
||||
printf '%s' "$executions" |
|
||||
jq -r '.[] | select(.providerId == "idp-create-user-if-unique") | .id' |
|
||||
head -1
|
||||
)"
|
||||
if [ -z "$create_user_id" ]; then
|
||||
curl -fsS -X POST \
|
||||
-H "$auth_header" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data '{"provider":"idp-create-user-if-unique"}' \
|
||||
"$admin_base/authentication/flows/$(encode "$vulnerable_flow")/executions/execution"
|
||||
executions="$(curl -fsS -H "$auth_header" "$executions_url")"
|
||||
create_user_id="$(
|
||||
printf '%s' "$executions" |
|
||||
jq -r '.[] | select(.providerId == "idp-create-user-if-unique") | .id' |
|
||||
head -1
|
||||
)"
|
||||
fi
|
||||
|
||||
auto_link_id="$(
|
||||
printf '%s' "$executions" |
|
||||
jq -r '.[] | select(.providerId == "idp-auto-link") | .id' |
|
||||
head -1
|
||||
)"
|
||||
|
||||
if [ -z "$auto_link_id" ]; then
|
||||
curl -fsS -X POST \
|
||||
-H "$auth_header" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data '{"provider":"idp-auto-link"}' \
|
||||
"$admin_base/authentication/flows/$(encode "$vulnerable_flow")/executions/execution"
|
||||
executions="$(curl -fsS -H "$auth_header" "$executions_url")"
|
||||
auto_link_id="$(
|
||||
printf '%s' "$executions" |
|
||||
jq -r '.[] | select(.providerId == "idp-auto-link") | .id' |
|
||||
head -1
|
||||
)"
|
||||
fi
|
||||
|
||||
if [ "$mode" = "vulnerable" ]; then
|
||||
curl -fsS -X PUT \
|
||||
-H "$auth_header" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data "$(jq -n --arg id "$create_user_id" '{id: $id, requirement: "ALTERNATIVE"}')" \
|
||||
"$executions_url"
|
||||
curl -fsS -X PUT \
|
||||
-H "$auth_header" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data "$(jq -n --arg id "$auto_link_id" '{id: $id, requirement: "ALTERNATIVE"}')" \
|
||||
"$executions_url"
|
||||
selected_flow="$vulnerable_flow"
|
||||
else
|
||||
selected_flow="first broker login"
|
||||
fi
|
||||
|
||||
idp="$(curl -fsS -H "$auth_header" "$idp_url")"
|
||||
printf '%s' "$idp" |
|
||||
jq --arg flow "$selected_flow" '.firstBrokerLoginFlowAlias = $flow' |
|
||||
curl -fsS -X PUT \
|
||||
-H "$auth_header" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data @- \
|
||||
"$idp_url"
|
||||
|
||||
assigned="$(
|
||||
curl -fsS -H "$auth_header" "$idp_url" |
|
||||
jq -r .firstBrokerLoginFlowAlias
|
||||
)"
|
||||
test "$assigned" = "$selected_flow"
|
||||
|
||||
if [ "$mode" = "secure" ]; then
|
||||
secure_executions="$(
|
||||
curl -fsS -H "$auth_header" \
|
||||
"$admin_base/authentication/flows/$(encode "first broker login")/executions"
|
||||
)"
|
||||
printf '%s' "$secure_executions" | jq -e '
|
||||
any(.[];
|
||||
.providerId == "idp-confirm-link" and .requirement == "REQUIRED"
|
||||
) and
|
||||
(any(.[];
|
||||
.providerId == "idp-auto-link" and .requirement != "DISABLED"
|
||||
) | not)
|
||||
' >/dev/null
|
||||
fi
|
||||
|
||||
echo "mock-google First Broker Login mode: $mode ($selected_flow)"
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env sh
|
||||
set -eu
|
||||
|
||||
if [ ! -f .env ]; then
|
||||
echo "missing .env" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -a
|
||||
. ./.env
|
||||
set +a
|
||||
|
||||
restore_secure_flow() {
|
||||
./scripts/set-first-broker-login-mode.sh secure >/dev/null 2>&1 || true
|
||||
}
|
||||
trap restore_secure_flow 0 1 2 15
|
||||
|
||||
npm --prefix google-e2e ci
|
||||
|
||||
./scripts/set-first-broker-login-mode.sh vulnerable
|
||||
FIRST_BROKER_EXPECTATION=vulnerable \
|
||||
npm --prefix google-e2e run test:first-broker
|
||||
|
||||
./scripts/set-first-broker-login-mode.sh secure
|
||||
FIRST_BROKER_EXPECTATION=secure \
|
||||
npm --prefix google-e2e run test:first-broker
|
||||
|
||||
trap - 0 1 2 15
|
||||
echo "First Broker Login verified: unsafe AutoLink reproduced, Confirm Link restored"
|
||||
Reference in New Issue
Block a user