From 1ce235ac38b9f511dfc2a908065a464e9012ef02 Mon Sep 17 00:00:00 2001 From: Jakub Jelen Date: Mon, 12 Mar 2018 16:48:08 +0100 Subject: [PATCH] tests/pam_ssh_agent_auth: Add a new sanity test --- tests/pam_ssh_agent_auth/Makefile | 64 +++++++ tests/pam_ssh_agent_auth/PURPOSE | 7 + tests/pam_ssh_agent_auth/pam_save_ssh_var.c | 73 ++++++++ tests/pam_ssh_agent_auth/runtest.sh | 184 ++++++++++++++++++++ tests/tests.yml | 5 + 5 files changed, 333 insertions(+) create mode 100644 tests/pam_ssh_agent_auth/Makefile create mode 100644 tests/pam_ssh_agent_auth/PURPOSE create mode 100644 tests/pam_ssh_agent_auth/pam_save_ssh_var.c create mode 100755 tests/pam_ssh_agent_auth/runtest.sh diff --git a/tests/pam_ssh_agent_auth/Makefile b/tests/pam_ssh_agent_auth/Makefile new file mode 100644 index 0000000..f77eb4d --- /dev/null +++ b/tests/pam_ssh_agent_auth/Makefile @@ -0,0 +1,64 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Makefile of /CoreOS/openssh/Sanity/pam_ssh_agent_auth +# Description: This is a basic sanity test for pam_ssh_agent_auth +# Author: Jakub Jelen +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2015 Red Hat, Inc. +# +# This program is free software: you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation, either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see http://www.gnu.org/licenses/. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +export TEST=/CoreOS/openssh/Sanity/pam_ssh_agent_auth +export TESTVERSION=1.0 + +BUILT_FILES= + +FILES=$(METADATA) runtest.sh Makefile PURPOSE pam_save_ssh_var.c + +.PHONY: all install download clean + +run: $(FILES) build + ./runtest.sh + +build: $(BUILT_FILES) + test -x runtest.sh || chmod a+x runtest.sh + +clean: + rm -f *~ $(BUILT_FILES) + + +-include /usr/share/rhts/lib/rhts-make.include + +$(METADATA): Makefile + @echo "Owner: Jakub Jelen " > $(METADATA) + @echo "Name: $(TEST)" >> $(METADATA) + @echo "TestVersion: $(TESTVERSION)" >> $(METADATA) + @echo "Path: $(TEST_DIR)" >> $(METADATA) + @echo "Description: This is basic sanity test for pam_ssh_agent_auth" >> $(METADATA) + @echo "Type: Sanity" >> $(METADATA) + @echo "TestTime: 5m" >> $(METADATA) + @echo "RunFor: openssh" >> $(METADATA) + @echo "Requires: openssh pam_ssh_agent_auth pam-devel expect" >> $(METADATA) + @echo "RhtsRequires: library(distribution/fips)" >> $(METADATA) + @echo "Priority: Normal" >> $(METADATA) + @echo "License: GPLv2+" >> $(METADATA) + @echo "Confidential: no" >> $(METADATA) + @echo "Destructive: no" >> $(METADATA) + @echo "Releases: -RHEL4 -RHELClient5 -RHELServer5" >> $(METADATA) + + rhts-lint $(METADATA) diff --git a/tests/pam_ssh_agent_auth/PURPOSE b/tests/pam_ssh_agent_auth/PURPOSE new file mode 100644 index 0000000..59557de --- /dev/null +++ b/tests/pam_ssh_agent_auth/PURPOSE @@ -0,0 +1,7 @@ +PURPOSE of /CoreOS/openssh/Sanity/pam_ssh_agent_auth +Description: This is basic sanity test for pam_ssh_agent_auth +Author: Jakub Jelen + +Created as a response to rhbz#1251777 and previous one rhbz#1225106. +The code of pam module is outdated and compiled with current openssh +version which went through quite enough refactoring. diff --git a/tests/pam_ssh_agent_auth/pam_save_ssh_var.c b/tests/pam_ssh_agent_auth/pam_save_ssh_var.c new file mode 100644 index 0000000..e422fff --- /dev/null +++ b/tests/pam_ssh_agent_auth/pam_save_ssh_var.c @@ -0,0 +1,73 @@ +/* +This simple pam module saves the content of SSH_USER_AUTH variable to /tmp/SSH_USER_AUTH +file. + +Setup: + - gcc -fPIC -DPIC -shared -rdynamic -o pam_save_ssh_var.o pam_save_ssh_var.c + - copy pam_save_ssh_var.o to /lib/security resp. /lib64/security + - add to /etc/pam.d/sshd + auth requisite pam_save_ssh_var.o +*/ + +/* Define which PAM interfaces we provide */ +#define PAM_SM_ACCOUNT +#define PAM_SM_AUTH +#define PAM_SM_PASSWORD +#define PAM_SM_SESSION + +/* Include PAM headers */ +#include +#include +#include +#include + +int save_ssh_var(pam_handle_t *pamh, const char *phase) { + FILE *fp; + const char *var; + + fp = fopen("/tmp/SSH_USER_AUTH","a"); + fprintf(fp, "BEGIN (%s)\n", phase); + var = pam_getenv(pamh, "SSH_USER_AUTH"); + if (var != NULL) { + fprintf(fp, "SSH_USER_AUTH: '%s'\n", var); + } + fprintf(fp, "END (%s)\n", phase); + fclose(fp); + + return 0; +} + +/* PAM entry point for session creation */ +int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { + return(PAM_IGNORE); +} + +/* PAM entry point for session cleanup */ +int pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { + return(PAM_IGNORE); +} + +/* PAM entry point for accounting */ +int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) { + return(PAM_IGNORE); +} + +/* PAM entry point for authentication verification */ +int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { + save_ssh_var(pamh, "auth"); + return(PAM_IGNORE); +} + +/* + PAM entry point for setting user credentials (that is, to actually + establish the authenticated user's credentials to the service provider) + */ +int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) { + return(PAM_IGNORE); +} + +/* PAM entry point for authentication token (password) changes */ +int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) { + return(PAM_IGNORE); +} + diff --git a/tests/pam_ssh_agent_auth/runtest.sh b/tests/pam_ssh_agent_auth/runtest.sh new file mode 100755 index 0000000..1660005 --- /dev/null +++ b/tests/pam_ssh_agent_auth/runtest.sh @@ -0,0 +1,184 @@ +#!/bin/bash +# vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# runtest.sh of /CoreOS/openssh/Sanity/pam_ssh_agent_auth +# Description: This is a basic sanity test for pam_ssh_agent_auth +# Author: Jakub Jelen +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2015 Red Hat, Inc. +# +# This program is free software: you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation, either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see http://www.gnu.org/licenses/. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Include Beaker environment +. /usr/bin/rhts-environment.sh || exit 1 +. /usr/share/beakerlib/beakerlib.sh || exit 1 + +PACKAGE="openssh" +PAM_SUDO="/etc/pam.d/sudo" +PAM_SSHD="/etc/pam.d/sshd" +PAM_MODULE="pam_save_ssh_var" +SUDOERS_CFG="/etc/sudoers.d/01_pam_ssh_auth" +SSHD_CFG="/etc/ssh/sshd_config" +USER="testuser$RANDOM" +PASS="testpassxy4re.3298fhdsaf" +AUTH_KEYS="/etc/security/authorized_keys" +AK_COMMAND_BIN="/root/ak.sh" +AK_COMMAND_KEYS="/root/akeys" +declare -a KEYS=("rsa" "ecdsa") + +rlJournalStart + rlPhaseStartSetup + rlAssertRpm $PACKAGE + rlAssertRpm pam_ssh_agent_auth + rlImport distribution/fips + rlServiceStart sshd + rlRun "TmpDir=\$(mktemp -d)" 0 "Creating tmp directory" + rlRun "cp ${PAM_MODULE}.c $TmpDir/" + rlRun "pushd $TmpDir" + rlFileBackup --clean $PAM_SUDO /etc/sudoers /etc/sudoers.d/ /etc/security/ $AUTH_KEYS + rlRun "sed -i '1 a\ +auth sufficient pam_ssh_agent_auth.so file=$AUTH_KEYS' $PAM_SUDO" + rlRun "echo 'Defaults env_keep += \"SSH_AUTH_SOCK\"' > $SUDOERS_CFG" + rlRun "echo 'Defaults !requiretty' >> $SUDOERS_CFG" + grep '^%wheel' /etc/sudoers || \ + rlRun "echo '%wheel ALL=(ALL) ALL' >> $SUDOERS_CFG" + rlRun "useradd $USER -G wheel" + rlRun "echo $PASS |passwd --stdin $USER" + rlPhaseEnd + + if ! fipsIsEnabled; then + KEYS+=("dsa") + fi + + for KEY in "${KEYS[@]}"; do + rlPhaseStartTest "Test with key type $KEY" + rlRun "su $USER -c 'ssh-keygen -t $KEY -f ~/.ssh/my_id_$KEY -N \"\"'" 0 + + # Without authorized_keys, the authentication should fail + rlRun -s "su $USER -c 'eval \`ssh-agent\`; sudo id; ssh-agent -k'" 0 + rlAssertNotGrep "uid=0(root) gid=0(root)" $rlRun_LOG + + # Append the keys only to make sure we can match also the non-first line + rlRun "cat ~$USER/.ssh/my_id_${KEY}.pub >> $AUTH_KEYS" + rlRun -s "su $USER -c 'eval \`ssh-agent\`; ssh-add ~/.ssh/my_id_$KEY; sudo id; ssh-agent -k'" + rlAssertGrep "uid=0(root) gid=0(root)" $rlRun_LOG + rlPhaseEnd + done + + if rlIsRHEL '<6.8' || ( rlIsRHEL '<7.3' && rlIsRHEL 7 ) ; then + : # not available + else + rlPhaseStartSetup "Setup for authorized_keys_command" + rlFileBackup --namespace ak_command $PAM_SUDO + rlRun "rm -f $AUTH_KEYS" + cat >$AK_COMMAND_BIN <<_EOF +#!/bin/bash +cat $AK_COMMAND_KEYS +_EOF + rlRun "chmod +x $AK_COMMAND_BIN" + rlRun "sed -i 's|.*pam_ssh_agent_auth.*|auth sufficient pam_ssh_agent_auth.so authorized_keys_command=$AK_COMMAND_BIN authorized_keys_command_user=root|' $PAM_SUDO" + rlRun "cat $PAM_SUDO" + rlPhaseEnd + + for KEY in "${KEYS[@]}"; do + rlPhaseStartTest "Test authorized_keys_command with key type $KEY (bz1299555, bz1317858)" + rlRun "cat ~$USER/.ssh/my_id_${KEY}.pub >$AK_COMMAND_KEYS" + rlRun -s "su $USER -c 'eval \`ssh-agent\`; ssh-add ~/.ssh/my_id_$KEY; sudo id; ssh-agent -k'" + rlAssertGrep "uid=0(root) gid=0(root)" $rlRun_LOG + rlPhaseEnd + done + + rlPhaseStartCleanup "Cleanup for authorized_keys_command" + rlFileRestore --namespace ak_command + rlRun "rm -f $AK_COMMAND_BIN $AK_COMMAND_KEYS" + rlPhaseEnd + fi + + if rlIsRHEL '>=7.3'; then # not in Fedora anymore + rlPhaseStartTest "bz1312304 - Exposing information about succesful auth" + rlRun "rlFileBackup --namespace exposing $PAM_SSHD" + rlRun "rlFileBackup --namespace exposing $SSHD_CFG" + rlRun "rlFileBackup --namespace exposing /root/.ssh/" + rlRun "rm -f ~/.ssh/id_rsa*" + rlRun "ssh-keygen -f ~/.ssh/id_rsa -N \"\"" 0 + rlRun "ssh-keyscan localhost >~/.ssh/known_hosts" 0 + USER_AK_FILE=~$USER/.ssh/authorized_keys + rlRun "cat ~/.ssh/id_rsa.pub >$USER_AK_FILE" + rlRun "chown $USER:$USER $USER_AK_FILE" + rlRun "chmod 0600 $USER_AK_FILE" + rlRun "gcc -fPIC -DPIC -shared -rdynamic -o $PAM_MODULE.o $PAM_MODULE.c" + rlRun "test -d /lib64/security && cp $PAM_MODULE.o /lib64/security/" 0,1 + rlRun "test -d /lib/security && cp $PAM_MODULE.o /lib/security/" 0,1 + rlRun "sed -i '1 i auth optional $PAM_MODULE.o' $PAM_SSHD" + + # pam-and-env should expose information to both PAM and environmental variable; + # we will be testing only env variable here for the time being, + rlRun "echo 'ExposeAuthenticationMethods pam-and-env' >>$SSHD_CFG" + rlRun "sed -i '/^ChallengeResponseAuthentication/ d' $SSHD_CFG" + rlRun "service sshd restart" + rlWaitForSocket 22 -t 5 + rlRun -s "ssh -i ~/.ssh/id_rsa $USER@localhost \"env|grep SSH_USER_AUTH\"" 0 \ + "Environment variable SSH_USER_AUTH is set" + rlAssertGrep "^SSH_USER_AUTH=publickey:" $rlRun_LOG + rlRun "rm -f $rlRun_LOG" + + # pam-only should expose information only to PAM and not to environment variable + rlRun "sed -i 's/pam-and-env/pam-only/' $SSHD_CFG" + rlRun "echo 'AuthenticationMethods publickey,keyboard-interactive:pam' >>$SSHD_CFG" + rlRun "service sshd restart" + rlWaitForSocket 22 -t 5 +ssh_with_pass() { + ssh_args=("-i /root/.ssh/id_rsa") + ssh_args+=("$USER@localhost") + cat >ssh.exp <<_EOF +#!/usr/bin/expect -f + +set timeout 5 +spawn ssh ${ssh_args[*]} "echo CONNECTED; env|grep SSH_USER_AUTH" +expect { + -re {.*[Pp]assword.*} { send -- "$PASS\r"; exp_continue } + timeout { exit 1 } + eof { exit 0 } +} +_EOF + rlRun -s "expect -f ssh.exp" +} + #rlRun -s "ssh ${ssh_args[*]} \"echo CONNECTED; env|grep SSH_USER_AUTH\"" 1 \ + #"Environment variable SSH_USER_AUTH is NOT set" + rlRun "ssh_with_pass" + rlRun "grep -q CONNECTED $rlRun_LOG" 0 "Connection was successful" + rlAssertGrep "^SSH_USER_AUTH: 'publickey:" /tmp/SSH_USER_AUTH + rlRun "cat /tmp/SSH_USER_AUTH" + rlRun "rm -f $rlRun_LOG /tmp/SSH_USER_AUTH" + for pm in /lib64/security/$PAM_MODULE.o /lib/security/$PAM_MODULE.o; do + rlRun "test -e $pm && rm -f $pm" 0,1 + done + rlRun "rlFileRestore --namespace exposing" + rlPhaseEnd + fi + + rlPhaseStartCleanup + rlRun "popd" + rlRun "rm -r $TmpDir" 0 "Removing tmp directory" + rlRun "userdel -r $USER" + rlFileRestore + rlServiceRestore sshd + rlPhaseEnd +rlJournalPrintText +rlJournalEnd diff --git a/tests/tests.yml b/tests/tests.yml index 1950859..8086af2 100644 --- a/tests/tests.yml +++ b/tests/tests.yml @@ -15,6 +15,7 @@ - role: standard-test-beakerlib tests: - port-forwarding + - pam_ssh_agent_auth required_packages: - iproute # needs ip command - procps-ng # needs ps and pgrep commands @@ -24,3 +25,7 @@ - net-tools # needs netstat command - libselinux-utils # needs selinuxenabled command - nmap-ncat # needs nc command + - pam_ssh_agent_auth + - gcc # needs to test pam_ssh_agent_auth + - pam-devel # needs to test pam_ssh_agent_auth + - expect # needs to test pam_ssh_agent_auth