#!/bin/sh
# PCP QA Test No. 1391
# Exercise pmproxy mandatory authentication mode with special and nonascii characters.
#
# Copyright (c) 2017,2019,2021 Red Hat.
#

seq=`basename $0`
echo "QA output created by $seq"

. ./common.python
. ./common.secure

$python -c "from pcp import pmda" >/dev/null 2>&1
[ $? -eq 0 ] || _notrun "python pcp pmda module not installed"
which curl >/dev/null 2>&1 || _notrun "No curl binary installed"

full_hostname=`hostname --fqdn`

sasl_notrun_checks saslpasswd2 sasldblistusers2
$pluginviewer -a | grep 'Plugin "sasldb"' >/dev/null
test $? -eq 0 || _notrun "SASL sasldb auxprop plugin unavailable"
$pluginviewer -c | grep 'Plugin "plain"' >/dev/null 2>&1
test $? -eq 0 || _notrun 'No client support for plain authentication'
$pluginviewer -s | grep 'Plugin "plain"' >/dev/null 2>&1
test $? -eq 0 || _notrun 'No server support for plain authentication'


signal=$PCP_BINADM_DIR/pmsignal
status=1	# failure is the default!
need_restore=false
groupid=`id -g`
userid=`id -u`
domain=242
loaded=2

_cleanup()
{
    cd $here

    # restore any modified pmcd and pmproxy configuration files
    if $need_restore
    then
	need_restore=false
	_restore_config $PCP_SASLCONF_DIR/pmcd.conf
	_restore_config $PCP_SYSCONF_DIR/labels
        _restore_config $PCP_SYSCONF_DIR/pmproxy
    fi

    if pmprobe -I pmcd.agent.status | grep '"test_python"' >/dev/null
    then
	$sudo rm $PCP_VAR_DIR/config/pmda/$domain.$loaded
	cd $here/pmdas/test_python
	$sudo ./Remove >>$seq_full 2>&1
	$sudo rm -f domain.h.python
	cd $here
    fi

    _service pmcd stop >>$seq_full 2>&1
    _service pmcd start >>$seq_full 2>&1
    _wait_for_pmcd

    if $pmproxy_was_running
    then
	echo "Restart pmproxy ..." >>$seq_full
	_service pmproxy restart >>$seq_full 2>&1
	_wait_for_pmproxy
    else
	echo "Stopping pmproxy ..." >>$seq_full
	_service pmproxy stop >>$seq_full 2>&1
    fi

    $sudo rm -f $tmp.*
}

trap "_cleanup; exit \$status" 0 1 2 3 15

pmproxy_was_running=false
[ -f $PCP_RUN_DIR/pmproxy.pid ] && pmproxy_was_running=true
echo "pmproxy_was_running=$pmproxy_was_running" >>$seq_full

_filter_credentials()
{
    sed \
	-e 's/"groupid": '$groupid',/"groupid": GID/g' \
	-e 's/"userid": '$userid'/"userid": UID/g' \
    #end
}

_filter_username()
{
    sed -e "s/user $username/user USER/"
}

_filter_listusers2()
{
    sed \
        -e "s/^$username/USER/" \
        -e "s/@$full_hostname:/@HOST:/" \
        -e "s/@$hostname:/@HOST:/" \
    #end
}

_filter_json()
{
    tee -a $seq_full | \
    sed -e 's,"machineid": .*,"machineid": "MACHINEID",g' \
        -e 's,"context": .*,"context": "CONTEXT",g' \
        -e 's,"hostname": .*,"hostname": "HOSTNAME",g' \
        -e 's,"domainname": .*,"domainname": "DOMAINNAME",g' \
        -e 's,"source": .*,"source": "SOURCE",g' \
        -e 's,"hostspec": .*,"hostspec": "HOSTSPEC",g' \
    # end
}

_filter_ctx()
{
    tee -a $seq_full | \
    sed -E -e 's/ctx [0-9]+/ctx ?/g'
}

_test_log()
{
    echo && echo "=== $@ ===" | tee -a $seq_full
}

_json_log()
{
    pmjson | tee -a $seq_full
}

