refactor addKnownHost

This commit is contained in:
ansgarz 2023-08-18 23:25:21 +02:00
parent 2071128371
commit 4452cf5d01
5 changed files with 55 additions and 29 deletions

View file

@ -7,7 +7,7 @@ package org.domaindrivenarchitecture.provs.desktop.domain
*/
typealias HostKey = String
open class KnownHost protected constructor(
open class KnownHost(
val hostName: String,
val hostKeys: List<HostKey>
) {

View file

@ -6,6 +6,6 @@ import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.base.addKnownHos
fun Prov.addKnownHosts(knownHosts: List<KnownHost> = KnownHost.values()) = task {
for (knownHost in knownHosts) {
addKnownHost(knownHost.hostName, knownHost.hostKeys, verifyKeys = true)
addKnownHost(knownHost, verifyKeys = true)
}
}

View file

@ -1,5 +1,6 @@
package org.domaindrivenarchitecture.provs.framework.ubuntu.keys.base
import org.domaindrivenarchitecture.provs.desktop.domain.KnownHost
import org.domaindrivenarchitecture.provs.framework.core.Prov
import org.domaindrivenarchitecture.provs.framework.core.ProvResult
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.*
@ -7,8 +8,6 @@ import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.SshKeyPair
import java.io.File
const val KNOWN_HOSTS_FILE = "~/.ssh/known_hosts"
/**
* Installs ssh keys for active user; ssh filenames depend on the ssh key type, e.g. for public key file: "id_rsa.pub", "id_id_ed25519.pub", etc
*/
@ -24,34 +23,37 @@ fun Prov.configureSshKeys(sshKeys: SshKeyPair) = task {
*
* @return whether if was found
*/
fun Prov.isHostKnown(hostOrIp: String) : Boolean {
fun Prov.isHostKnown(hostOrIp: String): Boolean {
return cmdNoEval("ssh-keygen -F $hostOrIp").out?.isNotEmpty() ?: false
}
/**
* Adds ssh keys for specified host (which also can be an ip-address) to ssh-file "known_hosts"
* Either add the specified keys or - if null - add keys automatically retrieved.
* Note: adding keys automatically is vulnerable to a man-in-the-middle attack, thus considered insecure and not recommended.
* Adds ssh keys for specified host (which also can be an ip-address) to the ssh-file "known_hosts".
* If parameter verifyKeys is true the keys are checked against the live keys of the host and only added if valid.
*/
fun Prov.addKnownHost(host: String, keysToBeAdded: List<String>?, verifyKeys: Boolean = false) = task {
if (!checkFile(KNOWN_HOSTS_FILE)) {
fun Prov.addKnownHost(knownHost: KnownHost, verifyKeys: Boolean = false) = task {
val knownHostsFile = "~/.ssh/known_hosts"
if (!checkFile(knownHostsFile)) {
createDir(".ssh")
createFile(KNOWN_HOSTS_FILE, null)
createFile(knownHostsFile, null)
}
if (keysToBeAdded == null) {
// auto add keys
cmd("ssh-keyscan $host >> $KNOWN_HOSTS_FILE")
} else {
for (key in keysToBeAdded) {
with(knownHost) {
for (key in hostKeys) {
if (!verifyKeys) {
addTextToFile("\n$host $key\n", File(KNOWN_HOSTS_FILE))
addTextToFile("\n$hostName $key\n", File(knownHostsFile))
} else {
val validKeys = getSshKeys(host)
val validKeys = getSshKeys(hostName)
if (validKeys?.contains(key) == true) {
addTextToFile("\n$host $key\n", File(KNOWN_HOSTS_FILE))
addTextToFile("\n$hostName $key\n", File(knownHostsFile))
} else {
addResultToEval(ProvResult(false, err = "The following key of host [$host] could not be verified successfully: " + key))
addResultToEval(
ProvResult(
false,
err = "The following key of host [$hostName] could not be verified successfully: " + key
)
)
}
}
}

View file

@ -2,7 +2,6 @@ package org.domaindrivenarchitecture.provs.desktop.domain
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.deleteFile
import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.aptInstall
import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.base.KNOWN_HOSTS_FILE
import org.domaindrivenarchitecture.provs.test.defaultTestContainer
import org.domaindrivenarchitecture.provs.test.tags.ContainerTest
import org.junit.jupiter.api.Assertions.assertEquals
@ -18,7 +17,7 @@ class KnownHostTest {
val prov = defaultTestContainer()
prov.task {
aptInstall("ssh")
deleteFile(KNOWN_HOSTS_FILE)
deleteFile("~/.ssh/known_hosts")
}
// when

View file

@ -1,5 +1,6 @@
package org.domaindrivenarchitecture.provs.framework.ubuntu.keys.base
import org.domaindrivenarchitecture.provs.desktop.domain.KnownHost
import org.domaindrivenarchitecture.provs.framework.core.Secret
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.deleteFile
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.fileContainsText
@ -10,6 +11,8 @@ import org.domaindrivenarchitecture.provs.test.defaultTestContainer
import org.domaindrivenarchitecture.provs.test.tags.ContainerTest
import org.junit.jupiter.api.Assertions.*
const val KNOWN_HOSTS_FILE = "~/.ssh/known_hosts"
internal class SshKtTest {
@ContainerTest
fun configureSshKeys_for_ssh_type_rsa() {
@ -48,7 +51,7 @@ internal class SshKtTest {
}
@ContainerTest
fun addKnownHost() {
fun addKnownHost_without_verification() {
// given
val prov = defaultTestContainer()
prov.task {
@ -57,10 +60,8 @@ internal class SshKtTest {
}
// when
val res = prov.addKnownHost("github.com", listOf("dummyProtocol dummyKey", "dummyProtocol2 dummyKey2", ))
val res2 = prov.addKnownHost("github.com", listOf("dummyProtocol dummyKey", "dummyProtocol2 dummyKey2", ))
val res3 = prov.addKnownHost("github.com", listOf("ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl", ), verifyKeys = true)
val res4 = prov.addKnownHost("github.com", listOf("ssh-ed25519 AAAAC3Nzalwrongkey!!!", ), verifyKeys = true)
val res = prov.addKnownHost(KnownHost("github.com", listOf("dummyProtocol dummyKey", "dummyProtocol2 dummyKey2", )))
val res2 = prov.addKnownHost(KnownHost("github.com", listOf("dummyProtocol dummyKey", "dummyProtocol2 dummyKey2", )))
// then
assertTrue(res.success)
@ -70,8 +71,32 @@ internal class SshKtTest {
assertTrue(res2.success)
val keyCount = prov.cmd("grep -o -i dummyKey2 $KNOWN_HOSTS_FILE | wc -l").out?.trim()
assertEquals("1", keyCount)
}
assertTrue(res3.success)
assertFalse(res4.success)
@ContainerTest
fun addKnownHost_with_verifications() {
// given
val prov = defaultTestContainer()
prov.task {
aptInstall("ssh")
deleteFile(KNOWN_HOSTS_FILE)
}
// when
val res1 = prov.addKnownHost(KnownHost.GITHUB, verifyKeys = true)
val res2 = prov.addKnownHost(KnownHost.GITHUB, verifyKeys = true)
val invalidKey = "ssh-ed25519 AAAAC3Nzalwrongkey!!!"
val res3 = prov.addKnownHost(KnownHost("github.com", listOf(invalidKey )), verifyKeys = true)
// then
assertTrue(res1.success)
assertTrue(prov.fileContainsText(KNOWN_HOSTS_FILE, KnownHost.GITHUB.hostKeys[0]))
assertTrue(res2.success)
assertTrue(prov.fileContainsText(KNOWN_HOSTS_FILE, KnownHost.GITHUB.hostKeys[0]))
assertFalse(res3.success)
assertFalse(prov.fileContainsText(KNOWN_HOSTS_FILE, invalidKey))
}
}