2025-09-17 21:35:11 +05:30
package middleware
import (
"log/slog"
"net/http"
"github.com/SigNoz/signoz/pkg/authz"
"github.com/SigNoz/signoz/pkg/http/render"
"github.com/SigNoz/signoz/pkg/types/authtypes"
"github.com/gorilla/mux"
)
const (
authzDeniedMessage string = "::AUTHZ-DENIED::"
)
type AuthZ struct {
logger * slog . Logger
authzService authz . AuthZ
}
func NewAuthZ ( logger * slog . Logger ) * AuthZ {
if logger == nil {
panic ( "cannot build authz middleware, logger is empty" )
}
return & AuthZ { logger : logger }
}
func ( middleware * AuthZ ) ViewAccess ( next http . HandlerFunc ) http . HandlerFunc {
return http . HandlerFunc ( func ( rw http . ResponseWriter , req * http . Request ) {
claims , err := authtypes . ClaimsFromContext ( req . Context ( ) )
if err != nil {
render . Error ( rw , err )
return
}
if err := claims . IsViewer ( ) ; err != nil {
middleware . logger . WarnContext ( req . Context ( ) , authzDeniedMessage , "claims" , claims )
render . Error ( rw , err )
return
}
next ( rw , req )
} )
}
func ( middleware * AuthZ ) EditAccess ( next http . HandlerFunc ) http . HandlerFunc {
return http . HandlerFunc ( func ( rw http . ResponseWriter , req * http . Request ) {
claims , err := authtypes . ClaimsFromContext ( req . Context ( ) )
if err != nil {
render . Error ( rw , err )
return
}
if err := claims . IsEditor ( ) ; err != nil {
middleware . logger . WarnContext ( req . Context ( ) , authzDeniedMessage , "claims" , claims )
render . Error ( rw , err )
return
}
next ( rw , req )
} )
}
func ( middleware * AuthZ ) AdminAccess ( next http . HandlerFunc ) http . HandlerFunc {
return http . HandlerFunc ( func ( rw http . ResponseWriter , req * http . Request ) {
claims , err := authtypes . ClaimsFromContext ( req . Context ( ) )
if err != nil {
render . Error ( rw , err )
return
}
if err := claims . IsAdmin ( ) ; err != nil {
middleware . logger . WarnContext ( req . Context ( ) , authzDeniedMessage , "claims" , claims )
render . Error ( rw , err )
return
}
next ( rw , req )
} )
}
func ( middleware * AuthZ ) SelfAccess ( next http . HandlerFunc ) http . HandlerFunc {
return http . HandlerFunc ( func ( rw http . ResponseWriter , req * http . Request ) {
claims , err := authtypes . ClaimsFromContext ( req . Context ( ) )
if err != nil {
render . Error ( rw , err )
return
}
id := mux . Vars ( req ) [ "id" ]
if err := claims . IsSelfAccess ( id ) ; err != nil {
middleware . logger . WarnContext ( req . Context ( ) , authzDeniedMessage , "claims" , claims )
render . Error ( rw , err )
return
}
next ( rw , req )
} )
}
func ( middleware * AuthZ ) OpenAccess ( next http . HandlerFunc ) http . HandlerFunc {
return http . HandlerFunc ( func ( rw http . ResponseWriter , req * http . Request ) {
next ( rw , req )
} )
}
// Check middleware accepts the relation, typeable, parentTypeable (for direct access + group relations) and a callback function to derive selector and parentSelectors on per request basis.
2025-09-29 17:45:52 +05:30
func ( middleware * AuthZ ) Check ( next http . HandlerFunc , relation authtypes . Relation , translation authtypes . Relation , typeable authtypes . Typeable , cb authtypes . SelectorCallbackFn ) http . HandlerFunc {
2025-09-17 21:35:11 +05:30
return http . HandlerFunc ( func ( rw http . ResponseWriter , req * http . Request ) {
claims , err := authtypes . ClaimsFromContext ( req . Context ( ) )
if err != nil {
render . Error ( rw , err )
return
}
2025-09-29 17:45:52 +05:30
selector , err := cb ( req . Context ( ) , claims )
2025-09-17 21:35:11 +05:30
if err != nil {
render . Error ( rw , err )
return
}
2025-09-29 17:45:52 +05:30
err = middleware . authzService . CheckWithTupleCreation ( req . Context ( ) , claims , relation , typeable , selector )
2025-09-17 21:35:11 +05:30
if err != nil {
render . Error ( rw , err )
return
}
next ( rw , req )
} )
}