@@ -342,3 +342,127 @@ func TestErrorCapture(t *testing.T) {
342342 t .Error ("expected non-empty error" )
343343 }
344344}
345+
346+ func TestComplexPasswordAuth (t * testing.T ) {
347+ t .Parallel ()
348+ complexPassword := `bbbH.A.|?ZAAAAi*RN)<*9(xxx`
349+
350+ ctx := t .Context ()
351+ ctr , err := mysql .Run (ctx , "mysql:8" ,
352+ mysql .WithDatabase (testDB ),
353+ mysql .WithUsername (testUser ),
354+ mysql .WithPassword (complexPassword ),
355+ )
356+ if err != nil {
357+ t .Fatalf ("start mysql container: %v" , err )
358+ }
359+ t .Cleanup (func () {
360+ if err := ctr .Terminate (context .Background ()); err != nil {
361+ t .Logf ("terminate mysql container: %v" , err )
362+ }
363+ })
364+
365+ host , err := ctr .Host (ctx )
366+ if err != nil {
367+ t .Fatalf ("get host: %v" , err )
368+ }
369+ port , err := ctr .MappedPort (ctx , "3306/tcp" )
370+ if err != nil {
371+ t .Fatalf ("get port: %v" , err )
372+ }
373+ upstream := fmt .Sprintf ("%s:%s" , host , port .Port ())
374+ _ , proxyAddr := startProxy (t , upstream )
375+
376+ // Connect through the proxy with the complex password.
377+ dsn := fmt .Sprintf ("%s:%s@tcp(%s)/%s?timeout=10s" , testUser , complexPassword , proxyAddr , testDB )
378+ db , err := sql .Open ("mysql" , dsn )
379+ if err != nil {
380+ t .Fatalf ("open db: %v" , err )
381+ }
382+ defer func () { _ = db .Close () }()
383+
384+ if err := db .PingContext (ctx ); err != nil {
385+ t .Fatalf ("ping through proxy with complex password: %v" , err )
386+ }
387+
388+ var result int
389+ if err := db .QueryRowContext (ctx , "SELECT 1" ).Scan (& result ); err != nil {
390+ t .Fatalf ("query through proxy with complex password: %v" , err )
391+ }
392+ if result != 1 {
393+ t .Errorf ("expected 1, got %d" , result )
394+ }
395+ }
396+
397+ func TestCachingSHA2PasswordFullAuth (t * testing.T ) {
398+ t .Parallel ()
399+ ctx := t .Context ()
400+
401+ // Start MySQL container with root user
402+ ctr , err := mysql .Run (ctx , "mysql:8" ,
403+ mysql .WithDatabase (testDB ),
404+ mysql .WithUsername (testUser ),
405+ mysql .WithPassword (testPassword ),
406+ )
407+ if err != nil {
408+ t .Fatalf ("start mysql container: %v" , err )
409+ }
410+ t .Cleanup (func () {
411+ if err := ctr .Terminate (context .Background ()); err != nil {
412+ t .Logf ("terminate mysql container: %v" , err )
413+ }
414+ })
415+
416+ host , err := ctr .Host (ctx )
417+ if err != nil {
418+ t .Fatalf ("get host: %v" , err )
419+ }
420+ port , err := ctr .MappedPort (ctx , "3306/tcp" )
421+ if err != nil {
422+ t .Fatalf ("get port: %v" , err )
423+ }
424+ upstream := fmt .Sprintf ("%s:%s" , host , port .Port ())
425+
426+ // Direct connection to inspect root's auth plugin and create a test user
427+ directDSN := fmt .Sprintf ("%s:%s@tcp(%s)/%s?timeout=10s" , testUser , testPassword , upstream , testDB )
428+ directDB , err := sql .Open ("mysql" , directDSN )
429+ if err != nil {
430+ t .Fatalf ("open direct db: %v" , err )
431+ }
432+ defer func () { _ = directDB .Close () }()
433+
434+ // Check root user's auth plugin
435+ var rootPlugin string
436+ if err := directDB .QueryRowContext (ctx ,
437+ "SELECT plugin FROM mysql.user WHERE user='root' LIMIT 1" ).Scan (& rootPlugin ); err != nil {
438+ t .Fatalf ("query auth plugin: %v" , err )
439+ }
440+ t .Logf ("Root user auth plugin: %s" , rootPlugin )
441+
442+ // Create a dedicated caching_sha2_password user with a complex password (never cached)
443+ complexPassword := `bbbH.A.|?ZAAAAi*RN)<*9(xxx`
444+ if _ , err := directDB .ExecContext (ctx ,
445+ "CREATE USER 'sha2user'@'%' IDENTIFIED WITH caching_sha2_password BY '" + complexPassword + "'" ); err != nil {
446+ t .Fatalf ("create sha2user: %v" , err )
447+ }
448+ if _ , err := directDB .ExecContext (ctx , "GRANT ALL ON " + testDB + ".* TO 'sha2user'@'%'" ); err != nil {
449+ t .Fatalf ("grant sha2user: %v" , err )
450+ }
451+
452+ // Start proxy
453+ _ , proxyAddr := startProxy (t , upstream )
454+
455+ // Connect as sha2user through proxy - password is NOT in caching_sha2_password cache
456+ // This forces the full auth path (RSA key exchange)
457+ proxyCachingDSN := fmt .Sprintf ("sha2user:%s@tcp(%s)/%s?timeout=10s" , complexPassword , proxyAddr , testDB )
458+ proxyCachingDB , err := sql .Open ("mysql" , proxyCachingDSN )
459+ if err != nil {
460+ t .Fatalf ("open caching_sha2_password db via proxy: %v" , err )
461+ }
462+ defer func () { _ = proxyCachingDB .Close () }()
463+
464+ if err := proxyCachingDB .PingContext (ctx ); err != nil {
465+ t .Fatalf ("ping through proxy (caching_sha2_password full auth): %v" , err )
466+ }
467+ t .Logf ("caching_sha2_password full auth through proxy: OK" )
468+ }
0 commit comments