@@ -0,0 +1,250 @@
1+package validation
2+
3+import (
4+ "testing"
5+ "time"
6+
7+ "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
8+ . "github.com/onsi/gomega"
9+)
10+
11+func TestValidateCookie(t *testing.T) {
12+ validName := "_oauth2_proxy"
13+ invalidName := "_oauth2;proxy" // Separater character not allowed
14+ validSecret := "secretthirtytwobytes+abcdefghijk"
15+ invalidSecret := "abcdef" // 6 bytes is not a valid size
16+ validBase64Secret := "c2VjcmV0dGhpcnR5dHdvYnl0ZXMrYWJjZGVmZ2hpams" // Base64 encoding of "secretthirtytwobytes+abcdefghijk"
17+ invalidBase64Secret := "YWJjZGVmCg" // Base64 encoding of "abcdef"
18+ emptyDomains := []string{}
19+ domains := []string{
20+ "a.localhost",
21+ "ba.localhost",
22+ "ca.localhost",
23+ "cba.localhost",
24+ "a.cba.localhost",
25+ }
26+
27+ invalidNameMsg := "invalid cookie name: \"_oauth2;proxy\""
28+ missingSecretMsg := "missing setting: cookie-secret"
29+ invalidSecretMsg := "cookie_secret must be 16, 24, or 32 bytes to create an AES cipher, but is 6 bytes"
30+ invalidBase64SecretMsg := "cookie_secret must be 16, 24, or 32 bytes to create an AES cipher, but is 10 bytes"
31+ refreshLongerThanExpireMsg := "cookie_refresh (\"1h0m0s\") must be less than cookie_expire (\"15m0s\")"
32+ invalidSameSiteMsg := "cookie_samesite (\"invalid\") must be one of ['', 'lax', 'strict', 'none']"
33+
34+ testCases := []struct {
35+ name string
36+ cookie options.CookieOptions
37+ errStrings []string
38+ }{
39+ {
40+ name: "with valid configuration",
41+ cookie: options.CookieOptions{
42+ Name: validName,
43+ Secret: validSecret,
44+ Domains: domains,
45+ Path: "",
46+ Expire: time.Hour,
47+ Refresh: 15 * time.Minute,
48+ Secure: true,
49+ HTTPOnly: false,
50+ SameSite: "",
51+ },
52+ errStrings: []string{},
53+ },
54+ {
55+ name: "with no cookie secret",
56+ cookie: options.CookieOptions{
57+ Name: validName,
58+ Secret: "",
59+ Domains: emptyDomains,
60+ Path: "",
61+ Expire: time.Hour,
62+ Refresh: 15 * time.Minute,
63+ Secure: true,
64+ HTTPOnly: false,
65+ SameSite: "",
66+ },
67+ errStrings: []string{
68+ missingSecretMsg,
69+ },
70+ },
71+ {
72+ name: "with an invalid cookie secret",
73+ cookie: options.CookieOptions{
74+ Name: validName,
75+ Secret: invalidSecret,
76+ Domains: emptyDomains,
77+ Path: "",
78+ Expire: time.Hour,
79+ Refresh: 15 * time.Minute,
80+ Secure: true,
81+ HTTPOnly: false,
82+ SameSite: "",
83+ },
84+ errStrings: []string{
85+ invalidSecretMsg,
86+ },
87+ },
88+ {
89+ name: "with a valid Base64 secret",
90+ cookie: options.CookieOptions{
91+ Name: validName,
92+ Secret: validBase64Secret,
93+ Domains: emptyDomains,
94+ Path: "",
95+ Expire: time.Hour,
96+ Refresh: 15 * time.Minute,
97+ Secure: true,
98+ HTTPOnly: false,
99+ SameSite: "",
100+ },
101+ errStrings: []string{},
102+ },
103+ {
104+ name: "with an invalid Base64 secret",
105+ cookie: options.CookieOptions{
106+ Name: validName,
107+ Secret: invalidBase64Secret,
108+ Domains: emptyDomains,
109+ Path: "",
110+ Expire: time.Hour,
111+ Refresh: 15 * time.Minute,
112+ Secure: true,
113+ HTTPOnly: false,
114+ SameSite: "",
115+ },
116+ errStrings: []string{
117+ invalidBase64SecretMsg,
118+ },
119+ },
120+ {
121+ name: "with an invalid name",
122+ cookie: options.CookieOptions{
123+ Name: invalidName,
124+ Secret: validSecret,
125+ Domains: emptyDomains,
126+ Path: "",
127+ Expire: time.Hour,
128+ Refresh: 15 * time.Minute,
129+ Secure: true,
130+ HTTPOnly: false,
131+ SameSite: "",
132+ },
133+ errStrings: []string{
134+ invalidNameMsg,
135+ },
136+ },
137+ {
138+ name: "with refresh longer than expire",
139+ cookie: options.CookieOptions{
140+ Name: validName,
141+ Secret: validSecret,
142+ Domains: emptyDomains,
143+ Path: "",
144+ Expire: 15 * time.Minute,
145+ Refresh: time.Hour,
146+ Secure: true,
147+ HTTPOnly: false,
148+ SameSite: "",
149+ },
150+ errStrings: []string{
151+ refreshLongerThanExpireMsg,
152+ },
153+ },
154+ {
155+ name: "with samesite \"none\"",
156+ cookie: options.CookieOptions{
157+ Name: validName,
158+ Secret: validSecret,
159+ Domains: emptyDomains,
160+ Path: "",
161+ Expire: time.Hour,
162+ Refresh: 15 * time.Minute,
163+ Secure: true,
164+ HTTPOnly: false,
165+ SameSite: "none",
166+ },
167+ errStrings: []string{},
168+ },
169+ {
170+ name: "with samesite \"lax\"",
171+ cookie: options.CookieOptions{
172+ Name: validName,
173+ Secret: validSecret,
174+ Domains: emptyDomains,
175+ Path: "",
176+ Expire: time.Hour,
177+ Refresh: 15 * time.Minute,
178+ Secure: true,
179+ HTTPOnly: false,
180+ SameSite: "none",
181+ },
182+ errStrings: []string{},
183+ },
184+ {
185+ name: "with samesite \"strict\"",
186+ cookie: options.CookieOptions{
187+ Name: validName,
188+ Secret: validSecret,
189+ Domains: emptyDomains,
190+ Path: "",
191+ Expire: time.Hour,
192+ Refresh: 15 * time.Minute,
193+ Secure: true,
194+ HTTPOnly: false,
195+ SameSite: "none",
196+ },
197+ errStrings: []string{},
198+ },
199+ {
200+ name: "with samesite \"invalid\"",
201+ cookie: options.CookieOptions{
202+ Name: validName,
203+ Secret: validSecret,
204+ Domains: emptyDomains,
205+ Path: "",
206+ Expire: time.Hour,
207+ Refresh: 15 * time.Minute,
208+ Secure: true,
209+ HTTPOnly: false,
210+ SameSite: "invalid",
211+ },
212+ errStrings: []string{
213+ invalidSameSiteMsg,
214+ },
215+ },
216+ {
217+ name: "with a combination of configuration errors",
218+ cookie: options.CookieOptions{
219+ Name: invalidName,
220+ Secret: invalidSecret,
221+ Domains: domains,
222+ Path: "",
223+ Expire: 15 * time.Minute,
224+ Refresh: time.Hour,
225+ Secure: true,
226+ HTTPOnly: false,
227+ SameSite: "invalid",
228+ },
229+ errStrings: []string{
230+ invalidNameMsg,
231+ invalidSecretMsg,
232+ refreshLongerThanExpireMsg,
233+ invalidSameSiteMsg,
234+ },
235+ },
236+ }
237+
238+ for _, tc := range testCases {
239+ t.Run(tc.name, func(t *testing.T) {
240+ errStrings := validateCookieOptions(tc.cookie)
241+ g := NewWithT(t)
242+
243+ g.Expect(errStrings).To(ConsistOf(tc.errStrings))
244+ // Check domains were sorted to the right lengths
245+ for i := 0; i < len(tc.cookie.Domains)-1; i++ {
246+ g.Expect(len(tc.cookie.Domains[i])).To(BeNumerically(">=", len(tc.cookie.Domains[i+1])))
247+ }
248+ })
249+ }
250+}