#!/usr/bin/env bash ################################################################################################## # Verify that login, logout, and login failure events are properly stored in system.session_log # when different `IDENTIFIED BY` clauses are used on user. # # Make sure that system.session_log entries are non-empty and provide enough info on each event. # # Using multiple protocols # * native TCP protocol with CH client # * HTTP with CURL # * MySQL - CH server accesses itself via mysql table function, query typically fails (unrelated) # but auth should be performed properly. # * PostgreSQL - CH server accesses itself via postgresql table function (currently out of order). # * gRPC - not done yet # # There is way to control how many time a query (e.g. via mysql table function) is retried # and hence variable number of records in session_log. To mitigate this and simplify final query, # each auth_type is tested for separate user. That way SELECT DISTINCT doesn't exclude log entries # from different cases. # # All created users added to the ALL_USERNAMES and later cleaned up. ################################################################################################## # To minimize amount of error context sent on failed queries when talking to CH via MySQL protocol. export CLICKHOUSE_CLIENT_SERVER_LOGS_LEVEL=none CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) # shellcheck source=../shell_config.sh . "$CURDIR"/../shell_config.sh set -eu # Since there is no way to cleanup system.session_log table, # make sure that we can identify log entries from this test by a random user name. readonly BASE_USERNAME="session_log_test_user_$(cat /dev/urandom | tr -cd 'a-f0-9' | head -c 32)" readonly TMP_QUERY_FILE=$(mktemp /tmp/tmp_query.log.XXXXXX) declare -a ALL_USERNAMES ALL_USERNAMES+=("${BASE_USERNAME}") function reportError() { if [ -s "${TMP_QUERY_FILE}" ] ; then echo "!!!!!! ERROR ${CLICKHOUSE_CLIENT} ${*} --queries-file ${TMP_QUERY_FILE}" >&2 echo "query:" >&2 cat "${TMP_QUERY_FILE}" >&2 rm -f "${TMP_QUERY_FILE}" fi } function executeQuery() { ## Execute query (provided via heredoc or herestring) and print query in case of error. trap 'rm -f ${TMP_QUERY_FILE}; trap - ERR RETURN' RETURN # Since we want to report with current values supplied to this function call # shellcheck disable=SC2064 trap "reportError $*" ERR cat - > "${TMP_QUERY_FILE}" ${CLICKHOUSE_CLIENT} "${@}" --queries-file "${TMP_QUERY_FILE}" } function cleanup() { local usernames_to_cleanup usernames_to_cleanup="$(IFS=, ; echo "${ALL_USERNAMES[*]}")" executeQuery < "${TMP_QUERY_FILE}" ! ${CLICKHOUSE_CLIENT} "${@}" --multiquery --queries-file "${TMP_QUERY_FILE}" 2>&1 | tee -a ${TMP_QUERY_FILE} } function createUser() { local auth_type="${1}" local username="${2}" local password="${3}" if [[ "${auth_type}" == "no_password" ]] then password="" elif [[ "${auth_type}" == "plaintext_password" ]] then password="${password}" elif [[ "${auth_type}" == "sha256_password" ]] then password="$(executeQuery <<< "SELECT hex(SHA256('${password}'))")" elif [[ "${auth_type}" == "double_sha1_password" ]] then password="$(executeQuery <<< "SELECT hex(SHA1(SHA1('${password}')))")" else echo "Invalid auth_type: ${auth_type}" >&2 exit 1 fi export RESULTING_PASS="${password}" if [ -n "${password}" ] then password="BY '${password}'" fi executeQuery < 1, 'many', toString(count(*))) -- do not rely on count value since MySQL does arbitrary number of retries FROM system.session_log WHERE (user LIKE '%session_log_test_xml_user%' OR user LIKE '%${BASE_USERNAME}%') AND event_time_microseconds >= test_start_time GROUP BY user_name, interface, type ORDER BY user_name, interface, type; EOF