Feat/OIDC middleware (#50)

* implement OIDC middleware

* auth code cleanup

* allow override allowed_user in middleware, fix typos

* fix tests and callbackURL

* update next release docs

* fix OIDC middleware not working with Authentik

* feat: add groups support for OIDC claims (#41)

Allow users to specify allowed groups in the env and use it to inspect the claims.

This performs a logical AND of users and groups (additive).

* merge feat/oidc-middleware (#49)

* api: enrich provider statistifcs

* fix: docker monitor now uses container status

* Feat/auto schemas (#48)

* use auto generated schemas

* go version bump and dependencies upgrade

* clarify some error messages

---------

Co-authored-by: yusing <yusing@6uo.me>

* cleanup some loadbalancer code

* api: cleanup websocket code

* api: add /v1/health/ws for health bubbles on dashboard

* feat: experimental memory logger and logs api for WebUI

---------

Co-authored-by: yusing <yusing@6uo.me>

---------

Co-authored-by: yusing <yusing@6uo.me>
Co-authored-by: Peter Olds <peter@olds.co>
This commit is contained in:
Yuzerion
2025-01-19 13:48:52 +08:00
committed by GitHub
parent 0fad7b3411
commit fb0dc7dea0
26 changed files with 1168 additions and 368 deletions

20
internal/utils/slices.go Normal file
View File

@@ -0,0 +1,20 @@
package utils
// Intersect returns a new slice containing the elements that are present in both input slices.
// This provides a more efficient solution than using two nested loops.
func Intersect[T comparable, Slice ~[]T](slice1 Slice, slice2 Slice) Slice {
var result Slice
seen := map[T]struct{}{}
for i := range slice1 {
seen[slice1[i]] = struct{}{}
}
for i := range slice2 {
if _, ok := seen[slice2[i]]; ok {
result = append(result, slice2[i])
}
}
return result
}

View File

@@ -0,0 +1,96 @@
package utils
import (
"slices"
"strings"
"testing"
utils "github.com/yusing/go-proxy/internal/utils/testing"
)
func TestIntersect(t *testing.T) {
t.Run("strings", func(t *testing.T) {
t.Run("no intersection", func(t *testing.T) {
var (
slice1 = []string{"a", "b", "c"}
slice2 = []string{"d", "e", "f"}
want []string
)
result := Intersect(slice1, slice2)
slices.Sort(result)
slices.Sort(want)
utils.ExpectDeepEqual(t, result, want)
})
t.Run("intersection", func(t *testing.T) {
var (
slice1 = []string{"a", "b", "c"}
slice2 = []string{"b", "c", "d"}
want = []string{"b", "c"}
)
result := Intersect(slice1, slice2)
slices.Sort(result)
slices.Sort(want)
utils.ExpectDeepEqual(t, result, want)
})
})
t.Run("ints", func(t *testing.T) {
t.Run("no intersection", func(t *testing.T) {
var (
slice1 = []int{1, 2, 3}
slice2 = []int{4, 5, 6}
want []int
)
result := Intersect(slice1, slice2)
slices.Sort(result)
slices.Sort(want)
utils.ExpectDeepEqual(t, result, want)
})
t.Run("intersection", func(t *testing.T) {
var (
slice1 = []int{1, 2, 3}
slice2 = []int{2, 3, 4}
want = []int{2, 3}
)
result := Intersect(slice1, slice2)
slices.Sort(result)
slices.Sort(want)
utils.ExpectDeepEqual(t, result, want)
})
})
t.Run("complex", func(t *testing.T) {
type T struct {
A string
B int
}
t.Run("no intersection", func(t *testing.T) {
var (
slice1 = []T{{"a", 1}, {"b", 2}, {"c", 3}}
slice2 = []T{{"d", 4}, {"e", 5}, {"f", 6}}
want []T
)
result := Intersect(slice1, slice2)
slices.SortFunc(result, func(i T, j T) int {
return strings.Compare(i.A, j.A)
})
slices.SortFunc(want, func(i T, j T) int {
return strings.Compare(i.A, j.A)
})
utils.ExpectDeepEqual(t, result, want)
})
t.Run("intersection", func(t *testing.T) {
var (
slice1 = []T{{"a", 1}, {"b", 2}, {"c", 3}}
slice2 = []T{{"b", 2}, {"c", 3}, {"d", 4}}
want = []T{{"b", 2}, {"c", 3}}
)
result := Intersect(slice1, slice2)
slices.SortFunc(result, func(i T, j T) int {
return strings.Compare(i.A, j.A)
})
slices.SortFunc(want, func(i T, j T) int {
return strings.Compare(i.A, j.A)
})
utils.ExpectDeepEqual(t, result, want)
})
})
}

View File

@@ -10,6 +10,9 @@ import (
// CommaSeperatedList returns a list of strings split by commas,
// then trim spaces from each element.
func CommaSeperatedList(s string) []string {
if s == "" {
return []string{}
}
res := SplitComma(s)
for i, part := range res {
res[i] = strings.TrimSpace(part)