policy_handlers.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. package handlers
  2. import (
  3. "fmt"
  4. "net/http"
  5. "time"
  6. "github.com/gin-gonic/gin"
  7. "github.com/seaweedfs/seaweedfs/weed/admin/dash"
  8. "github.com/seaweedfs/seaweedfs/weed/admin/view/app"
  9. "github.com/seaweedfs/seaweedfs/weed/admin/view/layout"
  10. "github.com/seaweedfs/seaweedfs/weed/glog"
  11. "github.com/seaweedfs/seaweedfs/weed/s3api/policy_engine"
  12. )
  13. // PolicyHandlers contains all the HTTP handlers for policy management
  14. type PolicyHandlers struct {
  15. adminServer *dash.AdminServer
  16. }
  17. // NewPolicyHandlers creates a new instance of PolicyHandlers
  18. func NewPolicyHandlers(adminServer *dash.AdminServer) *PolicyHandlers {
  19. return &PolicyHandlers{
  20. adminServer: adminServer,
  21. }
  22. }
  23. // ShowPolicies renders the policies management page
  24. func (h *PolicyHandlers) ShowPolicies(c *gin.Context) {
  25. // Get policies data from the server
  26. policiesData := h.getPoliciesData(c)
  27. // Render HTML template
  28. c.Header("Content-Type", "text/html")
  29. policiesComponent := app.Policies(policiesData)
  30. layoutComponent := layout.Layout(c, policiesComponent)
  31. err := layoutComponent.Render(c.Request.Context(), c.Writer)
  32. if err != nil {
  33. c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to render template: " + err.Error()})
  34. return
  35. }
  36. }
  37. // GetPolicies returns the list of policies as JSON
  38. func (h *PolicyHandlers) GetPolicies(c *gin.Context) {
  39. policies, err := h.adminServer.GetPolicies()
  40. if err != nil {
  41. c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get policies: " + err.Error()})
  42. return
  43. }
  44. c.JSON(http.StatusOK, gin.H{"policies": policies})
  45. }
  46. // CreatePolicy handles policy creation
  47. func (h *PolicyHandlers) CreatePolicy(c *gin.Context) {
  48. var req dash.CreatePolicyRequest
  49. if err := c.ShouldBindJSON(&req); err != nil {
  50. c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request: " + err.Error()})
  51. return
  52. }
  53. // Validate policy name
  54. if req.Name == "" {
  55. c.JSON(http.StatusBadRequest, gin.H{"error": "Policy name is required"})
  56. return
  57. }
  58. // Check if policy already exists
  59. existingPolicy, err := h.adminServer.GetPolicy(req.Name)
  60. if err != nil {
  61. c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to check existing policy: " + err.Error()})
  62. return
  63. }
  64. if existingPolicy != nil {
  65. c.JSON(http.StatusConflict, gin.H{"error": "Policy with this name already exists"})
  66. return
  67. }
  68. // Create the policy
  69. err = h.adminServer.CreatePolicy(req.Name, req.Document)
  70. if err != nil {
  71. glog.Errorf("Failed to create policy %s: %v", req.Name, err)
  72. c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create policy: " + err.Error()})
  73. return
  74. }
  75. c.JSON(http.StatusCreated, gin.H{
  76. "success": true,
  77. "message": "Policy created successfully",
  78. "policy": req.Name,
  79. })
  80. }
  81. // GetPolicy returns a specific policy
  82. func (h *PolicyHandlers) GetPolicy(c *gin.Context) {
  83. policyName := c.Param("name")
  84. if policyName == "" {
  85. c.JSON(http.StatusBadRequest, gin.H{"error": "Policy name is required"})
  86. return
  87. }
  88. policy, err := h.adminServer.GetPolicy(policyName)
  89. if err != nil {
  90. c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get policy: " + err.Error()})
  91. return
  92. }
  93. if policy == nil {
  94. c.JSON(http.StatusNotFound, gin.H{"error": "Policy not found"})
  95. return
  96. }
  97. c.JSON(http.StatusOK, policy)
  98. }
  99. // UpdatePolicy handles policy updates
  100. func (h *PolicyHandlers) UpdatePolicy(c *gin.Context) {
  101. policyName := c.Param("name")
  102. if policyName == "" {
  103. c.JSON(http.StatusBadRequest, gin.H{"error": "Policy name is required"})
  104. return
  105. }
  106. var req dash.UpdatePolicyRequest
  107. if err := c.ShouldBindJSON(&req); err != nil {
  108. c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request: " + err.Error()})
  109. return
  110. }
  111. // Check if policy exists
  112. existingPolicy, err := h.adminServer.GetPolicy(policyName)
  113. if err != nil {
  114. c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to check existing policy: " + err.Error()})
  115. return
  116. }
  117. if existingPolicy == nil {
  118. c.JSON(http.StatusNotFound, gin.H{"error": "Policy not found"})
  119. return
  120. }
  121. // Update the policy
  122. err = h.adminServer.UpdatePolicy(policyName, req.Document)
  123. if err != nil {
  124. glog.Errorf("Failed to update policy %s: %v", policyName, err)
  125. c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update policy: " + err.Error()})
  126. return
  127. }
  128. c.JSON(http.StatusOK, gin.H{
  129. "success": true,
  130. "message": "Policy updated successfully",
  131. "policy": policyName,
  132. })
  133. }
  134. // DeletePolicy handles policy deletion
  135. func (h *PolicyHandlers) DeletePolicy(c *gin.Context) {
  136. policyName := c.Param("name")
  137. if policyName == "" {
  138. c.JSON(http.StatusBadRequest, gin.H{"error": "Policy name is required"})
  139. return
  140. }
  141. // Check if policy exists
  142. existingPolicy, err := h.adminServer.GetPolicy(policyName)
  143. if err != nil {
  144. c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to check existing policy: " + err.Error()})
  145. return
  146. }
  147. if existingPolicy == nil {
  148. c.JSON(http.StatusNotFound, gin.H{"error": "Policy not found"})
  149. return
  150. }
  151. // Delete the policy
  152. err = h.adminServer.DeletePolicy(policyName)
  153. if err != nil {
  154. glog.Errorf("Failed to delete policy %s: %v", policyName, err)
  155. c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete policy: " + err.Error()})
  156. return
  157. }
  158. c.JSON(http.StatusOK, gin.H{
  159. "success": true,
  160. "message": "Policy deleted successfully",
  161. "policy": policyName,
  162. })
  163. }
  164. // ValidatePolicy validates a policy document without saving it
  165. func (h *PolicyHandlers) ValidatePolicy(c *gin.Context) {
  166. var req struct {
  167. Document policy_engine.PolicyDocument `json:"document" binding:"required"`
  168. }
  169. if err := c.ShouldBindJSON(&req); err != nil {
  170. c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request: " + err.Error()})
  171. return
  172. }
  173. // Basic validation
  174. if req.Document.Version == "" {
  175. c.JSON(http.StatusBadRequest, gin.H{"error": "Policy version is required"})
  176. return
  177. }
  178. if len(req.Document.Statement) == 0 {
  179. c.JSON(http.StatusBadRequest, gin.H{"error": "Policy must have at least one statement"})
  180. return
  181. }
  182. // Validate each statement
  183. for i, statement := range req.Document.Statement {
  184. if statement.Effect != "Allow" && statement.Effect != "Deny" {
  185. c.JSON(http.StatusBadRequest, gin.H{
  186. "error": fmt.Sprintf("Statement %d: Effect must be 'Allow' or 'Deny'", i+1),
  187. })
  188. return
  189. }
  190. if len(statement.Action.Strings()) == 0 {
  191. c.JSON(http.StatusBadRequest, gin.H{
  192. "error": fmt.Sprintf("Statement %d: Action is required", i+1),
  193. })
  194. return
  195. }
  196. if len(statement.Resource.Strings()) == 0 {
  197. c.JSON(http.StatusBadRequest, gin.H{
  198. "error": fmt.Sprintf("Statement %d: Resource is required", i+1),
  199. })
  200. return
  201. }
  202. }
  203. c.JSON(http.StatusOK, gin.H{
  204. "valid": true,
  205. "message": "Policy document is valid",
  206. })
  207. }
  208. // getPoliciesData retrieves policies data from the server
  209. func (h *PolicyHandlers) getPoliciesData(c *gin.Context) dash.PoliciesData {
  210. username := c.GetString("username")
  211. if username == "" {
  212. username = "admin"
  213. }
  214. // Get policies
  215. policies, err := h.adminServer.GetPolicies()
  216. if err != nil {
  217. glog.Errorf("Failed to get policies: %v", err)
  218. // Return empty data on error
  219. return dash.PoliciesData{
  220. Username: username,
  221. Policies: []dash.IAMPolicy{},
  222. TotalPolicies: 0,
  223. LastUpdated: time.Now(),
  224. }
  225. }
  226. // Ensure policies is never nil
  227. if policies == nil {
  228. policies = []dash.IAMPolicy{}
  229. }
  230. return dash.PoliciesData{
  231. Username: username,
  232. Policies: policies,
  233. TotalPolicies: len(policies),
  234. LastUpdated: time.Now(),
  235. }
  236. }