Add RBAC support with roles, permissions, and session management. Implement middleware for authentication and CSRF protection. Enhance audit logging with additional fields. Update HTTP handlers and routes for new features.

This commit is contained in:
2025-12-13 17:44:09 +00:00
parent d69e01bbaf
commit 8100f87686
44 changed files with 3262 additions and 76 deletions

183
internal/auth/rbac.go Normal file
View File

@@ -0,0 +1,183 @@
package auth
import (
"context"
"database/sql"
)
type Permission struct {
ID string
Name string
Description string
}
type Role struct {
ID string
Name string
Description string
}
type RBACStore struct {
DB *sql.DB
}
func NewRBACStore(db *sql.DB) *RBACStore {
return &RBACStore{DB: db}
}
// GetUserRoles retrieves all roles for a user
func (s *RBACStore) GetUserRoles(ctx context.Context, userID string) ([]Role, error) {
rows, err := s.DB.QueryContext(ctx,
`SELECT r.id, r.name, r.description FROM roles r
INNER JOIN user_roles ur ON r.id = ur.role_id
WHERE ur.user_id = ?`,
userID)
if err != nil {
return nil, err
}
defer rows.Close()
var roles []Role
for rows.Next() {
var role Role
if err := rows.Scan(&role.ID, &role.Name, &role.Description); err != nil {
return nil, err
}
roles = append(roles, role)
}
return roles, rows.Err()
}
// GetRolePermissions retrieves all permissions for a role
func (s *RBACStore) GetRolePermissions(ctx context.Context, roleID string) ([]Permission, error) {
rows, err := s.DB.QueryContext(ctx,
`SELECT p.id, p.name, p.description FROM permissions p
INNER JOIN role_permissions rp ON p.id = rp.permission_id
WHERE rp.role_id = ?`,
roleID)
if err != nil {
return nil, err
}
defer rows.Close()
var permissions []Permission
for rows.Next() {
var perm Permission
if err := rows.Scan(&perm.ID, &perm.Name, &perm.Description); err != nil {
return nil, err
}
permissions = append(permissions, perm)
}
return permissions, rows.Err()
}
// GetUserPermissions retrieves all permissions for a user (through their roles)
func (s *RBACStore) GetUserPermissions(ctx context.Context, userID string) ([]Permission, error) {
rows, err := s.DB.QueryContext(ctx,
`SELECT DISTINCT p.id, p.name, p.description FROM permissions p
INNER JOIN role_permissions rp ON p.id = rp.permission_id
INNER JOIN user_roles ur ON rp.role_id = ur.role_id
WHERE ur.user_id = ?`,
userID)
if err != nil {
return nil, err
}
defer rows.Close()
var permissions []Permission
for rows.Next() {
var perm Permission
if err := rows.Scan(&perm.ID, &perm.Name, &perm.Description); err != nil {
return nil, err
}
permissions = append(permissions, perm)
}
return permissions, rows.Err()
}
// UserHasPermission checks if a user has a specific permission
func (s *RBACStore) UserHasPermission(ctx context.Context, userID, permission string) (bool, error) {
var count int
err := s.DB.QueryRowContext(ctx,
`SELECT COUNT(*) FROM permissions p
INNER JOIN role_permissions rp ON p.id = rp.permission_id
INNER JOIN user_roles ur ON rp.role_id = ur.role_id
WHERE ur.user_id = ? AND p.name = ?`,
userID, permission).Scan(&count)
if err != nil {
return false, err
}
return count > 0, nil
}
// AssignRoleToUser assigns a role to a user
func (s *RBACStore) AssignRoleToUser(ctx context.Context, userID, roleID string) error {
_, err := s.DB.ExecContext(ctx,
`INSERT OR IGNORE INTO user_roles (user_id, role_id) VALUES (?, ?)`,
userID, roleID)
return err
}
// RemoveRoleFromUser removes a role from a user
func (s *RBACStore) RemoveRoleFromUser(ctx context.Context, userID, roleID string) error {
_, err := s.DB.ExecContext(ctx,
`DELETE FROM user_roles WHERE user_id = ? AND role_id = ?`,
userID, roleID)
return err
}
// GetAllRoles retrieves all roles
func (s *RBACStore) GetAllRoles(ctx context.Context) ([]Role, error) {
rows, err := s.DB.QueryContext(ctx,
`SELECT id, name, description FROM roles ORDER BY name`)
if err != nil {
return nil, err
}
defer rows.Close()
var roles []Role
for rows.Next() {
var role Role
if err := rows.Scan(&role.ID, &role.Name, &role.Description); err != nil {
return nil, err
}
roles = append(roles, role)
}
return roles, rows.Err()
}
// GetAllPermissions retrieves all permissions
func (s *RBACStore) GetAllPermissions(ctx context.Context) ([]Permission, error) {
rows, err := s.DB.QueryContext(ctx,
`SELECT id, name, description FROM permissions ORDER BY name`)
if err != nil {
return nil, err
}
defer rows.Close()
var permissions []Permission
for rows.Next() {
var perm Permission
if err := rows.Scan(&perm.ID, &perm.Name, &perm.Description); err != nil {
return nil, err
}
permissions = append(permissions, perm)
}
return permissions, rows.Err()
}
// AssignPermissionToRole assigns a permission to a role
func (s *RBACStore) AssignPermissionToRole(ctx context.Context, roleID, permissionID string) error {
_, err := s.DB.ExecContext(ctx,
`INSERT OR IGNORE INTO role_permissions (role_id, permission_id) VALUES (?, ?)`,
roleID, permissionID)
return err
}
// RemovePermissionFromRole removes a permission from a role
func (s *RBACStore) RemovePermissionFromRole(ctx context.Context, roleID, permissionID string) error {
_, err := s.DB.ExecContext(ctx,
`DELETE FROM role_permissions WHERE role_id = ? AND permission_id = ?`,
roleID, permissionID)
return err
}