package rbac type Permission string const ( Read Permission = "read" Write Permission = "write" // Root is the high-impact tier: destructive or irreversible operations // (reboot, shutdown, account deletion, firewall flush, …) that callers // should be able to grant separately from routine writes. Root Permission = "root" All Permission = "*" // wildcard: matches any permission ) // Wildcard is the module-key value that matches all modules in a Role's grants. const Wildcard = "*" type Role struct { Name string ModuleGrants map[string][]Permission // module ID (or "*") -> permissions (each may be "*") } type RBAC struct { roles map[string]Role userRoles map[string][]string } func New() *RBAC { return &RBAC{ roles: make(map[string]Role), userRoles: make(map[string][]string), } } func (r *RBAC) DefineRole(role Role) { r.roles[role.Name] = role } // RoleExists reports whether a role with the given name has been defined. func (r *RBAC) RoleExists(name string) bool { _, ok := r.roles[name] return ok } func (r *RBAC) AssignRole(username, roleName string) { r.userRoles[username] = append(r.userRoles[username], roleName) } // Can checks whether the user holds any role granting (module, perm), // honoring "*" wildcards on both the module key and inside the permission list. func (r *RBAC) Can(username, module string, perm Permission) bool { for _, roleName := range r.userRoles[username] { role, ok := r.roles[roleName] if !ok { continue } // Check the exact module key AND the wildcard module key. for _, key := range []string{module, Wildcard} { grants, ok := role.ModuleGrants[key] if !ok { continue } for _, p := range grants { if p == perm || p == All { return true } } } } return false }