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