#!/bin/bash

# (C) Copyright European Space Agency, 2026
#
# Owner:         European Space Agency
# Author:        K. Panitzek
# Version:       2.1
# Last updated:  31/03/2026
#
# Change log:
# Version  |  Date        |  Reason for change
# 1.0      |  24/02/2021  |  Initial version
# 1.1      |  08/10/2021  |  Removal of 'jq' from prerequisites and change of cookie name
# 1.2      |  28/03/2022  |  Improve consent handling as the consent is now stored in OpenAM
# 1.3      |  20/10/2022  |  Adjust to correct HAPI capabilities response
# 1.4      |  20/06/2023  |  Fix the HAPI login URL
# 2.0      |  25/02/2026  |  Added support for Keycloak authentication via OIDC access token
# 2.1      |  31/03/2026  |  Remove authentication via OpenAM and consolidation

# Purpose:
# This script will attempt to retrieve an OIDC access token for accessing the SWE
# HAPI server hosted at ESA's SWE Portal. If the Client-ID or the Client-Secret have
# not bee provided, the user will be prompted to provide the credentials.
# The variables Client-ID and Client-Secret refer to the OpenId client's credentials
# when authenticating against Keycloak.
# The Scope determines the extent of the requested access permissions. It is a list
# of white space separated string literals. It must contain at least the Client-ID of
# the protected resources the token is being requested for (e.g. 'swe_hapiserver' for
# the SWE HAPI Server). Keycloak will embed this information into the token, to
# prevent potential misuse.
# While this script is defaults to obtain an access token for the SWE HAPI Server, it
# can also be used to request an access token for the SWE Content Proxy by setting
# the scope to 'swe_contentproxy' (option -y).
# More details can be found on the SWE HAPI Server page on ESA's SWE Portal at:
# https://swe.ssa.esa.int/swe-hapi-server

# Prerequisites:
# This script requires cURL to be installed on the system.
#
# Available options:
#   -h                  Display this help page and exit.
#   -v                  Enable verbose mode.
#   -s                  Silent mode. If successful, only prints out the obtained
#                       access token. This mode is best suitable for programmatic use
#                       and with options -i and -x (and -y if necessary).
#   -i <CLIENT-ID>      Set the Client-ID to access HAPI. If not provided, the user
#                       will be prompted to enter the Client-ID.
#   -x <CLIENT-SECRET>  Set the Client-Secret to access HAPI. If not provided, the
#                       user will be prompted to enter the Client-secret.
#   -y <SCOPE>          Set the scope, a space-separated list, of the protected
#                       resource to access, e.g., 'openid swe_hapiserver'. If not
#                       provided, the default value 'swe_hapiserver' will be used.
#   -c <PORTAL-URL>     Set a custom SWE Portal URL where HAPI is hosted. This will
#                       override the default value:
#                       $PORTAL_URL
#   -t                  If provided, the script will access the HAPI capabilities
#                       endpoint at <PORTAL-URL>/hapi/capabilities with cURL to test
#                       the obtained access tokens (in verbose mode if enabled).

# Global constants
NOCOL="\e[0m"
RED="\e[31m"
GREEN="\e[32m"
YELLOW="\e[33m"
CYAN="\e[36m"
LGREEN="\e[92m"

# Global variables that can change across deployments
PORTAL_URL="https://swe.ssa.esa.int/"
KEYCLOAK_URL="https://sso.s2p.esa.int/realms/swe/protocol/openid-connect/token"

# Input variables
USER=""
PASSWORD=""
CLIENT_ID=""
CLIENT_SECRET=""
SCOPE="swe_hapiserver"
CAPABILITIES_TEST=false
VERBOSE=false
SILENT=false

# Output variables and flags
FULL_ACCESS_TOKEN=""
ACCESS_TOKEN=""

