@@ -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,255 @@ func TestTrustedIPs(t *testing.T) {
22402241 }
22412242}
22422243
2244+func Test_buildRoutesAllowlist(t *testing.T) {
2245+ type expectedAllowedRoute struct {
2246+ method string
2247+ regexString string
2248+ }
2249+
2250+ testCases := []struct {
2251+ name string
2252+ skipAuthRegex []string
2253+ skipAuthRoutes []string
2254+ expectedRoutes []expectedAllowedRoute
2255+ shouldError bool
2256+ }{
2257+ {
2258+ name: "No skip auth configured",
2259+ skipAuthRegex: []string{},
2260+ skipAuthRoutes: []string{},
2261+ expectedRoutes: []expectedAllowedRoute{},
2262+ shouldError: false,
2263+ },
2264+ {
2265+ name: "Only skipAuthRegex configured",
2266+ skipAuthRegex: []string{
2267+ "^/foo/bar",
2268+ "^/baz/[0-9]+/thing",
2269+ },
2270+ skipAuthRoutes: []string{},
2271+ expectedRoutes: []expectedAllowedRoute{
2272+ {
2273+ method: "",
2274+ regexString: "^/foo/bar",
2275+ },
2276+ {
2277+ method: "",
2278+ regexString: "^/baz/[0-9]+/thing",
2279+ },
2280+ },
2281+ shouldError: false,
2282+ },
2283+ {
2284+ name: "Only skipAuthRoutes configured",
2285+ skipAuthRegex: []string{},
2286+ skipAuthRoutes: []string{
2287+ "GET=^/foo/bar",
2288+ "POST=^/baz/[0-9]+/thing",
2289+ "^/all/methods$",
2290+ "WEIRD=^/methods/are/allowed",
2291+ "PATCH=/second/equals?are=handled&just=fine",
2292+ },
2293+ expectedRoutes: []expectedAllowedRoute{
2294+ {
2295+ method: "GET",
2296+ regexString: "^/foo/bar",
2297+ },
2298+ {
2299+ method: "POST",
2300+ regexString: "^/baz/[0-9]+/thing",
2301+ },
2302+ {
2303+ method: "",
2304+ regexString: "^/all/methods$",
2305+ },
2306+ {
2307+ method: "WEIRD",
2308+ regexString: "^/methods/are/allowed",
2309+ },
2310+ {
2311+ method: "PATCH",
2312+ regexString: "/second/equals?are=handled&just=fine",
2313+ },
2314+ },
2315+ shouldError: false,
2316+ },
2317+ {
2318+ name: "Both skipAuthRegexes and skipAuthRoutes configured",
2319+ skipAuthRegex: []string{
2320+ "^/foo/bar/regex",
2321+ "^/baz/[0-9]+/thing/regex",
2322+ },
2323+ skipAuthRoutes: []string{
2324+ "GET=^/foo/bar",
2325+ "POST=^/baz/[0-9]+/thing",
2326+ "^/all/methods$",
2327+ },
2328+ expectedRoutes: []expectedAllowedRoute{
2329+ {
2330+ method: "",
2331+ regexString: "^/foo/bar/regex",
2332+ },
2333+ {
2334+ method: "",
2335+ regexString: "^/baz/[0-9]+/thing/regex",
2336+ },
2337+ {
2338+ method: "GET",
2339+ regexString: "^/foo/bar",
2340+ },
2341+ {
2342+ method: "POST",
2343+ regexString: "^/baz/[0-9]+/thing",
2344+ },
2345+ {
2346+ method: "",
2347+ regexString: "^/all/methods$",
2348+ },
2349+ },
2350+ shouldError: false,
2351+ },
2352+ {
2353+ name: "Invalid skipAuthRegex entry",
2354+ skipAuthRegex: []string{
2355+ "^/foo/bar",
2356+ "^/baz/[0-9]+/thing",
2357+ "(bad[regex",
2358+ },
2359+ skipAuthRoutes: []string{},
2360+ expectedRoutes: []expectedAllowedRoute{},
2361+ shouldError: true,
2362+ },
2363+ {
2364+ name: "Invalid skipAuthRoutes entry",
2365+ skipAuthRegex: []string{},
2366+ skipAuthRoutes: []string{
2367+ "GET=^/foo/bar",
2368+ "POST=^/baz/[0-9]+/thing",
2369+ "^/all/methods$",
2370+ "PUT=(bad[regex",
2371+ },
2372+ expectedRoutes: []expectedAllowedRoute{},
2373+ shouldError: true,
2374+ },
2375+ }
2376+
2377+ for _, tc := range testCases {
2378+ t.Run(tc.name, func(t *testing.T) {
2379+ opts := &options.Options{
2380+ SkipAuthRegex: tc.skipAuthRegex,
2381+ SkipAuthRoutes: tc.skipAuthRoutes,
2382+ }
2383+ routes, err := buildRoutesAllowlist(opts)
2384+ if tc.shouldError {
2385+ assert.Error(t, err)
2386+ return
2387+ }
2388+ assert.NoError(t, err)
2389+
2390+ for i, route := range routes {
2391+ assert.Greater(t, len(tc.expectedRoutes), i)
2392+ assert.Equal(t, route.method, tc.expectedRoutes[i].method)
2393+ assert.Equal(t, route.pathRegex.String(), tc.expectedRoutes[i].regexString)
2394+ }
2395+ })
2396+ }
2397+}
2398+
2399+func TestAllowedRequest(t *testing.T) {
2400+ upstreamServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
2401+ w.WriteHeader(200)
2402+ _, err := w.Write([]byte("Allowed Request"))
2403+ if err != nil {
2404+ t.Fatal(err)
2405+ }
2406+ }))
2407+ t.Cleanup(upstreamServer.Close)
2408+
2409+ opts := baseTestOptions()
2410+ opts.UpstreamServers = options.Upstreams{
2411+ {
2412+ ID: upstreamServer.URL,
2413+ Path: "/",
2414+ URI: upstreamServer.URL,
2415+ },
2416+ }
2417+ opts.SkipAuthRegex = []string{
2418+ "^/skip/auth/regex$",
2419+ }
2420+ opts.SkipAuthRoutes = []string{
2421+ "GET=^/skip/auth/routes/get",
2422+ }
2423+ err := validation.Validate(opts)
2424+ assert.NoError(t, err)
2425+ proxy, err := NewOAuthProxy(opts, func(_ string) bool { return true })
2426+ if err != nil {
2427+ t.Fatal(err)
2428+ }
2429+
2430+ testCases := []struct {
2431+ name string
2432+ method string
2433+ url string
2434+ allowed bool
2435+ }{
2436+ {
2437+ name: "Regex GET allowed",
2438+ method: "GET",
2439+ url: "/skip/auth/regex",
2440+ allowed: true,
2441+ },
2442+ {
2443+ name: "Regex POST allowed ",
2444+ method: "POST",
2445+ url: "/skip/auth/regex",
2446+ allowed: true,
2447+ },
2448+ {
2449+ name: "Regex denied",
2450+ method: "GET",
2451+ url: "/wrong/denied",
2452+ allowed: false,
2453+ },
2454+ {
2455+ name: "Route allowed",
2456+ method: "GET",
2457+ url: "/skip/auth/routes/get",
2458+ allowed: true,
2459+ },
2460+ {
2461+ name: "Route denied with wrong method",
2462+ method: "PATCH",
2463+ url: "/skip/auth/routes/get",
2464+ allowed: false,
2465+ },
2466+ {
2467+ name: "Route denied with wrong path",
2468+ method: "GET",
2469+ url: "/skip/auth/routes/wrong/path",
2470+ allowed: false,
2471+ },
2472+ }
2473+
2474+ for _, tc := range testCases {
2475+ t.Run(tc.name, func(t *testing.T) {
2476+ req, err := http.NewRequest(tc.method, tc.url, nil)
2477+ assert.NoError(t, err)
2478+ assert.Equal(t, tc.allowed, proxy.isAllowedRoute(req))
2479+
2480+ rw := httptest.NewRecorder()
2481+ proxy.ServeHTTP(rw, req)
2482+
2483+ if tc.allowed {
2484+ assert.Equal(t, 200, rw.Code)
2485+ assert.Equal(t, "Allowed Request", rw.Body.String())
2486+ } else {
2487+ assert.Equal(t, 403, rw.Code)
2488+ }
2489+ })
2490+ }
2491+}
2492+
22432493func TestProxyAllowedGroups(t *testing.T) {
22442494 tests := []struct {
22452495 name string
@@ -2265,18 +2515,18 @@ func TestProxyAllowedGroups(t *testing.T) {
22652515 CreatedAt: &created,
22662516 }
22672517
2268− upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
2518+ upstreamServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
22692519 w.WriteHeader(200)
22702520 }))
2271− t.Cleanup(upstream.Close)
2521+ t.Cleanup(upstreamServer.Close)
22722522
22732523 test, err := NewProcessCookieTestWithOptionsModifiers(func(opts *options.Options) {
22742524 opts.AllowedGroups = tt.allowedGroups
22752525 opts.UpstreamServers = options.Upstreams{
22762526 {
2277− ID: upstream.URL,
2527+ ID: upstreamServer.URL,
22782528 Path: "/",
2279− URI: upstream.URL,
2529+ URI: upstreamServer.URL,
22802530 },
22812531 }
22822532 })
@@ -2287,7 +2537,8 @@ func TestProxyAllowedGroups(t *testing.T) {
22872537 test.req, _ = http.NewRequest("GET", "/", nil)
22882538
22892539 test.req.Header.Add("accept", applicationJSON)
2290− test.SaveSession(session)
2540+ err = test.SaveSession(session)
2541+ assert.NoError(t, err)
22912542 test.proxy.ServeHTTP(test.rw, test.req)
22922543
22932544 if tt.expectUnauthorized {