You've already forked oauth2-proxy
mirror of
https://github.com/oauth2-proxy/oauth2-proxy.git
synced 2025-06-15 00:15:00 +02:00
Support negating for skip auth routes
This commit is contained in:
@ -2248,6 +2248,7 @@ func TestTrustedIPs(t *testing.T) {
|
||||
func Test_buildRoutesAllowlist(t *testing.T) {
|
||||
type expectedAllowedRoute struct {
|
||||
method string
|
||||
negate bool
|
||||
regexString string
|
||||
}
|
||||
|
||||
@ -2275,10 +2276,12 @@ func Test_buildRoutesAllowlist(t *testing.T) {
|
||||
expectedRoutes: []expectedAllowedRoute{
|
||||
{
|
||||
method: "",
|
||||
negate: false,
|
||||
regexString: "^/foo/bar",
|
||||
},
|
||||
{
|
||||
method: "",
|
||||
negate: false,
|
||||
regexString: "^/baz/[0-9]+/thing",
|
||||
},
|
||||
},
|
||||
@ -2293,28 +2296,45 @@ func Test_buildRoutesAllowlist(t *testing.T) {
|
||||
"^/all/methods$",
|
||||
"WEIRD=^/methods/are/allowed",
|
||||
"PATCH=/second/equals?are=handled&just=fine",
|
||||
"!=^/api",
|
||||
"METHOD!=^/api",
|
||||
},
|
||||
expectedRoutes: []expectedAllowedRoute{
|
||||
{
|
||||
method: "GET",
|
||||
negate: false,
|
||||
regexString: "^/foo/bar",
|
||||
},
|
||||
{
|
||||
method: "POST",
|
||||
negate: false,
|
||||
regexString: "^/baz/[0-9]+/thing",
|
||||
},
|
||||
{
|
||||
method: "",
|
||||
negate: false,
|
||||
regexString: "^/all/methods$",
|
||||
},
|
||||
{
|
||||
method: "WEIRD",
|
||||
negate: false,
|
||||
regexString: "^/methods/are/allowed",
|
||||
},
|
||||
{
|
||||
method: "PATCH",
|
||||
negate: false,
|
||||
regexString: "/second/equals?are=handled&just=fine",
|
||||
},
|
||||
{
|
||||
method: "",
|
||||
negate: true,
|
||||
regexString: "^/api",
|
||||
},
|
||||
{
|
||||
method: "METHOD",
|
||||
negate: true,
|
||||
regexString: "^/api",
|
||||
},
|
||||
},
|
||||
shouldError: false,
|
||||
},
|
||||
@ -2394,6 +2414,7 @@ func Test_buildRoutesAllowlist(t *testing.T) {
|
||||
for i, route := range routes {
|
||||
assert.Greater(t, len(tc.expectedRoutes), i)
|
||||
assert.Equal(t, route.method, tc.expectedRoutes[i].method)
|
||||
assert.Equal(t, route.negate, tc.expectedRoutes[i].negate)
|
||||
assert.Equal(t, route.pathRegex.String(), tc.expectedRoutes[i].regexString)
|
||||
}
|
||||
})
|
||||
@ -2475,6 +2496,212 @@ func TestAllowedRequest(t *testing.T) {
|
||||
url: "/skip/auth/routes/wrong/path",
|
||||
allowed: false,
|
||||
},
|
||||
{
|
||||
name: "Route denied with wrong path and method",
|
||||
method: "POST",
|
||||
url: "/skip/auth/routes/wrong/path",
|
||||
allowed: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
req, err := http.NewRequest(tc.method, tc.url, nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tc.allowed, proxy.isAllowedRoute(req))
|
||||
|
||||
rw := httptest.NewRecorder()
|
||||
proxy.ServeHTTP(rw, req)
|
||||
|
||||
if tc.allowed {
|
||||
assert.Equal(t, 200, rw.Code)
|
||||
assert.Equal(t, "Allowed Request", rw.Body.String())
|
||||
} else {
|
||||
assert.Equal(t, 403, rw.Code)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllowedRequestNegateWithoutMethod(t *testing.T) {
|
||||
upstreamServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(200)
|
||||
_, err := w.Write([]byte("Allowed Request"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}))
|
||||
t.Cleanup(upstreamServer.Close)
|
||||
|
||||
opts := baseTestOptions()
|
||||
opts.UpstreamServers = options.UpstreamConfig{
|
||||
Upstreams: []options.Upstream{
|
||||
{
|
||||
ID: upstreamServer.URL,
|
||||
Path: "/",
|
||||
URI: upstreamServer.URL,
|
||||
},
|
||||
},
|
||||
}
|
||||
opts.SkipAuthRoutes = []string{
|
||||
"!=^/api", // any non-api routes
|
||||
"POST=^/api/public-entity/?$",
|
||||
}
|
||||
err := validation.Validate(opts)
|
||||
assert.NoError(t, err)
|
||||
proxy, err := NewOAuthProxy(opts, func(_ string) bool { return true })
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
method string
|
||||
url string
|
||||
allowed bool
|
||||
}{
|
||||
{
|
||||
name: "Some static file allowed",
|
||||
method: "GET",
|
||||
url: "/static/file.txt",
|
||||
allowed: true,
|
||||
},
|
||||
{
|
||||
name: "POST to contact form allowed",
|
||||
method: "POST",
|
||||
url: "/contact",
|
||||
allowed: true,
|
||||
},
|
||||
{
|
||||
name: "Regex POST allowed",
|
||||
method: "POST",
|
||||
url: "/api/public-entity",
|
||||
allowed: true,
|
||||
},
|
||||
{
|
||||
name: "Regex POST with trailing slash allowed",
|
||||
method: "POST",
|
||||
url: "/api/public-entity/",
|
||||
allowed: true,
|
||||
},
|
||||
{
|
||||
name: "Regex GET api route denied",
|
||||
method: "GET",
|
||||
url: "/api/users",
|
||||
allowed: false,
|
||||
},
|
||||
{
|
||||
name: "Regex POST api route denied",
|
||||
method: "POST",
|
||||
url: "/api/users",
|
||||
allowed: false,
|
||||
},
|
||||
{
|
||||
name: "Regex DELETE api route denied",
|
||||
method: "DELETE",
|
||||
url: "/api/users/1",
|
||||
allowed: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
req, err := http.NewRequest(tc.method, tc.url, nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tc.allowed, proxy.isAllowedRoute(req))
|
||||
|
||||
rw := httptest.NewRecorder()
|
||||
proxy.ServeHTTP(rw, req)
|
||||
|
||||
if tc.allowed {
|
||||
assert.Equal(t, 200, rw.Code)
|
||||
assert.Equal(t, "Allowed Request", rw.Body.String())
|
||||
} else {
|
||||
assert.Equal(t, 403, rw.Code)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllowedRequestNegateWithMethod(t *testing.T) {
|
||||
upstreamServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(200)
|
||||
_, err := w.Write([]byte("Allowed Request"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}))
|
||||
t.Cleanup(upstreamServer.Close)
|
||||
|
||||
opts := baseTestOptions()
|
||||
opts.UpstreamServers = options.UpstreamConfig{
|
||||
Upstreams: []options.Upstream{
|
||||
{
|
||||
ID: upstreamServer.URL,
|
||||
Path: "/",
|
||||
URI: upstreamServer.URL,
|
||||
},
|
||||
},
|
||||
}
|
||||
opts.SkipAuthRoutes = []string{
|
||||
"GET!=^/api", // any non-api routes
|
||||
"POST=^/api/public-entity/?$",
|
||||
}
|
||||
err := validation.Validate(opts)
|
||||
assert.NoError(t, err)
|
||||
proxy, err := NewOAuthProxy(opts, func(_ string) bool { return true })
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
method string
|
||||
url string
|
||||
allowed bool
|
||||
}{
|
||||
{
|
||||
name: "Some static file allowed",
|
||||
method: "GET",
|
||||
url: "/static/file.txt",
|
||||
allowed: true,
|
||||
},
|
||||
{
|
||||
name: "POST to contact form not allowed",
|
||||
method: "POST",
|
||||
url: "/contact",
|
||||
allowed: false,
|
||||
},
|
||||
{
|
||||
name: "Regex POST allowed",
|
||||
method: "POST",
|
||||
url: "/api/public-entity",
|
||||
allowed: true,
|
||||
},
|
||||
{
|
||||
name: "Regex POST with trailing slash allowed",
|
||||
method: "POST",
|
||||
url: "/api/public-entity/",
|
||||
allowed: true,
|
||||
},
|
||||
{
|
||||
name: "Regex GET api route denied",
|
||||
method: "GET",
|
||||
url: "/api/users",
|
||||
allowed: false,
|
||||
},
|
||||
{
|
||||
name: "Regex POST api route denied",
|
||||
method: "POST",
|
||||
url: "/api/users",
|
||||
allowed: false,
|
||||
},
|
||||
{
|
||||
name: "Regex DELETE api route denied",
|
||||
method: "DELETE",
|
||||
url: "/api/users/1",
|
||||
allowed: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
|
Reference in New Issue
Block a user