diff --git a/docker/ory/kratos/kratos.yml.template b/docker/ory/kratos/kratos.yml.template index ad713e9a..a82b210f 100644 --- a/docker/ory/kratos/kratos.yml.template +++ b/docker/ory/kratos/kratos.yml.template @@ -4,7 +4,7 @@ dsn: ${KRATOS_DSN} serve: public: - base_url: http://localhost:4433/ + base_url: ${KRATOS_BROWSER_URL:-http://localhost:4433/} cors: enabled: true allowed_origins: @@ -15,7 +15,7 @@ serve: - http://backend:3000 - http://baron_backend:3000 admin: - base_url: http://localhost:4434/ + base_url: ${KRATOS_ADMIN_URL:-http://localhost:4434/} session: cookie: @@ -24,20 +24,9 @@ session: path: / selfservice: - default_browser_return_url: http://localhost:5000/ + default_browser_return_url: ${KRATOS_UI_URL:-http://localhost:5000/} allowed_return_urls: - - http://localhost:5000 - - http://localhost:5000/ - - http://localhost:5000/ko - - http://localhost:5000/ko/ - - http://localhost:5000/en - - http://localhost:5000/en/ - - http://localhost:5000/auth/callback - - http://localhost:5000/ko/auth/callback - - http://localhost:5000/en/auth/callback - - http://localhost:5173/auth/callback - - http://localhost:5174/auth/callback - - http://localhost:5175/auth/callback +${KRATOS_ALLOWED_RETURN_URLS_YAML} methods: password: @@ -50,24 +39,24 @@ selfservice: flows: error: - ui_url: http://localhost:5000/error + ui_url: ${KRATOS_UI_URL:-http://localhost:5000}/error settings: - ui_url: http://localhost:5000/error?error=settings_disabled + ui_url: ${KRATOS_UI_URL:-http://localhost:5000}/error?error=settings_disabled privileged_session_max_age: 15m recovery: - ui_url: http://localhost:5000/recovery + ui_url: ${KRATOS_UI_URL:-http://localhost:5000}/recovery use: code verification: - ui_url: http://localhost:5000/verification + ui_url: ${KRATOS_UI_URL:-http://localhost:5000}/verification use: code logout: after: - default_browser_return_url: http://localhost:5000/login + default_browser_return_url: ${KRATOS_UI_URL:-http://localhost:5000}/login login: - ui_url: http://localhost:5000/login + ui_url: ${KRATOS_UI_URL:-http://localhost:5000}/login lifespan: 10m registration: - ui_url: http://localhost:5000/registration + ui_url: ${KRATOS_UI_URL:-http://localhost:5000}/registration lifespan: 10m log: diff --git a/scripts/render_ory_config.sh b/scripts/render_ory_config.sh index 5c5c5f0f..09613e6f 100755 --- a/scripts/render_ory_config.sh +++ b/scripts/render_ory_config.sh @@ -40,6 +40,78 @@ copy_if_exists() { fi } +json_array_to_lines() { + local json="$1" + local newline=$'\n' + json="${json//$'\n'/}" + json="${json#\[}" + json="${json%\]}" + json="${json//\",\"/$newline}" + json="${json//\"/}" + json="${json//,/$newline}" + printf '%s\n' "$json" | sed '/^[[:space:]]*$/d' +} + +append_unique_url() { + local candidate="${1:-}" + [[ -n "$candidate" ]] || return 0 + local existing + for existing in "${KRATOS_ALLOWED_RETURN_URLS[@]}"; do + [[ "$existing" == "$candidate" ]] && return 0 + done + KRATOS_ALLOWED_RETURN_URLS+=("$candidate") +} + +build_kratos_allowed_return_urls_yaml() { + KRATOS_ALLOWED_RETURN_URLS=() + if [[ -n "${KRATOS_ALLOWED_RETURN_URLS_JSON:-}" ]]; then + while IFS= read -r allowed_url; do + append_unique_url "$allowed_url" + done < <(json_array_to_lines "$KRATOS_ALLOWED_RETURN_URLS_JSON") + fi + + if [[ ${#KRATOS_ALLOWED_RETURN_URLS[@]} -eq 0 ]]; then + local kratos_ui="${KRATOS_UI_URL:-http://localhost:5000}" + local userfront="${USERFRONT_URL:-http://localhost:5000}" + local adminfront="${ADMINFRONT_URL:-http://localhost:5173}" + local devfront="${DEVFRONT_URL:-http://localhost:5174}" + local orgfront="${ORGFRONT_URL:-http://localhost:5175}" + + append_unique_url "$kratos_ui" + append_unique_url "$kratos_ui/" + append_unique_url "$userfront" + append_unique_url "$userfront/" + append_unique_url "$userfront/ko" + append_unique_url "$userfront/ko/" + append_unique_url "$userfront/en" + append_unique_url "$userfront/en/" + append_unique_url "$userfront/auth/callback" + append_unique_url "$userfront/ko/auth/callback" + append_unique_url "$userfront/en/auth/callback" + append_unique_url "$adminfront/auth/callback" + append_unique_url "$devfront/auth/callback" + append_unique_url "$orgfront/auth/callback" + fi + + if [[ -n "${KRATOS_ALLOWED_RETURN_URLS_EXTRA:-}" ]]; then + IFS=',' read -r -a extra_urls <<<"$KRATOS_ALLOWED_RETURN_URLS_EXTRA" + local extra_url + for extra_url in "${extra_urls[@]}"; do + extra_url="$(printf '%s' "$extra_url" | xargs)" + append_unique_url "$extra_url" + done + fi + + if [[ ${#KRATOS_ALLOWED_RETURN_URLS[@]} -eq 0 ]]; then + fail "Kratos allowed_return_urls is empty" + fi + + KRATOS_ALLOWED_RETURN_URLS_YAML="$( + printf '%s\n' "${KRATOS_ALLOWED_RETURN_URLS[@]}" | sed 's/^/ - /' + )" + export KRATOS_ALLOWED_RETURN_URLS_YAML +} + if [[ -n "${ORY_CONFIG_ENV_FILES:-}" ]]; then IFS=':' read -r -a env_files <<<"$ORY_CONFIG_ENV_FILES" for env_file in "${env_files[@]}"; do @@ -65,6 +137,8 @@ OATHKEEPER_INTROSPECT_CLIENT_SECRET="${OATHKEEPER_INTROSPECT_CLIENT_SECRET:-oath export KRATOS_DSN HYDRA_DSN KETO_DSN HYDRA_SYSTEM_SECRET export OATHKEEPER_INTROSPECT_CLIENT_ID OATHKEEPER_INTROSPECT_CLIENT_SECRET +build_kratos_allowed_return_urls_yaml + mkdir -p "$OUTPUT_DIR/kratos" "$OUTPUT_DIR/hydra" "$OUTPUT_DIR/keto" "$OUTPUT_DIR/oathkeeper" render_template "$TEMPLATE_ROOT/kratos/kratos.yml.template" "$OUTPUT_DIR/kratos/kratos.yml" diff --git a/test/ory_v26_compose_policy_test.sh b/test/ory_v26_compose_policy_test.sh index a46f1a6c..e13dd46d 100644 --- a/test/ory_v26_compose_policy_test.sh +++ b/test/ory_v26_compose_policy_test.sh @@ -281,6 +281,32 @@ fi "$repo_root/scripts/render_ory_config.sh" >/dev/null +stage_render_dir="$(mktemp -d)" +stage_render_env="$(mktemp)" +cat > "$stage_render_env" <<'EOF' +USERFRONT_URL=https://sso.hmac.kr +ADMINFRONT_URL=https://sadmin.hmac.kr +DEVFRONT_URL=https://sdev.hmac.kr +ORGFRONT_URL=https://sorg.hmac.kr +KRATOS_UI_URL=https://sso.hmac.kr +KRATOS_BROWSER_URL=https://sso.hmac.kr/auth +KRATOS_ADMIN_URL=http://kratos:4434 +ORY_POSTGRES_PASSWORD=policy-test +KRATOS_ALLOWED_RETURN_URLS_JSON= +KRATOS_ALLOWED_RETURN_URLS_EXTRA= +EOF +ORY_CONFIG_ENV_FILES="$stage_render_env" ORY_CONFIG_OUTPUT_DIR="$stage_render_dir/ory" "$repo_root/scripts/render_ory_config.sh" >/dev/null +stage_rendered_kratos="$stage_render_dir/ory/kratos/kratos.yml" +if ! awk '/allowed_return_urls:/ { in_block=1; next } in_block && /^[[:space:]]+methods:/ { exit } in_block { print }' "$stage_rendered_kratos" | grep -q 'https://sso.hmac.kr'; then + echo "ERROR: rendered stage Kratos config must include the public userfront URL in allowed_return_urls." >&2 + exit 1 +fi +if awk '/allowed_return_urls:/ { in_block=1; next } in_block && /^[[:space:]]+methods:/ { exit } in_block { print }' "$stage_rendered_kratos" | grep -q 'http://localhost:5000'; then + echo "ERROR: rendered stage Kratos allowed_return_urls must not fall back to localhost." >&2 + exit 1 +fi +rm -rf "$stage_render_dir" "$stage_render_env" + for generated_config in \ "$repo_root/config/.generated/ory/kratos/kratos.yml" \ "$repo_root/config/.generated/ory/hydra/hydra.yml" \