Skip to content

Commit 61966f1

Browse files
committed
authn: test against (non) nil CA
1 parent d0de5e3 commit 61966f1

File tree

1 file changed

+127
-0
lines changed

1 file changed

+127
-0
lines changed

pkg/authn/oidc_test.go

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*
2+
Copyright 2025 the kube-rbac-proxy maintainers All rights reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
package authn
17+
18+
import (
19+
"context"
20+
"crypto/tls"
21+
"encoding/pem"
22+
"fmt"
23+
"net/http"
24+
"net/http/httptest"
25+
"os"
26+
"testing"
27+
)
28+
29+
// newTestOIDCIssuer creates an HTTPS test server serving minimal OIDC discovery and JWKS endpoints.
30+
func newTestOIDCIssuer() *httptest.Server {
31+
var ts *httptest.Server
32+
ts = httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
33+
switch r.URL.Path {
34+
case "/.well-known/openid-configuration":
35+
w.Header().Set("Content-Type", "application/json")
36+
// Use the test server's URL as issuer and JWKS URI.
37+
fmt.Fprintf(w, `{"issuer": "%s", "jwks_uri": "%s/jwks"}`, ts.URL, ts.URL)
38+
case "/jwks":
39+
w.Header().Set("Content-Type", "application/json")
40+
fmt.Fprint(w, `{"keys": []}`)
41+
default:
42+
http.NotFound(w, r)
43+
}
44+
}))
45+
return ts
46+
}
47+
48+
func TestNewOIDCAuthenticator(t *testing.T) {
49+
// Create a dummy OIDC issuer (HTTPS).
50+
ts := newTestOIDCIssuer()
51+
defer ts.Close()
52+
53+
// Override the default transport to skip TLS verification.
54+
// This is needed because ts uses a self-signed certificate.
55+
// This should be legit for testing purpose, even with parallel test cases run at the same time.
56+
origTransport := http.DefaultTransport
57+
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
58+
defer func() {
59+
http.DefaultTransport = origTransport
60+
}()
61+
62+
// common dummy configuration values.
63+
baseConfig := OIDCConfig{
64+
IssuerURL: ts.URL,
65+
ClientID: "test-client",
66+
UsernameClaim: "email",
67+
UsernamePrefix: "",
68+
GroupsClaim: "groups",
69+
GroupsPrefix: "",
70+
SupportedSigningAlgs: []string{"RS256"},
71+
}
72+
73+
t.Run("EmptyCAFile", func(t *testing.T) {
74+
// CAFile is empty; the authenticator should default to using the host's trust store.
75+
config := baseConfig
76+
config.CAFile = ""
77+
78+
auth, err := NewOIDCAuthenticator(context.Background(), &config)
79+
if err != nil {
80+
t.Fatalf("expected no error, got: %v", err)
81+
}
82+
if auth.dynamicClientCA != nil {
83+
t.Errorf("expected dynamicClientCA to be nil when CAFile is empty, got non-nil")
84+
}
85+
})
86+
87+
t.Run("ValidCAFile", func(t *testing.T) {
88+
// Extract the test server's certificate and write it to a temporary file.
89+
if ts.TLS == nil || len(ts.TLS.Certificates) == 0 {
90+
t.Fatal("test server does not have a TLS certificate")
91+
}
92+
certBytes := ts.TLS.Certificates[0].Certificate[0]
93+
validCAPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certBytes})
94+
95+
tmpFile, err := os.CreateTemp("", "test-ca-*.pem")
96+
if err != nil {
97+
t.Fatalf("failed to create temporary file: %v", err)
98+
}
99+
defer os.Remove(tmpFile.Name())
100+
101+
if _, err = tmpFile.Write(validCAPEM); err != nil {
102+
t.Fatalf("failed to write certificate to temporary file: %v", err)
103+
}
104+
tmpFile.Close()
105+
106+
config := baseConfig
107+
config.CAFile = tmpFile.Name()
108+
109+
auth, err := NewOIDCAuthenticator(context.Background(), &config)
110+
if err != nil {
111+
t.Fatalf("expected no error, got: %v", err)
112+
}
113+
if auth.dynamicClientCA == nil {
114+
t.Errorf("expected dynamicClientCA to be non-nil when a valid CAFile is provided")
115+
}
116+
})
117+
118+
t.Run("InvalidCAFile", func(t *testing.T) {
119+
config := baseConfig
120+
config.CAFile = "non-existent-file.pem"
121+
122+
_, err := NewOIDCAuthenticator(context.Background(), &config)
123+
if err == nil {
124+
t.Errorf("expected error when using an invalid CAFile, got nil")
125+
}
126+
})
127+
}

0 commit comments

Comments
 (0)