mirror of
https://github.com/labstack/echo.git
synced 2024-11-24 08:22:21 +02:00
Moved casbin middlware to echo-contrib
Signed-off-by: Vishal Rana <vr@labstack.com>
This commit is contained in:
parent
c73dd1f54c
commit
b6a9836120
14
Gopkg.lock
generated
14
Gopkg.lock
generated
@ -1,4 +1,5 @@
|
||||
memo = "df64dab23d007c5d87035a578790e1dc311b8cd82446433a778bb3274807def7"
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/davecgh/go-spew"
|
||||
@ -58,10 +59,17 @@ memo = "df64dab23d007c5d87035a578790e1dc311b8cd82446433a778bb3274807def7"
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = ["acme","acme/autocert"]
|
||||
revision = "122d919ec1efcfb58483215da23f815853e24b81"
|
||||
revision = "e1a4589e7d3ea14a3352255d04b6f1a418845e5e"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix"]
|
||||
revision = "9ccfe848b9db8435a24c424abbc07a921adf1df5"
|
||||
revision = "b90f89a1e7a9c1f6b918820b3daa7f08488c8594"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "5f74a2a2ba5b07475ad0faa1b4c021b973ad40b2ae749e3d94e15fe839bb440e"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
45
Gopkg.toml
45
Gopkg.toml
@ -1,6 +1,13 @@
|
||||
|
||||
## Gopkg.toml example (these lines may be deleted)
|
||||
|
||||
## "metadata" defines metadata about the project that could be used by other independent
|
||||
## systems. The metadata defined here will be ignored by dep.
|
||||
# [metadata]
|
||||
# key1 = "value that convey data to other systems"
|
||||
# system1-data = "value that is used by a system"
|
||||
# system2-data = "value that is used by another system"
|
||||
|
||||
## "required" lists a set of packages (not projects) that must be included in
|
||||
## Gopkg.lock. This list is merged with the set of packages imported by the current
|
||||
## project. Use it when your project needs a package it doesn't explicitly import -
|
||||
@ -12,9 +19,10 @@
|
||||
## or in a dependency.
|
||||
# ignored = ["github.com/user/project/badpkg"]
|
||||
|
||||
## Dependencies define constraints on dependent projects. They are respected by
|
||||
## Constraints are rules for how directly imported projects
|
||||
## may be incorporated into the depgraph. They are respected by
|
||||
## dep whether coming from the Gopkg.toml of the current project or a dependency.
|
||||
# [[dependencies]]
|
||||
# [[constraint]]
|
||||
## Required: the root import path of the project being constrained.
|
||||
# name = "github.com/user/project"
|
||||
#
|
||||
@ -26,18 +34,25 @@
|
||||
#
|
||||
## Optional: an alternate location (URL or import path) for the project's source.
|
||||
# source = "https://github.com/myfork/package.git"
|
||||
#
|
||||
## "metadata" defines metadata about the dependency or override that could be used
|
||||
## by other independent systems. The metadata defined here will be ignored by dep.
|
||||
# [metadata]
|
||||
# key1 = "value that convey data to other systems"
|
||||
# system1-data = "value that is used by a system"
|
||||
# system2-data = "value that is used by another system"
|
||||
|
||||
## Overrides have the same structure as [[dependencies]], but supercede all
|
||||
## [[dependencies]] declarations from all projects. Only the current project's
|
||||
## [[overrides]] are applied.
|
||||
## Overrides have the same structure as [[constraint]], but supersede all
|
||||
## [[constraint]] declarations from all projects. Only [[override]] from
|
||||
## the current project's are applied.
|
||||
##
|
||||
## Overrides are a sledgehammer. Use them only as a last resort.
|
||||
# [[overrides]]
|
||||
# [[override]]
|
||||
## Required: the root import path of the project being constrained.
|
||||
# name = "github.com/user/project"
|
||||
#
|
||||
## Optional: specifying a version constraint override will cause all other
|
||||
## constraints on this project to be ignored; only the overriden constraint
|
||||
## constraints on this project to be ignored; only the overridden constraint
|
||||
## need be satisfied.
|
||||
## Again, only one of "branch", "version" or "revision" can be specified.
|
||||
# version = "1.0.0"
|
||||
@ -51,22 +66,22 @@
|
||||
|
||||
|
||||
|
||||
[[dependencies]]
|
||||
[[constraint]]
|
||||
name = "github.com/dgrijalva/jwt-go"
|
||||
version = "^3.0.0"
|
||||
version = "3.0.0"
|
||||
|
||||
[[dependencies]]
|
||||
[[constraint]]
|
||||
name = "github.com/labstack/gommon"
|
||||
version = ">=0.2.1, <1.0.0"
|
||||
version = "0.2.1"
|
||||
|
||||
[[dependencies]]
|
||||
[[constraint]]
|
||||
name = "github.com/stretchr/testify"
|
||||
version = "^1.1.4"
|
||||
version = "1.1.4"
|
||||
|
||||
[[dependencies]]
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/valyala/fasttemplate"
|
||||
|
||||
[[dependencies]]
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
|
@ -1,101 +0,0 @@
|
||||
// Package middleware CasbinAuth provides handlers to enable ACL, RBAC, ABAC authorization support.
|
||||
// Simple Usage:
|
||||
// package main
|
||||
//
|
||||
// import (
|
||||
// "github.com/casbin/casbin"
|
||||
// "github.com/labstack/echo"
|
||||
// "github.com/labstack/echo/middleware"
|
||||
// )
|
||||
//
|
||||
// func main() {
|
||||
// e := echo.New()
|
||||
//
|
||||
// // mediate the access for every request
|
||||
// e.Use(middleware.CasbinAuth(casbin.NewEnforcer("casbin_auth_model.conf", "casbin_auth_policy.csv")))
|
||||
//
|
||||
// e.Logger.Fatal(e.Start(":1323"))
|
||||
// }
|
||||
//
|
||||
// Advanced Usage:
|
||||
//
|
||||
// func main(){
|
||||
// ce := casbin.NewEnforcer("casbin_auth_model.conf", "")
|
||||
// ce.AddRoleForUser("alice", "admin")
|
||||
// ce.AddPolicy(...)
|
||||
//
|
||||
// e := echo.New()
|
||||
//
|
||||
// echo.Use(middleware.CasbinAuth(ce))
|
||||
//
|
||||
// e.Logger.Fatal(e.Start(":1323"))
|
||||
// }
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/casbin/casbin"
|
||||
"github.com/labstack/echo"
|
||||
)
|
||||
|
||||
type (
|
||||
// CasbinAuthConfig defines the config for CasbinAuth middleware.
|
||||
CasbinAuthConfig struct {
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
// Enforcer CasbinAuth main rule.
|
||||
// Required.
|
||||
Enforcer *casbin.Enforcer
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultCasbinAuthConfig is the default CasbinAuth middleware config.
|
||||
DefaultCasbinAuthConfig = CasbinAuthConfig{
|
||||
Skipper: DefaultSkipper,
|
||||
}
|
||||
)
|
||||
|
||||
// CasbinAuth returns an CasbinAuth middleware.
|
||||
//
|
||||
// For valid credentials it calls the next handler.
|
||||
// For missing or invalid credentials, it sends "401 - Unauthorized" response.
|
||||
func CasbinAuth(ce *casbin.Enforcer) echo.MiddlewareFunc {
|
||||
c := DefaultCasbinAuthConfig
|
||||
c.Enforcer = ce
|
||||
return CasbinAuthWithConfig(c)
|
||||
}
|
||||
|
||||
// CasbinAuthWithConfig returns an CasbinAuth middleware with config.
|
||||
// See `CasbinAuth()`.
|
||||
func CasbinAuthWithConfig(config CasbinAuthConfig) echo.MiddlewareFunc {
|
||||
// Defaults
|
||||
if config.Skipper == nil {
|
||||
config.Skipper = DefaultCasbinAuthConfig.Skipper
|
||||
}
|
||||
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
if config.Skipper(c) || config.CheckPermission(c) {
|
||||
return next(c)
|
||||
}
|
||||
|
||||
return echo.ErrForbidden
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetUserName gets the user name from the request.
|
||||
// Currently, only HTTP basic authentication is supported
|
||||
func (a *CasbinAuthConfig) GetUserName(c echo.Context) string {
|
||||
username, _, _ := c.Request().BasicAuth()
|
||||
return username
|
||||
}
|
||||
|
||||
// CheckPermission checks the user/method/path combination from the request.
|
||||
// Returns true (permission granted) or false (permission forbidden)
|
||||
func (a *CasbinAuthConfig) CheckPermission(c echo.Context) bool {
|
||||
user := a.GetUserName(c)
|
||||
method := c.Request().Method
|
||||
path := c.Request().URL.Path
|
||||
return a.Enforcer.Enforce(user, path, method)
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
[request_definition]
|
||||
r = sub, obj, act
|
||||
|
||||
[policy_definition]
|
||||
p = sub, obj, act
|
||||
|
||||
[role_definition]
|
||||
g = _, _
|
||||
|
||||
[policy_effect]
|
||||
e = some(where (p.eft == allow))
|
||||
|
||||
[matchers]
|
||||
m = g(r.sub, p.sub) && keyMatch(r.obj, p.obj) && (r.act == p.act || p.act == "*")
|
@ -1,7 +0,0 @@
|
||||
p, alice, /dataset1/*, GET
|
||||
p, alice, /dataset1/resource1, POST
|
||||
p, bob, /dataset2/resource1, *
|
||||
p, bob, /dataset2/resource2, GET
|
||||
p, bob, /dataset2/folder1/*, POST
|
||||
p, dataset1_admin, /dataset1/*, *
|
||||
g, cathy, dataset1_admin
|
|
@ -1,86 +0,0 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/casbin/casbin"
|
||||
"github.com/labstack/echo"
|
||||
)
|
||||
|
||||
func testRequest(t *testing.T, ce *casbin.Enforcer, user string, path string, method string, code int) {
|
||||
e := echo.New()
|
||||
req := httptest.NewRequest(method, path, nil)
|
||||
req.SetBasicAuth(user, "secret")
|
||||
res := httptest.NewRecorder()
|
||||
c := e.NewContext(req, res)
|
||||
h := CasbinAuth(ce)(func(c echo.Context) error {
|
||||
return c.String(http.StatusOK, "test")
|
||||
})
|
||||
|
||||
err := h(c)
|
||||
|
||||
if err != nil {
|
||||
if errObj, ok := err.(*echo.HTTPError); ok {
|
||||
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 {
|
||||
t.Errorf("%s, %s, %s: %d, supposed to be %d", user, path, method, c.Response().Status, code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCasbinAuth(t *testing.T) {
|
||||
ce := casbin.NewEnforcer("casbin_auth_model.conf", "casbin_auth_policy.csv")
|
||||
|
||||
testRequest(t, ce, "alice", "/dataset1/resource1", echo.GET, 200)
|
||||
testRequest(t, ce, "alice", "/dataset1/resource1", echo.POST, 200)
|
||||
testRequest(t, ce, "alice", "/dataset1/resource2", echo.GET, 200)
|
||||
testRequest(t, ce, "alice", "/dataset1/resource2", echo.POST, 403)
|
||||
}
|
||||
|
||||
func TestPathWildcard(t *testing.T) {
|
||||
ce := casbin.NewEnforcer("casbin_auth_model.conf", "casbin_auth_policy.csv")
|
||||
|
||||
testRequest(t, ce, "bob", "/dataset2/resource1", "GET", 200)
|
||||
testRequest(t, ce, "bob", "/dataset2/resource1", "POST", 200)
|
||||
testRequest(t, ce, "bob", "/dataset2/resource1", "DELETE", 200)
|
||||
testRequest(t, ce, "bob", "/dataset2/resource2", "GET", 200)
|
||||
testRequest(t, ce, "bob", "/dataset2/resource2", "POST", 403)
|
||||
testRequest(t, ce, "bob", "/dataset2/resource2", "DELETE", 403)
|
||||
|
||||
testRequest(t, ce, "bob", "/dataset2/folder1/item1", "GET", 403)
|
||||
testRequest(t, ce, "bob", "/dataset2/folder1/item1", "POST", 200)
|
||||
testRequest(t, ce, "bob", "/dataset2/folder1/item1", "DELETE", 403)
|
||||
testRequest(t, ce, "bob", "/dataset2/folder1/item2", "GET", 403)
|
||||
testRequest(t, ce, "bob", "/dataset2/folder1/item2", "POST", 200)
|
||||
testRequest(t, ce, "bob", "/dataset2/folder1/item2", "DELETE", 403)
|
||||
}
|
||||
|
||||
func TestRBAC(t *testing.T) {
|
||||
ce := casbin.NewEnforcer("casbin_auth_model.conf", "casbin_auth_policy.csv")
|
||||
|
||||
// cathy can access all /dataset1/* resources via all methods because it has the dataset1_admin role.
|
||||
testRequest(t, ce, "cathy", "/dataset1/item", "GET", 200)
|
||||
testRequest(t, ce, "cathy", "/dataset1/item", "POST", 200)
|
||||
testRequest(t, ce, "cathy", "/dataset1/item", "DELETE", 200)
|
||||
testRequest(t, ce, "cathy", "/dataset2/item", "GET", 403)
|
||||
testRequest(t, ce, "cathy", "/dataset2/item", "POST", 403)
|
||||
testRequest(t, ce, "cathy", "/dataset2/item", "DELETE", 403)
|
||||
|
||||
// delete all roles on user cathy, so cathy cannot access any resources now.
|
||||
ce.DeleteRolesForUser("cathy")
|
||||
|
||||
testRequest(t, ce, "cathy", "/dataset1/item", "GET", 403)
|
||||
testRequest(t, ce, "cathy", "/dataset1/item", "POST", 403)
|
||||
testRequest(t, ce, "cathy", "/dataset1/item", "DELETE", 403)
|
||||
testRequest(t, ce, "cathy", "/dataset2/item", "GET", 403)
|
||||
testRequest(t, ce, "cathy", "/dataset2/item", "POST", 403)
|
||||
testRequest(t, ce, "cathy", "/dataset2/item", "DELETE", 403)
|
||||
}
|
Loading…
Reference in New Issue
Block a user