Skip to content

Commit

Permalink
feat: improve casbin mw (#107)
Browse files Browse the repository at this point in the history
* feat: improve test readability and include README.md

---------

Co-authored-by: Luis Albarenga <luisalbarenga@Luiss-MacBook-Pro-2.local>
  • Loading branch information
laychopy and Luis Albarenga authored Dec 28, 2023
1 parent 939b0a9 commit fdc9c9a
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 38 deletions.
46 changes: 46 additions & 0 deletions casbin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Usage
Simple example:
```go
package main

import (
"github.com/casbin/casbin/v2"
"github.com/labstack/echo/v4"
casbin_mw "github.com/labstack/echo-contrib/casbin"
)

func main() {
e := echo.New()

// Mediate the access for every request
e.Use(casbin_mw.Middleware(casbin.NewEnforcer("auth_model.conf", "auth_policy.csv")))

e.Logger.Fatal(e.Start(":1323"))
}
```

Advanced example:
```go
package main

import (
"github.com/casbin/casbin/v2"
"github.com/labstack/echo/v4"
casbin_mw "github.com/labstack/echo-contrib/casbin"
)

func main() {
ce, _ := casbin.NewEnforcer("auth_model.conf", "")
ce.AddRoleForUser("alice", "admin")
ce.AddPolicy("added_user", "data1", "read")

e := echo.New()

e.Use(casbin_mw.Middleware(ce))

e.Logger.Fatal(e.Start(":1323"))
}
```

# API Reference
See [API Overview](https://casbin.org/docs/api-overview).
90 changes: 52 additions & 38 deletions casbin/casbin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,11 @@ func testRequest(t *testing.T, h echo.HandlerFunc, user string, path string, met
err := h(c)

if err != nil {
if errObj, ok := err.(*echo.HTTPError); ok {
var errObj *echo.HTTPError
if errors.As(err, &errObj) {
if errObj.Code != code {
t.Errorf("%s, %s, %s: %d, supposed to be %d", user, path, method, errObj.Code, code)
}
} else {
t.Error(err)
}
} else {
if c.Response().Status != code {
Expand All @@ -46,10 +45,10 @@ func TestAuth(t *testing.T) {
return c.String(http.StatusOK, "test")
})

testRequest(t, h, "alice", "/dataset1/resource1", echo.GET, 200)
testRequest(t, h, "alice", "/dataset1/resource1", echo.POST, 200)
testRequest(t, h, "alice", "/dataset1/resource2", echo.GET, 200)
testRequest(t, h, "alice", "/dataset1/resource2", echo.POST, 403)
testRequest(t, h, "alice", "/dataset1/resource1", echo.GET, http.StatusOK)
testRequest(t, h, "alice", "/dataset1/resource1", echo.POST, http.StatusOK)
testRequest(t, h, "alice", "/dataset1/resource2", echo.GET, http.StatusOK)
testRequest(t, h, "alice", "/dataset1/resource2", echo.POST, http.StatusForbidden)
}

func TestPathWildcard(t *testing.T) {
Expand All @@ -58,19 +57,19 @@ func TestPathWildcard(t *testing.T) {
return c.String(http.StatusOK, "test")
})

testRequest(t, h, "bob", "/dataset2/resource1", "GET", 200)
testRequest(t, h, "bob", "/dataset2/resource1", "POST", 200)
testRequest(t, h, "bob", "/dataset2/resource1", "DELETE", 200)
testRequest(t, h, "bob", "/dataset2/resource2", "GET", 200)
testRequest(t, h, "bob", "/dataset2/resource2", "POST", 403)
testRequest(t, h, "bob", "/dataset2/resource2", "DELETE", 403)

testRequest(t, h, "bob", "/dataset2/folder1/item1", "GET", 403)
testRequest(t, h, "bob", "/dataset2/folder1/item1", "POST", 200)
testRequest(t, h, "bob", "/dataset2/folder1/item1", "DELETE", 403)
testRequest(t, h, "bob", "/dataset2/folder1/item2", "GET", 403)
testRequest(t, h, "bob", "/dataset2/folder1/item2", "POST", 200)
testRequest(t, h, "bob", "/dataset2/folder1/item2", "DELETE", 403)
testRequest(t, h, "bob", "/dataset2/resource1", echo.GET, http.StatusOK)
testRequest(t, h, "bob", "/dataset2/resource1", echo.POST, http.StatusOK)
testRequest(t, h, "bob", "/dataset2/resource1", echo.DELETE, http.StatusOK)
testRequest(t, h, "bob", "/dataset2/resource2", echo.GET, http.StatusOK)
testRequest(t, h, "bob", "/dataset2/resource2", echo.POST, http.StatusForbidden)
testRequest(t, h, "bob", "/dataset2/resource2", echo.DELETE, http.StatusForbidden)

testRequest(t, h, "bob", "/dataset2/folder1/item1", echo.GET, http.StatusForbidden)
testRequest(t, h, "bob", "/dataset2/folder1/item1", echo.POST, http.StatusOK)
testRequest(t, h, "bob", "/dataset2/folder1/item1", echo.DELETE, http.StatusForbidden)
testRequest(t, h, "bob", "/dataset2/folder1/item2", echo.GET, http.StatusForbidden)
testRequest(t, h, "bob", "/dataset2/folder1/item2", echo.POST, http.StatusOK)
testRequest(t, h, "bob", "/dataset2/folder1/item2", echo.DELETE, http.StatusForbidden)
}

func TestRBAC(t *testing.T) {
Expand All @@ -80,22 +79,22 @@ func TestRBAC(t *testing.T) {
})

// cathy can access all /dataset1/* resources via all methods because it has the dataset1_admin role.
testRequest(t, h, "cathy", "/dataset1/item", "GET", 200)
testRequest(t, h, "cathy", "/dataset1/item", "POST", 200)
testRequest(t, h, "cathy", "/dataset1/item", "DELETE", 200)
testRequest(t, h, "cathy", "/dataset2/item", "GET", 403)
testRequest(t, h, "cathy", "/dataset2/item", "POST", 403)
testRequest(t, h, "cathy", "/dataset2/item", "DELETE", 403)
testRequest(t, h, "cathy", "/dataset1/item", echo.GET, http.StatusOK)
testRequest(t, h, "cathy", "/dataset1/item", echo.POST, http.StatusOK)
testRequest(t, h, "cathy", "/dataset1/item", echo.DELETE, http.StatusOK)
testRequest(t, h, "cathy", "/dataset2/item", echo.GET, http.StatusForbidden)
testRequest(t, h, "cathy", "/dataset2/item", echo.POST, http.StatusForbidden)
testRequest(t, h, "cathy", "/dataset2/item", echo.DELETE, http.StatusForbidden)

// delete all roles on user cathy, so cathy cannot access any resources now.
ce.DeleteRolesForUser("cathy")

testRequest(t, h, "cathy", "/dataset1/item", "GET", 403)
testRequest(t, h, "cathy", "/dataset1/item", "POST", 403)
testRequest(t, h, "cathy", "/dataset1/item", "DELETE", 403)
testRequest(t, h, "cathy", "/dataset2/item", "GET", 403)
testRequest(t, h, "cathy", "/dataset2/item", "POST", 403)
testRequest(t, h, "cathy", "/dataset2/item", "DELETE", 403)
testRequest(t, h, "cathy", "/dataset1/item", echo.GET, http.StatusForbidden)
testRequest(t, h, "cathy", "/dataset1/item", echo.POST, http.StatusForbidden)
testRequest(t, h, "cathy", "/dataset1/item", echo.DELETE, http.StatusForbidden)
testRequest(t, h, "cathy", "/dataset2/item", echo.GET, http.StatusForbidden)
testRequest(t, h, "cathy", "/dataset2/item", echo.POST, http.StatusForbidden)
testRequest(t, h, "cathy", "/dataset2/item", echo.DELETE, http.StatusForbidden)
}

func TestEnforceError(t *testing.T) {
Expand All @@ -104,7 +103,7 @@ func TestEnforceError(t *testing.T) {
return c.String(http.StatusOK, "test")
})

testRequest(t, h, "cathy", "/dataset1/item", "GET", 500)
testRequest(t, h, "cathy", "/dataset1/item", echo.GET, http.StatusInternalServerError)
}

func TestCustomUserGetter(t *testing.T) {
Expand All @@ -119,7 +118,7 @@ func TestCustomUserGetter(t *testing.T) {
h := MiddlewareWithConfig(cnf)(func(c echo.Context) error {
return c.String(http.StatusOK, "test")
})
testRequest(t, h, "cathy", "/dataset1/item", "GET", 403)
testRequest(t, h, "cathy", "/dataset1/item", echo.GET, http.StatusForbidden)
}

func TestUserGetterError(t *testing.T) {
Expand All @@ -134,7 +133,7 @@ func TestUserGetterError(t *testing.T) {
h := MiddlewareWithConfig(cnf)(func(c echo.Context) error {
return c.String(http.StatusOK, "test")
})
testRequest(t, h, "cathy", "/dataset1/item", "GET", 403)
testRequest(t, h, "cathy", "/dataset1/item", echo.GET, http.StatusForbidden)
}

func TestCustomEnforceHandler(t *testing.T) {
Expand All @@ -156,7 +155,22 @@ func TestCustomEnforceHandler(t *testing.T) {
h := MiddlewareWithConfig(cnf)(func(c echo.Context) error {
return c.String(http.StatusOK, "test")
})
testRequest(t, h, "bob", "/dataset2/resource1", "GET", http.StatusOK)
testRequest(t, h, "bob", "/user/alice", "PATCH", http.StatusForbidden)
testRequest(t, h, "bob", "/user/bob", "PATCH", http.StatusOK)
testRequest(t, h, "bob", "/dataset2/resource1", echo.GET, http.StatusOK)
testRequest(t, h, "bob", "/user/alice", echo.PATCH, http.StatusForbidden)
testRequest(t, h, "bob", "/user/bob", echo.PATCH, http.StatusOK)
}

func TestCustomSkipper(t *testing.T) {
ce, _ := casbin.NewEnforcer("auth_model.conf", "auth_policy.csv")
cnf := Config{
Skipper: func(c echo.Context) bool {
return c.Request().URL.Path == "/dataset1/resource1"
},
Enforcer: ce,
}
h := MiddlewareWithConfig(cnf)(func(c echo.Context) error {
return c.String(http.StatusOK, "test")
})
testRequest(t, h, "alice", "/dataset1/resource1", echo.GET, http.StatusOK)
testRequest(t, h, "alice", "/dataset1/resource2", echo.POST, http.StatusForbidden)
}

0 comments on commit fdc9c9a

Please sign in to comment.