refactor addKnownHost
This commit is contained in:
parent
2071128371
commit
4452cf5d01
5 changed files with 55 additions and 29 deletions
|
@ -7,7 +7,7 @@ package org.domaindrivenarchitecture.provs.desktop.domain
|
||||||
*/
|
*/
|
||||||
typealias HostKey = String
|
typealias HostKey = String
|
||||||
|
|
||||||
open class KnownHost protected constructor(
|
open class KnownHost(
|
||||||
val hostName: String,
|
val hostName: String,
|
||||||
val hostKeys: List<HostKey>
|
val hostKeys: List<HostKey>
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -6,6 +6,6 @@ import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.base.addKnownHos
|
||||||
|
|
||||||
fun Prov.addKnownHosts(knownHosts: List<KnownHost> = KnownHost.values()) = task {
|
fun Prov.addKnownHosts(knownHosts: List<KnownHost> = KnownHost.values()) = task {
|
||||||
for (knownHost in knownHosts) {
|
for (knownHost in knownHosts) {
|
||||||
addKnownHost(knownHost.hostName, knownHost.hostKeys, verifyKeys = true)
|
addKnownHost(knownHost, verifyKeys = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package org.domaindrivenarchitecture.provs.framework.ubuntu.keys.base
|
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.Prov
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.ProvResult
|
import org.domaindrivenarchitecture.provs.framework.core.ProvResult
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.*
|
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.*
|
||||||
|
@ -7,8 +8,6 @@ import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.SshKeyPair
|
||||||
import java.io.File
|
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
|
* 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
|
||||||
*/
|
*/
|
||||||
|
@ -30,28 +29,31 @@ fun Prov.isHostKnown(hostOrIp: String) : Boolean {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds ssh keys for specified host (which also can be an ip-address) to ssh-file "known_hosts"
|
* Adds ssh keys for specified host (which also can be an ip-address) to the ssh-file "known_hosts".
|
||||||
* Either add the specified keys or - if null - add keys automatically retrieved.
|
* If parameter verifyKeys is true the keys are checked against the live keys of the host and only added if valid.
|
||||||
* Note: adding keys automatically is vulnerable to a man-in-the-middle attack, thus considered insecure and not recommended.
|
|
||||||
*/
|
*/
|
||||||
fun Prov.addKnownHost(host: String, keysToBeAdded: List<String>?, verifyKeys: Boolean = false) = task {
|
fun Prov.addKnownHost(knownHost: KnownHost, verifyKeys: Boolean = false) = task {
|
||||||
if (!checkFile(KNOWN_HOSTS_FILE)) {
|
val knownHostsFile = "~/.ssh/known_hosts"
|
||||||
|
|
||||||
|
if (!checkFile(knownHostsFile)) {
|
||||||
createDir(".ssh")
|
createDir(".ssh")
|
||||||
createFile(KNOWN_HOSTS_FILE, null)
|
createFile(knownHostsFile, null)
|
||||||
}
|
}
|
||||||
if (keysToBeAdded == null) {
|
with(knownHost) {
|
||||||
// auto add keys
|
for (key in hostKeys) {
|
||||||
cmd("ssh-keyscan $host >> $KNOWN_HOSTS_FILE")
|
|
||||||
} else {
|
|
||||||
for (key in keysToBeAdded) {
|
|
||||||
if (!verifyKeys) {
|
if (!verifyKeys) {
|
||||||
addTextToFile("\n$host $key\n", File(KNOWN_HOSTS_FILE))
|
addTextToFile("\n$hostName $key\n", File(knownHostsFile))
|
||||||
} else {
|
} else {
|
||||||
val validKeys = getSshKeys(host)
|
val validKeys = getSshKeys(hostName)
|
||||||
if (validKeys?.contains(key) == true) {
|
if (validKeys?.contains(key) == true) {
|
||||||
addTextToFile("\n$host $key\n", File(KNOWN_HOSTS_FILE))
|
addTextToFile("\n$hostName $key\n", File(knownHostsFile))
|
||||||
} else {
|
} 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
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.filesystem.base.deleteFile
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.aptInstall
|
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.defaultTestContainer
|
||||||
import org.domaindrivenarchitecture.provs.test.tags.ContainerTest
|
import org.domaindrivenarchitecture.provs.test.tags.ContainerTest
|
||||||
import org.junit.jupiter.api.Assertions.assertEquals
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
@ -18,7 +17,7 @@ class KnownHostTest {
|
||||||
val prov = defaultTestContainer()
|
val prov = defaultTestContainer()
|
||||||
prov.task {
|
prov.task {
|
||||||
aptInstall("ssh")
|
aptInstall("ssh")
|
||||||
deleteFile(KNOWN_HOSTS_FILE)
|
deleteFile("~/.ssh/known_hosts")
|
||||||
}
|
}
|
||||||
|
|
||||||
// when
|
// when
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.domaindrivenarchitecture.provs.framework.ubuntu.keys.base
|
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.core.Secret
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.deleteFile
|
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.deleteFile
|
||||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.fileContainsText
|
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.domaindrivenarchitecture.provs.test.tags.ContainerTest
|
||||||
import org.junit.jupiter.api.Assertions.*
|
import org.junit.jupiter.api.Assertions.*
|
||||||
|
|
||||||
|
const val KNOWN_HOSTS_FILE = "~/.ssh/known_hosts"
|
||||||
|
|
||||||
internal class SshKtTest {
|
internal class SshKtTest {
|
||||||
@ContainerTest
|
@ContainerTest
|
||||||
fun configureSshKeys_for_ssh_type_rsa() {
|
fun configureSshKeys_for_ssh_type_rsa() {
|
||||||
|
@ -48,7 +51,7 @@ internal class SshKtTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ContainerTest
|
@ContainerTest
|
||||||
fun addKnownHost() {
|
fun addKnownHost_without_verification() {
|
||||||
// given
|
// given
|
||||||
val prov = defaultTestContainer()
|
val prov = defaultTestContainer()
|
||||||
prov.task {
|
prov.task {
|
||||||
|
@ -57,10 +60,8 @@ internal class SshKtTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
// when
|
// when
|
||||||
val res = prov.addKnownHost("github.com", listOf("dummyProtocol dummyKey", "dummyProtocol2 dummyKey2", ))
|
val res = prov.addKnownHost(KnownHost("github.com", listOf("dummyProtocol dummyKey", "dummyProtocol2 dummyKey2", )))
|
||||||
val res2 = prov.addKnownHost("github.com", listOf("dummyProtocol dummyKey", "dummyProtocol2 dummyKey2", ))
|
val res2 = prov.addKnownHost(KnownHost("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)
|
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertTrue(res.success)
|
assertTrue(res.success)
|
||||||
|
@ -70,8 +71,32 @@ internal class SshKtTest {
|
||||||
assertTrue(res2.success)
|
assertTrue(res2.success)
|
||||||
val keyCount = prov.cmd("grep -o -i dummyKey2 $KNOWN_HOSTS_FILE | wc -l").out?.trim()
|
val keyCount = prov.cmd("grep -o -i dummyKey2 $KNOWN_HOSTS_FILE | wc -l").out?.trim()
|
||||||
assertEquals("1", keyCount)
|
assertEquals("1", keyCount)
|
||||||
|
}
|
||||||
|
|
||||||
assertTrue(res3.success)
|
@ContainerTest
|
||||||
assertFalse(res4.success)
|
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue