aboutsummaryrefslogtreecommitdiff
path: root/weed/admin/handlers/policy_handlers.go
diff options
context:
space:
mode:
authorChris Lu <chrislusf@users.noreply.github.com>2025-07-12 01:13:11 -0700
committerGitHub <noreply@github.com>2025-07-12 01:13:11 -0700
commit687a6a6c1de0fb67b51ec9bfd1781a6c255ff695 (patch)
tree3ee2890c890e67a170cec2692425528aa9cd795f /weed/admin/handlers/policy_handlers.go
parent49d43003e1f5063c57cd1b122469c0cb68d0cd79 (diff)
downloadseaweedfs-687a6a6c1de0fb67b51ec9bfd1781a6c255ff695.tar.xz
seaweedfs-687a6a6c1de0fb67b51ec9bfd1781a6c255ff695.zip
Admin UI: Add policies (#6968)
* add policies to UI, accessing filer directly * view, edit policies * add back buttons for "users" page * remove unused * fix ui dark mode when modal is closed * bucket view details button * fix browser buttons * filer action button works * clean up masters page * fix volume servers action buttons * fix collections page action button * fix properties page * more obvious * fix directory creation file mode * Update file_browser_handlers.go * directory permission
Diffstat (limited to 'weed/admin/handlers/policy_handlers.go')
-rw-r--r--weed/admin/handlers/policy_handlers.go273
1 files changed, 273 insertions, 0 deletions
diff --git a/weed/admin/handlers/policy_handlers.go b/weed/admin/handlers/policy_handlers.go
new file mode 100644
index 000000000..8f5cc91b1
--- /dev/null
+++ b/weed/admin/handlers/policy_handlers.go
@@ -0,0 +1,273 @@
+package handlers
+
+import (
+ "fmt"
+ "net/http"
+ "time"
+
+ "github.com/gin-gonic/gin"
+ "github.com/seaweedfs/seaweedfs/weed/admin/dash"
+ "github.com/seaweedfs/seaweedfs/weed/admin/view/app"
+ "github.com/seaweedfs/seaweedfs/weed/admin/view/layout"
+ "github.com/seaweedfs/seaweedfs/weed/credential"
+ "github.com/seaweedfs/seaweedfs/weed/glog"
+)
+
+// PolicyHandlers contains all the HTTP handlers for policy management
+type PolicyHandlers struct {
+ adminServer *dash.AdminServer
+}
+
+// NewPolicyHandlers creates a new instance of PolicyHandlers
+func NewPolicyHandlers(adminServer *dash.AdminServer) *PolicyHandlers {
+ return &PolicyHandlers{
+ adminServer: adminServer,
+ }
+}
+
+// ShowPolicies renders the policies management page
+func (h *PolicyHandlers) ShowPolicies(c *gin.Context) {
+ // Get policies data from the server
+ policiesData := h.getPoliciesData(c)
+
+ // Render HTML template
+ c.Header("Content-Type", "text/html")
+ policiesComponent := app.Policies(policiesData)
+ layoutComponent := layout.Layout(c, policiesComponent)
+ err := layoutComponent.Render(c.Request.Context(), c.Writer)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to render template: " + err.Error()})
+ return
+ }
+}
+
+// GetPolicies returns the list of policies as JSON
+func (h *PolicyHandlers) GetPolicies(c *gin.Context) {
+ policies, err := h.adminServer.GetPolicies()
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get policies: " + err.Error()})
+ return
+ }
+ c.JSON(http.StatusOK, gin.H{"policies": policies})
+}
+
+// CreatePolicy handles policy creation
+func (h *PolicyHandlers) CreatePolicy(c *gin.Context) {
+ var req dash.CreatePolicyRequest
+ if err := c.ShouldBindJSON(&req); err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request: " + err.Error()})
+ return
+ }
+
+ // Validate policy name
+ if req.Name == "" {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Policy name is required"})
+ return
+ }
+
+ // Check if policy already exists
+ existingPolicy, err := h.adminServer.GetPolicy(req.Name)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to check existing policy: " + err.Error()})
+ return
+ }
+ if existingPolicy != nil {
+ c.JSON(http.StatusConflict, gin.H{"error": "Policy with this name already exists"})
+ return
+ }
+
+ // Create the policy
+ err = h.adminServer.CreatePolicy(req.Name, req.Document)
+ if err != nil {
+ glog.Errorf("Failed to create policy %s: %v", req.Name, err)
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create policy: " + err.Error()})
+ return
+ }
+
+ c.JSON(http.StatusCreated, gin.H{
+ "success": true,
+ "message": "Policy created successfully",
+ "policy": req.Name,
+ })
+}
+
+// GetPolicy returns a specific policy
+func (h *PolicyHandlers) GetPolicy(c *gin.Context) {
+ policyName := c.Param("name")
+ if policyName == "" {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Policy name is required"})
+ return
+ }
+
+ policy, err := h.adminServer.GetPolicy(policyName)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get policy: " + err.Error()})
+ return
+ }
+
+ if policy == nil {
+ c.JSON(http.StatusNotFound, gin.H{"error": "Policy not found"})
+ return
+ }
+
+ c.JSON(http.StatusOK, policy)
+}
+
+// UpdatePolicy handles policy updates
+func (h *PolicyHandlers) UpdatePolicy(c *gin.Context) {
+ policyName := c.Param("name")
+ if policyName == "" {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Policy name is required"})
+ return
+ }
+
+ var req dash.UpdatePolicyRequest
+ if err := c.ShouldBindJSON(&req); err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request: " + err.Error()})
+ return
+ }
+
+ // Check if policy exists
+ existingPolicy, err := h.adminServer.GetPolicy(policyName)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to check existing policy: " + err.Error()})
+ return
+ }
+ if existingPolicy == nil {
+ c.JSON(http.StatusNotFound, gin.H{"error": "Policy not found"})
+ return
+ }
+
+ // Update the policy
+ err = h.adminServer.UpdatePolicy(policyName, req.Document)
+ if err != nil {
+ glog.Errorf("Failed to update policy %s: %v", policyName, err)
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update policy: " + err.Error()})
+ return
+ }
+
+ c.JSON(http.StatusOK, gin.H{
+ "success": true,
+ "message": "Policy updated successfully",
+ "policy": policyName,
+ })
+}
+
+// DeletePolicy handles policy deletion
+func (h *PolicyHandlers) DeletePolicy(c *gin.Context) {
+ policyName := c.Param("name")
+ if policyName == "" {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Policy name is required"})
+ return
+ }
+
+ // Check if policy exists
+ existingPolicy, err := h.adminServer.GetPolicy(policyName)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to check existing policy: " + err.Error()})
+ return
+ }
+ if existingPolicy == nil {
+ c.JSON(http.StatusNotFound, gin.H{"error": "Policy not found"})
+ return
+ }
+
+ // Delete the policy
+ err = h.adminServer.DeletePolicy(policyName)
+ if err != nil {
+ glog.Errorf("Failed to delete policy %s: %v", policyName, err)
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete policy: " + err.Error()})
+ return
+ }
+
+ c.JSON(http.StatusOK, gin.H{
+ "success": true,
+ "message": "Policy deleted successfully",
+ "policy": policyName,
+ })
+}
+
+// ValidatePolicy validates a policy document without saving it
+func (h *PolicyHandlers) ValidatePolicy(c *gin.Context) {
+ var req struct {
+ Document credential.PolicyDocument `json:"document" binding:"required"`
+ }
+
+ if err := c.ShouldBindJSON(&req); err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request: " + err.Error()})
+ return
+ }
+
+ // Basic validation
+ if req.Document.Version == "" {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Policy version is required"})
+ return
+ }
+
+ if len(req.Document.Statement) == 0 {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Policy must have at least one statement"})
+ return
+ }
+
+ // Validate each statement
+ for i, statement := range req.Document.Statement {
+ if statement.Effect != "Allow" && statement.Effect != "Deny" {
+ c.JSON(http.StatusBadRequest, gin.H{
+ "error": fmt.Sprintf("Statement %d: Effect must be 'Allow' or 'Deny'", i+1),
+ })
+ return
+ }
+
+ if len(statement.Action) == 0 {
+ c.JSON(http.StatusBadRequest, gin.H{
+ "error": fmt.Sprintf("Statement %d: Action is required", i+1),
+ })
+ return
+ }
+
+ if len(statement.Resource) == 0 {
+ c.JSON(http.StatusBadRequest, gin.H{
+ "error": fmt.Sprintf("Statement %d: Resource is required", i+1),
+ })
+ return
+ }
+ }
+
+ c.JSON(http.StatusOK, gin.H{
+ "valid": true,
+ "message": "Policy document is valid",
+ })
+}
+
+// getPoliciesData retrieves policies data from the server
+func (h *PolicyHandlers) getPoliciesData(c *gin.Context) dash.PoliciesData {
+ username := c.GetString("username")
+ if username == "" {
+ username = "admin"
+ }
+
+ // Get policies
+ policies, err := h.adminServer.GetPolicies()
+ if err != nil {
+ glog.Errorf("Failed to get policies: %v", err)
+ // Return empty data on error
+ return dash.PoliciesData{
+ Username: username,
+ Policies: []dash.IAMPolicy{},
+ TotalPolicies: 0,
+ LastUpdated: time.Now(),
+ }
+ }
+
+ // Ensure policies is never nil
+ if policies == nil {
+ policies = []dash.IAMPolicy{}
+ }
+
+ return dash.PoliciesData{
+ Username: username,
+ Policies: policies,
+ TotalPolicies: len(policies),
+ LastUpdated: time.Now(),
+ }
+}