feat(admin): audit-log delegated admin section access

AdminSection passes for non-full admins now emit an Info-level log line
(user, method, path). Delegated admins exercise elevated permissions
without is_admin; silent access made privilege misuse invisible.

Authored By: TDvorak <info@tdvorak.dev>

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
pull/3582/head
Tomas Dvorak 2 weeks ago
parent 501c872191
commit 6c242b1f37

@ -1,13 +1,16 @@
package middleware package middleware
import ( import (
"context"
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"github.com/cloudreve/Cloudreve/v4/application/dependency"
"github.com/cloudreve/Cloudreve/v4/ent" "github.com/cloudreve/Cloudreve/v4/ent"
"github.com/cloudreve/Cloudreve/v4/inventory" "github.com/cloudreve/Cloudreve/v4/inventory"
"github.com/cloudreve/Cloudreve/v4/inventory/types" "github.com/cloudreve/Cloudreve/v4/inventory/types"
"github.com/cloudreve/Cloudreve/v4/pkg/boolset" "github.com/cloudreve/Cloudreve/v4/pkg/boolset"
"github.com/cloudreve/Cloudreve/v4/pkg/logging"
"github.com/cloudreve/Cloudreve/v4/pkg/util" "github.com/cloudreve/Cloudreve/v4/pkg/util"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@ -25,6 +28,10 @@ func newAdminRequest(t *testing.T, permissions *boolset.BooleanSet) *gin.Context
w := httptest.NewRecorder() w := httptest.NewRecorder()
c := gin.CreateTestContextOnly(w, testEngine) c := gin.CreateTestContextOnly(w, testEngine)
c.Request = httptest.NewRequest("GET", "/api/v4/admin/summary", nil) c.Request = httptest.NewRequest("GET", "/api/v4/admin/summary", nil)
dep := dependency.NewDependency(
dependency.WithLogger(logging.NewConsoleLogger(logging.LevelDebug)),
)
c.Request = c.Request.WithContext(context.WithValue(c.Request.Context(), dependency.DepCtx{}, dep))
u := &ent.User{ u := &ent.User{
ID: 2, ID: 2,
Edges: ent.UserEdges{ Edges: ent.UserEdges{

@ -362,7 +362,8 @@ func IsAdminOrDelegated() gin.HandlerFunc {
} }
// AdminSection requires the full admin permission or at least one of the // AdminSection requires the full admin permission or at least one of the
// given delegated admin section permissions. // given delegated admin section permissions. Delegated-admin passes are
// audit-logged since they exercise elevated permissions without full admin.
func AdminSection(sections ...types.GroupPermission) gin.HandlerFunc { func AdminSection(sections ...types.GroupPermission) gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
user := inventory.UserFromContext(c) user := inventory.UserFromContext(c)
@ -381,6 +382,11 @@ func AdminSection(sections ...types.GroupPermission) gin.HandlerFunc {
c.Abort() c.Abort()
return return
} }
dependency.FromContext(c).Logger().Info(
"Delegated admin %q (uid=%d) accessed %s %s",
user.Email, user.ID, c.Request.Method, c.FullPath(),
)
} }
c.Next() c.Next()

Loading…
Cancel
Save