commit fcf711ed13efa16228385b58306df1252be6f4b9 Author: MohamadTahir Date: Mon Oct 30 10:17:22 2023 +0300 init diff --git a/.traefik.yml b/.traefik.yml new file mode 100644 index 0000000..0839fde --- /dev/null +++ b/.traefik.yml @@ -0,0 +1,16 @@ +displayName: UsersBlocker + +type: middleware + +import: github.com/ditkrg/traefik-users-blocker-plugin + +summary: A middleware that checks if users is allowed to access a path. + +testData: + userIds: + - userId1 + - userId2 + paths: + - prefix: /v1/users + value: testValue + - prefix: /v1/organizations diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..5642d26 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module traefik-users-blocker-plugin + +go 1.21.3 diff --git a/main.go b/main.go new file mode 100644 index 0000000..58ac157 --- /dev/null +++ b/main.go @@ -0,0 +1,78 @@ +// Package example a example plugin. +package UsersBlocker + +import ( + "context" + "fmt" + "net/http" + "slices" + "strings" +) + +type Path struct { + Prefix string `json:"prefix,omitempty"` + MustContain string `json:"mustContain,omitempty"` +} + +type Config struct { + UserIds []string `json:"userIds,omitempty"` + Paths []Path `json:"paths,omitempty"` +} + +func CreateConfig() *Config { + return &Config{ + UserIds: make([]string, 0), + Paths: make([]Path, 0), + } +} + +type UsersBlocker struct { + next http.Handler + userId []string + paths []Path + name string +} + +func New(ctx context.Context, next http.Handler, config *Config, name string) (http.Handler, error) { + if len(config.UserIds) == 0 { + return nil, fmt.Errorf("UserIds cannot be empty") + } + + for _, path := range config.Paths { + if path.Prefix == "" { + return nil, fmt.Errorf("Paths.Prefix cannot be empty") + } + } + + return &UsersBlocker{ + next: next, + name: name, + userId: config.UserIds, + paths: config.Paths, + }, nil +} + +func (a *UsersBlocker) ServeHTTP(rw http.ResponseWriter, req *http.Request) { + userId := req.Header["X-Auth-User-Id"][0] + isUserBlocked := slices.Contains(a.userId, userId) + + if !isUserBlocked { + a.next.ServeHTTP(rw, req) + return + } + + for _, path := range a.paths { + isPathBlocked := strings.HasPrefix(req.URL.Path, path.Prefix) + + if isPathBlocked && path.MustContain != "" { + isPathBlocked = !strings.Contains(req.URL.Path, path.MustContain) + } + + if isPathBlocked { + http.Error(rw, "Forbidden", http.StatusForbidden) + return + } + } + + a.next.ServeHTTP(rw, req) +}