You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							273 lines
						
					
					
						
							7.4 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							273 lines
						
					
					
						
							7.4 KiB
						
					
					
				| 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/glog" | |
| 	"github.com/seaweedfs/seaweedfs/weed/s3api/policy_engine" | |
| ) | |
| 
 | |
| // 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 policy_engine.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.Strings()) == 0 { | |
| 			c.JSON(http.StatusBadRequest, gin.H{ | |
| 				"error": fmt.Sprintf("Statement %d: Action is required", i+1), | |
| 			}) | |
| 			return | |
| 		} | |
| 
 | |
| 		if len(statement.Resource.Strings()) == 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(), | |
| 	} | |
| }
 |