feature: #135 Permissions for logs (#273)

This commit is contained in:
James Read 2024-04-18 21:52:04 +01:00 committed by GitHub
parent f60ab6ce85
commit db5de9be97
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 54 additions and 24 deletions

View File

@ -17,24 +17,51 @@ type AuthenticatedUser struct {
acls []string acls []string
} }
// IsAllowedExec checks if a AuthenticatedUser is allowed to execute an Action func logAclNotMatched(cfg *config.Config, aclFunction string, user *AuthenticatedUser, action *config.Action) {
func IsAllowedExec(cfg *config.Config, user *AuthenticatedUser, action *config.Action) bool { if cfg.LogDebugOptions.AclNotMatched {
log.WithFields(log.Fields{
"User": user.Username,
"Action": action.Title,
}).Debugf("%v - No ACLs Matched", aclFunction)
}
}
func logAclMatched(cfg *config.Config, aclFunction string, user *AuthenticatedUser, action *config.Action, acl *config.AccessControlList) {
if cfg.LogDebugOptions.AclMatched {
log.WithFields(log.Fields{
"User": user.Username,
"Action": action.Title,
"ACL": acl.Name,
}).Debugf("%v - Matched ACL", aclFunction)
}
}
// IsAllowedLogs checks if a AuthenticatedUser is allowed to view an action's logs
func IsAllowedLogs(cfg *config.Config, user *AuthenticatedUser, action *config.Action) bool {
for _, acl := range getRelevantAcls(cfg, action.Acls, user) { for _, acl := range getRelevantAcls(cfg, action.Acls, user) {
if acl.Permissions.Exec { if acl.Permissions.Logs {
log.WithFields(log.Fields{ logAclMatched(cfg, "isAllowedLogs", user, action, acl)
"User": user.Username,
"Action": action.Title,
"ACL": acl.Name,
}).Trace("isAllowedExec - Matched ACL")
return true return true
} }
} }
log.WithFields(log.Fields{ logAclNotMatched(cfg, "isAllowedLogs", user, action)
"User": user.Username,
"Action": action.Title, return cfg.DefaultPermissions.Logs
}).Trace("isAllowedExec - No ACLs matched") }
// IsAllowedExec checks if a AuthenticatedUser is allowed to execute an Action
func IsAllowedExec(cfg *config.Config, user *AuthenticatedUser, action *config.Action) bool {
for _, acl := range getRelevantAcls(cfg, action.Acls, user) {
if acl.Permissions.Exec {
logAclMatched(cfg, "isAllowedExec", user, action, acl)
return true
}
}
logAclNotMatched(cfg, "isAllowedExec", user, action)
return cfg.DefaultPermissions.Exec return cfg.DefaultPermissions.Exec
} }
@ -47,20 +74,13 @@ func IsAllowedView(cfg *config.Config, user *AuthenticatedUser, action *config.A
for _, acl := range getRelevantAcls(cfg, action.Acls, user) { for _, acl := range getRelevantAcls(cfg, action.Acls, user) {
if acl.Permissions.View { if acl.Permissions.View {
log.WithFields(log.Fields{ logAclMatched(cfg, "isAllowedView", user, action, acl)
"User": user.Username,
"Action": action.Title,
"ACL": acl.Name,
}).Trace("isAllowedView - Matched ACL")
return true return true
} }
} }
log.WithFields(log.Fields{ logAclNotMatched(cfg, "isAllowedView", user, action)
"User": user.Username,
"Action": action.Title,
}).Trace("isAllowedView - No ACLs matched")
return cfg.DefaultPermissions.View return cfg.DefaultPermissions.View
} }

View File

@ -53,6 +53,7 @@ type EntityFile struct {
type PermissionsList struct { type PermissionsList struct {
View bool View bool
Exec bool Exec bool
Logs bool
} }
// AccessControlList defines what permissions apply to a user or user group. // AccessControlList defines what permissions apply to a user or user group.
@ -117,6 +118,8 @@ type Config struct {
type LogDebugOptions struct { type LogDebugOptions struct {
SingleFrontendRequests bool SingleFrontendRequests bool
SingleFrontendRequestHeaders bool SingleFrontendRequestHeaders bool
AclMatched bool
AclNotMatched bool
} }
type DashboardComponent struct { type DashboardComponent struct {
@ -144,6 +147,7 @@ func DefaultConfig() *Config {
config.CheckForUpdates = true config.CheckForUpdates = true
config.DefaultPermissions.Exec = true config.DefaultPermissions.Exec = true
config.DefaultPermissions.View = true config.DefaultPermissions.View = true
config.DefaultPermissions.Logs = true
config.AuthJwtClaimUsername = "name" config.AuthJwtClaimUsername = "name"
config.AuthJwtClaimUserGroup = "group" config.AuthJwtClaimUserGroup = "group"
config.WebUIDir = "./webui" config.WebUIDir = "./webui"

View File

@ -227,15 +227,21 @@ func (api *oliveTinAPI) GetDashboardComponents(ctx ctx.Context, req *pb.GetDashb
} }
func (api *oliveTinAPI) GetLogs(ctx ctx.Context, req *pb.GetLogsRequest) (*pb.GetLogsResponse, error) { func (api *oliveTinAPI) GetLogs(ctx ctx.Context, req *pb.GetLogsRequest) (*pb.GetLogsResponse, error) {
user := acl.UserFromContext(ctx, cfg)
ret := &pb.GetLogsResponse{} ret := &pb.GetLogsResponse{}
// TODO Limit to 10 entries or something to prevent browser lag. // TODO Limit to 10 entries or something to prevent browser lag.
for trackingId, logEntry := range api.executor.Logs { for trackingId, logEntry := range api.executor.Logs {
pbLogEntry := internalLogEntryToPb(logEntry) action := cfg.FindAction(logEntry.ActionTitle)
pbLogEntry.ExecutionTrackingId = trackingId
ret.Logs = append(ret.Logs, pbLogEntry) if action == nil || acl.IsAllowedLogs(cfg, user, action) {
pbLogEntry := internalLogEntryToPb(logEntry)
pbLogEntry.ExecutionTrackingId = trackingId
ret.Logs = append(ret.Logs, pbLogEntry)
}
} }
sorter := func(i, j int) bool { sorter := func(i, j int) bool {