crypto/ssh: return unexpected msg error when server fails keyboard-in… · golang/crypto@4f1243e (original) (raw)
`@@ -16,6 +16,7 @@ import (
`
16
16
`"runtime"
`
17
17
`"strings"
`
18
18
`"testing"
`
``
19
`+
"time"
`
19
20
`)
`
20
21
``
21
22
`type keyboardInteractive map[string]string
`
`@@ -1293,3 +1294,97 @@ func TestCertAuthOpenSSHCompat(t *testing.T) {
`
1293
1294
`t.Fatalf("unable to dial remote side: %s", err)
`
1294
1295
` }
`
1295
1296
`}
`
``
1297
+
``
1298
`+
func TestKeyboardInteractiveAuthEarlyFail(t *testing.T) {
`
``
1299
`+
const maxAuthTries = 2
`
``
1300
+
``
1301
`+
c1, c2, err := netPipe()
`
``
1302
`+
if err != nil {
`
``
1303
`+
t.Fatalf("netPipe: %v", err)
`
``
1304
`+
}
`
``
1305
`+
defer c1.Close()
`
``
1306
`+
defer c2.Close()
`
``
1307
+
``
1308
`+
// Start testserver
`
``
1309
`+
serverConfig := &ServerConfig{
`
``
1310
`+
MaxAuthTries: maxAuthTries,
`
``
1311
`+
KeyboardInteractiveCallback: func(c ConnMetadata,
`
``
1312
`+
client KeyboardInteractiveChallenge) (*Permissions, error) {
`
``
1313
`+
// Fail keyboard-interactive authentication early before
`
``
1314
`+
// any prompt is sent to client.
`
``
1315
`+
return nil, errors.New("keyboard-interactive auth failed")
`
``
1316
`+
},
`
``
1317
`+
PasswordCallback: func(c ConnMetadata,
`
``
1318
`+
pass []byte) (*Permissions, error) {
`
``
1319
`+
if string(pass) == clientPassword {
`
``
1320
`+
return nil, nil
`
``
1321
`+
}
`
``
1322
`+
return nil, errors.New("password auth failed")
`
``
1323
`+
},
`
``
1324
`+
}
`
``
1325
`+
serverConfig.AddHostKey(testSigners["rsa"])
`
``
1326
+
``
1327
`+
serverDone := make(chan struct{})
`
``
1328
`+
go func() {
`
``
1329
`+
defer func() { serverDone <- struct{}{} }()
`
``
1330
`+
conn, chans, reqs, err := NewServerConn(c2, serverConfig)
`
``
1331
`+
if err != nil {
`
``
1332
`+
return
`
``
1333
`+
}
`
``
1334
`+
_ = conn.Close()
`
``
1335
+
``
1336
`+
discarderDone := make(chan struct{})
`
``
1337
`+
go func() {
`
``
1338
`+
defer func() { discarderDone <- struct{}{} }()
`
``
1339
`+
DiscardRequests(reqs)
`
``
1340
`+
}()
`
``
1341
`+
for newChannel := range chans {
`
``
1342
`+
newChannel.Reject(Prohibited,
`
``
1343
`+
"testserver not accepting requests")
`
``
1344
`+
}
`
``
1345
+
``
1346
`+
<-discarderDone
`
``
1347
`+
}()
`
``
1348
+
``
1349
`+
// Connect to testserver, expect KeyboardInteractive() to be not called,
`
``
1350
`+
// PasswordCallback() to be called and connection to succeed.
`
``
1351
`+
passwordCallbackCalled := false
`
``
1352
`+
clientConfig := &ClientConfig{
`
``
1353
`+
User: "testuser",
`
``
1354
`+
Auth: []AuthMethod{
`
``
1355
`+
RetryableAuthMethod(KeyboardInteractive(func(name,
`
``
1356
`+
instruction string, questions []string,
`
``
1357
`+
echos []bool) ([]string, error) {
`
``
1358
`+
t.Errorf("unexpected call to KeyboardInteractive()")
`
``
1359
`+
return []string{clientPassword}, nil
`
``
1360
`+
}), maxAuthTries),
`
``
1361
`+
RetryableAuthMethod(PasswordCallback(func() (secret string,
`
``
1362
`+
err error) {
`
``
1363
`+
t.Logf("PasswordCallback()")
`
``
1364
`+
passwordCallbackCalled = true
`
``
1365
`+
return clientPassword, nil
`
``
1366
`+
}), maxAuthTries),
`
``
1367
`+
},
`
``
1368
`+
HostKeyCallback: InsecureIgnoreHostKey(),
`
``
1369
`+
}
`
``
1370
+
``
1371
`+
conn, _, _, err := NewClientConn(c1, "", clientConfig)
`
``
1372
`+
if err != nil {
`
``
1373
`+
t.Errorf("unexpected NewClientConn() error: %v", err)
`
``
1374
`+
}
`
``
1375
`+
if conn != nil {
`
``
1376
`+
conn.Close()
`
``
1377
`+
}
`
``
1378
+
``
1379
`+
// Wait for server to finish. Fail test eventually in case server does not
`
``
1380
`+
// finish in reasonable time.
`
``
1381
`+
select {
`
``
1382
`+
case <-serverDone:
`
``
1383
`+
case <-time.After(60 * time.Second):
`
``
1384
`+
t.Fatalf("server did not finish")
`
``
1385
`+
}
`
``
1386
+
``
1387
`+
if !passwordCallbackCalled {
`
``
1388
`+
t.Errorf("expected PasswordCallback() to be called")
`
``
1389
`+
}
`
``
1390
`+
}
`