go vendor
This commit is contained in:
53
vendor/github.com/revel/modules/auth/casbin/README.md
generated
vendored
Normal file
53
vendor/github.com/revel/modules/auth/casbin/README.md
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
modules/casbin
|
||||
======
|
||||
|
||||
Casbin authz is an authorization middleware for [Revel](https://github.com/revel/revel), it's based on [https://github.com/casbin/casbin](https://github.com/casbin/casbin).
|
||||
|
||||
## Simple Example
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
|
||||
"github.com/casbin/casbin"
|
||||
"github.com/revel/revel"
|
||||
"github.com/revel/modules/auth/casbin"
|
||||
)
|
||||
|
||||
var adapter = casbinauth.NewAdapter(params)
|
||||
var enforcer = casbin.NewEnforcer("authz_model.conf", adapter)
|
||||
var casbinModule = casbinauth.NewCasbinModule(enforcer)
|
||||
|
||||
var testFilters = []revel.Filter{
|
||||
casbinModule.AuthzFilter,
|
||||
func(c *revel.Controller, fc []revel.Filter) {
|
||||
c.RenderHTML("OK.")
|
||||
},
|
||||
}
|
||||
|
||||
func main() {
|
||||
r, _ := http.NewRequest("GET", "/dataset1/resource1", nil)
|
||||
r.SetBasicAuth("alice", "123")
|
||||
w := httptest.NewRecorder()
|
||||
context := revel.NewGoContext(nil)
|
||||
context.Request.SetRequest(r)
|
||||
context.Response.SetResponse(w)
|
||||
c := revel.NewController(context)
|
||||
|
||||
testFilters[0](c, testFilters)
|
||||
}
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
The authorization determines a request based on ``{subject, object, action}``, which means what ``subject`` can perform what ``action`` on what ``object``. In this plugin, the meanings are:
|
||||
|
||||
1. ``subject``: the logged-on user name
|
||||
2. ``object``: the URL path for the web resource like "dataset1/item1"
|
||||
3. ``action``: HTTP method like GET, POST, PUT, DELETE, or the high-level actions you defined like "read-file", "write-blog"
|
||||
|
||||
|
||||
For how to write authorization policy and other details, please refer to [the Casbin's documentation](https://github.com/casbin/casbin).
|
||||
162
vendor/github.com/revel/modules/auth/casbin/adapter.go
generated
vendored
Normal file
162
vendor/github.com/revel/modules/auth/casbin/adapter.go
generated
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
package casbinauthz
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/casbin/casbin/model"
|
||||
"github.com/casbin/casbin/persist"
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/revel/modules/orm/gorm/app"
|
||||
)
|
||||
|
||||
type Line struct {
|
||||
PType string `gorm:"size:100"`
|
||||
V0 string `gorm:"size:100"`
|
||||
V1 string `gorm:"size:100"`
|
||||
V2 string `gorm:"size:100"`
|
||||
V3 string `gorm:"size:100"`
|
||||
V4 string `gorm:"size:100"`
|
||||
V5 string `gorm:"size:100"`
|
||||
}
|
||||
|
||||
// Adapter represents the Gorm adapter for policy storage.
|
||||
type Adapter struct {
|
||||
driverName string
|
||||
dataSourceName string
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
// NewAdapter is the constructor for Adapter.
|
||||
func NewAdapter(params gormdb.DbInfo) *Adapter {
|
||||
a := &Adapter{}
|
||||
gormdb.InitDBWithParameters(params)
|
||||
a.db = gormdb.DB
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *Adapter) createTable() {
|
||||
if a.db.HasTable(&Line{}) {
|
||||
return
|
||||
}
|
||||
|
||||
err := a.db.CreateTable(&Line{}).Error
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Adapter) dropTable() {
|
||||
err := a.db.DropTable(&Line{}).Error
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func loadPolicyLine(line Line, model model.Model) {
|
||||
lineText := line.PType
|
||||
if line.V0 != "" {
|
||||
lineText += ", " + line.V0
|
||||
}
|
||||
if line.V1 != "" {
|
||||
lineText += ", " + line.V1
|
||||
}
|
||||
if line.V2 != "" {
|
||||
lineText += ", " + line.V2
|
||||
}
|
||||
if line.V3 != "" {
|
||||
lineText += ", " + line.V3
|
||||
}
|
||||
if line.V4 != "" {
|
||||
lineText += ", " + line.V4
|
||||
}
|
||||
if line.V5 != "" {
|
||||
lineText += ", " + line.V5
|
||||
}
|
||||
|
||||
persist.LoadPolicyLine(lineText, model)
|
||||
}
|
||||
|
||||
// LoadPolicy loads policy from database.
|
||||
func (a *Adapter) LoadPolicy(model model.Model) error {
|
||||
var lines []Line
|
||||
err := a.db.Find(&lines).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, line := range lines {
|
||||
loadPolicyLine(line, model)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func savePolicyLine(ptype string, rule []string) Line {
|
||||
line := Line{}
|
||||
|
||||
line.PType = ptype
|
||||
if len(rule) > 0 {
|
||||
line.V0 = rule[0]
|
||||
}
|
||||
if len(rule) > 1 {
|
||||
line.V1 = rule[1]
|
||||
}
|
||||
if len(rule) > 2 {
|
||||
line.V2 = rule[2]
|
||||
}
|
||||
if len(rule) > 3 {
|
||||
line.V3 = rule[3]
|
||||
}
|
||||
if len(rule) > 4 {
|
||||
line.V4 = rule[4]
|
||||
}
|
||||
if len(rule) > 5 {
|
||||
line.V5 = rule[5]
|
||||
}
|
||||
|
||||
return line
|
||||
}
|
||||
|
||||
// SavePolicy saves policy to database.
|
||||
func (a *Adapter) SavePolicy(model model.Model) error {
|
||||
a.dropTable()
|
||||
a.createTable()
|
||||
|
||||
for ptype, ast := range model["p"] {
|
||||
for _, rule := range ast.Policy {
|
||||
line := savePolicyLine(ptype, rule)
|
||||
err := a.db.Create(&line).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ptype, ast := range model["g"] {
|
||||
for _, rule := range ast.Policy {
|
||||
line := savePolicyLine(ptype, rule)
|
||||
err := a.db.Create(&line).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddPolicy adds a policy rule to the storage.
|
||||
func (a *Adapter) AddPolicy(sec string, ptype string, rule []string) error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
// RemovePolicy removes a policy rule from the storage.
|
||||
func (a *Adapter) RemovePolicy(sec string, ptype string, rule []string) error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
// RemoveFilteredPolicy removes policy rules that match the filter from the storage.
|
||||
func (a *Adapter) RemoveFilteredPolicy(sec string, ptype string, fieldIndex int, fieldValues ...string) error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
49
vendor/github.com/revel/modules/auth/casbin/authz.go
generated
vendored
Normal file
49
vendor/github.com/revel/modules/auth/casbin/authz.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
package casbinauthz
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/casbin/casbin"
|
||||
"github.com/revel/revel"
|
||||
)
|
||||
|
||||
type CasbinModule struct {
|
||||
enforcer *casbin.Enforcer
|
||||
}
|
||||
|
||||
func NewCasbinModule(enforcer *casbin.Enforcer) *CasbinModule {
|
||||
cm := &CasbinModule{}
|
||||
cm.enforcer = enforcer
|
||||
return cm
|
||||
}
|
||||
|
||||
// AuthzFilter enables the authorization based on Casbin.
|
||||
//
|
||||
// Usage:
|
||||
// 1) Add `casbin.AuthzFilter` to the app's filters (it must come after the authentication).
|
||||
// 2) Init the Casbin enforcer.
|
||||
func (cm *CasbinModule) AuthzFilter(c *revel.Controller, fc []revel.Filter) {
|
||||
if !CheckPermission(cm.enforcer, c.Request) {
|
||||
c.Result = c.Forbidden("Access denied by the Authz plugin.")
|
||||
return
|
||||
} else {
|
||||
fc[0](c, fc[1:])
|
||||
}
|
||||
}
|
||||
|
||||
// GetUserName gets the user name from the request.
|
||||
// Currently, only HTTP basic authentication is supported
|
||||
func GetUserName(r *revel.Request) string {
|
||||
req := r.In.GetRaw().(*http.Request)
|
||||
username, _, _ := req.BasicAuth()
|
||||
return username
|
||||
}
|
||||
|
||||
// CheckPermission checks the user/method/path combination from the request.
|
||||
// Returns true (permission granted) or false (permission forbidden)
|
||||
func CheckPermission(e *casbin.Enforcer, r *revel.Request) bool {
|
||||
user := GetUserName(r)
|
||||
method := r.Method
|
||||
path := r.URL.Path
|
||||
return e.Enforce(user, path, method)
|
||||
}
|
||||
14
vendor/github.com/revel/modules/auth/casbin/authz_model.conf
generated
vendored
Normal file
14
vendor/github.com/revel/modules/auth/casbin/authz_model.conf
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
[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 == "*")
|
||||
7
vendor/github.com/revel/modules/auth/casbin/authz_policy.csv
generated
vendored
Normal file
7
vendor/github.com/revel/modules/auth/casbin/authz_policy.csv
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
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
|
||||
|
129
vendor/github.com/revel/modules/auth/casbin/authz_test.go
generated
vendored
Normal file
129
vendor/github.com/revel/modules/auth/casbin/authz_test.go
generated
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
package casbinauthz
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/casbin/casbin"
|
||||
"github.com/casbin/casbin/util"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/revel/revel"
|
||||
"github.com/revel/modules/orm/gorm/app"
|
||||
)
|
||||
|
||||
var adapter = NewAdapter(DefaultDbParams())
|
||||
var enforcer = casbin.NewEnforcer("authz_model.conf", adapter)
|
||||
var casbinModule = NewCasbinModule(enforcer)
|
||||
|
||||
var testFilters = []revel.Filter{
|
||||
casbinModule.AuthzFilter,
|
||||
func(c *revel.Controller, fc []revel.Filter) {
|
||||
c.RenderHTML("OK.")
|
||||
},
|
||||
}
|
||||
|
||||
func DefaultDbParams() gormdb.DbInfo {
|
||||
params := gormdb.DbInfo{}
|
||||
params.DbDriver = "mysql"
|
||||
params.DbHost = "(localhost:3306)"
|
||||
params.DbUser = "root"
|
||||
params.DbPassword = ""
|
||||
params.DbName = "casbin"
|
||||
return params
|
||||
}
|
||||
|
||||
func testRequest(t *testing.T, user string, path string, method string, code int) {
|
||||
r, _ := http.NewRequest(method, path, nil)
|
||||
r.SetBasicAuth(user, "123")
|
||||
w := httptest.NewRecorder()
|
||||
context := revel.NewGoContext(nil)
|
||||
context.Request.SetRequest(r)
|
||||
context.Response.SetResponse(w)
|
||||
c := revel.NewController(context)
|
||||
|
||||
testFilters[0](c, testFilters)
|
||||
|
||||
if c.Response.Status != code {
|
||||
t.Errorf("%s, %s, %s: %d, supposed to be %d", user, path, method, c.Response.Status, code)
|
||||
}
|
||||
}
|
||||
|
||||
func testGetPolicy(t *testing.T, e *casbin.Enforcer, res [][]string) {
|
||||
myRes := e.GetPolicy()
|
||||
log.Print("Policy: ", myRes)
|
||||
|
||||
if !util.Array2DEquals(res, myRes) {
|
||||
t.Error("Policy: ", myRes, ", supposed to be ", res)
|
||||
}
|
||||
}
|
||||
|
||||
func initPolicy(t *testing.T) {
|
||||
// Because the DB is empty at first,
|
||||
// so we need to load the policy from the file adapter (.CSV) first.
|
||||
e := casbin.NewEnforcer("authz_model.conf", "authz_policy.csv")
|
||||
|
||||
a := NewAdapter(DefaultDbParams())
|
||||
// This is a trick to save the current policy to the DB.
|
||||
// We can't call e.SavePolicy() because the adapter in the enforcer is still the file adapter.
|
||||
// The current policy means the policy in the Casbin enforcer (aka in memory).
|
||||
err := a.SavePolicy(e.GetModel())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBasic(t *testing.T) {
|
||||
// Initialize some policy in DB.
|
||||
initPolicy(t)
|
||||
// Note: you don't need to look at the above code
|
||||
// if you already have a working DB with policy inside.
|
||||
|
||||
// Now the DB has policy, so we can provide a normal use case.
|
||||
|
||||
testRequest(t, "alice", "/dataset1/resource1", "GET", 200)
|
||||
testRequest(t, "alice", "/dataset1/resource1", "POST", 200)
|
||||
testRequest(t, "alice", "/dataset1/resource2", "GET", 200)
|
||||
testRequest(t, "alice", "/dataset1/resource2", "POST", 403)
|
||||
}
|
||||
|
||||
func TestPathWildcard(t *testing.T) {
|
||||
// Initialize some policy in DB.
|
||||
initPolicy(t)
|
||||
// Note: you don't need to look at the above code
|
||||
// if you already have a working DB with policy inside.
|
||||
|
||||
// Now the DB has policy, so we can provide a normal use case.
|
||||
|
||||
testRequest(t, "bob", "/dataset2/resource1", "GET", 200)
|
||||
testRequest(t, "bob", "/dataset2/resource1", "POST", 200)
|
||||
testRequest(t, "bob", "/dataset2/resource1", "DELETE", 200)
|
||||
testRequest(t, "bob", "/dataset2/resource2", "GET", 200)
|
||||
testRequest(t, "bob", "/dataset2/resource2", "POST", 403)
|
||||
testRequest(t, "bob", "/dataset2/resource2", "DELETE", 403)
|
||||
|
||||
testRequest(t, "bob", "/dataset2/folder1/item1", "GET", 403)
|
||||
testRequest(t, "bob", "/dataset2/folder1/item1", "POST", 200)
|
||||
testRequest(t, "bob", "/dataset2/folder1/item1", "DELETE", 403)
|
||||
testRequest(t, "bob", "/dataset2/folder1/item2", "GET", 403)
|
||||
testRequest(t, "bob", "/dataset2/folder1/item2", "POST", 200)
|
||||
testRequest(t, "bob", "/dataset2/folder1/item2", "DELETE", 403)
|
||||
}
|
||||
|
||||
func TestRBAC(t *testing.T) {
|
||||
// Initialize some policy in DB.
|
||||
initPolicy(t)
|
||||
// Note: you don't need to look at the above code
|
||||
// if you already have a working DB with policy inside.
|
||||
|
||||
// Now the DB has policy, so we can provide a normal use case.
|
||||
|
||||
// cathy can access all /dataset1/* resources via all methods because it has the dataset1_admin role.
|
||||
testRequest(t, "cathy", "/dataset1/item", "GET", 200)
|
||||
testRequest(t, "cathy", "/dataset1/item", "POST", 200)
|
||||
testRequest(t, "cathy", "/dataset1/item", "DELETE", 200)
|
||||
testRequest(t, "cathy", "/dataset2/item", "GET", 403)
|
||||
testRequest(t, "cathy", "/dataset2/item", "POST", 403)
|
||||
testRequest(t, "cathy", "/dataset2/item", "DELETE", 403)
|
||||
}
|
||||
Reference in New Issue
Block a user