From 6b595fa4a3b0d9d9b6434fa255f615b6585305f7 Mon Sep 17 00:00:00 2001 From: "Hahn Axel (hahn)" <axel.hahn@unibe.ch> Date: Wed, 19 Feb 2025 13:26:22 +0100 Subject: [PATCH 1/2] more clear HTTP responses on error --- public_html/api/index.php | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/public_html/api/index.php b/public_html/api/index.php index 15c0b25a..7b197c9c 100644 --- a/public_html/api/index.php +++ b/public_html/api/index.php @@ -59,7 +59,7 @@ function _wd(string $s, string $sLevel = 'info'): bool } /** - * Abort execution of API requestwith error + * Abort execution of API request with error * * @param string $s message * @param integer $iStatus http status code to send @@ -68,6 +68,7 @@ function _quit(string $s, int $iStatus = 400): void { $aStatus = [ 400 => 'HTTP/1.0 400 Bad Request', + 401 => 'HTTP/1.0 401 Unauthorized', 403 => 'HTTP/1.0 403 Access denied', 404 => 'HTTP/1.0 404 Not found', ]; @@ -105,7 +106,7 @@ function _checkAuth(string $sProjectSecret): bool $aReqHeaders = apache_request_headers(); _wd('<pre>' . print_r($aReqHeaders, 1) . '</pre>'); if (!isset($aReqHeaders['Authorization'])) { - _quit('Access denied. Missing authorization.', 403); + _quit('Access denied. Missing authorization.', 401); } if (!isset($aReqHeaders['Date'])) { _quit('Access denied. Missing field "Date:" in the request header.', 403); @@ -123,7 +124,7 @@ function _checkAuth(string $sProjectSecret): bool _wd('Hash: ' . $sGotHash . ' -- from header'); _wd('Hash: ' . $sMyHash . ' -- rebuilt'); if ($sGotHash !== $sMyHash) { - _quit('Access denied. Invalid hash.', 403); + _quit('Access denied. Invalid hash.', 401); } $iAge = date('U') - date('U', strtotime($sGotDate)); @@ -216,14 +217,18 @@ switch ($sApiVersion) { ob_end_clean(); } catch (Exception $exc) { - _quit('ERROR: project with id [' . $sPrjId . '] does not exist.', 404); + _quit('ERROR: project with id [' . $sPrjId . '] cannot be initialized.', 400); // never reached } // get secret $aPrjCfg = $oProject->getConfig(); - $sProjectSecret = isset($aPrjCfg['api']['secret']) ? $aPrjCfg['api']['secret'] : false; + if(!count($aPrjCfg)){ + _quit('ERROR: project with id [' . $sPrjId . '] does not exist.', 404); + } + + $sProjectSecret = $aPrjCfg['api']['secret'] ?? false; if (!$sProjectSecret) { - _quit('Access denied. API access is disabled.'); + _quit('Access denied. API access is disabled.', 403); } // check authorization -- GitLab From b635762161a52e0d4380717fa59e2f683291448b Mon Sep 17 00:00:00 2001 From: "Hahn Axel (hahn)" <axel.hahn@unibe.ch> Date: Wed, 19 Feb 2025 15:18:52 +0100 Subject: [PATCH 2/2] api shel script: shell fixes; long cli parameters --- shellscripts/api-imlciserver.sh | 124 ++++++++++++++++---------------- 1 file changed, 64 insertions(+), 60 deletions(-) diff --git a/shellscripts/api-imlciserver.sh b/shellscripts/api-imlciserver.sh index 099e7ff3..7b1932e5 100755 --- a/shellscripts/api-imlciserver.sh +++ b/shellscripts/api-imlciserver.sh @@ -7,6 +7,7 @@ # 2020-07-23 v1.0 <axel.hahn@iml.unibe.ch> first lines # 2020-07-29 v1.1 <axel.hahn@iml.unibe.ch> check "/" in branch; check http status 200 # 2021-03-29 v1.2 <axel.hahn@iml.unibe.ch> support slashes in branch names +# 2025-02-19 v1.3 <axel.hahn@iml.unibe.ch> shell fixes; long cli parameters # ====================================================================== # ---------------------------------------------------------------------- @@ -22,30 +23,35 @@ line="----------------------------------------------------------------------" # FUNCTIONS # ---------------------------------------------------------------------- +# Show help with parameters function showhelp(){ + local _self; _self="$( basename "$0" )" echo " SYNTAX: - -a ACTION set name of an action - -b BRANCH set custom branch to access, i.e. origin/feature-123 - -p PROJECT project name in the ci server; overrides env variable IMLCI_PROJECT - -s SECRET API secret for the given project; overrides env variable IMLCI_API_SECRET - -u URL URL of iml ci server without trailing /; overrides env variable IMLCI_URL - -ACTION: - ... without given project and secret - projects show projects - - ... with project and secret - buildinfo [branch] - show infos about what happens on build - build [branch] - execute build - phases show status of phases + -a, --action ACTION + set name of an action + ... without given project and secret + projects show projects + + ... with project and secret + buildinfo BRANCH + show infos about what happens on build + build BRANCH + execute build + phases show status of phases + -b, --branch BRANCH + set custom branch to access, i.e. origin/feature-123 + -p, --project PROJECT + project name in the ci server; overrides env variable IMLCI_PROJECT + -s, --secret SECRET + API secret for the given project; overrides env variable IMLCI_API_SECRET + -u. --url URL + URL of iml ci server without trailing /; overrides env variable IMLCI_URL EXAMPLES: - `basename $0` -u https://ci.example.com -a projects - `basename $0` -u https://ci.example.com -p myproject -s 12345678 -a buildinfo - `basename $0` -u https://ci.example.com -p myproject -s 12345678 -a build + $_self -u https://ci.example.com -a projects + $_self -u https://ci.example.com -p myproject -s 12345678 -a buildinfo + $_self -u https://ci.example.com -p myproject -s 12345678 -a build " } @@ -59,7 +65,7 @@ function makeRequest(){ local outfile=$( mktemp ) echo $line - echo $apiMethod ${apiHost}${apiRequest} + echo "$apiMethod ${IMLCI_URL}${apiRequest}" echo $line if [ ! -z "$secret" ]; then @@ -67,7 +73,7 @@ function makeRequest(){ # --- date in http format LANG=en_EN # export TZ=GMT - apiTS=`date "+%a, %d %b %Y %H:%M:%S %Z"` + apiTS=$( date "+%a, %d %b %Y %H:%M:%S %Z" ) # --- generate data to hash: method + uri + timestamp; delimited with line break @@ -77,30 +83,32 @@ ${apiTS} " # generate hash - split in 2 commands (piping "cut" sends additional line break) - myHash=`echo -n "$data" | openssl sha1 -hmac "${secret}" | cut -f 2 -d" "` - myHash=`echo -n "$myHash" | base64` + myHash=$( echo -n "$data" | openssl sha1 -hmac "${secret}" | cut -f 2 -d" ") + myHash=$( echo -n "$myHash" | base64 ) curl -i \ -H "Accept: application/json" -H "Content-Type: application/json" \ -H "Date: ${apiTS}" \ -H "Authorization: demo-bash-client:${myHash}" \ - -X $apiMethod \ - ${IMLCI_URL}${apiRequest} | tee -a $outfile + -X "$apiMethod" \ + -s \ + "${IMLCI_URL}${apiRequest}" | tee -a "$outfile" else curl -i \ -H "Accept: application/json" -H "Content-Type: application/json" \ - -X $apiMethod \ - ${IMLCI_URL}${apiRequest} | tee -a $outfile + -X "$apiMethod" \ + -s \ + "${IMLCI_URL}${apiRequest}" | tee -a "$outfile" fi - grep "^HTTP/" $outfile | head -1 | grep " 200 " >/dev/null + grep "^HTTP/" "$outfile" | head -1 | grep " 200 " >/dev/null local rccurl=$? - rm -f $outfile + rm -f "$outfile" if [ $rccurl -ne 0 ]; then echo echo "ERROR: API request failed. CURL request did not get respond status code 200." - exit 4 + exit 5 fi } @@ -110,38 +118,34 @@ ${apiTS} # ---------------------------------------------------------------------- echo -echo ===== API CALL TO IML CI SERVER :: `date` ===== +echo "===== API CALL TO IML CI SERVER :: $( date ) =====" echo -if [ $# -lt 1 ]; then +if [ $# -eq 0 ]; then showhelp exit 1 fi -while getopts "a:b:u:p:s:" option; do -case ${option} in - a) - apiAction=$OPTARG - ;; - b) - branch=$OPTARG - ;; - u) - export IMLCI_URL=$OPTARG - ;; - p) - export IMLCI_PROJECT=$OPTARG - ;; - s) - export IMLCI_API_SECRET=$OPTARG - ;; - *) - echo ERROR: invalid option [${option}] - exit 2 -esac -done +while [[ "$#" -gt 0 ]]; do case $1 in + -a|--action) apiAction="$2";shift; shift;; + -b|--branch) branch="$2";shift; shift;; + -h|--help) showhelp; exit 0;; + -u|--url) IMLCI_URL="$2";shift; shift;; + -p|--project) IMLCI_PROJECT="$2";shift; shift;; + -s|--secret) IMLCI_API_SECRET="$2";shift; shift;; + *) if grep "^-" <<< "$1" >/dev/null ; then + echo; echo "ERROR: Unknown parameter: $1"; echo; showhelp; exit 2 + fi + break; + ;; +esac; done +if [ $# -gt 0 ]; then + showhelp + exit 3 +fi + -echo Params: $* +echo "Params: $*" echo "IMLCI_URL = $IMLCI_URL" echo "IMLCI_PROJECT = $IMLCI_PROJECT" echo "IMLCI_API_SECRET = $IMLCI_API_SECRET" @@ -151,7 +155,7 @@ echo # echo $branch | grep '/.*/.*' >/dev/null && ( echo "WARNING: Do NOT use a branch containing a slash [/] in the name"; echo ) -echo ACTION: $apiAction +echo "ACTION: $apiAction" case $apiAction in # --- projects is an access without autorization @@ -161,17 +165,17 @@ case $apiAction in # --- access WITH autorization only "build") - makeRequest POST /api/v1/project/$IMLCI_PROJECT/build/$branch "$IMLCI_API_SECRET" + makeRequest POST "/api/v1/project/$IMLCI_PROJECT/build/$branch" "$IMLCI_API_SECRET" ;; "buildinfo") - makeRequest GET /api/v1/project/$IMLCI_PROJECT/build/$branch "$IMLCI_API_SECRET" + makeRequest GET "/api/v1/project/$IMLCI_PROJECT/build/$branch" "$IMLCI_API_SECRET" ;; "phases") - makeRequest GET /api/v1/project/$IMLCI_PROJECT/phases "$IMLCI_API_SECRET" + makeRequest GET "/api/v1/project/$IMLCI_PROJECT/phases" "$IMLCI_API_SECRET" ;; *) echo "ERROR: unknown action [$apiAction]" - exit 3 + exit 4 esac rc=$? -- GitLab