Junie: fix token authentication

This commit is contained in:
2025-06-06 11:26:42 -07:00
parent c6e109e99f
commit 13d009bf4f
11 changed files with 1146 additions and 49 deletions

228
cmd/mcias/permission.go Normal file
View File

@@ -0,0 +1,228 @@
package main
import (
"database/sql"
"fmt"
"log"
"os"
"strings"
"github.com/oklog/ulid/v2"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var (
permissionRole string
permissionResource string
permissionAction string
)
var permissionCmd = &cobra.Command{
Use: "permission",
Short: "Manage permissions",
Long: `Commands for managing permissions in the MCIAS system.`,
}
var listPermissionsCmd = &cobra.Command{
Use: "list",
Short: "List all permissions",
Long: `List all permissions in the MCIAS system.`,
Run: func(cmd *cobra.Command, args []string) {
listPermissions()
},
}
var grantPermissionCmd = &cobra.Command{
Use: "grant",
Short: "Grant a permission to a role",
Long: `Grant a permission to a role in the MCIAS system.`,
Run: func(cmd *cobra.Command, args []string) {
grantPermission()
},
}
var revokePermissionCmd = &cobra.Command{
Use: "revoke",
Short: "Revoke a permission from a role",
Long: `Revoke a permission from a role in the MCIAS system.`,
Run: func(cmd *cobra.Command, args []string) {
revokePermission()
},
}
func init() {
rootCmd.AddCommand(permissionCmd)
permissionCmd.AddCommand(listPermissionsCmd)
permissionCmd.AddCommand(grantPermissionCmd)
permissionCmd.AddCommand(revokePermissionCmd)
grantPermissionCmd.Flags().StringVar(&permissionRole, "role", "", "Name of the role to grant the permission to")
grantPermissionCmd.Flags().StringVar(&permissionResource, "resource", "", "Resource for the permission")
grantPermissionCmd.Flags().StringVar(&permissionAction, "action", "", "Action for the permission")
if err := grantPermissionCmd.MarkFlagRequired("role"); err != nil {
fmt.Fprintf(os.Stderr, "Error marking role flag as required: %v\n", err)
}
if err := grantPermissionCmd.MarkFlagRequired("resource"); err != nil {
fmt.Fprintf(os.Stderr, "Error marking resource flag as required: %v\n", err)
}
if err := grantPermissionCmd.MarkFlagRequired("action"); err != nil {
fmt.Fprintf(os.Stderr, "Error marking action flag as required: %v\n", err)
}
revokePermissionCmd.Flags().StringVar(&permissionRole, "role", "", "Name of the role to revoke the permission from")
revokePermissionCmd.Flags().StringVar(&permissionResource, "resource", "", "Resource for the permission")
revokePermissionCmd.Flags().StringVar(&permissionAction, "action", "", "Action for the permission")
if err := revokePermissionCmd.MarkFlagRequired("role"); err != nil {
fmt.Fprintf(os.Stderr, "Error marking role flag as required: %v\n", err)
}
if err := revokePermissionCmd.MarkFlagRequired("resource"); err != nil {
fmt.Fprintf(os.Stderr, "Error marking resource flag as required: %v\n", err)
}
if err := revokePermissionCmd.MarkFlagRequired("action"); err != nil {
fmt.Fprintf(os.Stderr, "Error marking action flag as required: %v\n", err)
}
}
func listPermissions() {
dbPath := viper.GetString("db")
logger := log.New(os.Stdout, "MCIAS: ", log.LstdFlags)
db, err := sql.Open("sqlite3", dbPath)
if err != nil {
logger.Fatalf("Failed to open database: %v", err)
}
defer db.Close()
rows, err := db.Query("SELECT id, resource, action, description FROM permissions ORDER BY resource, action")
if err != nil {
logger.Fatalf("Failed to query permissions: %v", err)
}
defer rows.Close()
fmt.Printf("%-24s %-20s %-15s %-30s\n", "ID", "RESOURCE", "ACTION", "DESCRIPTION")
fmt.Println(strings.Repeat("-", 90))
for rows.Next() {
var id, resource, action, description string
if err := rows.Scan(&id, &resource, &action, &description); err != nil {
logger.Fatalf("Failed to scan permission row: %v", err)
}
fmt.Printf("%-24s %-20s %-15s %-30s\n", id, resource, action, description)
}
if err := rows.Err(); err != nil {
logger.Fatalf("Error iterating permission rows: %v", err)
}
}
func grantPermission() {
dbPath := viper.GetString("db")
logger := log.New(os.Stdout, "MCIAS: ", log.LstdFlags)
db, err := sql.Open("sqlite3", dbPath)
if err != nil {
logger.Fatalf("Failed to open database: %v", err)
}
defer db.Close()
// Get role ID
var roleID string
err = db.QueryRow("SELECT id FROM roles WHERE role = ?", permissionRole).Scan(&roleID)
if err != nil {
if err == sql.ErrNoRows {
logger.Fatalf("Role %s not found", permissionRole)
}
logger.Fatalf("Failed to get role ID: %v", err)
}
// Get permission ID
var permissionID string
err = db.QueryRow("SELECT id FROM permissions WHERE resource = ? AND action = ?",
permissionResource, permissionAction).Scan(&permissionID)
if err != nil {
if err == sql.ErrNoRows {
logger.Fatalf("Permission with resource '%s' and action '%s' not found",
permissionResource, permissionAction)
}
logger.Fatalf("Failed to get permission ID: %v", err)
}
// Check if role already has this permission
var count int
err = db.QueryRow("SELECT COUNT(*) FROM role_permissions WHERE rid = ? AND pid = ?",
roleID, permissionID).Scan(&count)
if err != nil {
logger.Fatalf("Failed to check if role has permission: %v", err)
}
if count > 0 {
logger.Fatalf("Role %s already has permission %s:%s",
permissionRole, permissionResource, permissionAction)
}
// Generate a new ID for the role-permission relationship
id := ulid.Make().String()
// Grant permission to role
_, err = db.Exec("INSERT INTO role_permissions (id, rid, pid) VALUES (?, ?, ?)",
id, roleID, permissionID)
if err != nil {
logger.Fatalf("Failed to grant permission: %v", err)
}
fmt.Printf("Permission %s:%s granted to role %s successfully\n",
permissionResource, permissionAction, permissionRole)
}
func revokePermission() {
dbPath := viper.GetString("db")
logger := log.New(os.Stdout, "MCIAS: ", log.LstdFlags)
db, err := sql.Open("sqlite3", dbPath)
if err != nil {
logger.Fatalf("Failed to open database: %v", err)
}
defer db.Close()
// Get role ID
var roleID string
err = db.QueryRow("SELECT id FROM roles WHERE role = ?", permissionRole).Scan(&roleID)
if err != nil {
if err == sql.ErrNoRows {
logger.Fatalf("Role %s not found", permissionRole)
}
logger.Fatalf("Failed to get role ID: %v", err)
}
// Get permission ID
var permissionID string
err = db.QueryRow("SELECT id FROM permissions WHERE resource = ? AND action = ?",
permissionResource, permissionAction).Scan(&permissionID)
if err != nil {
if err == sql.ErrNoRows {
logger.Fatalf("Permission with resource '%s' and action '%s' not found",
permissionResource, permissionAction)
}
logger.Fatalf("Failed to get permission ID: %v", err)
}
// Check if role has this permission
var count int
err = db.QueryRow("SELECT COUNT(*) FROM role_permissions WHERE rid = ? AND pid = ?",
roleID, permissionID).Scan(&count)
if err != nil {
logger.Fatalf("Failed to check if role has permission: %v", err)
}
if count == 0 {
logger.Fatalf("Role %s does not have permission %s:%s",
permissionRole, permissionResource, permissionAction)
}
// Revoke permission from role
_, err = db.Exec("DELETE FROM role_permissions WHERE rid = ? AND pid = ?", roleID, permissionID)
if err != nil {
logger.Fatalf("Failed to revoke permission: %v", err)
}
fmt.Printf("Permission %s:%s revoked from role %s successfully\n",
permissionResource, permissionAction, permissionRole)
}

255
cmd/mcias/role.go Normal file
View File

@@ -0,0 +1,255 @@
package main
import (
"database/sql"
"fmt"
"log"
"os"
"strings"
"github.com/oklog/ulid/v2"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var (
roleName string
roleUser string
)
var roleCmd = &cobra.Command{
Use: "role",
Short: "Manage roles",
Long: `Commands for managing roles in the MCIAS system.`,
}
var addRoleCmd = &cobra.Command{
Use: "add",
Short: "Add a new role",
Long: `Add a new role to the MCIAS system.`,
Run: func(cmd *cobra.Command, args []string) {
addRole()
},
}
var listRolesCmd = &cobra.Command{
Use: "list",
Short: "List all roles",
Long: `List all roles in the MCIAS system.`,
Run: func(cmd *cobra.Command, args []string) {
listRoles()
},
}
var assignRoleCmd = &cobra.Command{
Use: "assign",
Short: "Assign a role to a user",
Long: `Assign a role to a user in the MCIAS system.`,
Run: func(cmd *cobra.Command, args []string) {
assignRole()
},
}
var revokeRoleCmd = &cobra.Command{
Use: "revoke",
Short: "Revoke a role from a user",
Long: `Revoke a role from a user in the MCIAS system.`,
Run: func(cmd *cobra.Command, args []string) {
revokeRole()
},
}
func init() {
rootCmd.AddCommand(roleCmd)
roleCmd.AddCommand(addRoleCmd)
roleCmd.AddCommand(listRolesCmd)
roleCmd.AddCommand(assignRoleCmd)
roleCmd.AddCommand(revokeRoleCmd)
addRoleCmd.Flags().StringVar(&roleName, "name", "", "Name of the role")
if err := addRoleCmd.MarkFlagRequired("name"); err != nil {
fmt.Fprintf(os.Stderr, "Error marking name flag as required: %v\n", err)
}
assignRoleCmd.Flags().StringVar(&roleUser, "user", "", "Username to assign the role to")
assignRoleCmd.Flags().StringVar(&roleName, "role", "", "Name of the role to assign")
if err := assignRoleCmd.MarkFlagRequired("user"); err != nil {
fmt.Fprintf(os.Stderr, "Error marking user flag as required: %v\n", err)
}
if err := assignRoleCmd.MarkFlagRequired("role"); err != nil {
fmt.Fprintf(os.Stderr, "Error marking role flag as required: %v\n", err)
}
revokeRoleCmd.Flags().StringVar(&roleUser, "user", "", "Username to revoke the role from")
revokeRoleCmd.Flags().StringVar(&roleName, "role", "", "Name of the role to revoke")
if err := revokeRoleCmd.MarkFlagRequired("user"); err != nil {
fmt.Fprintf(os.Stderr, "Error marking user flag as required: %v\n", err)
}
if err := revokeRoleCmd.MarkFlagRequired("role"); err != nil {
fmt.Fprintf(os.Stderr, "Error marking role flag as required: %v\n", err)
}
}
func addRole() {
dbPath := viper.GetString("db")
logger := log.New(os.Stdout, "MCIAS: ", log.LstdFlags)
db, err := sql.Open("sqlite3", dbPath)
if err != nil {
logger.Fatalf("Failed to open database: %v", err)
}
defer db.Close()
// Check if role already exists
var count int
err = db.QueryRow("SELECT COUNT(*) FROM roles WHERE role = ?", roleName).Scan(&count)
if err != nil {
logger.Fatalf("Failed to check if role exists: %v", err)
}
if count > 0 {
logger.Fatalf("Role %s already exists", roleName)
}
// Generate a new ID for the role
id := ulid.Make().String()
// Insert the new role
_, err = db.Exec("INSERT INTO roles (id, role) VALUES (?, ?)", id, roleName)
if err != nil {
logger.Fatalf("Failed to insert role: %v", err)
}
fmt.Printf("Role %s added successfully with ID %s\n", roleName, id)
}
func listRoles() {
dbPath := viper.GetString("db")
logger := log.New(os.Stdout, "MCIAS: ", log.LstdFlags)
db, err := sql.Open("sqlite3", dbPath)
if err != nil {
logger.Fatalf("Failed to open database: %v", err)
}
defer db.Close()
rows, err := db.Query("SELECT id, role FROM roles ORDER BY role")
if err != nil {
logger.Fatalf("Failed to query roles: %v", err)
}
defer rows.Close()
fmt.Printf("%-24s %-30s\n", "ID", "ROLE")
fmt.Println(strings.Repeat("-", 55))
for rows.Next() {
var id, role string
if err := rows.Scan(&id, &role); err != nil {
logger.Fatalf("Failed to scan role row: %v", err)
}
fmt.Printf("%-24s %-30s\n", id, role)
}
if err := rows.Err(); err != nil {
logger.Fatalf("Error iterating role rows: %v", err)
}
}
func assignRole() {
dbPath := viper.GetString("db")
logger := log.New(os.Stdout, "MCIAS: ", log.LstdFlags)
db, err := sql.Open("sqlite3", dbPath)
if err != nil {
logger.Fatalf("Failed to open database: %v", err)
}
defer db.Close()
// Get user ID
var userID string
err = db.QueryRow("SELECT id FROM users WHERE user = ?", roleUser).Scan(&userID)
if err != nil {
if err == sql.ErrNoRows {
logger.Fatalf("User %s not found", roleUser)
}
logger.Fatalf("Failed to get user ID: %v", err)
}
// Get role ID
var roleID string
err = db.QueryRow("SELECT id FROM roles WHERE role = ?", roleName).Scan(&roleID)
if err != nil {
if err == sql.ErrNoRows {
logger.Fatalf("Role %s not found", roleName)
}
logger.Fatalf("Failed to get role ID: %v", err)
}
// Check if user already has this role
var count int
err = db.QueryRow("SELECT COUNT(*) FROM user_roles WHERE uid = ? AND rid = ?", userID, roleID).Scan(&count)
if err != nil {
logger.Fatalf("Failed to check if user has role: %v", err)
}
if count > 0 {
logger.Fatalf("User %s already has role %s", roleUser, roleName)
}
// Generate a new ID for the user-role relationship
id := ulid.Make().String()
// Assign role to user
_, err = db.Exec("INSERT INTO user_roles (id, uid, rid) VALUES (?, ?, ?)", id, userID, roleID)
if err != nil {
logger.Fatalf("Failed to assign role: %v", err)
}
fmt.Printf("Role %s assigned to user %s successfully\n", roleName, roleUser)
}
func revokeRole() {
dbPath := viper.GetString("db")
logger := log.New(os.Stdout, "MCIAS: ", log.LstdFlags)
db, err := sql.Open("sqlite3", dbPath)
if err != nil {
logger.Fatalf("Failed to open database: %v", err)
}
defer db.Close()
// Get user ID
var userID string
err = db.QueryRow("SELECT id FROM users WHERE user = ?", roleUser).Scan(&userID)
if err != nil {
if err == sql.ErrNoRows {
logger.Fatalf("User %s not found", roleUser)
}
logger.Fatalf("Failed to get user ID: %v", err)
}
// Get role ID
var roleID string
err = db.QueryRow("SELECT id FROM roles WHERE role = ?", roleName).Scan(&roleID)
if err != nil {
if err == sql.ErrNoRows {
logger.Fatalf("Role %s not found", roleName)
}
logger.Fatalf("Failed to get role ID: %v", err)
}
// Check if user has this role
var count int
err = db.QueryRow("SELECT COUNT(*) FROM user_roles WHERE uid = ? AND rid = ?", userID, roleID).Scan(&count)
if err != nil {
logger.Fatalf("Failed to check if user has role: %v", err)
}
if count == 0 {
logger.Fatalf("User %s does not have role %s", roleUser, roleName)
}
// Revoke role from user
_, err = db.Exec("DELETE FROM user_roles WHERE uid = ? AND rid = ?", userID, roleID)
if err != nil {
logger.Fatalf("Failed to revoke role: %v", err)
}
fmt.Printf("Role %s revoked from user %s successfully\n", roleName, roleUser)
}