diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/core/docker/dockerimages/DockerImages.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/core/docker/dockerimages/DockerImages.kt index 1efbc40..3278758 100644 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/core/docker/dockerimages/DockerImages.kt +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/core/docker/dockerimages/DockerImages.kt @@ -7,7 +7,7 @@ interface DockerImage { } /** - * Provides a docker image based on ubuntu additionally with a non-root default user and sudo isntalled + * Provides a docker image based on ubuntu additionally with a non-root default user and sudo installed */ class UbuntuPlusUser(private val userName: String = "testuser") : DockerImage { diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/core/platforms/UbuntuProv.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/core/platforms/UbuntuProv.kt index 67fae5b..b892135 100644 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/core/platforms/UbuntuProv.kt +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/core/platforms/UbuntuProv.kt @@ -10,24 +10,34 @@ import org.domaindrivenarchitecture.provs.core.processors.Processor const val SHELL = "/bin/bash" -class UbuntuProv internal constructor(processor : Processor = LocalProcessor(), name: String? = null, progressType: ProgressType) - : Prov(processor, name, progressType) { +class UbuntuProv internal constructor( + processor: Processor = LocalProcessor(), + name: String? = null, + progressType: ProgressType +) : Prov(processor, name, progressType) { - override fun cmd(cmd: String, dir: String?, sudo: Boolean) : ProvResult = def { + init { + val user = cmdNoLog("whoami").out?.trim() + if (!cmdNoLog("timeout 1 sudo id").success) { + println("!!!!!!!!!! WARNING !!!!!!!!!!\nUser $user cannot sudo without entering a password, i.e. most functions may fail!\nPlease ensure $user can sudo without password.") + } + } + + override fun cmd(cmd: String, dir: String?, sudo: Boolean): ProvResult = def { xec(SHELL, "-c", commandWithDirAndSudo(cmd, dir, sudo)) } - override fun cmdNoLog(cmd: String, dir: String?, sudo: Boolean) : ProvResult { + override fun cmdNoLog(cmd: String, dir: String?, sudo: Boolean): ProvResult { return xecNoLog(SHELL, "-c", commandWithDirAndSudo(cmd, dir, sudo)) } - override fun cmdNoEval(cmd: String, dir: String?, sudo: Boolean) : ProvResult { + override fun cmdNoEval(cmd: String, dir: String?, sudo: Boolean): ProvResult { return xec(SHELL, "-c", commandWithDirAndSudo(cmd, dir, sudo)) } } private fun commandWithDirAndSudo(cmd: String, dir: String?, sudo: Boolean): String { - val cmdWithDir= if (dir == null) cmd else "cd $dir && $cmd" + val cmdWithDir = if (dir == null) cmd else "cd $dir && $cmd" return if (sudo) cmdWithDir.sudoize() else cmdWithDir } diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/extensions/workplace/ProvisionWorkplace.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/extensions/workplace/ProvisionWorkplace.kt index c5146c4..c77ba99 100644 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/extensions/workplace/ProvisionWorkplace.kt +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/extensions/workplace/ProvisionWorkplace.kt @@ -46,7 +46,7 @@ fun Prov.provisionWorkplace( userPassword?.also { makeUserSudoerWithNoSudoPasswordRequired(it) } if (!currentUserCanSudo()) { - throw Exception("Current user ${whoami()} cannot execute sudo without a password, but he must be able to in order to provisionWorkplace") + throw Exception("Current user ${whoami()} cannot execute sudo without entering a password! This is necessary to execute provisionWorkplace") } aptInstall("ssh gnupg curl git") diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/ubuntu/user/base/User.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/ubuntu/user/base/User.kt index 4d80dc3..d83dcfb 100644 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/ubuntu/user/base/User.kt +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/ubuntu/user/base/User.kt @@ -67,7 +67,6 @@ fun Prov.configureUser(config: UserConfig) = requireAll { @Suppress("unused") -// todo create test fun Prov.deleteUser(userName: String, deleteHomeDir: Boolean = false): ProvResult = requireAll { val flagToDeleteHomeDir = if (deleteHomeDir) " -r " else "" if (userExists(userName)) { @@ -130,7 +129,7 @@ fun Prov.userIsInGroupSudo(userName: String): Boolean { */ @Suppress("unused") fun Prov.currentUserCanSudo(): Boolean { - return cmd("timeout 1 sudo id").success + return chk("timeout 1 sudo id") } diff --git a/src/test/kotlin/org/domaindrivenarchitecture/provs/core/platformTest/UbuntuProvTests.kt b/src/test/kotlin/org/domaindrivenarchitecture/provs/core/platformTest/UbuntuProvTests.kt index b7f5bf0..2dc6be9 100644 --- a/src/test/kotlin/org/domaindrivenarchitecture/provs/core/platformTest/UbuntuProvTests.kt +++ b/src/test/kotlin/org/domaindrivenarchitecture/provs/core/platformTest/UbuntuProvTests.kt @@ -1,8 +1,18 @@ package org.domaindrivenarchitecture.provs.core.platformTest +import org.domaindrivenarchitecture.provs.core.ProgressType import org.domaindrivenarchitecture.provs.core.Prov +import org.domaindrivenarchitecture.provs.core.docker.dockerImageExists +import org.domaindrivenarchitecture.provs.core.docker.dockerProvideImage +import org.domaindrivenarchitecture.provs.core.docker.dockerimages.DockerImage +import org.domaindrivenarchitecture.provs.core.processors.ContainerStartMode +import org.domaindrivenarchitecture.provs.core.processors.ContainerUbuntuHostProcessor +import org.domaindrivenarchitecture.provs.test.defaultTestContainerName import org.domaindrivenarchitecture.provs.test.tags.NonCi +import org.domaindrivenarchitecture.provs.test.testDockerWithSudo import org.domaindrivenarchitecture.provs.test.testLocal +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertFalse import org.junit.jupiter.api.Test import org.junit.jupiter.api.condition.EnabledOnOs import org.junit.jupiter.api.condition.OS @@ -95,5 +105,57 @@ internal class UbuntuProvTests { assert(res3.out?.trim() == "echoed") } + @Test + @EnabledOnOs(OS.LINUX) + fun test_user_cannot_sudo_without_password() { + // given + val image = UbuntuUserNeedsPasswordForSudo() + val prov = testLocal() + if (!prov.dockerImageExists(image.imageName(), true)) { + prov.dockerProvideImage(image, sudo = true) + } + + val a = Prov.newInstance( + ContainerUbuntuHostProcessor( + "provs_test_without_password_for_sudo", + startMode = ContainerStartMode.CREATE_NEW_KILL_EXISTING, + sudo = testDockerWithSudo, + dockerImage = image.imageName() + ), + progressType = ProgressType.NONE + ) + + // when + val result = a.cmd("sudo echo bla") + + // then + assertFalse(result.success) + assertEquals("sudo: no tty present and no askpass program specified\n", result.err) + } + } +/** + * Provides a docker image based on ubuntu additionally with a non-root default user and sudo installed but user needs password to sudo + */ +class UbuntuUserNeedsPasswordForSudo(private val userName: String = "testuser") : DockerImage { + + override fun imageName(): String { + return "ubuntu_user_needs_password_for_sudo" + } + + override fun imageText(): String { + return """ +FROM ubuntu:18.04 + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get -y install sudo +RUN useradd -m $userName && echo "$userName:$userName" | chpasswd && adduser $userName sudo + +USER $userName +CMD /bin/bash +WORKDIR /home/$userName +""" + } +}