github.com/technosophos/deis@v1.7.1-0.20150915173815-f9005256004b/builder/sshd/server_test.go (about) 1 package sshd 2 3 import ( 4 "net" 5 "testing" 6 "time" 7 8 "github.com/Masterminds/cookoo" 9 "golang.org/x/crypto/ssh" 10 ) 11 12 var testingServerAddr = "127.0.0.1:2244" 13 14 // TestServer tests the SSH server. 15 // 16 // This listens on the non-standard port 2244 of localhost. This will generate 17 // an entry in your known_hosts file, and will tie that to the testing key 18 // used here. It's not recommended that you try to start another SSH server on 19 // the same port (at a later time) or else you will have key issues that you 20 // must manually resolve. 21 func TestServer(t *testing.T) { 22 key, err := sshTestingHostKey() 23 if err != nil { 24 t.Fatal(err) 25 } 26 27 cfg := ssh.ServerConfig{ 28 NoClientAuth: true, 29 } 30 cfg.AddHostKey(key) 31 32 cxt := runServer(&cfg, t) 33 34 // Give server time to initialize. 35 time.Sleep(200 * time.Millisecond) 36 37 // Connect to the server and issue env var set. This should return true. 38 client, err := ssh.Dial("tcp", testingServerAddr, &ssh.ClientConfig{}) 39 if err != nil { 40 t.Fatalf("Failed to connect client to local server: %s", err) 41 } 42 sess, err := client.NewSession() 43 if err != nil { 44 t.Fatalf("Failed to create client session: %s", err) 45 } 46 defer sess.Close() 47 48 if err := sess.Setenv("HELLO", "world"); err != nil { 49 t.Fatal(err) 50 } 51 52 if out, err := sess.Output("ping"); err != nil { 53 t.Errorf("Output '%s' Error %s", out, err) 54 } else if string(out) != "pong" { 55 t.Errorf("Expected 'pong', got '%s'", out) 56 } 57 58 // Create a new session because the success of the last one closed the 59 // connection. 60 sess, err = client.NewSession() 61 if err != nil { 62 t.Fatalf("Failed to create client session: %s", err) 63 } 64 if err := sess.Run("illegal"); err == nil { 65 t.Fatalf("expected a failed run with command 'illegal'") 66 } 67 if err := sess.Run("illegal command"); err == nil { 68 t.Fatalf("expected a failed run with command 'illegal command'") 69 } 70 71 closer := cxt.Get("sshd.Closer", nil).(chan interface{}) 72 closer <- true 73 } 74 75 // sshTestingHostKey loads the testing key. 76 func sshTestingHostKey() (ssh.Signer, error) { 77 return ssh.ParsePrivateKey([]byte(testingHostKey)) 78 } 79 80 func sshTestingClientKey() (ssh.Signer, error) { 81 return ssh.ParsePrivateKey([]byte(testingClientKey)) 82 } 83 84 func runServer(config *ssh.ServerConfig, t *testing.T) cookoo.Context { 85 reg, router, cxt := cookoo.Cookoo() 86 cxt.Put(ServerConfig, config) 87 cxt.Put(Address, testingServerAddr) 88 cxt.Put("cookoo.Router", router) 89 90 reg.AddRoute(cookoo.Route{ 91 Name: "sshPing", 92 Help: "Handles an ssh exec ping.", 93 Does: cookoo.Tasks{ 94 cookoo.Cmd{ 95 Name: "ping", 96 Fn: Ping, 97 Using: []cookoo.Param{ 98 {Name: "request", From: "cxt:request"}, 99 {Name: "channel", From: "cxt:channel"}, 100 }, 101 }, 102 }, 103 }) 104 105 go func() { 106 if err := Serve(reg, router, cxt); err != nil { 107 t.Fatalf("Failed serving with %s", err) 108 } 109 }() 110 111 return cxt 112 113 } 114 115 // connMetadata mocks ssh.ConnMetadata for authentication. 116 type connMetadata struct{} 117 118 func (cm *connMetadata) User() string { return "deis" } 119 func (cm *connMetadata) SessionID() []byte { return []byte("1") } 120 func (cm *connMetadata) ClientVersion() []byte { return []byte("2.3.4") } 121 func (cm *connMetadata) ServerVersion() []byte { return []byte("2.3.4") } 122 func (cm *connMetadata) RemoteAddr() net.Addr { return cm.localhost() } 123 func (cm *connMetadata) LocalAddr() net.Addr { return cm.localhost() } 124 func (cm *connMetadata) localhost() net.Addr { 125 addrs, err := net.InterfaceAddrs() 126 if err != nil { 127 panic(err) 128 } 129 return addrs[0] 130 } 131 132 var ( 133 testingHostKey = `-----BEGIN RSA PRIVATE KEY----- 134 MIIEpAIBAAKCAQEA0xOK/wubqj+e4HNp+yAdK4WJnLZCvcjS2DwaxwF+E968kSeU 135 27SOqiol7Y0UwLGLpB6rpIBnSqXo70xiMUSrnteKmMejddzfbGkvnyvo0dwE4nDd 136 vnbz64I25xfjTldb4RtNvpk6ymr0soq0EEYssLmdnt7pIgHT71n9RNtu+RPpRe5n 137 B2ImVeeEsQBhxFsIkkT21JqBhZQRVpeAAOHwainWpkP2MF2ajYUoirs5qOkPxxaw 138 Mc4i5CSvmFDkWjqkNt84QH9M9M/ws8qX76nImYOPHiF0KRbxamWsYjvdHJCSckdC 139 mOM7UtsQs8wC3E0xpuPEI0pNRTHCsgH7+KGxmwIDAQABAoIBAAOQufFS7d8zUeiy 140 qmCeiz+X8todzgTMppsWcNFZuhp10bOV+pK3ew1uxtM7ZdVXamdsSTPvI0+Ee+nG 141 3YW9hjSZqXKpNJ6iC3gWUsKaiEU7NS3qACTed4JL4ceHhMRm/1tPDcIhbnfK1LVL 142 WH1J4ileCUaMt11msIDDgV6vYjF81733O+8kPnh5BaFLIOuPdmAPfsZC2WQfBTka 143 6F5bhe9mcraQohWOGC/NKBbV9o6Ua2GT5ZJILtyPwfx8ctnQHLfmlTOI7qpRyMCU 144 1hGwlWxyvZRyY4loZehy0c7DaEWJqWS1AST9AbUcNXciYSt/5pUP76W0L6NzwJdh 145 C1jIY2ECgYEA+JwlIzhsZRsN0jA3A2qWRt3WGdliujAqDvVj4e8E+QnlTh/MDVKF 146 x3F+w58DHRKJrH7d1nD1fq2id6vh3Sl7xGHZiztOpolY0xlOt71X+2anX+QTEX5Q 147 d1jB/zQliUsxzIjqn31dKUlAfoI5XiWrxuP1Py8gZSTnnBl8bkdKZysCgYEA2VnG 148 +bhBdw/0RJVsleyHBrq0+MnQ80dxj6XatKvniVDqjHQefq088W2ULeI5wVjdMy59 149 CVnDVS6759pLkWu5br7Agb+NGyVKd3o0CT0Jn6JJj9kq1Wq7iOedJF+GtabVp4gk 150 efIYECkS7BKe1GFH5vRM8FbyyepRFBCgrH1ep1ECgYEAiRojaO7+6CspThcE379y 151 LJa+MfcueRuCtkkh0kFsbqLEcHccouQ1nq26iMsyfl/wyM4WLOKSoE/FX1XM85ij 152 BsQnop8MWs83ywMT5ERpNt1/xGQVF/qfCZJLOiBZ6wMq7W88ZMRQEiqxhJLwbDk+ 153 KCsi3rtwlBbsG6v6cR6jq40CgYAzH4nMvQkw7yC+bQMgdIUCETJ1/kpWnqxYZGN/ 154 8ZtBUjYJGVr+4tKd2u9qp3Z8QuGsozen1mQ6igaKr27s4pC4Osfe/OY8x1Wvqp/I 155 uIGl+a8h1avcjQFVX1036/wsh/RjNoOV51q/mlmoC20ueT9HVJkwQtNSqPmvJYYV 156 bFuyMQKBgQCsRVEJ6eqai+Pz4bY2UfBnkU6ZHdySI+fQB/T770p0/SbrYMBxNrPQ 157 v3+ZZfZMlci4pxBtXqrnoyj4uUoqZtR3ENLz53SN1i0vpT7DtC6gMnEF1UWiaoJ6 158 6mGH5/bxCg9wpV7qpqR0EbFM/dhQFZmmnirOS8x+00hJvc1HFiuN/A== 159 -----END RSA PRIVATE KEY----- 160 ` 161 testingClientKey = `-----BEGIN RSA PRIVATE KEY----- 162 MIIEowIBAAKCAQEAvziJnoiaaVyUGPnyqVC49XLzNRS+TPW63Nw4qovCG8lVbxKG 163 DIHC64tJrCDiZd0ppEhY+RQDGaPwrMInHnV8IwdS1wX22UTRuXA/oXmHcIxO2zmU 164 nrjFDlpKm2o+2Xd167ifdV9AiqNBtquO0M882RaGy99LbNPcl9ugAnxo5DVI1jES 165 l5vYqtiOAnRSvmJn2c+hkJfKXryH7hU4y+blDK5Vz44eSsC7bgG3ZbKfKGR9mlf2 166 ozVlzMNi2ACZ58vDBxn5WVLb1bPV1LHpicJ00fU3TDRnK3MkwvvAnqp78bNzi+ou 167 YIAwYSZ41iHNd596LQJchr1vs3Fo8qbgYaLY8wIDAQABAoIBAEJgQL0ME/Vw0mOd 168 F5OYVqu0vCF30trqDXQu6Wih3L5Cc+p7Vpau0Fds4STjwVK0o4jIKEJFpRHYa2m8 169 d1HGXFHYb/P9uQMQNXCWOzA0/EOgIJtOcH1sC9MAmpc6GRjps8AgNRHL/55gLyZW 170 hNuMpEWC4UWRfCAJpq/7554VS1+zWK0vy1GszikROjsZnopLTshMV+/7217tSk4O 171 1GY9ucNJX5iX3M83pmBOJX0ce8fqxeNnAdQIaAtp+ytm5TRzyaQtTjMlq0oqP8+7 172 Zx9aZKT11IpbOKBSIc6twRArlV1dT9kEI15zS9hfbWuvguB0zuhbhejS4wmZb9Tt 173 X8rGL4ECgYEA+MZcRzxpBKL+VNuQ4iSwF3RUYL1FIglJV7AM8UdM2hiNeiKidhD5 174 kmNXVf9C6XWg3OIHCno7HetBo0WZIPmOQMy4CDGC2bWEnQN+/bf3xsKzbECCLtH+ 175 DALXSztihGGiY2zSoOCwTe7WZjGaF9s4C2rVkhsU/9di4qbapGTaWMECgYEAxMZD 176 c/sVTTT+/thdcLbBDhAfy6RMQwAy/1IPxNVR4C4O+l/rspbKxvV7JyaErP66g871 177 dBwrOGMfEsYoOOsUBFaj2/jJZdHvQj9jY/kdsfMBivHzkWEFte09NROOThbq+sgX 178 5bIPwS+IcVCgcA4We+aBv+rYKdvk05RJ8owPSrMCgYBjz4H6erxPxe1wsl8gvEOC 179 RYQNBCMWks9ARTwMGeU1o6AvnnG8GPdoyj6iHDYGYNFXjb/xbjUFvfupvCTB3B48 180 1WYIs4SiQHeiX2K1/PeGYVuHVSJmEo5w1zr1zi+qmVmDtoeTUFKsEeUnP0NpyuRj 181 gEuLwR3dv9bGxNb4GhaYgQKBgDNQCFL8TMe/ZCeMwIEeByXlqoTuKTznlmTiP15y 182 ylENcbZ0wP/nNqW/aggBkWOTYYvxsiw/FD42CupYZjDBjIy9EynPrKUyo5PA9+gg 183 FFBNMD/NbFii1lxkqytmGBvg+hG/kAvD7TvRa2ExR0UxR0e0Cm3Dje8MepV5+/aV 184 837lAoGBAPcvnrDFWKUy8dlrw05+9esiuZgCrCzZPw5xIxhrnRPcBOBl+QdpMscP 185 eWVutcVy5Frxl5tTf71WK/YhGPgWBt/CQz73Bf1+CX80CeApWWAqiAr240NED5a0 186 dBAFNBWp8IdHnQmdp9HKvxEXSK+RgOzPNLrpaRv+FPuiD6OtvhmD 187 -----END RSA PRIVATE KEY-----` 188 189 testingClientPubKey = `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC/OImeiJppXJQY+fKpULj1cvM1FL5M9brc3Diqi8IbyVVvEoYMgcLri0msIOJl3SmkSFj5FAMZo/CswicedXwjB1LXBfbZRNG5cD+heYdwjE7bOZSeuMUOWkqbaj7Zd3XruJ91X0CKo0G2q47QzzzZFobL30ts09yX26ACfGjkNUjWMRKXm9iq2I4CdFK+YmfZz6GQl8pevIfuFTjL5uUMrlXPjh5KwLtuAbdlsp8oZH2aV/ajNWXMw2LYAJnny8MHGflZUtvVs9XUsemJwnTR9TdMNGcrcyTC+8Ceqnvxs3OL6i5ggDBhJnjWIc13n3otAlyGvW+zcWjypuBhotjz donotuse` 190 testingClientFingerprint = `78:b9:21:20:1a:ed:e6:10:05:35:47:da:d4:1f:b6:73` 191 )