@@ -1482,28 +1482,28 @@ func TestAuthOnlyEndpointSetBasicAuthFalseRequestHeaders(t *testing.T) {
14821482}
14831483
14841484func TestAuthSkippedForPreflightRequests(t *testing.T) {
1485− upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1485+ upstreamServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
14861486 w.WriteHeader(200)
14871487 _, err := w.Write([]byte("response"))
14881488 if err != nil {
14891489 t.Fatal(err)
14901490 }
14911491 }))
1492− t.Cleanup(upstream.Close)
1492+ t.Cleanup(upstreamServer.Close)
14931493
14941494 opts := baseTestOptions()
14951495 opts.UpstreamServers = options.Upstreams{
14961496 {
1497− ID: upstream.URL,
1497+ ID: upstreamServer.URL,
14981498 Path: "/",
1499− URI: upstream.URL,
1499+ URI: upstreamServer.URL,
15001500 },
15011501 }
15021502 opts.SkipAuthPreflight = true
15031503 err := validation.Validate(opts)
15041504 assert.NoError(t, err)
15051505
1506− upstreamURL, _ := url.Parse(upstream.URL)
1506+ upstreamURL, _ := url.Parse(upstreamServer.URL)
15071507 opts.SetProvider(NewTestProvider(upstreamURL, ""))
15081508
15091509 proxy, err := NewOAuthProxy(opts, func(string) bool { return false })
@@ -1561,17 +1561,17 @@ func NewSignatureTest() (*SignatureTest, error) {
15611561 opts.EmailDomains = []string{"acm.org"}
15621562
15631563 authenticator := &SignatureAuthenticator{}
1564− upstream := httptest.NewServer(
1564+ upstreamServer := httptest.NewServer(
15651565 http.HandlerFunc(authenticator.Authenticate))
1566− upstreamURL, err := url.Parse(upstream.URL)
1566+ upstreamURL, err := url.Parse(upstreamServer.URL)
15671567 if err != nil {
15681568 return nil, err
15691569 }
15701570 opts.UpstreamServers = options.Upstreams{
15711571 {
1572− ID: upstream.URL,
1572+ ID: upstreamServer.URL,
15731573 Path: "/",
1574− URI: upstream.URL,
1574+ URI: upstreamServer.URL,
15751575 },
15761576 }
15771577
@@ -1590,7 +1590,7 @@ func NewSignatureTest() (*SignatureTest, error) {
15901590
15911591 return &SignatureTest{
15921592 opts,
1593− upstream,
1593+ upstreamServer,
15941594 upstreamURL.Host,
15951595 provider,
15961596 make(http.Header),
@@ -1974,20 +1974,20 @@ func Test_prepareNoCache(t *testing.T) {
19741974}
19751975
19761976func Test_noCacheHeaders(t *testing.T) {
1977− upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1977+ upstreamServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
19781978 _, err := w.Write([]byte("upstream"))
19791979 if err != nil {
19801980 t.Error(err)
19811981 }
19821982 }))
1983− t.Cleanup(upstream.Close)
1983+ t.Cleanup(upstreamServer.Close)
19841984
19851985 opts := baseTestOptions()
19861986 opts.UpstreamServers = options.Upstreams{
19871987 {
1988− ID: upstream.URL,
1988+ ID: upstreamServer.URL,
19891989 Path: "/",
1990− URI: upstream.URL,
1990+ URI: upstreamServer.URL,
19911991 },
19921992 }
19931993 opts.SkipAuthRegex = []string{".*"}
@@ -2224,7 +2224,8 @@ func TestTrustedIPs(t *testing.T) {
22242224 opts.TrustedIPs = tt.trustedIPs
22252225 opts.ReverseProxy = tt.reverseProxy
22262226 opts.RealClientIPHeader = tt.realClientIPHeader
2227− validation.Validate(opts)
2227+ err := validation.Validate(opts)
2228+ assert.NoError(t, err)
22282229
22292230 proxy, err := NewOAuthProxy(opts, func(string) bool { return true })
22302231 assert.NoError(t, err)
@@ -2240,6 +2241,237 @@ func TestTrustedIPs(t *testing.T) {
22402241 }
22412242}
22422243
2244+func Test_buildRoutesAllowlist(t *testing.T) {
2245+ testCases := []struct {
2246+ name string
2247+ skipAuthRegex []string
2248+ skipAuthRoutes []string
2249+ expectedMethods []string
2250+ expectedRegexes []string
2251+ shouldError bool
2252+ }{
2253+ {
2254+ name: "No skip auth configured",
2255+ skipAuthRegex: []string{},
2256+ skipAuthRoutes: []string{},
2257+ expectedMethods: []string{},
2258+ expectedRegexes: []string{},
2259+ shouldError: false,
2260+ },
2261+ {
2262+ name: "Only skipAuthRegex configured",
2263+ skipAuthRegex: []string{
2264+ "^/foo/bar",
2265+ "^/baz/[0-9]+/thing",
2266+ },
2267+ skipAuthRoutes: []string{},
2268+ expectedMethods: []string{
2269+ "",
2270+ "",
2271+ },
2272+ expectedRegexes: []string{
2273+ "^/foo/bar",
2274+ "^/baz/[0-9]+/thing",
2275+ },
2276+ shouldError: false,
2277+ },
2278+ {
2279+ name: "Only skipAuthRoutes configured",
2280+ skipAuthRegex: []string{},
2281+ skipAuthRoutes: []string{
2282+ "GET=^/foo/bar",
2283+ "POST=^/baz/[0-9]+/thing",
2284+ "^/all/methods$",
2285+ "WEIRD=^/methods/are/allowed",
2286+ "PATCH=/second/equals?are=handled&just=fine",
2287+ },
2288+ expectedMethods: []string{
2289+ "GET",
2290+ "POST",
2291+ "",
2292+ "WEIRD",
2293+ "PATCH",
2294+ },
2295+ expectedRegexes: []string{
2296+ "^/foo/bar",
2297+ "^/baz/[0-9]+/thing",
2298+ "^/all/methods$",
2299+ "^/methods/are/allowed",
2300+ "/second/equals?are=handled&just=fine",
2301+ },
2302+ shouldError: false,
2303+ },
2304+ {
2305+ name: "Both skipAuthRegexes and skipAuthRoutes configured",
2306+ skipAuthRegex: []string{
2307+ "^/foo/bar/regex",
2308+ "^/baz/[0-9]+/thing/regex",
2309+ },
2310+ skipAuthRoutes: []string{
2311+ "GET=^/foo/bar",
2312+ "POST=^/baz/[0-9]+/thing",
2313+ "^/all/methods$",
2314+ },
2315+ expectedMethods: []string{
2316+ "",
2317+ "",
2318+ "GET",
2319+ "POST",
2320+ "",
2321+ },
2322+ expectedRegexes: []string{
2323+ "^/foo/bar/regex",
2324+ "^/baz/[0-9]+/thing/regex",
2325+ "^/foo/bar",
2326+ "^/baz/[0-9]+/thing",
2327+ "^/all/methods$",
2328+ },
2329+ shouldError: false,
2330+ },
2331+ {
2332+ name: "Invalid skipAuthRegex entry",
2333+ skipAuthRegex: []string{
2334+ "^/foo/bar",
2335+ "^/baz/[0-9]+/thing",
2336+ "(bad[regex",
2337+ },
2338+ skipAuthRoutes: []string{},
2339+ expectedMethods: []string{},
2340+ expectedRegexes: []string{},
2341+ shouldError: true,
2342+ },
2343+ {
2344+ name: "Invalid skipAuthRoutes entry",
2345+ skipAuthRegex: []string{},
2346+ skipAuthRoutes: []string{
2347+ "GET=^/foo/bar",
2348+ "POST=^/baz/[0-9]+/thing",
2349+ "^/all/methods$",
2350+ "PUT=(bad[regex",
2351+ },
2352+ expectedMethods: []string{},
2353+ expectedRegexes: []string{},
2354+ shouldError: true,
2355+ },
2356+ }
2357+
2358+ for _, tc := range testCases {
2359+ t.Run(tc.name, func(t *testing.T) {
2360+ opts := &options.Options{
2361+ SkipAuthRegex: tc.skipAuthRegex,
2362+ SkipAuthRoutes: tc.skipAuthRoutes,
2363+ }
2364+ routes, err := buildRoutesAllowlist(opts)
2365+ if tc.shouldError {
2366+ assert.Error(t, err)
2367+ return
2368+ } else {
2369+ assert.NoError(t, err)
2370+ }
2371+ for i, route := range routes {
2372+ assert.Greater(t, len(tc.expectedMethods), i)
2373+ assert.Equal(t, route.method, tc.expectedMethods[i])
2374+ assert.Greater(t, len(tc.expectedRegexes), i)
2375+ assert.Equal(t, route.pathRegex.String(), tc.expectedRegexes[i])
2376+ }
2377+ })
2378+ }
2379+}
2380+
2381+func TestAllowedRequest(t *testing.T) {
2382+ upstreamServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
2383+ w.WriteHeader(200)
2384+ _, err := w.Write([]byte("Allowed Request"))
2385+ if err != nil {
2386+ t.Fatal(err)
2387+ }
2388+ }))
2389+ t.Cleanup(upstreamServer.Close)
2390+
2391+ opts := baseTestOptions()
2392+ opts.UpstreamServers = options.Upstreams{
2393+ {
2394+ ID: upstreamServer.URL,
2395+ Path: "/",
2396+ URI: upstreamServer.URL,
2397+ },
2398+ }
2399+ opts.SkipAuthRegex = []string{
2400+ "^/skip/auth/regex$",
2401+ }
2402+ opts.SkipAuthRoutes = []string{
2403+ "GET=^/skip/auth/routes/get",
2404+ }
2405+ err := validation.Validate(opts)
2406+ assert.NoError(t, err)
2407+ proxy, err := NewOAuthProxy(opts, func(_ string) bool { return true })
2408+ if err != nil {
2409+ t.Fatal(err)
2410+ }
2411+
2412+ testCases := []struct {
2413+ name string
2414+ method string
2415+ url string
2416+ allowed bool
2417+ }{
2418+ {
2419+ name: "Regex GET allowed",
2420+ method: "GET",
2421+ url: "/skip/auth/regex",
2422+ allowed: true,
2423+ },
2424+ {
2425+ name: "Regex POST allowed ",
2426+ method: "POST",
2427+ url: "/skip/auth/regex",
2428+ allowed: true,
2429+ },
2430+ {
2431+ name: "Regex denied",
2432+ method: "GET",
2433+ url: "/wrong/denied",
2434+ allowed: false,
2435+ },
2436+ {
2437+ name: "Route allowed",
2438+ method: "GET",
2439+ url: "/skip/auth/routes/get",
2440+ allowed: true,
2441+ },
2442+ {
2443+ name: "Route denied with wrong method",
2444+ method: "PATCH",
2445+ url: "/skip/auth/routes/get",
2446+ allowed: false,
2447+ },
2448+ {
2449+ name: "Route denied with wrong path",
2450+ method: "GET",
2451+ url: "/skip/auth/routes/wrong/path",
2452+ allowed: false,
2453+ },
2454+ }
2455+
2456+ for _, tc := range testCases {
2457+ t.Run(tc.name, func(t *testing.T) {
2458+ req, err := http.NewRequest(tc.method, tc.url, nil)
2459+ assert.NoError(t, err)
2460+ assert.Equal(t, tc.allowed, proxy.isAllowedRoute(req))
2461+
2462+ rw := httptest.NewRecorder()
2463+ proxy.ServeHTTP(rw, req)
2464+
2465+ if tc.allowed {
2466+ assert.Equal(t, 200, rw.Code)
2467+ assert.Equal(t, "Allowed Request", rw.Body.String())
2468+ } else {
2469+ assert.Equal(t, 403, rw.Code)
2470+ }
2471+ })
2472+ }
2473+}
2474+
22432475func TestProxyAllowedGroups(t *testing.T) {
22442476 tests := []struct {
22452477 name string
@@ -2265,18 +2497,18 @@ func TestProxyAllowedGroups(t *testing.T) {
22652497 CreatedAt: &created,
22662498 }
22672499
2268− upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
2500+ upstreamServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
22692501 w.WriteHeader(200)
22702502 }))
2271− t.Cleanup(upstream.Close)
2503+ t.Cleanup(upstreamServer.Close)
22722504
22732505 test, err := NewProcessCookieTestWithOptionsModifiers(func(opts *options.Options) {
22742506 opts.AllowedGroups = tt.allowedGroups
22752507 opts.UpstreamServers = options.Upstreams{
22762508 {
2277− ID: upstream.URL,
2509+ ID: upstreamServer.URL,
22782510 Path: "/",
2279− URI: upstream.URL,
2511+ URI: upstreamServer.URL,
22802512 },
22812513 }
22822514 })
@@ -2287,7 +2519,8 @@ func TestProxyAllowedGroups(t *testing.T) {
22872519 test.req, _ = http.NewRequest("GET", "/", nil)
22882520
22892521 test.req.Header.Add("accept", applicationJSON)
2290− test.SaveSession(session)
2522+ err = test.SaveSession(session)
2523+ assert.NoError(t, err)
22912524 test.proxy.ServeHTTP(test.rw, test.req)
22922525
22932526 if tt.expectUnauthorized {