#!/bin/bash

set -e
set -o pipefail

realm="EXAMPLE.FAKE"
myhostname="sshd-gssapi.${realm,,}"
testuser="testuser$$"
adduser --quiet --disabled-password --gecos "" "${testuser}"
password="secret"
user_principal="${testuser}@${realm}"
service_principal="host/${myhostname}"

source debian/tests/util

cleanup() {
    result=$?
    set +e
    if [ ${result} -ne 0 ]; then
        echo "## Something failed"
        echo
        echo "## klist"
        klist
        echo
        echo "## ssh server log"
        journalctl -b -u ssh.service --lines 100
        echo
        echo "## Kerberos KDC logs"
        journalctl -b -u krb5-kdc.service --lines 100
        echo
        echo "## Kerberos Admin server logs"
        journalctl -b -u krb5-admin-server.service --lines 100
        echo
        echo "## Skipping cleanup to facilitate troubleshooting"
    else
        echo "## ALL TESTS PASSED"
        echo "## Cleaning up"
        rm -f /etc/krb5.keytab
        rm -f /etc/ssh/sshd_config.d/gssapi.conf
        rm -f /etc/ssh/ssh_config.d/gssapi.conf
        rm -f /etc/ssh/ssh_config.d/dep8.conf
    fi
}

trap cleanup EXIT

setup() {
    echo "## Setting up test environment"
    adjust_hostname "${myhostname}"
    echo "## Creating Kerberos realm ${realm}"
    create_realm "${realm}" "${myhostname}"
    echo "## Creating principals"
    kadmin.local -q "addprinc -clearpolicy -pw ${password} ${user_principal}"
    kadmin.local -q "addprinc -clearpolicy -randkey ${service_principal}"
    echo "## Extracting service principal ${service_principal}"
    kadmin.local -q "ktadd -k /etc/krb5.keytab ${service_principal}"
    cat > /etc/ssh/ssh_config.d/dep8.conf <<EOF
Host *
    StrictHostKeyChecking no
    UserKnownHostsFile /dev/null
EOF
    echo "## Adjusting /etc/krb5.conf"
    cat > /etc/krb5.conf <<EOF
[libdefaults]
    default_realm = ${realm}
    rdns = false
    forwardable = true
    dns_lookup_kdc = falase
    dns_uri_lookup = false
    dns_lookup_realm = false

[realms]
    ${realm} = {
        kdc = ${myhostname}
        admin_server = ${myhostname}
    }
EOF
}

configure_sshd() {
    local auth_method="${1}"

    if [ "${auth_method}" = "gssapi-with-mic" ]; then
        # server
        echo "## Configuring sshd for ${auth_method} authentication"
        cat > /etc/ssh/sshd_config.d/gssapi.conf <<EOF
GSSAPIAuthentication yes
GSSAPIKeyExchange no
GSSAPICleanupCredentials yes
PubkeyAuthentication no
AuthenticationMethods ${auth_method}
EOF
    # client
    cat > /etc/ssh/ssh_config.d/gssapi.conf <<EOF
Host *
    GSSAPIAuthentication yes
    GSSAPIKeyExchange no
    PubkeyAuthentication no
EOF
    elif [ "${auth_method}" = "gssapi-keyex" ]; then
        # server
        echo "## Configuring sshd for ${auth_method} authentication"
        cat > /etc/ssh/sshd_config.d/gssapi.conf <<EOF
GSSAPIAuthentication yes
GSSAPIKeyExchange yes
GSSAPICleanupCredentials yes
PubkeyAuthentication no
AuthenticationMethods ${auth_method}
EOF
    # client
    cat > /etc/ssh/ssh_config.d/gssapi.conf <<EOF
Host *
    GSSAPIAuthentication yes
    GSSAPIKeyExchange yes
    PubkeyAuthentication no
EOF
    else
        echo "## ERROR: unknown auth_method \"${auth_method}\""
        return 1
    fi
    echo "## Restarting ssh"
    systemctl restart ssh.service
}

_test_ssh_login() {
    local auth_method="${1}"

    kdestroy 2>/dev/null || :
    configure_sshd "${auth_method}" || return $?
    echo "## Obtaining TGT"
    echo "${password}" | timeout --verbose 30 kinit "${user_principal}" || return $?
    klist
    echo
    echo "## ssh'ing into localhost using ${auth_method} auth"
    timeout --verbose 30 ssh "${testuser}@${myhostname}" date || return $?
    echo
    echo "## checking that we got a service ticket for ssh (host/)"
    klist | grep -F "${service_principal}" || return $?
    echo
    echo "## Checking ssh logs to confirm ${auth_method} auth was used"
    journalctl -u ssh.service -b --grep "Accepted ${auth_method}"
}

test_gssapi_login() {
    local auth_method="gssapi-with-mic"

    _test_ssh_login "${auth_method}"
}

test_gssapi_keyex_login() {
    local auth_method="gssapi-keyex"

    _test_ssh_login "${auth_method}"
}

setup
echo "## TESTS"
echo
run_test test_gssapi_login
run_test test_gssapi_keyex_login
