From 94bee9e8821ed51f5aa1dec0d173472c6155cbe5 Mon Sep 17 00:00:00 2001 From: Joshua Casey Date: Fri, 19 Apr 2024 10:20:41 -0500 Subject: [PATCH] Remove testutil.TLSTestServerWithCert in favor of the testutil/tlsserver package --- cmd/pinniped/cmd/kubeconfig_test.go | 20 ++-- .../impersonator/impersonator_test.go | 8 +- .../jwtcachefiller/jwtcachefiller_test.go | 8 +- .../webhookcachefiller_test.go | 18 +-- .../pod_command_executor_test.go | 6 +- .../oidc_upstream_watcher_test.go | 31 +++--- internal/net/phttp/phttp_test.go | 6 +- internal/testutil/fakekubeapi/fakekubeapi.go | 6 +- internal/testutil/tlsserver.go | 61 ---------- internal/testutil/tlsserver/tlsserver.go | 53 +++++++-- internal/upstreamldap/upstreamldap_test.go | 17 ++- pkg/conciergeclient/conciergeclient_test.go | 28 ++--- pkg/oidcclient/login_test.go | 105 +++++++++--------- test/integration/securetls_fips_test.go | 6 +- test/integration/securetls_test.go | 12 +- 15 files changed, 175 insertions(+), 210 deletions(-) delete mode 100644 internal/testutil/tlsserver.go diff --git a/cmd/pinniped/cmd/kubeconfig_test.go b/cmd/pinniped/cmd/kubeconfig_test.go index 4b30456f4..1af712dcf 100644 --- a/cmd/pinniped/cmd/kubeconfig_test.go +++ b/cmd/pinniped/cmd/kubeconfig_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved. +// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package cmd @@ -18,6 +18,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" kubetesting "k8s.io/client-go/testing" "k8s.io/client-go/tools/clientcmd" + "k8s.io/utils/ptr" conciergev1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/authentication/v1alpha1" configv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1" @@ -27,6 +28,7 @@ import ( "go.pinniped.dev/internal/here" "go.pinniped.dev/internal/testutil" "go.pinniped.dev/internal/testutil/testlogger" + "go.pinniped.dev/internal/testutil/tlsserver" ) func TestGetKubeconfig(t *testing.T) { @@ -3198,7 +3200,7 @@ func TestGetKubeconfig(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { var issuerEndpointPtr *string - issuerCABundle, issuerEndpoint := testutil.TLSTestServer(t, func(w http.ResponseWriter, r *http.Request) { + testServer, testServerCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") switch r.URL.Path { case "/.well-known/openid-configuration": @@ -3226,8 +3228,8 @@ func TestGetKubeconfig(t *testing.T) { default: t.Fatalf("tried to call issuer at a path that wasn't one of the expected discovery endpoints.") } - }) - issuerEndpointPtr = &issuerEndpoint + }), nil) + issuerEndpointPtr = ptr.To(testServer.URL) testLog := testlogger.NewLegacy(t) //nolint:staticcheck // old test with lots of log statements cmd := kubeconfigCommand(kubeconfigDeps{ @@ -3248,7 +3250,7 @@ func TestGetKubeconfig(t *testing.T) { } fake := fakeconciergeclientset.NewSimpleClientset() if tt.conciergeObjects != nil { - fake = fakeconciergeclientset.NewSimpleClientset(tt.conciergeObjects(issuerCABundle, issuerEndpoint)...) + fake = fakeconciergeclientset.NewSimpleClientset(tt.conciergeObjects(string(testServerCA), testServer.URL)...) } if len(tt.conciergeReactions) > 0 { fake.ReactionChain = append(tt.conciergeReactions, fake.ReactionChain...) @@ -3263,7 +3265,7 @@ func TestGetKubeconfig(t *testing.T) { cmd.SetOut(&stdout) cmd.SetErr(&stderr) - cmd.SetArgs(tt.args(issuerCABundle, issuerEndpoint)) + cmd.SetArgs(tt.args(string(testServerCA), testServer.URL)) err := cmd.Execute() if tt.wantError { @@ -3274,19 +3276,19 @@ func TestGetKubeconfig(t *testing.T) { var expectedLogs []string if tt.wantLogs != nil { - expectedLogs = tt.wantLogs(issuerCABundle, issuerEndpoint) + expectedLogs = tt.wantLogs(string(testServerCA), testServer.URL) } testLog.Expect(expectedLogs) expectedStdout := "" if tt.wantStdout != nil { - expectedStdout = tt.wantStdout(issuerCABundle, issuerEndpoint) + expectedStdout = tt.wantStdout(string(testServerCA), testServer.URL) } require.Equal(t, expectedStdout, stdout.String(), "unexpected stdout") actualStderr := stderr.String() if tt.wantStderr != nil { - testutil.RequireErrorString(t, actualStderr, tt.wantStderr(issuerCABundle, issuerEndpoint)) + testutil.RequireErrorString(t, actualStderr, tt.wantStderr(string(testServerCA), testServer.URL)) } else { require.Empty(t, actualStderr, "unexpected stderr") } diff --git a/internal/concierge/impersonator/impersonator_test.go b/internal/concierge/impersonator/impersonator_test.go index b424e6a21..783ae8e07 100644 --- a/internal/concierge/impersonator/impersonator_test.go +++ b/internal/concierge/impersonator/impersonator_test.go @@ -692,7 +692,7 @@ func TestImpersonator(t *testing.T) { // will proxy incoming calls to this fake server. testKubeAPIServerWasCalled := false var testKubeAPIServerSawHeaders http.Header - testKubeAPIServer := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + testKubeAPIServer, testKubeAPIServerCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { tlsConfigFunc := func(rootCAs *x509.CertPool) *tls.Config { // Requests to get configmaps, flowcontrol requests, and healthz requests // are not done by our http round trippers that specify only one protocol @@ -815,7 +815,7 @@ func TestImpersonator(t *testing.T) { // Create the client config that the impersonation server should use to talk to the Kube API server. testKubeAPIServerKubeconfig := rest.Config{ Host: testKubeAPIServer.URL, - TLSClientConfig: rest.TLSClientConfig{CAData: tlsserver.TLSTestServerCA(testKubeAPIServer)}, + TLSClientConfig: rest.TLSClientConfig{CAData: testKubeAPIServerCA}, } // Punch out just enough stuff to make New actually run without error. @@ -1806,7 +1806,7 @@ func TestImpersonatorHTTPHandler(t *testing.T) { testKubeAPIServerWasCalled := false testKubeAPIServerSawHeaders := http.Header{} - testKubeAPIServer := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + testKubeAPIServer, testKubeAPIServerCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { tlsConfigFunc := func(rootCAs *x509.CertPool) *tls.Config { // Requests to get configmaps, flowcontrol requests, and healthz requests // are not done by our http round trippers that specify only one protocol @@ -1842,7 +1842,7 @@ func TestImpersonatorHTTPHandler(t *testing.T) { testKubeAPIServerKubeconfig := rest.Config{ Host: testKubeAPIServer.URL, BearerToken: "some-service-account-token", - TLSClientConfig: rest.TLSClientConfig{CAData: tlsserver.TLSTestServerCA(testKubeAPIServer)}, + TLSClientConfig: rest.TLSClientConfig{CAData: testKubeAPIServerCA}, } if tt.restConfig == nil { tt.restConfig = &testKubeAPIServerKubeconfig diff --git a/internal/controller/authenticator/jwtcachefiller/jwtcachefiller_test.go b/internal/controller/authenticator/jwtcachefiller/jwtcachefiller_test.go index 3e1868f22..188ce5398 100644 --- a/internal/controller/authenticator/jwtcachefiller/jwtcachefiller_test.go +++ b/internal/controller/authenticator/jwtcachefiller/jwtcachefiller_test.go @@ -76,7 +76,7 @@ func TestController(t *testing.T) { distributedGroups := []string{"some-distributed-group-1", "some-distributed-group-2"} goodMux := http.NewServeMux() - goodOIDCIssuerServer := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + goodOIDCIssuerServer, _ := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { tlsserver.AssertTLS(t, r, ptls.Default) goodMux.ServeHTTP(w, r) }), tlsserver.RecordTLSHello) @@ -174,7 +174,7 @@ func TestController(t *testing.T) { })) badMuxInvalidJWKSURI := http.NewServeMux() - badOIDCIssuerServerInvalidJWKSURI := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + badOIDCIssuerServerInvalidJWKSURI, _ := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { tlsserver.AssertTLS(t, r, ptls.Default) badMuxInvalidJWKSURI.ServeHTTP(w, r) }), tlsserver.RecordTLSHello) @@ -185,7 +185,7 @@ func TestController(t *testing.T) { })) badMuxInvalidJWKSURIScheme := http.NewServeMux() - badOIDCIssuerServerInvalidJWKSURIScheme := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + badOIDCIssuerServerInvalidJWKSURIScheme, _ := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { tlsserver.AssertTLS(t, r, ptls.Default) badMuxInvalidJWKSURIScheme.ServeHTTP(w, r) }), tlsserver.RecordTLSHello) @@ -196,7 +196,7 @@ func TestController(t *testing.T) { })) jwksFetchShouldFailMux := http.NewServeMux() - jwksFetchShouldFailServer := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + jwksFetchShouldFailServer, _ := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { tlsserver.AssertTLS(t, r, ptls.Default) jwksFetchShouldFailMux.ServeHTTP(w, r) }), tlsserver.RecordTLSHello) diff --git a/internal/controller/authenticator/webhookcachefiller/webhookcachefiller_test.go b/internal/controller/authenticator/webhookcachefiller/webhookcachefiller_test.go index 77a95df0d..3664e1ef4 100644 --- a/internal/controller/authenticator/webhookcachefiller/webhookcachefiller_test.go +++ b/internal/controller/authenticator/webhookcachefiller/webhookcachefiller_test.go @@ -88,25 +88,25 @@ func TestController(t *testing.T) { ) require.NoError(t, err) - hostAsLocalhostWebhookServer := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + hostAsLocalhostWebhookServer, _ := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // only expecting dials, which will not get into handler func }), func(s *httptest.Server) { s.TLS.Certificates = []tls.Certificate{*hostAsLocalhostServingCert} }) - hostAs127001WebhookServer := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + hostAs127001WebhookServer, _ := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // only expecting dials, which will not get into handler func }), func(s *httptest.Server) { s.TLS.Certificates = []tls.Certificate{*hostAs127001ServingCert} }) - hostLocalWithExampleDotComCertServer := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + hostLocalWithExampleDotComCertServer, _ := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // only expecting dials, which will not get into handler func }), func(s *httptest.Server) { s.TLS.Certificates = []tls.Certificate{*localButExampleDotComServerCert} }) - hostLocalIPv6Server := tlsserver.TLSTestIPv6Server(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}), tlsserver.RecordTLSHello) + hostLocalIPv6Server, ipv6CA := tlsserver.TestServerIPv6(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}), tlsserver.RecordTLSHello) mux := http.NewServeMux() mux.Handle("/nothing/here", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -114,7 +114,7 @@ func TestController(t *testing.T) { w.WriteHeader(http.StatusNotFound) _, _ = fmt.Fprint(w, "404 nothing here") })) - hostGoodDefaultServingCertServer := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + hostGoodDefaultServingCertServer, _ := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { mux.ServeHTTP(w, r) }), nil) @@ -533,7 +533,7 @@ func TestController(t *testing.T) { ipv6 := goodWebhookAuthenticatorSpecWithCA.DeepCopy() ipv6.Endpoint = hostLocalIPv6Server.URL ipv6.TLS = ptr.To(auth1alpha1.TLSSpec{ - CertificateAuthorityData: base64.StdEncoding.EncodeToString(tlsserver.TLSTestServerCA(hostLocalIPv6Server)), + CertificateAuthorityData: base64.StdEncoding.EncodeToString(ipv6CA), }) return *ipv6 }(), @@ -560,7 +560,7 @@ func TestController(t *testing.T) { ipv6 := goodWebhookAuthenticatorSpecWithCA.DeepCopy() ipv6.Endpoint = hostLocalIPv6Server.URL ipv6.TLS = ptr.To(auth1alpha1.TLSSpec{ - CertificateAuthorityData: base64.StdEncoding.EncodeToString(tlsserver.TLSTestServerCA(hostLocalIPv6Server)), + CertificateAuthorityData: base64.StdEncoding.EncodeToString(ipv6CA), }) return *ipv6 }(), @@ -1365,7 +1365,7 @@ func TestController(t *testing.T) { } func TestNewWebhookAuthenticator(t *testing.T) { - server := tlsserver.TLSTestServer(t, + server, serverCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Webhook clients should always use ptls.Default when making requests to the webhook. Assert that here. tlsserver.AssertTLS(t, r, ptls.Default) @@ -1446,7 +1446,7 @@ func TestNewWebhookAuthenticator(t *testing.T) { }, { name: "valid config, webhook authenticator created, and test calling webhook server", endpoint: server.URL, - pemBytes: tlsserver.TLSTestServerCA(server), + pemBytes: serverCA, prereqOk: true, wantConditions: []*metav1.Condition{{ Type: "AuthenticatorValid", diff --git a/internal/controller/kubecertagent/pod_command_executor_test.go b/internal/controller/kubecertagent/pod_command_executor_test.go index 662b2a011..938fa16b4 100644 --- a/internal/controller/kubecertagent/pod_command_executor_test.go +++ b/internal/controller/kubecertagent/pod_command_executor_test.go @@ -1,4 +1,4 @@ -// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2024 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package kubecertagent @@ -19,7 +19,7 @@ import ( func TestSecureTLS(t *testing.T) { var sawRequest bool - server := tlsserver.TLSTestServer(t, http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) { + server, serverCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) { tlsserver.AssertTLS(t, r, ptls.Secure) sawRequest = true }), tlsserver.RecordTLSHello) @@ -27,7 +27,7 @@ func TestSecureTLS(t *testing.T) { config := &rest.Config{ Host: server.URL, TLSClientConfig: rest.TLSClientConfig{ - CAData: tlsserver.TLSTestServerCA(server), + CAData: serverCA, }, } diff --git a/internal/controller/supervisorconfig/oidcupstreamwatcher/oidc_upstream_watcher_test.go b/internal/controller/supervisorconfig/oidcupstreamwatcher/oidc_upstream_watcher_test.go index c6a63698c..6837fa62a 100644 --- a/internal/controller/supervisorconfig/oidcupstreamwatcher/oidc_upstream_watcher_test.go +++ b/internal/controller/supervisorconfig/oidcupstreamwatcher/oidc_upstream_watcher_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved. +// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package oidcupstreamwatcher @@ -35,6 +35,7 @@ import ( "go.pinniped.dev/internal/testutil/oidctestutil" "go.pinniped.dev/internal/testutil/testlogger" "go.pinniped.dev/internal/testutil/tlsassertions" + "go.pinniped.dev/internal/testutil/tlsserver" "go.pinniped.dev/internal/upstreamoidc" ) @@ -113,7 +114,7 @@ func TestOIDCUpstreamWatcherControllerSync(t *testing.T) { earlier := metav1.NewTime(now.Add(-1 * time.Hour).UTC()) // Start another test server that answers discovery successfully. - testIssuerCA, testIssuerURL := newTestIssuer(t) + testIssuerURL, testIssuerCA := newTestIssuer(t) testIssuerCABase64 := base64.StdEncoding.EncodeToString([]byte(testIssuerCA)) testIssuerAuthorizeURL, err := url.Parse("https://example.com/authorize") require.NoError(t, err) @@ -1529,7 +1530,7 @@ func normalizeOIDCUpstreams(upstreams []v1alpha1.OIDCIdentityProvider, now metav func newTestIssuer(t *testing.T) (string, string) { mux := http.NewServeMux() - caBundlePEM, testURL := testutil.TLSTestServer(t, mux.ServeHTTP) + server, serverCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(mux.ServeHTTP), nil) type providerJSON struct { Issuer string `json:"issuer"` @@ -1543,7 +1544,7 @@ func newTestIssuer(t *testing.T) (string, string) { mux.HandleFunc("/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") _ = json.NewEncoder(w).Encode(&providerJSON{ - Issuer: testURL, + Issuer: server.URL, AuthURL: "https://example.com/authorize", RevocationURL: "https://example.com/revoke", TokenURL: "https://example.com/token", @@ -1554,7 +1555,7 @@ func newTestIssuer(t *testing.T) (string, string) { mux.HandleFunc("/valid-without-revocation/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") _ = json.NewEncoder(w).Encode(&providerJSON{ - Issuer: testURL + "/valid-without-revocation", + Issuer: server.URL + "/valid-without-revocation", AuthURL: "https://example.com/authorize", RevocationURL: "", // none TokenURL: "https://example.com/token", @@ -1565,7 +1566,7 @@ func newTestIssuer(t *testing.T) (string, string) { mux.HandleFunc("/invalid/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") _ = json.NewEncoder(w).Encode(&providerJSON{ - Issuer: testURL + "/invalid", + Issuer: server.URL + "/invalid", AuthURL: "%", TokenURL: "https://example.com/token", }) @@ -1575,7 +1576,7 @@ func newTestIssuer(t *testing.T) (string, string) { mux.HandleFunc("/invalid-revocation-url/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") _ = json.NewEncoder(w).Encode(&providerJSON{ - Issuer: testURL + "/invalid-revocation-url", + Issuer: server.URL + "/invalid-revocation-url", AuthURL: "https://example.com/authorize", RevocationURL: "%", TokenURL: "https://example.com/token", @@ -1586,7 +1587,7 @@ func newTestIssuer(t *testing.T) (string, string) { mux.HandleFunc("/insecure/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") _ = json.NewEncoder(w).Encode(&providerJSON{ - Issuer: testURL + "/insecure", + Issuer: server.URL + "/insecure", AuthURL: "http://example.com/authorize", TokenURL: "https://example.com/token", }) @@ -1596,7 +1597,7 @@ func newTestIssuer(t *testing.T) (string, string) { mux.HandleFunc("/insecure-revocation-url/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") _ = json.NewEncoder(w).Encode(&providerJSON{ - Issuer: testURL + "/insecure-revocation-url", + Issuer: server.URL + "/insecure-revocation-url", AuthURL: "https://example.com/authorize", RevocationURL: "http://example.com/revoke", TokenURL: "https://example.com/token", @@ -1607,7 +1608,7 @@ func newTestIssuer(t *testing.T) (string, string) { mux.HandleFunc("/insecure-token-url/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") _ = json.NewEncoder(w).Encode(&providerJSON{ - Issuer: testURL + "/insecure-token-url", + Issuer: server.URL + "/insecure-token-url", AuthURL: "https://example.com/authorize", RevocationURL: "https://example.com/revoke", TokenURL: "http://example.com/token", @@ -1619,7 +1620,7 @@ func newTestIssuer(t *testing.T) (string, string) { mux.HandleFunc("/missing-token-url/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") _ = json.NewEncoder(w).Encode(&providerJSON{ - Issuer: testURL + "/missing-token-url", + Issuer: server.URL + "/missing-token-url", AuthURL: "https://example.com/authorize", RevocationURL: "https://example.com/revoke", }) @@ -1629,7 +1630,7 @@ func newTestIssuer(t *testing.T) (string, string) { mux.HandleFunc("/missing-auth-url/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") _ = json.NewEncoder(w).Encode(&providerJSON{ - Issuer: testURL + "/missing-auth-url", + Issuer: server.URL + "/missing-auth-url", RevocationURL: "https://example.com/revoke", TokenURL: "https://example.com/token", }) @@ -1638,13 +1639,13 @@ func newTestIssuer(t *testing.T) (string, string) { // handle the four issuer with trailing slash configs // valid case in= out= - // handled above at the root of testURL + // handled above at the root of server.URL // valid case in=/ out=/ mux.HandleFunc("/ends-with-slash/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") _ = json.NewEncoder(w).Encode(&providerJSON{ - Issuer: testURL + "/ends-with-slash/", + Issuer: server.URL + "/ends-with-slash/", AuthURL: "https://example.com/authorize", RevocationURL: "https://example.com/revoke", TokenURL: "https://example.com/token", @@ -1657,5 +1658,5 @@ func newTestIssuer(t *testing.T) (string, string) { // invalid case in=/ out= // can be tested using root endpoint - return caBundlePEM, testURL + return server.URL, string(serverCA) } diff --git a/internal/net/phttp/phttp_test.go b/internal/net/phttp/phttp_test.go index 83792df1a..3a37983cf 100644 --- a/internal/net/phttp/phttp_test.go +++ b/internal/net/phttp/phttp_test.go @@ -1,4 +1,4 @@ -// Copyright 2021 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2024 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package phttp @@ -83,13 +83,13 @@ func TestClient(t *testing.T) { t.Parallel() var sawRequest bool - server := tlsserver.TLSTestServer(t, http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) { + server, serverCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) { tlsserver.AssertTLS(t, r, tt.configFunc) assertUserAgent(t, r) sawRequest = true }), tlsserver.RecordTLSHello) - rootCAs, err := cert.NewPoolFromBytes(tlsserver.TLSTestServerCA(server)) + rootCAs, err := cert.NewPoolFromBytes(serverCA) require.NoError(t, err) c := tt.clientFunc(rootCAs) diff --git a/internal/testutil/fakekubeapi/fakekubeapi.go b/internal/testutil/fakekubeapi/fakekubeapi.go index 7ac26ccc1..0fb176b34 100644 --- a/internal/testutil/fakekubeapi/fakekubeapi.go +++ b/internal/testutil/fakekubeapi/fakekubeapi.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2024 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 /* @@ -58,7 +58,7 @@ func Start(t *testing.T, resources map[string]runtime.Object) (*httptest.Server, resources = make(map[string]runtime.Object) } - server := tlsserver.TLSTestServer(t, httperr.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error { + server, serverCA := tlsserver.TestServerIPv4(t, httperr.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error { tlsserver.AssertTLS(t, r, ptls.Secure) obj, err := decodeObj(r) @@ -84,7 +84,7 @@ func Start(t *testing.T, resources map[string]runtime.Object) (*httptest.Server, restConfig := &restclient.Config{ Host: server.URL, TLSClientConfig: restclient.TLSClientConfig{ - CAData: tlsserver.TLSTestServerCA(server), + CAData: serverCA, }, } return server, restConfig diff --git a/internal/testutil/tlsserver.go b/internal/testutil/tlsserver.go deleted file mode 100644 index 4ebe526bd..000000000 --- a/internal/testutil/tlsserver.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -package testutil - -import ( - "crypto/tls" - "errors" - "net" - "net/http" - "testing" - "time" - - "github.com/stretchr/testify/require" - - "go.pinniped.dev/internal/crypto/ptls" - "go.pinniped.dev/internal/testutil/tlsserver" -) - -// TLSTestServer starts a test server listening on a local port using a test CA. It returns the PEM CA bundle and the -// URL of the listening server. The lifetime of the server is bound to the provided *testing.T. -func TLSTestServer(t *testing.T, handler http.HandlerFunc) (caBundlePEM, url string) { - t.Helper() - - server := tlsserver.TLSTestServer(t, handler, nil) - - return string(tlsserver.TLSTestServerCA(server)), server.URL -} - -func TLSTestServerWithCert(t *testing.T, handler http.HandlerFunc, certificate *tls.Certificate) (url string) { - t.Helper() - - c := ptls.Default(nil) // mimic API server config - c.Certificates = []tls.Certificate{*certificate} - - server := http.Server{ - TLSConfig: c, - Handler: handler, - ReadHeaderTimeout: 10 * time.Second, - } - - l, err := net.Listen("tcp", "127.0.0.1:0") - require.NoError(t, err) - - serverShutdownChan := make(chan error) - go func() { - // Empty certFile and keyFile will use certs from Server.TLSConfig. - serverShutdownChan <- server.ServeTLS(l, "", "") - }() - - t.Cleanup(func() { - _ = server.Close() - serveErr := <-serverShutdownChan - if !errors.Is(serveErr, http.ErrServerClosed) { - t.Log("Got an unexpected error while starting the fake http server!") - require.NoError(t, serveErr) - } - }) - - return l.Addr().String() -} diff --git a/internal/testutil/tlsserver/tlsserver.go b/internal/testutil/tlsserver/tlsserver.go index 0c3e2851d..b1ad27494 100644 --- a/internal/testutil/tlsserver/tlsserver.go +++ b/internal/testutil/tlsserver/tlsserver.go @@ -7,6 +7,7 @@ import ( "context" "crypto/tls" "encoding/pem" + "errors" "fmt" "net" "net/http" @@ -14,6 +15,7 @@ import ( "reflect" "sync" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -30,9 +32,8 @@ const ( helloKey ) -// TLSTestIPv6Server returns a TLS-required server that listens at an IPv6 loopback -// TODO: Rename since the package name already includes TLS. -func TLSTestIPv6Server(t *testing.T, handler http.Handler, f func(*httptest.Server)) *httptest.Server { +// TestServerIPv6 returns a TLS-required server that listens at an IPv6 loopback. +func TestServerIPv6(t *testing.T, handler http.Handler, f func(*httptest.Server)) (*httptest.Server, []byte) { t.Helper() listener, err := net.Listen("tcp6", "[::1]:0") @@ -46,16 +47,15 @@ func TLSTestIPv6Server(t *testing.T, handler http.Handler, f func(*httptest.Serv return testServer(t, server, f) } -// TLSTestServer returns a TLS-required server that listens at an IPv4 loopback. -// TODO: Rename since the package name already includes TLS. -func TLSTestServer(t *testing.T, handler http.Handler, f func(*httptest.Server)) *httptest.Server { +// TestServerIPv4 returns a TLS-required server that listens at an IPv4 loopback. +func TestServerIPv4(t *testing.T, handler http.Handler, f func(*httptest.Server)) (*httptest.Server, []byte) { t.Helper() server := httptest.NewUnstartedServer(handler) return testServer(t, server, f) } -func testServer(t *testing.T, server *httptest.Server, f func(*httptest.Server)) *httptest.Server { +func testServer(t *testing.T, server *httptest.Server, f func(*httptest.Server)) (*httptest.Server, []byte) { t.Helper() server.TLS = ptls.Default(nil) // mimic API server config @@ -64,16 +64,45 @@ func testServer(t *testing.T, server *httptest.Server, f func(*httptest.Server)) } server.StartTLS() t.Cleanup(server.Close) - return server -} - -func TLSTestServerCA(server *httptest.Server) []byte { - return pem.EncodeToMemory(&pem.Block{ + return server, pem.EncodeToMemory(&pem.Block{ Type: "CERTIFICATE", Bytes: server.Certificate().Raw, }) } +func TLSTestServerWithCert(t *testing.T, handler http.HandlerFunc, certificate *tls.Certificate) (url string) { + t.Helper() + + c := ptls.Default(nil) // mimic API server config + c.Certificates = []tls.Certificate{*certificate} + + server := http.Server{ + TLSConfig: c, + Handler: handler, + ReadHeaderTimeout: 10 * time.Second, + } + + l, err := net.Listen("tcp", "127.0.0.1:0") + require.NoError(t, err) + + serverShutdownChan := make(chan error) + go func() { + // Empty certFile and keyFile will use certs from Server.TLSConfig. + serverShutdownChan <- server.ServeTLS(l, "", "") + }() + + t.Cleanup(func() { + _ = server.Close() + serveErr := <-serverShutdownChan + if !errors.Is(serveErr, http.ErrServerClosed) { + t.Log("Got an unexpected error while starting the fake http server!") + require.NoError(t, serveErr) + } + }) + + return l.Addr().String() +} + func RecordTLSHello(server *httptest.Server) { server.Config.ConnContext = func(ctx context.Context, _ net.Conn) context.Context { return context.WithValue(ctx, mapKey, &sync.Map{}) diff --git a/internal/upstreamldap/upstreamldap_test.go b/internal/upstreamldap/upstreamldap_test.go index d8f314881..8842292ff 100644 --- a/internal/upstreamldap/upstreamldap_test.go +++ b/internal/upstreamldap/upstreamldap_test.go @@ -2363,7 +2363,7 @@ func TestGetURL(t *testing.T) { // Testing of host parsing, TLS negotiation, and CA bundle, etc. for the production code's dialer. func TestRealTLSDialing(t *testing.T) { - testServer := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}), + testServer, testServerCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}), func(server *httptest.Server) { tlsserver.RecordTLSHello(server) recordFunc := server.TLS.GetConfigForClient @@ -2378,14 +2378,13 @@ func TestRealTLSDialing(t *testing.T) { parsedURL, err := url.Parse(testServer.URL) require.NoError(t, err) testServerHostAndPort := parsedURL.Host - testServerCABundle := tlsserver.TLSTestServerCA(testServer) caForTestServerWithBadCertName, err := certauthority.New("Test CA", time.Hour) require.NoError(t, err) wrongIP := net.ParseIP("10.2.3.4") cert, err := caForTestServerWithBadCertName.IssueServerCert([]string{"wrong-dns-name"}, []net.IP{wrongIP}, time.Hour) require.NoError(t, err) - testServerWithBadCertNameAddr := testutil.TLSTestServerWithCert(t, func(w http.ResponseWriter, r *http.Request) {}, cert) + testServerWithBadCertNameAddr := tlsserver.TLSTestServerWithCert(t, func(w http.ResponseWriter, r *http.Request) {}, cert) unusedPortGrabbingListener, err := net.Listen("tcp", "127.0.0.1:0") require.NoError(t, err) @@ -2406,7 +2405,7 @@ func TestRealTLSDialing(t *testing.T) { { name: "happy path", host: testServerHostAndPort, - caBundle: testServerCABundle, + caBundle: testServerCA, connProto: TLS, context: context.Background(), }, @@ -2437,7 +2436,7 @@ func TestRealTLSDialing(t *testing.T) { { name: "invalid host with TLS", host: "this:is:not:a:valid:hostname", - caBundle: testServerCABundle, + caBundle: testServerCA, connProto: TLS, context: context.Background(), wantError: testutil.WantExactErrorString(`LDAP Result Code 200 "Network Error": host "this:is:not:a:valid:hostname" is not a valid hostname or IP address`), @@ -2445,7 +2444,7 @@ func TestRealTLSDialing(t *testing.T) { { name: "invalid host with StartTLS", host: "this:is:not:a:valid:hostname", - caBundle: testServerCABundle, + caBundle: testServerCA, connProto: StartTLS, context: context.Background(), wantError: testutil.WantExactErrorString(`LDAP Result Code 200 "Network Error": host "this:is:not:a:valid:hostname" is not a valid hostname or IP address`), @@ -2462,7 +2461,7 @@ func TestRealTLSDialing(t *testing.T) { name: "cannot connect to host", // This is assuming that this port was not reclaimed by another app since the test setup ran. Seems safe enough. host: recentlyClaimedHostAndPort, - caBundle: testServerCABundle, + caBundle: testServerCA, connProto: TLS, context: context.Background(), wantError: testutil.WantSprintfErrorString(`LDAP Result Code 200 "Network Error": dial tcp %s: connect: connection refused`, recentlyClaimedHostAndPort), @@ -2470,7 +2469,7 @@ func TestRealTLSDialing(t *testing.T) { { name: "pays attention to the passed context", host: testServerHostAndPort, - caBundle: testServerCABundle, + caBundle: testServerCA, connProto: TLS, context: alreadyCancelledContext, wantError: testutil.WantSprintfErrorString(`LDAP Result Code 200 "Network Error": dial tcp %s: operation was canceled`, testServerHostAndPort), @@ -2478,7 +2477,7 @@ func TestRealTLSDialing(t *testing.T) { { name: "unsupported connection protocol", host: testServerHostAndPort, - caBundle: testServerCABundle, + caBundle: testServerCA, connProto: "bad usage of this type", context: alreadyCancelledContext, wantError: testutil.WantExactErrorString(`LDAP Result Code 200 "Network Error": did not specify valid ConnectionProtocol`), diff --git a/pkg/conciergeclient/conciergeclient_test.go b/pkg/conciergeclient/conciergeclient_test.go index c0af26f47..d44c9508e 100644 --- a/pkg/conciergeclient/conciergeclient_test.go +++ b/pkg/conciergeclient/conciergeclient_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package conciergeclient @@ -20,7 +20,7 @@ import ( loginv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/login/v1alpha1" "go.pinniped.dev/internal/certauthority" - "go.pinniped.dev/internal/testutil" + "go.pinniped.dev/internal/testutil/tlsserver" ) func TestNew(t *testing.T) { @@ -163,12 +163,12 @@ func TestExchangeToken(t *testing.T) { t.Run("server error", func(t *testing.T) { t.Parallel() // Start a test server that returns only 500 errors. - caBundle, endpoint := testutil.TLSTestServer(t, func(w http.ResponseWriter, r *http.Request) { + server, serverCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusInternalServerError) _, _ = w.Write([]byte("some server error")) - }) + }), nil) - client, err := New(WithEndpoint(endpoint), WithCABundle(caBundle), WithAuthenticator("jwt", "test-authenticator")) + client, err := New(WithEndpoint(server.URL), WithCABundle(string(serverCA)), WithAuthenticator("jwt", "test-authenticator")) require.NoError(t, err) got, err := client.ExchangeToken(ctx, "test-token") @@ -180,15 +180,15 @@ func TestExchangeToken(t *testing.T) { t.Parallel() // Start a test server that returns success but with an error message errorMessage := "some login failure" - caBundle, endpoint := testutil.TLSTestServer(t, func(w http.ResponseWriter, r *http.Request) { + server, serverCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") _ = json.NewEncoder(w).Encode(&loginv1alpha1.TokenCredentialRequest{ TypeMeta: metav1.TypeMeta{APIVersion: "login.concierge.pinniped.dev/v1alpha1", Kind: "TokenCredentialRequest"}, Status: loginv1alpha1.TokenCredentialRequestStatus{Message: &errorMessage}, }) - }) + }), nil) - client, err := New(WithEndpoint(endpoint), WithCABundle(caBundle), WithAuthenticator("jwt", "test-authenticator")) + client, err := New(WithEndpoint(server.URL), WithCABundle(string(serverCA)), WithAuthenticator("jwt", "test-authenticator")) require.NoError(t, err) got, err := client.ExchangeToken(ctx, "test-token") @@ -199,14 +199,14 @@ func TestExchangeToken(t *testing.T) { t.Run("login failure unknown error", func(t *testing.T) { t.Parallel() // Start a test server that returns without any error message but also without valid credentials - caBundle, endpoint := testutil.TLSTestServer(t, func(w http.ResponseWriter, r *http.Request) { + server, serverCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") _ = json.NewEncoder(w).Encode(&loginv1alpha1.TokenCredentialRequest{ TypeMeta: metav1.TypeMeta{APIVersion: "login.concierge.pinniped.dev/v1alpha1", Kind: "TokenCredentialRequest"}, }) - }) + }), nil) - client, err := New(WithEndpoint(endpoint), WithCABundle(caBundle), WithAuthenticator("jwt", "test-authenticator")) + client, err := New(WithEndpoint(server.URL), WithCABundle(string(serverCA)), WithAuthenticator("jwt", "test-authenticator")) require.NoError(t, err) got, err := client.ExchangeToken(ctx, "test-token") @@ -219,7 +219,7 @@ func TestExchangeToken(t *testing.T) { expires := metav1.NewTime(time.Now().Truncate(time.Second)) // Start a test server that returns successfully and asserts various properties of the request. - caBundle, endpoint := testutil.TLSTestServer(t, func(w http.ResponseWriter, r *http.Request) { + server, serverCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { require.Equal(t, http.MethodPost, r.Method) require.Equal(t, "/apis/login.concierge.pinniped.dev/v1alpha1/tokencredentialrequests", r.URL.Path) require.Equal(t, "application/json", r.Header.Get("content-type")) @@ -257,9 +257,9 @@ func TestExchangeToken(t *testing.T) { }, }, }) - }) + }), nil) - client, err := New(WithEndpoint(endpoint), WithCABundle(caBundle), WithAuthenticator("webhook", "test-webhook")) + client, err := New(WithEndpoint(server.URL), WithCABundle(string(serverCA)), WithAuthenticator("webhook", "test-webhook")) require.NoError(t, err) got, err := client.ExchangeToken(ctx, "test-token") diff --git a/pkg/oidcclient/login_test.go b/pkg/oidcclient/login_test.go index d7669f74d..7d71a8899 100644 --- a/pkg/oidcclient/login_test.go +++ b/pkg/oidcclient/login_test.go @@ -66,10 +66,9 @@ func (m *mockSessionCache) PutToken(key SessionCacheKey, token *oidctypes.Token) m.sawPutTokens = append(m.sawPutTokens, token) } -func newClientForServer(server *httptest.Server) *http.Client { +func buildHTTPClientForPEM(pemData []byte) *http.Client { pool := x509.NewCertPool() - caPEMData := tlsserver.TLSTestServerCA(server) - pool.AppendCertsFromPEM(caPEMData) + pool.AppendCertsFromPEM(pemData) return phttp.Default(pool) } @@ -91,13 +90,13 @@ func TestLogin(t *testing.T) { //nolint:gocyclo } // Start a test server that returns 500 errors. - errorServer := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + errorServer, errorServerCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.Error(w, "some discovery error", http.StatusInternalServerError) }), nil) // Start a test server that returns discovery data with a broken response_modes_supported value. brokenResponseModeMux := http.NewServeMux() - brokenResponseModeServer := tlsserver.TLSTestServer(t, brokenResponseModeMux, nil) + brokenResponseModeServer, brokenResponseModeServerCA := tlsserver.TestServerIPv4(t, brokenResponseModeMux, nil) brokenResponseModeMux.HandleFunc("/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") type providerJSON struct { @@ -116,7 +115,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo // Start a test server that returns discovery data with a broken token URL. brokenTokenURLMux := http.NewServeMux() - brokenTokenURLServer := tlsserver.TLSTestServer(t, brokenTokenURLMux, nil) + brokenTokenURLServer, brokenTokenURLServerCA := tlsserver.TestServerIPv4(t, brokenTokenURLMux, nil) brokenTokenURLMux.HandleFunc("/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") type providerJSON struct { @@ -135,7 +134,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo // Start a test server that returns discovery data with an insecure token URL. insecureTokenURLMux := http.NewServeMux() - insecureTokenURLServer := tlsserver.TLSTestServer(t, insecureTokenURLMux, nil) + insecureTokenURLServer, insecureTokenURLServerCA := tlsserver.TestServerIPv4(t, insecureTokenURLMux, nil) insecureTokenURLMux.HandleFunc("/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") type providerJSON struct { @@ -154,7 +153,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo // Start a test server that returns discovery data with a broken authorize URL. brokenAuthURLMux := http.NewServeMux() - brokenAuthURLServer := tlsserver.TLSTestServer(t, brokenAuthURLMux, nil) + brokenAuthURLServer, brokenAuthURLServerCA := tlsserver.TestServerIPv4(t, brokenAuthURLMux, nil) brokenAuthURLMux.HandleFunc("/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") type providerJSON struct { @@ -173,7 +172,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo // Start a test server that returns discovery data with an insecure authorize URL. insecureAuthURLMux := http.NewServeMux() - insecureAuthURLServer := tlsserver.TLSTestServer(t, insecureAuthURLMux, nil) + insecureAuthURLServer, insecureAuthURLServerCA := tlsserver.TestServerIPv4(t, insecureAuthURLMux, nil) insecureAuthURLMux.HandleFunc("/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") type providerJSON struct { @@ -298,13 +297,13 @@ func TestLogin(t *testing.T) { //nolint:gocyclo // Start a test server that returns a real discovery document and answers refresh requests. providerMux := http.NewServeMux() - successServer := tlsserver.TLSTestServer(t, providerMux, nil) + successServer, successServerCA := tlsserver.TestServerIPv4(t, providerMux, nil) providerMux.HandleFunc("/.well-known/openid-configuration", discoveryHandler(successServer, nil)) providerMux.HandleFunc("/token", tokenHandler) // Start a test server that returns a real discovery document and answers refresh requests, _and_ supports form_mode=post. formPostProviderMux := http.NewServeMux() - formPostSuccessServer := tlsserver.TLSTestServer(t, formPostProviderMux, nil) + formPostSuccessServer, formPostSuccessServerCA := tlsserver.TestServerIPv4(t, formPostProviderMux, nil) formPostProviderMux.HandleFunc("/.well-known/openid-configuration", discoveryHandler(formPostSuccessServer, []string{"query", "form_post"})) formPostProviderMux.HandleFunc("/token", tokenHandler) @@ -339,7 +338,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithCLISendingCredentials()(h)) require.NoError(t, WithUpstreamIdentityProvider("some-upstream-name", "ldap")(h)) - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) require.NoError(t, WithClient(&http.Client{ Transport: roundtripper.Func(func(req *http.Request) (*http.Response, error) { @@ -436,7 +435,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo clientID: "test-client-id", opt: func(t *testing.T) Option { return func(h *handlerState) error { - require.NoError(t, WithClient(newClientForServer(errorServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(errorServerCA))(h)) cache := &mockSessionCache{t: t, getReturnsToken: &oidctypes.Token{ IDToken: &oidctypes.IDToken{ Token: "test-id-token", @@ -485,7 +484,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo name: "discovery failure due to 500 error", opt: func(t *testing.T) Option { return func(h *handlerState) error { - require.NoError(t, WithClient(newClientForServer(errorServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(errorServerCA))(h)) return nil } }, @@ -497,7 +496,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo name: "discovery failure due to invalid response_modes_supported", opt: func(t *testing.T) Option { return func(h *handlerState) error { - require.NoError(t, WithClient(newClientForServer(brokenResponseModeServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(brokenResponseModeServerCA))(h)) return nil } }, @@ -511,7 +510,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo clientID: "test-client-id", opt: func(t *testing.T) Option { return func(h *handlerState) error { - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) h.getProvider = func(config *oauth2.Config, provider *oidc.Provider, client *http.Client) upstreamprovider.UpstreamOIDCIdentityProviderI { mock := mockUpstream(t) @@ -562,7 +561,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo clientID: "test-client-id", opt: func(t *testing.T) Option { return func(h *handlerState) error { - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) h.getProvider = func(config *oauth2.Config, provider *oidc.Provider, client *http.Client) upstreamprovider.UpstreamOIDCIdentityProviderI { mock := mockUpstream(t) @@ -605,7 +604,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo clientID: "not-the-test-client-id", opt: func(t *testing.T) Option { return func(h *handlerState) error { - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) cache := &mockSessionCache{t: t, getReturnsToken: &oidctypes.Token{ IDToken: &oidctypes.IDToken{ @@ -638,7 +637,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo name: "issuer has invalid token URL", opt: func(t *testing.T) Option { return func(h *handlerState) error { - require.NoError(t, WithClient(newClientForServer(brokenTokenURLServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(brokenTokenURLServerCA))(h)) return nil } }, @@ -650,7 +649,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo name: "issuer has insecure token URL", opt: func(t *testing.T) Option { return func(h *handlerState) error { - require.NoError(t, WithClient(newClientForServer(insecureTokenURLServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(insecureTokenURLServerCA))(h)) return nil } }, @@ -662,7 +661,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo name: "issuer has invalid authorize URL", opt: func(t *testing.T) Option { return func(h *handlerState) error { - require.NoError(t, WithClient(newClientForServer(brokenAuthURLServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(brokenAuthURLServerCA))(h)) return nil } }, @@ -674,7 +673,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo name: "issuer has insecure authorize URL", opt: func(t *testing.T) Option { return func(h *handlerState) error { - require.NoError(t, WithClient(newClientForServer(insecureAuthURLServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(insecureAuthURLServerCA))(h)) return nil } }, @@ -686,7 +685,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo name: "listen failure and non-tty stdin", opt: func(t *testing.T) Option { return func(h *handlerState) error { - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) h.listen = func(net string, addr string) (net.Listener, error) { assert.Equal(t, "tcp", net) assert.Equal(t, "localhost:0", addr) @@ -711,7 +710,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo h.generatePKCE = func() (pkce.Code, error) { return "test-pkce", nil } h.generateNonce = func() (nonce.Nonce, error) { return "test-nonce", nil } h.stdinIsTTY = func() bool { return true } - require.NoError(t, WithClient(newClientForServer(formPostSuccessServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(formPostSuccessServerCA))(h)) require.NoError(t, WithSkipListen()(h)) h.openURL = func(authorizeURL string) error { parsed, err := url.Parse(authorizeURL) @@ -750,7 +749,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo h.generatePKCE = func() (pkce.Code, error) { return "test-pkce", nil } h.generateNonce = func() (nonce.Nonce, error) { return "test-nonce", nil } h.stdinIsTTY = func() bool { return true } - require.NoError(t, WithClient(newClientForServer(formPostSuccessServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(formPostSuccessServerCA))(h)) h.listen = func(string, string) (net.Listener, error) { return nil, fmt.Errorf("some listen error") } h.openURL = func(authorizeURL string) error { parsed, err := url.Parse(authorizeURL) @@ -790,7 +789,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo h.generateNonce = func() (nonce.Nonce, error) { return "test-nonce", nil } h.stdinIsTTY = func() bool { return true } - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) ctx, cancel := context.WithCancel(h.ctx) h.ctx = ctx @@ -824,7 +823,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo h.generatePKCE = func() (pkce.Code, error) { return "test-pkce", nil } h.generateNonce = func() (nonce.Nonce, error) { return "test-nonce", nil } h.stdinIsTTY = func() bool { return true } - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) h.openURL = func(_ string) error { go func() { h.callbacks <- callbackResult{err: fmt.Errorf("some callback error")} @@ -873,7 +872,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }) require.NoError(t, WithSessionCache(cache)(h)) - client := newClientForServer(successServer) + client := buildHTTPClientForPEM(successServerCA) client.Timeout = 10 * time.Second require.NoError(t, WithClient(client)(h)) @@ -947,7 +946,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }) require.NoError(t, WithSessionCache(cache)(h)) - client := newClientForServer(successServer) + client := buildHTTPClientForPEM(successServerCA) client.Timeout = 10 * time.Second require.NoError(t, WithClient(client)(h)) @@ -1013,7 +1012,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }) require.NoError(t, WithSessionCache(cache)(h)) - client := newClientForServer(successServer) + client := buildHTTPClientForPEM(successServerCA) client.Timeout = 10 * time.Second require.NoError(t, WithClient(client)(h)) @@ -1091,7 +1090,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }) require.NoError(t, WithSessionCache(cache)(h)) - client := newClientForServer(successServer) + client := buildHTTPClientForPEM(successServerCA) client.Timeout = 10 * time.Second require.NoError(t, WithClient(client)(h)) @@ -1182,7 +1181,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }) require.NoError(t, WithSessionCache(cache)(h)) - client := newClientForServer(formPostSuccessServer) + client := buildHTTPClientForPEM(formPostSuccessServerCA) client.Timeout = 10 * time.Second require.NoError(t, WithClient(client)(h)) @@ -1258,7 +1257,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithUpstreamIdentityProvider("some-upstream-name", "oidc")(h)) - client := newClientForServer(successServer) + client := buildHTTPClientForPEM(successServerCA) client.Timeout = 10 * time.Second require.NoError(t, WithClient(client)(h)) @@ -1349,7 +1348,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo return func(h *handlerState) error { _ = defaultLDAPTestOpts(t, h, nil, nil) - client := newClientForServer(successServer) + client := buildHTTPClientForPEM(successServerCA) client.Transport = roundtripper.Func(func(req *http.Request) (*http.Response, error) { switch req.URL.Scheme + "://" + req.URL.Host + req.URL.Path { case "https://" + successServer.Listener.Addr().String() + "/.well-known/openid-configuration": @@ -1567,7 +1566,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo require.True(t, authorizeRequestWasMade, "should have made an authorize request") }) - client := newClientForServer(successServer) + client := buildHTTPClientForPEM(successServerCA) client.Transport = roundtripper.Func(func(req *http.Request) (*http.Response, error) { switch req.URL.Scheme + "://" + req.URL.Host + req.URL.Path { case "https://" + successServer.Listener.Addr().String() + "/.well-known/openid-configuration": @@ -1671,7 +1670,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo require.True(t, authorizeRequestWasMade, "should have made an authorize request") }) - client := newClientForServer(successServer) + client := buildHTTPClientForPEM(successServerCA) client.Transport = roundtripper.Func(func(req *http.Request) (*http.Response, error) { switch req.URL.Scheme + "://" + req.URL.Host + req.URL.Path { case "https://" + successServer.Listener.Addr().String() + "/.well-known/openid-configuration": @@ -1778,7 +1777,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo require.True(t, authorizeRequestWasMade, "should have made an authorize request") }) - client := newClientForServer(successServer) + client := buildHTTPClientForPEM(successServerCA) client.Transport = roundtripper.Func(func(req *http.Request) (*http.Response, error) { switch req.URL.Scheme + "://" + req.URL.Host + req.URL.Path { case "https://" + successServer.Listener.Addr().String() + "/.well-known/openid-configuration": @@ -1842,7 +1841,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(errorServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(errorServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("cluster-1234")(h)) return nil @@ -1871,7 +1870,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(insecureTokenURLServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(insecureTokenURLServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("cluster-1234")(h)) return nil @@ -1900,7 +1899,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(brokenTokenURLServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(brokenTokenURLServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("cluster-1234")(h)) return nil @@ -1929,7 +1928,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("test-audience-produce-invalid-http-response")(h)) return nil @@ -1958,7 +1957,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("test-audience-produce-http-400")(h)) return nil @@ -1987,7 +1986,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("test-audience-produce-invalid-content-type")(h)) return nil @@ -2016,7 +2015,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("test-audience-produce-wrong-content-type")(h)) return nil @@ -2045,7 +2044,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("test-audience-produce-invalid-json")(h)) return nil @@ -2074,7 +2073,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("test-audience-produce-invalid-tokentype")(h)) return nil @@ -2103,7 +2102,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("test-audience-produce-invalid-issuedtokentype")(h)) return nil @@ -2132,7 +2131,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("test-audience-produce-invalid-jwt")(h)) return nil @@ -2161,7 +2160,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("test-audience")(h)) @@ -2204,7 +2203,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("request-this-test-audience")(h)) @@ -2256,7 +2255,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo Claims: map[string]interface{}{"aud": "test-custom-request-audience"}, }, cache.sawPutTokens[0].IDToken) }) - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("test-custom-request-audience")(h)) @@ -2318,7 +2317,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("request-this-test-audience")(h)) @@ -2343,7 +2342,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo clientID: "test-client-id", opt: func(t *testing.T) Option { return func(h *handlerState) error { - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) cache := &mockSessionCache{t: t, getReturnsToken: &oidctypes.Token{ IDToken: &oidctypes.IDToken{ diff --git a/test/integration/securetls_fips_test.go b/test/integration/securetls_fips_test.go index 5a35ab5ef..46168ac5a 100644 --- a/test/integration/securetls_fips_test.go +++ b/test/integration/securetls_fips_test.go @@ -1,4 +1,4 @@ -// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2024 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 //go:build fips_strict @@ -23,14 +23,14 @@ import ( func TestFIPSCipherSuites_Parallel(t *testing.T) { _ = testlib.IntegrationEnv(t) - server := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + Server, _ := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // use the default fips config which contains a hard coded list of cipher suites // that should be equal to the default list of fips cipher suites. // assert that the client hello response has the same tls config as this test server. tlsserver.AssertTLS(t, r, ptls.Default) }), tlsserver.RecordTLSHello) - ca := tlsserver.TLSTestServerCA(server) + ca := tlsserver.TestServerIPv4CA(server) pool, err := cert.NewPoolFromBytes(ca) require.NoError(t, err) // create a tls config that does not explicitly set cipher suites, diff --git a/test/integration/securetls_test.go b/test/integration/securetls_test.go index 0d2187bf5..209e1dd89 100644 --- a/test/integration/securetls_test.go +++ b/test/integration/securetls_test.go @@ -23,7 +23,7 @@ import ( func TestSecureTLSPinnipedCLIToKAS_Parallel(t *testing.T) { _ = testlib.IntegrationEnv(t) - server := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + server, serverCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // pinniped CLI uses ptls.Secure when talking to KAS // in FIPS mode the distinction doesn't matter much because // each of the configs is a wrapper for the same base FIPS config @@ -33,15 +33,13 @@ func TestSecureTLSPinnipedCLIToKAS_Parallel(t *testing.T) { `"status":{"credential":{"token":"some-fancy-token"}}}`) }), tlsserver.RecordTLSHello) - ca := tlsserver.TLSTestServerCA(server) - pinnipedExe := testlib.PinnipedCLIPath(t) stdout, stderr := runPinnipedCLI(t, nil, pinnipedExe, "login", "static", "--token", "does-not-matter", "--concierge-authenticator-type", "webhook", "--concierge-authenticator-name", "does-not-matter", - "--concierge-ca-bundle-data", base64.StdEncoding.EncodeToString(ca), + "--concierge-ca-bundle-data", base64.StdEncoding.EncodeToString(serverCA), "--concierge-endpoint", server.URL, "--enable-concierge", "--credential-cache", "", @@ -57,7 +55,7 @@ func TestSecureTLSPinnipedCLIToKAS_Parallel(t *testing.T) { func TestSecureTLSPinnipedCLIToSupervisor_Parallel(t *testing.T) { _ = testlib.IntegrationEnv(t) - server := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + server, serverCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // pinniped CLI uses ptls.Default when talking to supervisor // in FIPS mode the distinction doesn't matter much because // each of the configs is a wrapper for the same base FIPS config @@ -66,12 +64,10 @@ func TestSecureTLSPinnipedCLIToSupervisor_Parallel(t *testing.T) { fmt.Fprint(w, `{"issuer":"https://not-a-good-issuer"}`) }), tlsserver.RecordTLSHello) - ca := tlsserver.TLSTestServerCA(server) - pinnipedExe := testlib.PinnipedCLIPath(t) stdout, stderr := runPinnipedCLI(&fakeT{T: t}, nil, pinnipedExe, "login", "oidc", - "--ca-bundle-data", base64.StdEncoding.EncodeToString(ca), + "--ca-bundle-data", base64.StdEncoding.EncodeToString(serverCA), "--issuer", server.URL, "--credential-cache", "", "--upstream-identity-provider-flow", "cli_password",