@@ -15,6 +15,7 @@ import (
1515 "os"
1616 "runtime"
1717 "strings"
18+ "sync"
1819 "testing"
1920)
2021
@@ -1282,3 +1283,88 @@ func TestCertAuthOpenSSHCompat(t *testing.T) {
12821283 t .Fatalf ("unable to dial remote side: %s" , err )
12831284 }
12841285}
1286+
1287+ func TestKeyboardInteractiveAuthEarlyFail (t * testing.T ) {
1288+ const maxAuthTries = 2
1289+
1290+ c1 , c2 , err := netPipe ()
1291+ if err != nil {
1292+ t .Fatalf ("netPipe: %v" , err )
1293+ }
1294+ defer c1 .Close ()
1295+ defer c2 .Close ()
1296+
1297+ // Start testserver
1298+ go func () {
1299+ config := & ServerConfig {
1300+ MaxAuthTries : maxAuthTries ,
1301+ KeyboardInteractiveCallback : func (c ConnMetadata ,
1302+ client KeyboardInteractiveChallenge ) (* Permissions , error ) {
1303+ // Fail keyboard-interactive authentication early before
1304+ // any prompt is sent to client.
1305+ return nil , errors .New ("keyboard-interactive auth failed" )
1306+ },
1307+ PasswordCallback : func (c ConnMetadata ,
1308+ pass []byte ) (* Permissions , error ) {
1309+ if string (pass ) == clientPassword {
1310+ return nil , nil
1311+ }
1312+ return nil , errors .New ("password auth failed" )
1313+ },
1314+ }
1315+ config .AddHostKey (testSigners ["rsa" ])
1316+
1317+ conn , chans , reqs , err := NewServerConn (c2 , config )
1318+ if err != nil {
1319+ return
1320+ }
1321+ _ = conn .Close ()
1322+
1323+ var connWg sync.WaitGroup
1324+ connWg .Add (1 )
1325+ go func () {
1326+ defer connWg .Done ()
1327+ DiscardRequests (reqs )
1328+ }()
1329+ for newChannel := range chans {
1330+ newChannel .Reject (Prohibited ,
1331+ "testserver not accepting requests" )
1332+ }
1333+ connWg .Wait ()
1334+ }()
1335+
1336+ if err != nil {
1337+ t .Fatalf ("failed to start testserver: %v" , err )
1338+ }
1339+
1340+ // Connect to testserver expect KeyboardInteractive() to be not called and
1341+ // PasswordCallback() to be called.
1342+ passwordCallbackCalled := false
1343+ cfg := & ClientConfig {
1344+ User : "testuser" ,
1345+ Auth : []AuthMethod {
1346+ RetryableAuthMethod (KeyboardInteractive (func (name ,
1347+ instruction string , questions []string ,
1348+ echos []bool ) ([]string , error ) {
1349+ t .Errorf ("unexpected call to KeyboardInteractive()" )
1350+ return []string {clientPassword }, nil
1351+ }), maxAuthTries ),
1352+ RetryableAuthMethod (PasswordCallback (func () (secret string ,
1353+ err error ) {
1354+ t .Logf ("PasswordCallback()" )
1355+ passwordCallbackCalled = true
1356+ return clientPassword , nil
1357+ }), maxAuthTries ),
1358+ },
1359+ HostKeyCallback : InsecureIgnoreHostKey (),
1360+ }
1361+
1362+ conn , _ , _ , _ := NewClientConn (c1 , "" , cfg )
1363+ if conn != nil {
1364+ conn .Close ()
1365+ }
1366+
1367+ if ! passwordCallbackCalled {
1368+ t .Errorf ("expected PasswordCallback() to be called" )
1369+ }
1370+ }
0 commit comments