Files
KNELAgentIdentityProvisioning/skills/agent-provisioning/scripts/glpi-sso-login.sh
T
mrcharles 35bd13de8b glpi: REST auth recipe (app_token + encrypted-at-rest trap), SSO script known-issue
GLPI 11 encrypts api/app tokens at rest and decrypts before comparing;
the DB ciphertext never authenticates. Document the working
initSession?user_token+app_token recipe, per-user token minting via
GLPIKey, REST account provisioning, and the singlesignon plugin
callback breakage.

https://projects.knownelement.com/issues/947#note-5519
2026-09-09 22:43:28 -05:00

60 lines
3.0 KiB
Bash
Executable File

#!/bin/bash
# GLPI SSO first-login via Cloudron OIDC (singlesignon plugin, callback.php/provider/1).
# usage: glpi-sso-login.sh <cloudron-username> [vault-item]
# Verifies a logged-in session at front/preference.php (HTTP 200 + no login redirect).
# KNOWN ISSUE 2026-09-09: the singlesignon plugin callback fails on GLPI 11 (include-path +
# session/CSRF Access denied) — interactive GLPI SSO broken; REST provisioning used instead
# (see SKILL.md GLPI recipe + Redmine #947). Script kept for when the plugin is fixed.
set -uo pipefail
U="${1:?usage: glpi-sso-login.sh <cloudron-username> [vault-item]}"
ITEM="${2:-$U Cloudron}"
BASE="https://cmdb.knownelement.com"
IDP="https://my.knownelement.com"
JAR="/tmp/glpi-jar-$U.txt"; rm -f "$JAR"
SM() { if [ "$(id -un)" = "TSGCOO" ]; then /data2/TSGCOO/.local/bin/sm "$@" </dev/null; else sudo -u TSGCOO /data2/TSGCOO/.local/bin/sm "$@" </dev/null; fi; }
PW=$(SM get "$ITEM" --field password)
[ -n "$PW" ] || { echo "FAIL: no password in vault item $ITEM" >&2; exit 1; }
SEED=$(SM get "$ITEM" --field totp_seed 2>/dev/null || true)
# entry: the SSO plugin callback kickoff (provider id 1 = KNEL Cloud)
INT=$(curl -sk -b "$JAR" -c "$JAR" -o /dev/null -w '%{url_effective}' -L --max-redirs 8 "$BASE/plugins/singlesignon/front/callback.php/provider/1?remember=1")
case "$INT" in
*/openid/interaction/*) : ;;
*) echo "FAIL: no interaction reached: $INT" >&2; exit 3 ;;
esac
UIDPATH=$(printf '%s' "$INT" | grep -o '/openid/interaction/[^?]*')
BODY="{\"username\":\"$U\",\"password\":\"$PW\""
if [ -n "$SEED" ]; then
TCODE=$(bash "$(dirname "$0")/totp.sh" "$SEED")
BODY="$BODY,\"totpToken\":\"$TCODE\""
fi
BODY="$BODY}"
LOGIN_RESP=$(curl -sk -b "$JAR" -c "$JAR" -X POST "$IDP$UIDPATH/login" -H 'Content-Type: application/json' -d "$BODY")
unset BODY
case "$LOGIN_RESP" in
*redirectTo*) : ;;
*) echo "FAIL: login rejected: $LOGIN_RESP" >&2; exit 5 ;;
esac
RED=$(printf '%s' "$LOGIN_RESP" | sed -n 's/.*"redirectTo":"\([^"]*\)".*/\1/p')
FINAL=$(curl -sk -b "$JAR" -c "$JAR" -o /dev/null -w '%{url_effective}' -L --max-redirs 8 "$RED")
case "$FINAL" in
*/openid/interaction/*)
CUIDPATH=$(printf '%s' "$FINAL" | grep -o '/openid/interaction/[^?]*')
CLOC=$(curl -sk -b "$JAR" -c "$JAR" -D - -o /dev/null -X POST "$IDP$CUIDPATH/confirm" -d '' | grep -i '^location:' | head -1 | tr -d '\r' | sed 's/^[Ll]ocation: //')
[ -n "$CLOC" ] || { echo "FAIL: consent confirm produced no redirect" >&2; exit 6; }
CLOC=$(printf '%s' "$CLOC" | sed 's|^https//|https://|; s|^http//|http://|')
case "$CLOC" in http://*|https://*) : ;; /*) CLOC="$IDP$CLOC" ;; *) CLOC="$IDP/$CLOC" ;; esac
FINAL=$(curl -sk -b "$JAR" -c "$JAR" -o /dev/null -w '%{url_effective}' -L --max-redirs 8 "$CLOC")
;;
esac
CODE=$(curl -sk -b "$JAR" -o /dev/null -w '%{http_code}' "$BASE/front/preference.php")
if [ "$CODE" = "200" ]; then
echo "OK: $U logged into GLPI (session verified at preference.php)"
exit 0
fi
echo "FAIL: no GLPI session (preference.php HTTP $CODE), landed: $FINAL" >&2
exit 7