175 lines
4.9 KiB
Go
175 lines
4.9 KiB
Go
package data
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
|
|
"github.com/oklog/ulid/v2"
|
|
)
|
|
|
|
// Permission represents a system permission
|
|
type Permission struct {
|
|
ID string
|
|
Resource string
|
|
Action string
|
|
Description string
|
|
}
|
|
|
|
// AuthorizationService provides methods for checking user permissions
|
|
type AuthorizationService struct {
|
|
db *sql.DB
|
|
}
|
|
|
|
// NewAuthorizationService creates a new authorization service
|
|
func NewAuthorizationService(db *sql.DB) *AuthorizationService {
|
|
return &AuthorizationService{db: db}
|
|
}
|
|
|
|
// UserHasPermission checks if a user has a specific permission for a resource and action
|
|
func (a *AuthorizationService) UserHasPermission(userID, resource, action string) (bool, error) {
|
|
query := `
|
|
SELECT COUNT(*) FROM permissions p
|
|
JOIN role_permissions rp ON p.id = rp.pid
|
|
JOIN user_roles ur ON rp.rid = ur.rid
|
|
WHERE ur.uid = ? AND p.resource = ? AND p.action = ?
|
|
`
|
|
|
|
var count int
|
|
err := a.db.QueryRow(query, userID, resource, action).Scan(&count)
|
|
if err != nil {
|
|
return false, fmt.Errorf("failed to check user permission: %w", err)
|
|
}
|
|
|
|
return count > 0, nil
|
|
}
|
|
|
|
// GetUserPermissions returns all permissions for a user based on their roles
|
|
func (a *AuthorizationService) GetUserPermissions(userID string) ([]Permission, error) {
|
|
query := `
|
|
SELECT DISTINCT p.id, p.resource, p.action, p.description FROM permissions p
|
|
JOIN role_permissions rp ON p.id = rp.pid
|
|
JOIN user_roles ur ON rp.rid = ur.rid
|
|
WHERE ur.uid = ?
|
|
`
|
|
|
|
rows, err := a.db.Query(query, userID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get user permissions: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
var permissions []Permission
|
|
for rows.Next() {
|
|
var perm Permission
|
|
if err := rows.Scan(&perm.ID, &perm.Resource, &perm.Action, &perm.Description); err != nil {
|
|
return nil, fmt.Errorf("failed to scan permission: %w", err)
|
|
}
|
|
permissions = append(permissions, perm)
|
|
}
|
|
|
|
if err := rows.Err(); err != nil {
|
|
return nil, fmt.Errorf("error iterating permissions: %w", err)
|
|
}
|
|
|
|
return permissions, nil
|
|
}
|
|
|
|
// GetRolePermissions returns all permissions for a specific role
|
|
func (a *AuthorizationService) GetRolePermissions(roleID string) ([]Permission, error) {
|
|
query := `
|
|
SELECT p.id, p.resource, p.action, p.description FROM permissions p
|
|
JOIN role_permissions rp ON p.id = rp.pid
|
|
WHERE rp.rid = ?
|
|
`
|
|
|
|
rows, err := a.db.Query(query, roleID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get role permissions: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
var permissions []Permission
|
|
for rows.Next() {
|
|
var perm Permission
|
|
if err := rows.Scan(&perm.ID, &perm.Resource, &perm.Action, &perm.Description); err != nil {
|
|
return nil, fmt.Errorf("failed to scan permission: %w", err)
|
|
}
|
|
permissions = append(permissions, perm)
|
|
}
|
|
|
|
if err := rows.Err(); err != nil {
|
|
return nil, fmt.Errorf("error iterating permissions: %w", err)
|
|
}
|
|
|
|
return permissions, nil
|
|
}
|
|
|
|
// GrantPermissionToRole grants a permission to a role
|
|
func (a *AuthorizationService) GrantPermissionToRole(roleID, permissionID string) error {
|
|
// Check if the role-permission relationship already exists
|
|
checkQuery := `SELECT COUNT(*) FROM role_permissions WHERE rid = ? AND pid = ?`
|
|
var count int
|
|
err := a.db.QueryRow(checkQuery, roleID, permissionID).Scan(&count)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to check role permission: %w", err)
|
|
}
|
|
|
|
if count > 0 {
|
|
return nil // Permission already granted
|
|
}
|
|
|
|
// Generate a new ID for the role-permission relationship
|
|
id := GenerateID()
|
|
|
|
// Insert the new role-permission relationship
|
|
insertQuery := `INSERT INTO role_permissions (id, rid, pid) VALUES (?, ?, ?)`
|
|
_, err = a.db.Exec(insertQuery, id, roleID, permissionID)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to grant permission to role: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// RevokePermissionFromRole revokes a permission from a role
|
|
func (a *AuthorizationService) RevokePermissionFromRole(roleID, permissionID string) error {
|
|
query := `DELETE FROM role_permissions WHERE rid = ? AND pid = ?`
|
|
_, err := a.db.Exec(query, roleID, permissionID)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to revoke permission from role: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetAllPermissions returns all permissions in the system
|
|
func (a *AuthorizationService) GetAllPermissions() ([]Permission, error) {
|
|
query := `SELECT id, resource, action, description FROM permissions`
|
|
|
|
rows, err := a.db.Query(query)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get permissions: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
var permissions []Permission
|
|
for rows.Next() {
|
|
var perm Permission
|
|
if err := rows.Scan(&perm.ID, &perm.Resource, &perm.Action, &perm.Description); err != nil {
|
|
return nil, fmt.Errorf("failed to scan permission: %w", err)
|
|
}
|
|
permissions = append(permissions, perm)
|
|
}
|
|
|
|
if err := rows.Err(); err != nil {
|
|
return nil, fmt.Errorf("error iterating permissions: %w", err)
|
|
}
|
|
|
|
return permissions, nil
|
|
}
|
|
|
|
// GenerateID generates a unique ID for database records
|
|
func GenerateID() string {
|
|
return ulid.Make().String()
|
|
}
|