# real QA test starts here
_save_config $PCP_SYSCONF_DIR/labels
_save_config $PCP_SYSCONF_DIR/pmproxy
_save_config $PCP_SASLCONF_DIR/pmcd.conf
need_restore=true
$sudo rm -rf $PCP_SYSCONF_DIR/labels/*

# start pmcd in sasldb authenticating mode
echo 'mech_list: plain' >$tmp.sasl
echo "sasldb_path: $tmp.passwd.db" >>$tmp.sasl
$sudo cp $tmp.sasl $PCP_SASLCONF_DIR/pmcd.conf
$sudo chown $PCP_USER:$PCP_GROUP $PCP_SASLCONF_DIR/pmcd.conf
ls -l $PCP_SASLCONF_DIR/pmcd.conf >>$seq_full
$sudo -u $PCP_USER cat $PCP_SASLCONF_DIR/pmcd.conf >>$seq_full

echo "Creating temporary sasldb, add user running QA to it" | tee -a $seq_full
password="some=very&secret.passwörd"
password_urlencoded="some%3Dvery%26secret.passw%C3%B6rd"
echo $password | saslpasswd2 -p -a pmcd -f $tmp.passwd.db $username
echo "Using secret password: $password"

echo "Verify saslpasswd2 has successfully added a new user" | tee -a $seq_full
sasldblistusers2 -f $tmp.passwd.db \
| tee -a $seq_full \
| _filter_listusers2

echo "Ensure pmcd can read the password file" | tee -a $seq_full
# don't let umask get in the way!
#
chmod 640 $tmp.passwd.db
$sudo chgrp pcp $tmp.passwd.db
ls -l $tmp.passwd.db >>$seq_full
$sudo -u $PCP_USER od -c $tmp.passwd.db >>$seq_full

echo "Start pmcd with this shiny new sasldb"
if ! _service pmcd restart 2>&1; then _exit 1; fi | tee -a $seq_full >$tmp.out
_wait_for_pmcd || _exit 1

if [ "$PCPQA_SYSTEMD" = yes ]
then
    $sudo systemctl daemon-reload
fi

echo "Start pmproxy with mandatory authentication"
if ! _service pmproxy stop >/dev/null; then _exit 1; fi
if ! _service pmproxy start >>$seq_full 2>&1; then _exit 1; fi

echo "Start test Python PMDA to check if username is in per-context state"
cd pmdas/test_python
$sudo ./Install </dev/null \
| _filter_pmda_install
cd $here

_test_log "invalid username with pminfo"
pminfo -f -h "pcp://127.0.0.1?username=nonexisting_user&password=bob" test_python.current_username

_test_log "invalid password with pminfo"
pminfo -f -h "pcp://127.0.0.1?username=$username&password=bob" test_python.current_username

_test_log "correct password with pminfo"
pminfo -f -h "pcp://127.0.0.1?username=$username&password=$password_urlencoded" test_python.current_username | _filter_ctx | _filter_username


_test_log "no authentication"
response=$(curl -s "http://localhost:44322/pmapi/context")
echo "${response}" | pmjson | _filter_json
ctx_unauthenticated=$(echo "${response}" | pmpython -c 'import sys,json; print(json.load(sys.stdin)["context"])')

_test_log "invalid username"
curl -s --user nonexisting_user:bob "http://localhost:44322/pmapi/context" | _json_log | _filter_json

_test_log "invalid password"
curl -s --user $username:bob "http://localhost:44322/pmapi/context" | _json_log | _filter_json

_test_log "correct password"
response=$(curl -s --user "$username:$password" "http://localhost:44322/pmapi/context")
echo "${response}" | pmjson | _filter_json | _filter_credentials
ctx_authenticated=$(echo "${response}" | pmpython -c 'import sys,json; print(json.load(sys.stdin)["context"])')

_test_log "using unauthenticated context"
curl -s "http://localhost:44322/pmapi/$ctx_unauthenticated/fetch?names=test_python.current_username" | _json_log | grep '"value"' | _filter_ctx

_test_log "using authenticated context, missing HTTP auth headers (expect failure)"
curl -s "http://localhost:44322/pmapi/$ctx_authenticated/fetch?names=test_python.current_username" | _json_log | _filter_json

_test_log "using authenticated context, with HTTP auth headers (expect success)"
curl -s --user "$username:$password" "http://localhost:44322/pmapi/$ctx_authenticated/fetch?names=test_python.current_username" | _json_log | grep '"value"' | _filter_ctx | _filter_username


echo >>$seq_full
echo "=== pmproxy log ===" >>$seq_full
cat $PCP_LOG_DIR/pmproxy/pmproxy.log >>$seq_full
echo "=== test_python PMDA log ===" >>$seq_full
cat $PCP_LOG_DIR/pmcd/test_python.log >>$seq_full

status=0
exit
