From 86f599e88de4c6f0926730813c4ca9b15095dc4f Mon Sep 17 00:00:00 2001 From: Max Date: Sun, 15 Dec 2024 16:53:34 +0300 Subject: [PATCH] Start of migration --- enshi_back/middleware/MiddlewareProvider.go | 112 ++++++++++++++++++++ enshi_back/middleware/TargetMiddleware.go | 30 ++++++ enshi_back/routes/routesSetup.go | 71 +++++++++++++ 3 files changed, 213 insertions(+) create mode 100644 enshi_back/middleware/MiddlewareProvider.go create mode 100644 enshi_back/middleware/TargetMiddleware.go diff --git a/enshi_back/middleware/MiddlewareProvider.go b/enshi_back/middleware/MiddlewareProvider.go new file mode 100644 index 0000000..7e897b0 --- /dev/null +++ b/enshi_back/middleware/MiddlewareProvider.go @@ -0,0 +1,112 @@ +package middleware + +import ( + "enshi/ABAC/rules" + "fmt" + + "github.com/gin-gonic/gin" +) + +type WorkRule struct { + Rules []rules.RuleFunction + MustBeCompleted int +} + +type Policy func(c *gin.Context) (bool, []error) +type RuleSets map[string]rules.RuleFunction +type RulesToCheck map[string]WorkRule + +type MiddlewareProvider struct { + Policies map[string]Policy +} + +func CreateRuleFunction(rulesToCheck []rules.RuleFunction, mustBeCompleted int) rules.RuleFunction { + return func(c *gin.Context) (bool, []error) { + + isAllowed, errors := rules.CheckRules( + c, + rulesToCheck, + mustBeCompleted, + ) + + return isAllowed, errors + } +} + +func CreatePolicy(ruleSets RuleSets) Policy { + + return func(c *gin.Context) (bool, []error) { + targetAction, exists := c.Get("target") + if !exists { + return false, nil + } + + for action, rule := range ruleSets { + if action == targetAction { + return rules.CheckRule(c, rule) + } + } + + return false, nil + } + +} + +// Accepts +// +// ruleSetName -> `string` name of the policy(like old one "postPolicy" etc.) +// +// rulesToCheck -> map where keys like ["GET", "POST", etc.] and values are struct of type {rules: [list of rules to check], mustBeCompleted: how many rules must be completed from the list before} +func (m *MiddlewareProvider) RegisterPolicy( + ruleSetName string, + rulesToCheck RulesToCheck, +) error { + + for k := range m.Policies { + if k == ruleSetName { + return fmt.Errorf("name: " + ruleSetName + " already exists") + } + } + + newRuleSets := make(RuleSets) + for setName, workRule := range rulesToCheck { + newRuleFunction := CreateRuleFunction(workRule.Rules, workRule.MustBeCompleted) + newRuleSets[setName] = newRuleFunction + } + + newPolicy := CreatePolicy(newRuleSets) + + m.Policies[ruleSetName] = newPolicy + + return nil +} + +func (m *MiddlewareProvider) GetMiddleware( + policyName string, +) gin.HandlerFunc { + + return func(c *gin.Context) { + + validName := false + for key := range m.Policies { + if key == policyName { + validName = true + } + } + if !validName { + c.Abort() + fmt.Println("invalid policy name: " + policyName) + return + } + + isAllowed, errors := m.Policies[policyName](c) + + if rules.ShouldAbortRequest(c, isAllowed, errors) { + c.Abort() + return + } + + c.Next() + } + +} diff --git a/enshi_back/middleware/TargetMiddleware.go b/enshi_back/middleware/TargetMiddleware.go new file mode 100644 index 0000000..ea7d3ac --- /dev/null +++ b/enshi_back/middleware/TargetMiddleware.go @@ -0,0 +1,30 @@ +package middleware + +import ( + "github.com/gin-gonic/gin" +) + +const ( + GET = "GET" + PUT = "PUT" + POST = "POST" + DELETE = "DELETE" +) + +func TargetMiddleware() gin.HandlerFunc { + return func(c *gin.Context) { + + switch c.Request.Method { + case "DELETE": + c.Set("target", DELETE) + case "PUT": + c.Set("target", PUT) + case "POST": + c.Set("target", POST) + case "GET": + c.Set("target", DELETE) + } + + c.Next() + } +} diff --git a/enshi_back/routes/routesSetup.go b/enshi_back/routes/routesSetup.go index 12afb8b..54f847b 100644 --- a/enshi_back/routes/routesSetup.go +++ b/enshi_back/routes/routesSetup.go @@ -1,6 +1,8 @@ package routes import ( + globalrules "enshi/ABAC/GlobalRules" + "enshi/ABAC/rules" "enshi/middleware" "enshi/middleware/getters" "enshi/routes/authRoutes" @@ -16,6 +18,10 @@ import ( "github.com/gin-gonic/gin" ) +const ( + POST_MIDDLEWARE = "post_middleware" +) + func testCookie(c *gin.Context) { cock, _ := c.Cookie("auth_cookie") c.IndentedJSON(http.StatusOK, gin.H{"token": "SLESAR' U STASA " + strings.Split(cock, "_")[0]}) @@ -43,7 +49,72 @@ func testAuth(c *gin.Context) { } func SetupRotes(g *gin.Engine) error { + middlewareProvider := middleware.MiddlewareProvider{ + Policies: make(map[string]middleware.Policy), + } + + var policies = map[string]middleware.RulesToCheck{ + POST_MIDDLEWARE: { + middleware.GET: { + Rules: make([]rules.RuleFunction, 0), + MustBeCompleted: rules.ALL_RULES_MUST_BE_COMPLETED, + }, + middleware.POST: { + Rules: []rules.RuleFunction{ + globalrules.AuthorizedRule, + }, + MustBeCompleted: rules.ALL_RULES_MUST_BE_COMPLETED, + }, + middleware.PUT: { + Rules: []rules.RuleFunction{ + globalrules.AuthorizedRule, + globalrules.IsOwnerOfThePostRule, + }, + MustBeCompleted: rules.ALL_RULES_MUST_BE_COMPLETED, + }, + middleware.DELETE: { + Rules: []rules.RuleFunction{ + globalrules.AuthorizedRule, + globalrules.IsOwnerOfThePostRule, + globalrules.IsAdminRule, + }, + MustBeCompleted: 2, + }, + }, + } + + for middlewareName, rulesToCheck := range policies { + middlewareProvider.RegisterPolicy(middlewareName, rulesToCheck) + } + g.Use(middleware.CORSMiddleware()) + g.Use(middleware.TargetMiddleware()) + + testGroup := g.Group("/test/") + testGroup.Use(middlewareProvider.GetMiddleware(POST_MIDDLEWARE)) + + testGroup.GET( + "posts/:post-id", + postsRoutes.GetPost, + ) + + testGroup.GET( + "posts/random", + postsRoutes.GetRandomPost, + ) + + testGroup.PUT( + "posts/:post-id", + postsRoutes.UpdatePost, + ) + testGroup.POST( + "posts", + postsRoutes.CreatePost, + ) + testGroup.DELETE( + "posts/:post-id", + postsRoutes.DeletePost, + ) // Free group routes freeGroup := g.Group("/")