From 652e196b427ce9673676e214c6ad3905b21a68b0 Mon Sep 17 00:00:00 2001 From: Eno Compton Date: Fri, 7 Oct 2022 16:22:10 -0600 Subject: [PATCH] fix: throw error when Auto IAM AuthN is unsupported (#310) Fixes #283. --- dialer_test.go | 52 ++++++++++++++++++++++++++++++++++++ internal/cloudsql/refresh.go | 18 +++++++++++++ 2 files changed, 70 insertions(+) diff --git a/dialer_test.go b/dialer_test.go index b52d37bb..7f3d95d7 100644 --- a/dialer_test.go +++ b/dialer_test.go @@ -249,6 +249,58 @@ func TestIAMAuthn(t *testing.T) { } } +func TestIAMAuthNErrors(t *testing.T) { + tcs := []struct { + desc string + version string + opts Option + }{ + { + desc: "when the database engine is MySQL", + version: "MYSQL", + opts: WithIAMAuthN(), + }, + { + desc: "when the database engine is SQL Server", + version: "SQLSERVER", + opts: WithIAMAuthN(), + }, + } + + for _, tc := range tcs { + t.Run(tc.desc, func(t *testing.T) { + inst := mock.NewFakeCSQLInstance("proj", "region", "inst", + mock.WithEngineVersion(tc.version), + ) + svc, cleanup, err := mock.NewSQLAdminService( + context.Background(), + mock.InstanceGetSuccess(inst, 1), + mock.CreateEphemeralSuccess(inst, 1), + ) + if err != nil { + t.Fatalf("mock.NewSQLAdminService(): %v", err) + } + defer cleanup() + + stop := mock.StartServerProxy(t, inst) + defer stop() + + d, err := NewDialer(context.Background(), + WithTokenSource(mock.EmptyTokenSource{}), tc.opts) + if err != nil { + t.Fatalf("NewDialer failed with error = %v", err) + } + d.sqladmin = svc + + _, err = d.Dial(context.Background(), "proj:region:inst") + t.Log(err) + if err == nil { + t.Fatalf("version = %v, want error, got nil", tc.version) + } + }) + } +} + func TestDialerWithCustomDialFunc(t *testing.T) { inst := mock.NewFakeCSQLInstance("my-project", "my-region", "my-instance") svc, cleanup, err := mock.NewSQLAdminService( diff --git a/internal/cloudsql/refresh.go b/internal/cloudsql/refresh.go index d8dfee51..c5414747 100644 --- a/internal/cloudsql/refresh.go +++ b/internal/cloudsql/refresh.go @@ -21,6 +21,7 @@ import ( "crypto/x509" "encoding/pem" "fmt" + "strings" "time" "cloud.google.com/go/cloudsqlconn/errtype" @@ -357,6 +358,12 @@ func (r refresher) performRefresh(ctx context.Context, cn connName, k *rsa.Priva case <-ctx.Done(): return md, nil, time.Time{}, fmt.Errorf("refresh failed: %w", ctx.Err()) } + if iamAuthN { + if vErr := supportsAutoIAMAuthN(md.version); vErr != nil { + return metadata{}, nil, time.Time{}, vErr + } + } + var ec tls.Certificate select { case r := <-ecC: @@ -375,3 +382,14 @@ func (r refresher) performRefresh(ctx context.Context, cn connName, k *rsa.Priva } return md, c, expiry, nil } + +// supportsAutoIAMAuthN checks that the engine support automatic IAM authn. If +// auto IAM authn was not request, this is a no-op. +func supportsAutoIAMAuthN(version string) error { + switch { + case strings.HasPrefix(version, "POSTGRES"): + return nil + default: + return fmt.Errorf("%s does not support Auto IAM DB Authentication", version) + } +}