#!/usr/bin/env bash

set -euo pipefail

###############################################################################
# list-rbac-subject.sh
#
# Scopo:
#   Listare tutti i Role/ClusterRole associati a:
#     - un utente OpenShift/Kubernetes
#     - un gruppo OpenShift/Kubernetes
#
# Per utente:
#   Mostra:
#     - binding diretti a User:<utente>
#     - binding ereditati dai gruppi OpenShift a cui appartiene l'utente
#
# Requisiti:
#   - oc login già effettuato
#   - jq
###############################################################################

require_cmd() {
  command -v "$1" >/dev/null 2>&1 || {
    echo "ERRORE: comando '$1' non trovato"
    exit 1
  }
}

print_line() {
  printf '%*s\n' "${COLUMNS:-160}" '' | tr ' ' '-'
}

print_empty_if_needed() {
  local OUTPUT="$1"
  if [[ -z "$OUTPUT" ]]; then
    echo "Nessun binding trovato"
  else
    echo "$OUTPUT" | column -t -s $'\t'
  fi
}

list_for_user() {
  local SUBJECT_USER="$1"
  local INCLUDE_SYSTEM_GROUPS="$2"

  echo
  print_line
  echo "RBAC per utente: $SUBJECT_USER"
  print_line

  mapfile -t USER_GROUPS < <(
    oc get groups -o json | jq -r --arg U "$SUBJECT_USER" '
      .items[]
      | select(.users[]? == $U)
      | .metadata.name
    ' | sort -u
  )

  if [[ "$INCLUDE_SYSTEM_GROUPS" =~ ^[YySs]$ ]]; then
    USER_GROUPS+=("system:authenticated" "system:authenticated:oauth")
  fi

  GROUPS_JSON="$(printf '%s\n' "${USER_GROUPS[@]:-}" | sed '/^$/d' | jq -R . | jq -s .)"

  echo
  echo "Gruppi rilevati per $SUBJECT_USER:"
  if [[ "${#USER_GROUPS[@]}" -eq 0 ]]; then
    echo "  Nessun gruppo trovato"
  else
    printf '  - %s\n' "${USER_GROUPS[@]}"
  fi

  echo
  print_line
  echo "ClusterRoleBinding dirette o ereditate"
  print_line

  CRB_OUTPUT="$(
    oc get clusterrolebindings -o json | jq -r \
      --arg U "$SUBJECT_USER" \
      --argjson G "$GROUPS_JSON" '
    .items[]
    | . as $binding
    | [
        .subjects[]?
        | . as $s
        | select(
            ($s.kind == "User" and $s.name == $U)
            or
            ($s.kind == "Group" and ($G | index($s.name)))
          )
      ] as $matched_subjects
    | select($matched_subjects | length > 0)
    | [
        .metadata.name,
        .roleRef.kind,
        .roleRef.name,
        ($matched_subjects | map(.kind + ":" + .name) | join(","))
      ]
    | @tsv
    '
  )"

  {
    echo -e "BINDING\tROLE_REF_KIND\tROLE_REF_NAME\tMATCHED_SUBJECT"
    echo "$CRB_OUTPUT"
  } | sed '/^$/d' | column -t -s $'\t'

  echo
  print_line
  echo "RoleBinding namespace-scoped dirette o ereditate"
  print_line

  RB_OUTPUT="$(
    oc get rolebindings -A -o json | jq -r \
      --arg U "$SUBJECT_USER" \
      --argjson G "$GROUPS_JSON" '
    .items[]
    | . as $binding
    | [
        .subjects[]?
        | . as $s
        | select(
            ($s.kind == "User" and $s.name == $U)
            or
            ($s.kind == "Group" and ($G | index($s.name)))
          )
      ] as $matched_subjects
    | select($matched_subjects | length > 0)
    | [
        .metadata.namespace,
        .metadata.name,
        .roleRef.kind,
        .roleRef.name,
        ($matched_subjects | map(.kind + ":" + .name) | join(","))
      ]
    | @tsv
    '
  )"

  {
    echo -e "NAMESPACE\tBINDING\tROLE_REF_KIND\tROLE_REF_NAME\tMATCHED_SUBJECT"
    echo "$RB_OUTPUT"
  } | sed '/^$/d' | column -t -s $'\t'
}

list_for_group() {
  local SUBJECT_GROUP="$1"

  echo
  print_line
  echo "RBAC per gruppo: $SUBJECT_GROUP"
  print_line

  echo
  print_line
  echo "ClusterRoleBinding del gruppo"
  print_line

  CRB_OUTPUT="$(
    oc get clusterrolebindings -o json | jq -r \
      --arg G "$SUBJECT_GROUP" '
    .items[]
    | [
        .subjects[]?
        | select(.kind == "Group" and .name == $G)
      ] as $matched_subjects
    | select($matched_subjects | length > 0)
    | [
        .metadata.name,
        .roleRef.kind,
        .roleRef.name,
        ($matched_subjects | map(.kind + ":" + .name) | join(","))
      ]
    | @tsv
    '
  )"

  {
    echo -e "BINDING\tROLE_REF_KIND\tROLE_REF_NAME\tMATCHED_SUBJECT"
    echo "$CRB_OUTPUT"
  } | sed '/^$/d' | column -t -s $'\t'

  echo
  print_line
  echo "RoleBinding namespace-scoped del gruppo"
  print_line

  RB_OUTPUT="$(
    oc get rolebindings -A -o json | jq -r \
      --arg G "$SUBJECT_GROUP" '
    .items[]
    | [
        .subjects[]?
        | select(.kind == "Group" and .name == $G)
      ] as $matched_subjects
    | select($matched_subjects | length > 0)
    | [
        .metadata.namespace,
        .metadata.name,
        .roleRef.kind,
        .roleRef.name,
        ($matched_subjects | map(.kind + ":" + .name) | join(","))
      ]
    | @tsv
    '
  )"

  {
    echo -e "NAMESPACE\tBINDING\tROLE_REF_KIND\tROLE_REF_NAME\tMATCHED_SUBJECT"
    echo "$RB_OUTPUT"
  } | sed '/^$/d' | column -t -s $'\t'
}

main() {
  require_cmd oc
  require_cmd jq
  require_cmd column

  echo
  echo "Selettore RBAC OpenShift"
  echo
  echo "1) Cerca per utente"
  echo "2) Cerca per gruppo"
  echo

  read -rp "Scelta [1/2]: " CHOICE

  case "$CHOICE" in
    1)
      echo
      read -rp "Inserisci username, es. J18327: " SUBJECT_USER
      read -rp "Includere anche system:authenticated e system:authenticated:oauth? [s/N]: " INCLUDE_SYSTEM_GROUPS

      if [[ -z "$SUBJECT_USER" ]]; then
        echo "ERRORE: username vuoto"
        exit 1
      fi

      list_for_user "$SUBJECT_USER" "$INCLUDE_SYSTEM_GROUPS"
      ;;

    2)
      echo
      read -rp "Inserisci nome gruppo esatto: " SUBJECT_GROUP

      if [[ -z "$SUBJECT_GROUP" ]]; then
        echo "ERRORE: gruppo vuoto"
        exit 1
      fi

      list_for_group "$SUBJECT_GROUP"
      ;;

    *)
      echo "ERRORE: scelta non valida"
      exit 1
      ;;
  esac
}

main "$@"
