// PGUrl returns a postgres connection url which connects to this server with // the given user. Returns a connection string and a cleanup function which must // be called after any connection created using the string has been closed. // // In order to connect securely using postgres, this method will create // temporary on-disk copies of certain embedded security certificates. The // certificates will be created as temporary files in the provided directory, // and their filenames will have the provided prefix. The returned cleanup // function will delete these temporary files. func PGUrl(t util.Tester, ts *server.TestServer, user, tempDir, prefix string) (url.URL, func()) { host, port, err := net.SplitHostPort(ts.PGAddr()) if err != nil { t.Fatal(err) } caPath := filepath.Join(security.EmbeddedCertsDir, "ca.crt") certPath := security.ClientCertPath(security.EmbeddedCertsDir, user) keyPath := security.ClientKeyPath(security.EmbeddedCertsDir, user) // Copy these assets to disk from embedded strings, so this test can // run from a standalone binary. tempCAPath, tempCACleanup := securitytest.TempRestrictedCopy(t, caPath, tempDir, "TestLogic_ca") tempCertPath, tempCertCleanup := securitytest.TempRestrictedCopy(t, certPath, tempDir, "TestLogic_cert") tempKeyPath, tempKeyCleanup := securitytest.TempRestrictedCopy(t, keyPath, tempDir, "TestLogic_key") return url.URL{ Scheme: "postgres", User: url.User(user), Host: net.JoinHostPort(host, port), RawQuery: fmt.Sprintf("sslmode=verify-full&sslrootcert=%s&sslcert=%s&sslkey=%s", url.QueryEscape(tempCAPath), url.QueryEscape(tempCertPath), url.QueryEscape(tempKeyPath), ), }, func() { tempCACleanup() tempCertCleanup() tempKeyCleanup() } }
func TestPGWire(t *testing.T) { defer leaktest.AfterTest(t) certUser := server.TestUser certPath := security.ClientCertPath(security.EmbeddedCertsDir, certUser) keyPath := security.ClientKeyPath(security.EmbeddedCertsDir, certUser) // Copy these assets to disk from embedded strings, so this test can // run from a standalone binary. tempCertPath, tempCertCleanup := securitytest.TempRestrictedCopy(t, certPath, os.TempDir(), "TestPGWire_cert") defer tempCertCleanup() tempKeyPath, tempKeyCleanup := securitytest.TempRestrictedCopy(t, keyPath, os.TempDir(), "TestPGWire_key") defer tempKeyCleanup() for _, insecure := range [...]bool{true, false} { ctx := server.NewTestContext() ctx.Insecure = insecure s := setupTestServerWithContext(t, ctx) host, port, err := net.SplitHostPort(s.PGAddr()) if err != nil { t.Fatal(err) } basePgUrl := url.URL{ Scheme: "postgres", Host: net.JoinHostPort(host, port), } if err := trivialQuery(basePgUrl); err != nil { if insecure { if err != pq.ErrSSLNotSupported { t.Error(err) } } else { if !testutils.IsError(err, "no client certificates in request") { t.Error(err) } } } { disablePgUrl := basePgUrl disablePgUrl.RawQuery = "sslmode=disable" err := trivialQuery(disablePgUrl) if insecure { if err != nil { t.Error(err) } } else { if !testutils.IsError(err, pgwire.ErrSSLRequired) { t.Error(err) } } } { requirePgUrlNoCert := basePgUrl requirePgUrlNoCert.RawQuery = "sslmode=require" err := trivialQuery(requirePgUrlNoCert) if insecure { if err != pq.ErrSSLNotSupported { t.Error(err) } } else { if !testutils.IsError(err, "no client certificates in request") { t.Error(err) } } } { for _, optUser := range []string{certUser, security.RootUser} { requirePgUrlWithCert := basePgUrl requirePgUrlWithCert.User = url.User(optUser) requirePgUrlWithCert.RawQuery = fmt.Sprintf("sslmode=require&sslcert=%s&sslkey=%s", url.QueryEscape(tempCertPath), url.QueryEscape(tempKeyPath), ) err := trivialQuery(requirePgUrlWithCert) if insecure { if err != pq.ErrSSLNotSupported { t.Error(err) } } else { if optUser == certUser { if err != nil { t.Error(err) } } else { if !testutils.IsError(err, `requested user is \w+, but certificate is for \w+`) { t.Error(err) } } } } } cleanupTestServer(s) } }