diff --git a/iface/module_linux.go b/iface/module_linux.go index 61cbdb967..46f46095e 100644 --- a/iface/module_linux.go +++ b/iface/module_linux.go @@ -214,8 +214,9 @@ func isBuiltinModule(name string) (bool, error) { } // /proc/modules -// name | memory size | reference count | references | state: -// macvlan 28672 1 macvtap, Live 0x0000000000000000 +// +// name | memory size | reference count | references | state: +// macvlan 28672 1 macvtap, Live 0x0000000000000000 func moduleStatus(name string) (status, error) { state := unknown f, err := os.Open("/proc/modules") diff --git a/management/server/http/handler.go b/management/server/http/handler.go index 1f85dd995..f0d0c5b4a 100644 --- a/management/server/http/handler.go +++ b/management/server/http/handler.go @@ -23,7 +23,7 @@ func APIHandler(accountManager s.AccountManager, authIssuer string, authAudience corsMiddleware := cors.AllowAll() - acMiddleware := middleware.NewAccessControll( + acMiddleware := middleware.NewAccessControl( authAudience, accountManager.IsUserAdmin) diff --git a/management/server/http/middleware/access_control.go b/management/server/http/middleware/access_control.go index 51b36fc5e..3592363a7 100644 --- a/management/server/http/middleware/access_control.go +++ b/management/server/http/middleware/access_control.go @@ -1,32 +1,38 @@ package middleware import ( + "context" "fmt" "net/http" "github.com/netbirdio/netbird/management/server/jwtclaims" ) +const ( + IsUserAdminProperty = "isAdminUser" +) + type IsUserAdminFunc func(claims jwtclaims.AuthorizationClaims) (bool, error) -// AccessControll middleware to restrict to make POST/PUT/DELETE requests by admin only -type AccessControll struct { +// AccessControl middleware to restrict to make POST/PUT/DELETE requests by admin only +type AccessControl struct { jwtExtractor jwtclaims.ClaimsExtractor isUserAdmin IsUserAdminFunc audience string } -// NewAccessControll instance constructor -func NewAccessControll(audience string, isUserAdmin IsUserAdminFunc) *AccessControll { - return &AccessControll{ +// NewAccessControl instance constructor +func NewAccessControl(audience string, isUserAdmin IsUserAdminFunc) *AccessControl { + return &AccessControl{ isUserAdmin: isUserAdmin, audience: audience, jwtExtractor: *jwtclaims.NewClaimsExtractor(nil), } } -// Handler method of the middleware which forbinneds all modify requests for non admin users -func (a *AccessControll) Handler(h http.Handler) http.Handler { +// Handler method of the middleware which forbids all modify requests for non admin users +// It also adds +func (a *AccessControl) Handler(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { jwtClaims := a.jwtExtractor.ExtractClaimsFromRequestContext(r, a.audience) @@ -34,7 +40,6 @@ func (a *AccessControll) Handler(h http.Handler) http.Handler { if err != nil { http.Error(w, fmt.Sprintf("error get user from JWT: %v", err), http.StatusUnauthorized) return - } if !ok { @@ -45,6 +50,10 @@ func (a *AccessControll) Handler(h http.Handler) http.Handler { } } + newRequest := r.Clone(context.WithValue(r.Context(), IsUserAdminProperty, ok)) //nolint + // Update the current request with the new context information. + *r = *newRequest + h.ServeHTTP(w, r) }) } diff --git a/management/server/http/setupkeys.go b/management/server/http/setupkeys.go index 632b7afdb..d7b1ce8b7 100644 --- a/management/server/http/setupkeys.go +++ b/management/server/http/setupkeys.go @@ -6,12 +6,15 @@ import ( "github.com/gorilla/mux" "github.com/netbirdio/netbird/management/server" "github.com/netbirdio/netbird/management/server/http/api" + "github.com/netbirdio/netbird/management/server/http/middleware" "github.com/netbirdio/netbird/management/server/jwtclaims" log "github.com/sirupsen/logrus" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "net/http" + "strings" "time" + "unicode/utf8" ) // SetupKeys is a handler that returns a list of setup keys of the account @@ -107,6 +110,11 @@ func (h *SetupKeys) GetSetupKeyHandler(w http.ResponseWriter, r *http.Request) { return } + isUserAdmin, ok := r.Context().Value(middleware.IsUserAdminProperty).(bool) + if !ok || !isUserAdmin { + key = hideKey(key) + } + writeSuccess(w, key) } @@ -175,6 +183,11 @@ func (h *SetupKeys) GetAllSetupKeysHandler(w http.ResponseWriter, r *http.Reques return } + isUserAdmin, ok := r.Context().Value(middleware.IsUserAdminProperty).(bool) + if !ok { + isUserAdmin = false + } + setupKeys, err := h.accountManager.ListSetupKeys(account.Id) if err != nil { log.Error(err) @@ -183,12 +196,23 @@ func (h *SetupKeys) GetAllSetupKeysHandler(w http.ResponseWriter, r *http.Reques } apiSetupKeys := make([]*api.SetupKey, 0) for _, key := range setupKeys { - apiSetupKeys = append(apiSetupKeys, toResponseBody(key)) + k := key.Copy() + if !isUserAdmin { + k = hideKey(key) + } + apiSetupKeys = append(apiSetupKeys, toResponseBody(k)) } writeJSONObject(w, apiSetupKeys) } +func hideKey(key *server.SetupKey) *server.SetupKey { + k := key.Copy() + prefix := k.Key[0:5] + k.Key = prefix + strings.Repeat("*", utf8.RuneCountInString(key.Key)-len(prefix)) + return k +} + func writeSuccess(w http.ResponseWriter, key *server.SetupKey) { w.WriteHeader(200) w.Header().Set("Content-Type", "application/json") diff --git a/management/server/http/setupkeys_test.go b/management/server/http/setupkeys_test.go index 239e196df..6819ae03d 100644 --- a/management/server/http/setupkeys_test.go +++ b/management/server/http/setupkeys_test.go @@ -2,6 +2,7 @@ package http import ( "bytes" + "context" "encoding/json" "fmt" "github.com/gorilla/mux" @@ -159,6 +160,7 @@ func TestSetupKeysHandlers(t *testing.T) { t.Run(tc.name, func(t *testing.T) { recorder := httptest.NewRecorder() req := httptest.NewRequest(tc.requestType, tc.requestPath, tc.requestBody) + req = req.Clone(context.WithValue(context.TODO(), "isAdminUser", true)) //nolint router := mux.NewRouter() router.HandleFunc("/api/setup-keys", handler.GetAllSetupKeysHandler).Methods("GET", "OPTIONS")