Rewrite BMS skill from bash to Python
This commit is contained in:
154
scripts/bms-auth.sh
Normal file → Executable file
154
scripts/bms-auth.sh
Normal file → Executable file
@@ -1,153 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
# bms-auth.sh — Kaseya BMS authentication helper
|
||||
# Obtains and caches JWT tokens. Called by bms.sh.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Import logging
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "${SCRIPT_DIR}/bms-logging.sh"
|
||||
|
||||
BMS_API_BASE="${BMS_API_BASE:-https://api.bms.kaseya.com}"
|
||||
BMS_TOKEN_FILE="${BMS_TOKEN_FILE:-$HOME/.bms_token.json}"
|
||||
|
||||
# ─── Helpers ────────────────────────────────────────────────────────────────
|
||||
|
||||
die() { echo "ERROR: $*" >&2; exit 1; }
|
||||
|
||||
require_env() {
|
||||
local var="$1"
|
||||
[[ -n "${!var:-}" ]] || die "Environment variable $var is required. See SKILL.md for setup."
|
||||
}
|
||||
|
||||
token_is_valid() {
|
||||
# Returns 0 (true) if cached token exists and has not expired (with 60s buffer)
|
||||
[[ -f "$BMS_TOKEN_FILE" ]] || return 1
|
||||
local exp
|
||||
exp=$(jq -r '.expires_at // 0' "$BMS_TOKEN_FILE" 2>/dev/null) || return 1
|
||||
local now
|
||||
now=$(date +%s)
|
||||
[[ $((exp - 60)) -gt $now ]]
|
||||
}
|
||||
|
||||
save_token() {
|
||||
local response="$1"
|
||||
local access_token refresh_token expires_in expires_at
|
||||
access_token=$(echo "$response" | jq -r '.result.AccessToken // .result.accessToken // .result.access_token // empty')
|
||||
refresh_token=$(echo "$response" | jq -r '.result.RefreshToken // .result.refreshToken // .result.refresh_token // empty')
|
||||
expires_in=$(echo "$response" | jq -r '.result.ExpiresIn // .result.expires_in // 3600')
|
||||
expires_at=$(( $(date +%s) + expires_in ))
|
||||
|
||||
[[ -n "$access_token" ]] || die "No access token in auth response: $response"
|
||||
|
||||
jq -n \
|
||||
--arg at "$access_token" \
|
||||
--arg rt "${refresh_token:-}" \
|
||||
--argjson ea "$expires_at" \
|
||||
'{access_token: $at, refresh_token: $rt, expires_at: $ea}' \
|
||||
> "$BMS_TOKEN_FILE"
|
||||
chmod 600 "$BMS_TOKEN_FILE"
|
||||
}
|
||||
|
||||
# ─── Auth Actions ────────────────────────────────────────────────────────────
|
||||
|
||||
cmd_auth_login() {
|
||||
require_env BMS_TENANT
|
||||
|
||||
local response
|
||||
|
||||
if [[ -n "${BMS_CLIENT_ID:-}" && -n "${BMS_CLIENT_SECRET:-}" ]]; then
|
||||
# OAuth2 client credentials flow
|
||||
echo "Authenticating with client credentials..." >&2
|
||||
response=$(curl -sf -X POST "${BMS_API_BASE}/v2/security/authenticate" \
|
||||
-F "GrantType=client_credentials" \
|
||||
-F "ClientId=${BMS_CLIENT_ID}" \
|
||||
-F "ClientSecret=${BMS_CLIENT_SECRET}" \
|
||||
-F "Tenant=${BMS_TENANT}") || die "Authentication request failed"
|
||||
else
|
||||
# Password flow
|
||||
require_env BMS_USERNAME
|
||||
require_env BMS_PASSWORD
|
||||
echo "Authenticating with username/password..." >&2
|
||||
local curl_args=(-s -X POST "${BMS_API_BASE}/v2/security/authenticate" \
|
||||
-F "GrantType=password" \
|
||||
-F "UserName=${BMS_USERNAME}" \
|
||||
-F "Password=${BMS_PASSWORD}" \
|
||||
-F "Tenant=${BMS_TENANT}")
|
||||
[[ -n "${BMS_MFA_CODE:-}" ]] && curl_args+=(-F "MFACode=${BMS_MFA_CODE}")
|
||||
response=$(curl "${curl_args[@]}") || die "Authentication request failed"
|
||||
fi
|
||||
|
||||
save_token "$response"
|
||||
echo "Authenticated successfully. Token cached at $BMS_TOKEN_FILE" >&2
|
||||
|
||||
# Log successful login
|
||||
local args_json
|
||||
args_json=$(jq -n \
|
||||
--arg tenant "${BMS_TENANT}" \
|
||||
--arg username "${BMS_USERNAME}" \
|
||||
'{"tenant": $tenant, "username": $username}')
|
||||
local result_json='{"success": true}'
|
||||
log_action "auth.login" "$args_json" "$result_json" "success"
|
||||
}
|
||||
|
||||
cmd_auth_refresh() {
|
||||
[[ -f "$BMS_TOKEN_FILE" ]] || die "No cached token. Run: bms auth"
|
||||
local access_token refresh_token
|
||||
access_token=$(jq -r '.access_token' "$BMS_TOKEN_FILE")
|
||||
refresh_token=$(jq -r '.refresh_token // empty' "$BMS_TOKEN_FILE")
|
||||
|
||||
[[ -n "$refresh_token" ]] || { cmd_auth_login; return; }
|
||||
|
||||
local response
|
||||
response=$(curl -sf -X POST "${BMS_API_BASE}/v2/security/refreshtoken" \
|
||||
-F "AccessToken=${access_token}" \
|
||||
-F "RefreshToken=${refresh_token}") \
|
||||
|| { echo "Refresh failed, re-authenticating..." >&2; cmd_auth_login; return; }
|
||||
|
||||
save_token "$response"
|
||||
echo "Token refreshed." >&2
|
||||
|
||||
# Log token refresh
|
||||
local result_json='{"success": true}'
|
||||
log_action "auth.refresh" "{}" "$result_json" "success"
|
||||
}
|
||||
|
||||
cmd_auth_status() {
|
||||
if [[ ! -f "$BMS_TOKEN_FILE" ]]; then
|
||||
echo "No token cached."
|
||||
return
|
||||
fi
|
||||
local expires_at now remaining
|
||||
expires_at=$(jq -r '.expires_at // 0' "$BMS_TOKEN_FILE")
|
||||
now=$(date +%s)
|
||||
remaining=$((expires_at - now))
|
||||
if [[ $remaining -gt 0 ]]; then
|
||||
echo "Token valid. Expires in ${remaining}s (at $(date -d "@${expires_at}" 2>/dev/null || date -r "${expires_at}" 2>/dev/null || echo "unknown"))"
|
||||
else
|
||||
echo "Token expired ${remaining#-}s ago."
|
||||
fi
|
||||
}
|
||||
|
||||
# ─── Public: get_token ───────────────────────────────────────────────────────
|
||||
# Prints the current access token, refreshing/authenticating as needed.
|
||||
get_token() {
|
||||
if ! token_is_valid; then
|
||||
if [[ -f "$BMS_TOKEN_FILE" ]]; then
|
||||
cmd_auth_refresh
|
||||
else
|
||||
cmd_auth_login
|
||||
fi
|
||||
fi
|
||||
jq -r '.access_token' "$BMS_TOKEN_FILE"
|
||||
}
|
||||
|
||||
# ─── Dispatch ────────────────────────────────────────────────────────────────
|
||||
|
||||
case "${1:-}" in
|
||||
login|"") cmd_auth_login ;;
|
||||
refresh) cmd_auth_refresh ;;
|
||||
status) cmd_auth_status ;;
|
||||
get-token) get_token ;;
|
||||
*) echo "Usage: bms-auth.sh [login|refresh|status|get-token]" >&2; exit 1 ;;
|
||||
esac
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
export PYTHONPATH="${REPO_ROOT}/src${PYTHONPATH:+:$PYTHONPATH}"
|
||||
action="${1:-login}"
|
||||
exec python3 -m openclaw_bms auth "$action"
|
||||
|
||||
Reference in New Issue
Block a user