# the help text to print if -h or invalid arguments are provided
function printHelp()
{
    echo "Usage: $0 [OPTION]"
    echo
    echo "Prerequisites:"
    echo "This script requires cURL to be installed on the system."
    echo
    echo "This script will attempt to retrieve an OIDC access token for accessing the SWE"
    echo "HAPI server hosted at ESA's SWE Portal. If the Client-ID or the Client-Secret have"
    echo "not bee provided, the user will be prompted to provide the credentials."
    echo "The variables Client-ID and Client-Secret refer to the OpenId client's credentials"
    echo "when authenticating against Keycloak."
    echo "The Scope determines the extent of the requested access permissions. It is a list"
    echo "of white space separated string literals. It must contain at least the Client-ID of"
    echo "the protected resources the token is being requested for (e.g. 'swe_hapiserver' for"
    echo "the SWE HAPI Server). Keycloak will embed this information into the token, to"
    echo "prevent potential misuse."
    echo "While this script defaults to obtain an access token for the SWE HAPI Server, it"
    echo "can also be used to request an access token for the SWE Content Proxy by setting"
    echo "the scope to 'swe_contentproxy' (option -y)."
    echo "More details can be found on the SWE HAPI Server page on ESA's SWE Portal at:"
    echo "https://swe.ssa.esa.int/swe-hapi-server"
    echo
    echo "Available options:"
    echo "  -h                  Display this help page and exit."
    echo "  -v                  Enable verbose mode."
    echo "  -s                  Silent mode. If successful, only prints out the obtained"
    echo "                      access token. This mode is best suitable for programmatic use"
    echo "                      and with options -i and -x (and -y if necessary)."
    echo "  -i <CLIENT-ID>      Set the Client-ID to access HAPI. If not provided, the user"
    echo "                      will be prompted to enter the Client-ID."
    echo "  -x <CLIENT-SECRET>  Set the Client-Secret to access HAPI. If not provided, the"
    echo "                      user will be prompted to enter the Client-secret."
    echo "  -y <SCOPE>          Set the scope, a space-separated list, of the protected"
    echo "                      resource to access, e.g., 'openid swe_hapiserver'. If not"
    echo "                      provided, the default value 'swe_hapiserver' will be used."
    echo "  -c <PORTAL-URL>     Set a custom SWE Portal URL where HAPI is hosted. This will"
    echo "                      override the default value:"
    echo "                      $PORTAL_URL"
    echo "  -t                  If provided, the script will access the HAPI capabilities"
    echo "                      endpoint at <PORTAL-URL>/hapi/capabilities with cURL to test"
    echo "                      the obtained access token (in verbose mode if enabled)."
}

# use the provided client-ID and -secret to obtain an access_token for the provided scope
function obtainAccessToken()
{
    if [[ -z "$CLIENT_ID" || -z "$CLIENT_SECRET" || -z "$SCOPE" ]]
    then
        if [ $SILENT == false ]
        then
            echo
            echo -e "Client-ID, Client-Secret or Scope not provided, skipping access token..."
        fi
        return
    fi

    local ACCESS_TOKEN_CMD="curl -s \
                            -w '\n%{http_code}' \
                            -d 'client_id=$CLIENT_ID' \
                            -d 'client_secret=$CLIENT_SECRET' \
                            -d 'grant_type=client_credentials' \
                            -d 'scope=$SCOPE' \
                            '${KEYCLOAK_URL}'"

    local ACCESS_TOKEN_PRINT="curl -d 'client_id=CLIENT_ID' -d 'client_secret=CLIENT_SECRET' -d 'grant_type=client_credentials' -d 'scope=${SCOPE}' '${KEYCLOAK_URL}'"

    if [ $VERBOSE == true ]
    then
        echo
        echo -e "${CYAN}Retrieving access token for scope '${SCOPE}'...${NOCOL}"
        echo -e "\$ ${YELLOW}$ACCESS_TOKEN_PRINT${NOCOL}"
    fi

    local ACCESS_TOKEN_RESPONSE=$(eval "$ACCESS_TOKEN_CMD")
    local HTTP_CODE=$(echo "$ACCESS_TOKEN_RESPONSE" | tail -n1)
    if [[ $HTTP_CODE == "200" ]]
    then
        FULL_ACCESS_TOKEN=$(echo "$ACCESS_TOKEN_RESPONSE" | sed '$d')
        ACCESS_TOKEN=$(echo "$FULL_ACCESS_TOKEN" | sed -E 's/[{},]/\n/g' | sed -E 's/"//g' | grep -E "^access_token:" | cut -d: -f2-)
    fi

    if [ $VERBOSE == true ]
    then
        echo
        echo -e "${CYAN}HTTP response code: $HTTP_CODE"
        echo -e "${CYAN}Received access token for scope '${SCOPE}':${NOCOL}"
        echo -e "${LGREEN}$FULL_ACCESS_TOKEN${NOCOL}"
    fi
}

# use the acces_token for all future HAPI requests until it expires.
# here we just request the capabilities again as a test. We use cURL in verbose mode if enabled
function runCapabilitiesTests()
{
    echo
    echo -e "${CYAN}Running verbose capabilities tests...${NOCOL}"

    VERB_TOGGLE=""
    if [ $VERBOSE == true ]
    then
        VERB_TOGGLE="-v"
    fi

    if [ -n "$ACCESS_TOKEN" ]
    then
        curl $VERB_TOGGLE -H "Authorization: Bearer $ACCESS_TOKEN" "${PORTAL_URL}/hapi/capabilities"
    fi
    echo
}

####################
##      MAIN      ##
####################

# evaluate provided arguments
while getopts ":hvstc:i:x:y:" ARG
do
    case $ARG in
        i) CLIENT_ID=$OPTARG ;;
        x) CLIENT_SECRET=$OPTARG ;;
        y) SCOPE=$OPTARG ;;
        c) PORTAL_URL=$OPTARG ;;
        t) CAPABILITIES_TEST=true ;;
        v) VERBOSE=true ;;
        s) SILENT=true ;;
        h | *) printHelp ; exit 0 ;;
    esac
done

# prompt for the client-ID if it was not provided
if [[ -z "$CLIENT_ID" ]]
then
    echo -n -e "${CYAN}Please enter Client-ID: ${NOCOL}"
    read CLIENT_ID
fi

# prompt for the client-secret if it was not provided
if [[ -z "$CLIENT_SECRET" ]]
then
    echo -n -e "${CYAN}Please enter Client-Secret: ${NOCOL}"
    read -s CLIENT_SECRET
    echo
fi

# print all variables and options for reference
if [ $VERBOSE == true ]
then
    echo -e "${CYAN}Running with the following options:${NOCOL}"
    echo "  VERBOSE=$VERBOSE"
    echo "  SILENT=$SILENT"
    echo "  CAPABILITIES_TEST=$CAPABILITIES_TEST"
    echo "  CLIENT_ID=$CLIENT_ID"
    echo "  CLIENT_SECRET=$CLIENT_SECRET"
    echo "  SCOPE=$SCOPE"
    echo
    echo -e "${CYAN}Using the following global variables:${NOCOL}"
    echo "  PORTAL_URL=$PORTAL_URL"
    echo "  KEYCLOAK_URL=$KEYCLOAK_URL"
fi

# obtain openid access token
obtainAccessToken

# run the capabilities test if requested by the user (option -t)
if [ $CAPABILITIES_TEST == true ]
then
    runCapabilitiesTests
fi

# print the results
if [[ -n $ACCESS_TOKEN ]]
then
    if [ $SILENT == false ]
    then
        echo
        echo -e "${CYAN}Authentication was successful!${NOCOL}"
        echo
        echo -e "${CYAN}Access Token to be used for subsequent HAPI calls:${NOCOL}"
    fi
    echo "$ACCESS_TOKEN"
    exit 0
else
    echo
    echo -e "${RED}Authentication has failed${NOCOL}"
    if [ $VERBOSE == false ]
    then
        echo -e "${RED}Please consider turning on verbose mode (-v) to identify the root cause for the issue.${NOCOL}"
    fi
fi
