mirror of
https://github.com/paralus/paralus.git
synced 2026-05-14 04:16:59 +00:00
Inital commit for authz server
This commit is contained in:
87
components/authz/pkg/server/abac.go
Normal file
87
components/authz/pkg/server/abac.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
type AbacAttrList struct {
|
||||
V0 string
|
||||
V1 string
|
||||
V2 string
|
||||
V3 string
|
||||
V4 string
|
||||
V5 string
|
||||
V6 string
|
||||
V7 string
|
||||
V8 string
|
||||
V9 string
|
||||
V10 string
|
||||
nameMap map[string]string
|
||||
}
|
||||
|
||||
func toUpperFirstChar(str string) string {
|
||||
for i, v := range str {
|
||||
return string(unicode.ToUpper(v)) + str[i+1:]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func MakeABAC(obj interface{}) (string, error) {
|
||||
data, err := json.Marshal(&obj)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "ABAC::" + string(data), nil
|
||||
}
|
||||
|
||||
func resolveABAC(obj string) (AbacAttrList, error) {
|
||||
var jsonMap map[string]interface{}
|
||||
attrList := AbacAttrList{nameMap: map[string]string{}}
|
||||
|
||||
err := json.Unmarshal([]byte(obj[len("ABAC::"):]), &jsonMap)
|
||||
if err != nil {
|
||||
return attrList, err
|
||||
}
|
||||
|
||||
i := 0
|
||||
for k, v := range jsonMap {
|
||||
key := toUpperFirstChar(k)
|
||||
value := fmt.Sprintf("%v", v)
|
||||
attrList.nameMap[key] = "V" + strconv.Itoa(i)
|
||||
switch i {
|
||||
case 0:
|
||||
attrList.V0 = value
|
||||
case 1:
|
||||
attrList.V1 = value
|
||||
case 2:
|
||||
attrList.V2 = value
|
||||
case 3:
|
||||
attrList.V3 = value
|
||||
case 4:
|
||||
attrList.V4 = value
|
||||
case 5:
|
||||
attrList.V5 = value
|
||||
case 6:
|
||||
attrList.V6 = value
|
||||
case 7:
|
||||
attrList.V7 = value
|
||||
case 8:
|
||||
attrList.V8 = value
|
||||
case 9:
|
||||
attrList.V9 = value
|
||||
case 10:
|
||||
attrList.V10 = value
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
return attrList, nil
|
||||
}
|
||||
|
||||
func (attr AbacAttrList) GetCacheKey() string {
|
||||
res, _ := MakeABAC(&attr)
|
||||
return res
|
||||
}
|
||||
99
components/authz/pkg/server/adapter.go
Normal file
99
components/authz/pkg/server/adapter.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
pb "github.com/RafaySystems/rcloud-base/components/authz/proto/rpc"
|
||||
"github.com/casbin/casbin/v2/persist"
|
||||
fileadapter "github.com/casbin/casbin/v2/persist/file-adapter"
|
||||
gormadapter "github.com/casbin/gorm-adapter/v2"
|
||||
//_ "github.com/jinzhu/gorm/dialects/mssql"
|
||||
//_ "github.com/jinzhu/gorm/dialects/mysql"
|
||||
//_ "github.com/jinzhu/gorm/dialects/postgres"
|
||||
)
|
||||
|
||||
var errDriverName = errors.New("currently supported DriverName: file | mysql | postgres | mssql")
|
||||
|
||||
func newAdapter(in *pb.NewAdapterRequest) (persist.Adapter, error) {
|
||||
var a persist.Adapter
|
||||
in = checkLocalConfig(in)
|
||||
supportDriverNames := [...]string{"file", "mysql", "postgres", "mssql"}
|
||||
|
||||
switch in.DriverName {
|
||||
case "file":
|
||||
a = fileadapter.NewAdapter(in.ConnectString)
|
||||
default:
|
||||
var support = false
|
||||
for _, driverName := range supportDriverNames {
|
||||
if driverName == in.DriverName {
|
||||
support = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !support {
|
||||
return nil, errDriverName
|
||||
}
|
||||
|
||||
var err error
|
||||
a, err = gormadapter.NewAdapter(in.DriverName, in.ConnectString, in.DbSpecified)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func checkLocalConfig(in *pb.NewAdapterRequest) *pb.NewAdapterRequest {
|
||||
cfg := LoadConfiguration(getLocalConfigPath())
|
||||
if in.ConnectString == "" || in.DriverName == "" {
|
||||
in.DriverName = cfg.Driver
|
||||
in.ConnectString = cfg.Connection
|
||||
in.DbSpecified = cfg.DBSpecified
|
||||
}
|
||||
return in
|
||||
}
|
||||
|
||||
const (
|
||||
configFileDefaultPath = "config/connection_config.json"
|
||||
configFilePathEnvironmentVariable = "CONNECTION_CONFIG_PATH"
|
||||
)
|
||||
|
||||
func getLocalConfigPath() string {
|
||||
configFilePath := os.Getenv(configFilePathEnvironmentVariable)
|
||||
if configFilePath == "" {
|
||||
configFilePath = configFileDefaultPath
|
||||
}
|
||||
return configFilePath
|
||||
}
|
||||
|
||||
func LoadConfiguration(file string) Config {
|
||||
//Loads a default config from adapter_config in case a custom adapter isn't provided by the client.
|
||||
//DriverName, ConnectionString, and dbSpecified can be configured in the file. Defaults to 'file' mode.
|
||||
|
||||
configFile, err := os.Open(file)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
decoder := json.NewDecoder(configFile)
|
||||
config := Config{}
|
||||
decoder.Decode(&config)
|
||||
re := regexp.MustCompile(`\$\b((\w*))\b`)
|
||||
config.Connection = re.ReplaceAllStringFunc(config.Connection, func(s string) string {
|
||||
return os.Getenv(strings.TrimPrefix(s, `$`))
|
||||
})
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Driver string
|
||||
Connection string
|
||||
Enforcer string
|
||||
DBSpecified bool
|
||||
}
|
||||
15
components/authz/pkg/server/adapter_test.go
Normal file
15
components/authz/pkg/server/adapter_test.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetLocalConfig(t *testing.T) {
|
||||
assert.Equal(t, configFileDefaultPath, getLocalConfigPath(), "read from default connection config path if environment variable is not set")
|
||||
|
||||
os.Setenv(configFilePathEnvironmentVariable, "dir/custom_path.json")
|
||||
assert.Equal(t, "dir/custom_path.json", getLocalConfigPath())
|
||||
}
|
||||
181
components/authz/pkg/server/enforcer.go
Normal file
181
components/authz/pkg/server/enforcer.go
Normal file
@@ -0,0 +1,181 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
pb "github.com/RafaySystems/rcloud-base/components/authz/proto/rpc"
|
||||
"github.com/casbin/casbin/v2"
|
||||
"github.com/casbin/casbin/v2/model"
|
||||
"github.com/casbin/casbin/v2/persist"
|
||||
)
|
||||
|
||||
// Server is used to implement proto.CasbinServer.
|
||||
type Server struct {
|
||||
enforcerMap map[int]*casbin.Enforcer
|
||||
adapterMap map[int]persist.Adapter
|
||||
}
|
||||
|
||||
func NewServer() *Server {
|
||||
s := Server{}
|
||||
|
||||
s.enforcerMap = map[int]*casbin.Enforcer{}
|
||||
s.adapterMap = map[int]persist.Adapter{}
|
||||
|
||||
return &s
|
||||
}
|
||||
|
||||
func (s *Server) getEnforcer(handle int) (*casbin.Enforcer, error) {
|
||||
if _, ok := s.enforcerMap[handle]; ok {
|
||||
return s.enforcerMap[handle], nil
|
||||
} else {
|
||||
return nil, errors.New("enforcer not found")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) getAdapter(handle int) (persist.Adapter, error) {
|
||||
if _, ok := s.adapterMap[handle]; ok {
|
||||
return s.adapterMap[handle], nil
|
||||
} else {
|
||||
return nil, errors.New("adapter not found")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) addEnforcer(e *casbin.Enforcer) int {
|
||||
cnt := len(s.enforcerMap)
|
||||
s.enforcerMap[cnt] = e
|
||||
return cnt
|
||||
}
|
||||
|
||||
func (s *Server) addAdapter(a persist.Adapter) int {
|
||||
cnt := len(s.adapterMap)
|
||||
s.adapterMap[cnt] = a
|
||||
return cnt
|
||||
}
|
||||
|
||||
func (s *Server) NewEnforcer(ctx context.Context, in *pb.NewEnforcerRequest) (*pb.NewEnforcerReply, error) {
|
||||
var a persist.Adapter
|
||||
var e *casbin.Enforcer
|
||||
|
||||
if in.AdapterHandle != -1 {
|
||||
var err error
|
||||
a, err = s.getAdapter(int(in.AdapterHandle))
|
||||
if err != nil {
|
||||
return &pb.NewEnforcerReply{Handler: 0}, err
|
||||
}
|
||||
}
|
||||
|
||||
if in.ModelText == "" {
|
||||
cfg := LoadConfiguration(getLocalConfigPath())
|
||||
data, err := ioutil.ReadFile(cfg.Enforcer)
|
||||
if err != nil {
|
||||
return &pb.NewEnforcerReply{Handler: 0}, err
|
||||
}
|
||||
in.ModelText = string(data)
|
||||
}
|
||||
|
||||
if a == nil {
|
||||
m, err := model.NewModelFromString(in.ModelText)
|
||||
if err != nil {
|
||||
return &pb.NewEnforcerReply{Handler: 0}, err
|
||||
}
|
||||
|
||||
a, err = newAdapter(&pb.NewAdapterRequest{})
|
||||
if err != nil {
|
||||
return &pb.NewEnforcerReply{Handler: 0}, err
|
||||
}
|
||||
|
||||
e, err = casbin.NewEnforcer(m, a)
|
||||
if err != nil {
|
||||
return &pb.NewEnforcerReply{Handler: 0}, err
|
||||
}
|
||||
} else {
|
||||
m, err := model.NewModelFromString(in.ModelText)
|
||||
if err != nil {
|
||||
return &pb.NewEnforcerReply{Handler: 0}, err
|
||||
}
|
||||
|
||||
e, err = casbin.NewEnforcer(m, a)
|
||||
if err != nil {
|
||||
return &pb.NewEnforcerReply{Handler: 0}, err
|
||||
}
|
||||
}
|
||||
h := s.addEnforcer(e)
|
||||
|
||||
return &pb.NewEnforcerReply{Handler: int32(h)}, nil
|
||||
}
|
||||
|
||||
func (s *Server) NewAdapter(ctx context.Context, in *pb.NewAdapterRequest) (*pb.NewAdapterReply, error) {
|
||||
a, err := newAdapter(in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
h := s.addAdapter(a)
|
||||
|
||||
return &pb.NewAdapterReply{Handler: int32(h)}, nil
|
||||
}
|
||||
|
||||
func (s *Server) parseParam(param, matcher string) (interface{}, string) {
|
||||
if strings.HasPrefix(param, "ABAC::") {
|
||||
attrList, err := resolveABAC(param)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for k, v := range attrList.nameMap {
|
||||
old := "." + k
|
||||
if strings.Contains(matcher, old) {
|
||||
matcher = strings.Replace(matcher, old, "."+v, -1)
|
||||
}
|
||||
}
|
||||
return attrList, matcher
|
||||
} else {
|
||||
return param, matcher
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) Enforce(ctx context.Context, in *pb.EnforceRequest) (*pb.BoolReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.BoolReply{Res: false}, err
|
||||
}
|
||||
var param interface{}
|
||||
params := make([]interface{}, 0, len(in.Params))
|
||||
m := e.GetModel()["m"]["m"].Value
|
||||
|
||||
for index := range in.Params {
|
||||
param, m = s.parseParam(in.Params[index], m)
|
||||
params = append(params, param)
|
||||
}
|
||||
|
||||
res, err := e.EnforceWithMatcher(m, params...)
|
||||
if err != nil {
|
||||
return &pb.BoolReply{Res: false}, err
|
||||
}
|
||||
|
||||
return &pb.BoolReply{Res: res}, nil
|
||||
}
|
||||
|
||||
func (s *Server) LoadPolicy(ctx context.Context, in *pb.EmptyRequest) (*pb.EmptyReply, error) {
|
||||
e, err := s.getEnforcer(int(in.Handler))
|
||||
if err != nil {
|
||||
return &pb.EmptyReply{}, err
|
||||
}
|
||||
|
||||
err = e.LoadPolicy()
|
||||
|
||||
return &pb.EmptyReply{}, err
|
||||
}
|
||||
|
||||
func (s *Server) SavePolicy(ctx context.Context, in *pb.EmptyRequest) (*pb.EmptyReply, error) {
|
||||
e, err := s.getEnforcer(int(in.Handler))
|
||||
if err != nil {
|
||||
return &pb.EmptyReply{}, err
|
||||
}
|
||||
|
||||
err = e.SavePolicy()
|
||||
|
||||
return &pb.EmptyReply{}, err
|
||||
}
|
||||
278
components/authz/pkg/server/management_api.go
Normal file
278
components/authz/pkg/server/management_api.go
Normal file
@@ -0,0 +1,278 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
pb "github.com/RafaySystems/rcloud-base/components/authz/proto/rpc"
|
||||
)
|
||||
|
||||
func (s *Server) wrapPlainPolicy(policy [][]string) *pb.Array2DReply {
|
||||
if len(policy) == 0 {
|
||||
return &pb.Array2DReply{}
|
||||
}
|
||||
|
||||
policyReply := &pb.Array2DReply{}
|
||||
policyReply.D2 = make([]*pb.Array2DReplyD, len(policy))
|
||||
for e := range policy {
|
||||
policyReply.D2[e] = &pb.Array2DReplyD{D1: policy[e]}
|
||||
}
|
||||
|
||||
return policyReply
|
||||
}
|
||||
|
||||
// GetAllSubjects gets the list of subjects that show up in the current policy.
|
||||
func (s *Server) GetAllSubjects(ctx context.Context, in *pb.EmptyRequest) (*pb.ArrayReply, error) {
|
||||
return s.GetAllNamedSubjects(ctx, &pb.SimpleGetRequest{EnforcerHandler: in.Handler, PType: "p"})
|
||||
}
|
||||
|
||||
// GetAllNamedSubjects gets the list of subjects that show up in the current named policy.
|
||||
func (s *Server) GetAllNamedSubjects(ctx context.Context, in *pb.SimpleGetRequest) (*pb.ArrayReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.ArrayReply{}, err
|
||||
}
|
||||
|
||||
return &pb.ArrayReply{Array: e.GetModel().GetValuesForFieldInPolicy("p", in.PType, 0)}, nil
|
||||
}
|
||||
|
||||
// GetAllObjects gets the list of objects that show up in the current policy.
|
||||
func (s *Server) GetAllObjects(ctx context.Context, in *pb.EmptyRequest) (*pb.ArrayReply, error) {
|
||||
return s.GetAllNamedObjects(ctx, &pb.SimpleGetRequest{EnforcerHandler: in.Handler, PType: "p"})
|
||||
}
|
||||
|
||||
// GetAllNamedObjects gets the list of objects that show up in the current named policy.
|
||||
func (s *Server) GetAllNamedObjects(ctx context.Context, in *pb.SimpleGetRequest) (*pb.ArrayReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.ArrayReply{}, err
|
||||
}
|
||||
|
||||
return &pb.ArrayReply{Array: e.GetModel().GetValuesForFieldInPolicy("p", in.PType, 1)}, nil
|
||||
}
|
||||
|
||||
// GetAllActions gets the list of actions that show up in the current policy.
|
||||
func (s *Server) GetAllActions(ctx context.Context, in *pb.EmptyRequest) (*pb.ArrayReply, error) {
|
||||
return s.GetAllNamedActions(ctx, &pb.SimpleGetRequest{EnforcerHandler: in.Handler, PType: "p"})
|
||||
}
|
||||
|
||||
// GetAllNamedActions gets the list of actions that show up in the current named policy.
|
||||
func (s *Server) GetAllNamedActions(ctx context.Context, in *pb.SimpleGetRequest) (*pb.ArrayReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.ArrayReply{}, err
|
||||
}
|
||||
|
||||
return &pb.ArrayReply{Array: e.GetModel().GetValuesForFieldInPolicy("p", in.PType, 2)}, nil
|
||||
}
|
||||
|
||||
// GetAllRoles gets the list of roles that show up in the current policy.
|
||||
func (s *Server) GetAllRoles(ctx context.Context, in *pb.EmptyRequest) (*pb.ArrayReply, error) {
|
||||
return s.GetAllNamedRoles(ctx, &pb.SimpleGetRequest{EnforcerHandler: in.Handler, PType: "g"})
|
||||
}
|
||||
|
||||
// GetAllNamedRoles gets the list of roles that show up in the current named policy.
|
||||
func (s *Server) GetAllNamedRoles(ctx context.Context, in *pb.SimpleGetRequest) (*pb.ArrayReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.ArrayReply{}, err
|
||||
}
|
||||
|
||||
return &pb.ArrayReply{Array: e.GetModel().GetValuesForFieldInPolicy("g", in.PType, 1)}, nil
|
||||
}
|
||||
|
||||
// GetPolicy gets all the authorization rules in the policy.
|
||||
func (s *Server) GetPolicy(ctx context.Context, in *pb.EmptyRequest) (*pb.Array2DReply, error) {
|
||||
return s.GetNamedPolicy(ctx, &pb.PolicyRequest{EnforcerHandler: in.Handler, PType: "p"})
|
||||
}
|
||||
|
||||
// GetNamedPolicy gets all the authorization rules in the named policy.
|
||||
func (s *Server) GetNamedPolicy(ctx context.Context, in *pb.PolicyRequest) (*pb.Array2DReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.Array2DReply{}, err
|
||||
}
|
||||
|
||||
return s.wrapPlainPolicy(e.GetModel().GetPolicy("p", in.PType)), nil
|
||||
}
|
||||
|
||||
// GetFilteredPolicy gets all the authorization rules in the policy, field filters can be specified.
|
||||
func (s *Server) GetFilteredPolicy(ctx context.Context, in *pb.FilteredPolicyRequest) (*pb.Array2DReply, error) {
|
||||
in.PType = "p"
|
||||
|
||||
return s.GetFilteredNamedPolicy(ctx, in)
|
||||
}
|
||||
|
||||
// GetFilteredNamedPolicy gets all the authorization rules in the named policy, field filters can be specified.
|
||||
func (s *Server) GetFilteredNamedPolicy(ctx context.Context, in *pb.FilteredPolicyRequest) (*pb.Array2DReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.Array2DReply{}, err
|
||||
}
|
||||
|
||||
return s.wrapPlainPolicy(e.GetModel().GetFilteredPolicy("p", in.PType, int(in.FieldIndex), in.FieldValues...)), nil
|
||||
}
|
||||
|
||||
// GetGroupingPolicy gets all the role inheritance rules in the policy.
|
||||
func (s *Server) GetGroupingPolicy(ctx context.Context, in *pb.EmptyRequest) (*pb.Array2DReply, error) {
|
||||
return s.GetNamedGroupingPolicy(ctx, &pb.PolicyRequest{EnforcerHandler: in.Handler, PType: "g"})
|
||||
}
|
||||
|
||||
// GetNamedGroupingPolicy gets all the role inheritance rules in the policy.
|
||||
func (s *Server) GetNamedGroupingPolicy(ctx context.Context, in *pb.PolicyRequest) (*pb.Array2DReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.Array2DReply{}, err
|
||||
}
|
||||
|
||||
return s.wrapPlainPolicy(e.GetModel().GetPolicy("g", in.PType)), nil
|
||||
}
|
||||
|
||||
// GetFilteredGroupingPolicy gets all the role inheritance rules in the policy, field filters can be specified.
|
||||
func (s *Server) GetFilteredGroupingPolicy(ctx context.Context, in *pb.FilteredPolicyRequest) (*pb.Array2DReply, error) {
|
||||
in.PType = "g"
|
||||
|
||||
return s.GetFilteredNamedGroupingPolicy(ctx, in)
|
||||
}
|
||||
|
||||
// GetFilteredNamedGroupingPolicy gets all the role inheritance rules in the policy, field filters can be specified.
|
||||
func (s *Server) GetFilteredNamedGroupingPolicy(ctx context.Context, in *pb.FilteredPolicyRequest) (*pb.Array2DReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.Array2DReply{}, err
|
||||
}
|
||||
|
||||
return s.wrapPlainPolicy(e.GetModel().GetFilteredPolicy("g", in.PType, int(in.FieldIndex), in.FieldValues...)), nil
|
||||
}
|
||||
|
||||
// HasPolicy determines whether an authorization rule exists.
|
||||
func (s *Server) HasPolicy(ctx context.Context, in *pb.PolicyRequest) (*pb.BoolReply, error) {
|
||||
return s.HasNamedPolicy(ctx, in)
|
||||
}
|
||||
|
||||
// HasNamedPolicy determines whether a named authorization rule exists.
|
||||
func (s *Server) HasNamedPolicy(ctx context.Context, in *pb.PolicyRequest) (*pb.BoolReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.BoolReply{}, err
|
||||
}
|
||||
|
||||
return &pb.BoolReply{Res: e.GetModel().HasPolicy("p", in.PType, in.Params)}, nil
|
||||
}
|
||||
|
||||
// HasGroupingPolicy determines whether a role inheritance rule exists.
|
||||
func (s *Server) HasGroupingPolicy(ctx context.Context, in *pb.PolicyRequest) (*pb.BoolReply, error) {
|
||||
in.PType = "g"
|
||||
return s.HasNamedGroupingPolicy(ctx, in)
|
||||
}
|
||||
|
||||
// HasNamedGroupingPolicy determines whether a named role inheritance rule exists.
|
||||
func (s *Server) HasNamedGroupingPolicy(ctx context.Context, in *pb.PolicyRequest) (*pb.BoolReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.BoolReply{}, err
|
||||
}
|
||||
|
||||
return &pb.BoolReply{Res: e.GetModel().HasPolicy("g", in.PType, in.Params)}, nil
|
||||
}
|
||||
|
||||
func (s *Server) AddPolicy(ctx context.Context, in *pb.PolicyRequest) (*pb.BoolReply, error) {
|
||||
in.PType = "p"
|
||||
return s.AddNamedPolicy(ctx, in)
|
||||
}
|
||||
|
||||
func (s *Server) AddNamedPolicy(ctx context.Context, in *pb.PolicyRequest) (*pb.BoolReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.BoolReply{}, err
|
||||
}
|
||||
|
||||
ruleAdded, err := e.AddNamedPolicy(in.PType, in.Params)
|
||||
return &pb.BoolReply{Res: ruleAdded}, err
|
||||
}
|
||||
|
||||
func (s *Server) RemovePolicy(ctx context.Context, in *pb.PolicyRequest) (*pb.BoolReply, error) {
|
||||
in.PType = "p"
|
||||
return s.RemoveNamedPolicy(ctx, in)
|
||||
}
|
||||
|
||||
func (s *Server) RemoveNamedPolicy(ctx context.Context, in *pb.PolicyRequest) (*pb.BoolReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.BoolReply{}, err
|
||||
}
|
||||
|
||||
ruleRemoved, err := e.RemoveNamedPolicy(in.PType, in.Params)
|
||||
return &pb.BoolReply{Res: ruleRemoved}, err
|
||||
}
|
||||
|
||||
// RemoveFilteredPolicy removes an authorization rule from the current policy, field filters can be specified.
|
||||
func (s *Server) RemoveFilteredPolicy(ctx context.Context, in *pb.FilteredPolicyRequest) (*pb.BoolReply, error) {
|
||||
in.PType = "p"
|
||||
return s.RemoveFilteredNamedPolicy(ctx, in)
|
||||
}
|
||||
|
||||
// RemoveFilteredNamedPolicy removes an authorization rule from the current named policy, field filters can be specified.
|
||||
func (s *Server) RemoveFilteredNamedPolicy(ctx context.Context, in *pb.FilteredPolicyRequest) (*pb.BoolReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.BoolReply{}, err
|
||||
}
|
||||
|
||||
ruleRemoved, err := e.RemoveFilteredNamedPolicy(in.PType, int(in.FieldIndex), in.FieldValues...)
|
||||
return &pb.BoolReply{Res: ruleRemoved}, err
|
||||
}
|
||||
|
||||
// AddGroupingPolicy adds a role inheritance rule to the current policy.
|
||||
// If the rule already exists, the function returns false and the rule will not be added.
|
||||
// Otherwise the function returns true by adding the new rule.
|
||||
func (s *Server) AddGroupingPolicy(ctx context.Context, in *pb.PolicyRequest) (*pb.BoolReply, error) {
|
||||
in.PType = "g"
|
||||
return s.AddNamedGroupingPolicy(ctx, in)
|
||||
}
|
||||
|
||||
// AddNamedGroupingPolicy adds a named role inheritance rule to the current policy.
|
||||
// If the rule already exists, the function returns false and the rule will not be added.
|
||||
// Otherwise the function returns true by adding the new rule.
|
||||
func (s *Server) AddNamedGroupingPolicy(ctx context.Context, in *pb.PolicyRequest) (*pb.BoolReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.BoolReply{}, err
|
||||
}
|
||||
|
||||
ruleAdded, err := e.AddNamedGroupingPolicy(in.PType, in.Params)
|
||||
return &pb.BoolReply{Res: ruleAdded}, err
|
||||
}
|
||||
|
||||
// RemoveGroupingPolicy removes a role inheritance rule from the current policy.
|
||||
func (s *Server) RemoveGroupingPolicy(ctx context.Context, in *pb.PolicyRequest) (*pb.BoolReply, error) {
|
||||
in.PType = "g"
|
||||
return s.RemoveNamedGroupingPolicy(ctx, in)
|
||||
}
|
||||
|
||||
// RemoveNamedGroupingPolicy removes a role inheritance rule from the current named policy.
|
||||
func (s *Server) RemoveNamedGroupingPolicy(ctx context.Context, in *pb.PolicyRequest) (*pb.BoolReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.BoolReply{}, err
|
||||
}
|
||||
|
||||
ruleRemoved, err := e.RemoveNamedGroupingPolicy(in.PType, in.Params)
|
||||
return &pb.BoolReply{Res: ruleRemoved}, err
|
||||
}
|
||||
|
||||
// RemoveFilteredGroupingPolicy removes a role inheritance rule from the current policy, field filters can be specified.
|
||||
func (s *Server) RemoveFilteredGroupingPolicy(ctx context.Context, in *pb.FilteredPolicyRequest) (*pb.BoolReply, error) {
|
||||
in.PType = "g"
|
||||
return s.RemoveFilteredNamedGroupingPolicy(ctx, in)
|
||||
}
|
||||
|
||||
// RemoveFilteredNamedGroupingPolicy removes a role inheritance rule from the current named policy, field filters can be specified.
|
||||
func (s *Server) RemoveFilteredNamedGroupingPolicy(ctx context.Context, in *pb.FilteredPolicyRequest) (*pb.BoolReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.BoolReply{}, err
|
||||
}
|
||||
|
||||
ruleRemoved, err := e.RemoveFilteredNamedGroupingPolicy(in.PType, int(in.FieldIndex), in.FieldValues...)
|
||||
return &pb.BoolReply{Res: ruleRemoved}, err
|
||||
}
|
||||
294
components/authz/pkg/server/management_api_test.go
Normal file
294
components/authz/pkg/server/management_api_test.go
Normal file
@@ -0,0 +1,294 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
pb "github.com/RafaySystems/rcloud-base/components/authz/proto/rpc"
|
||||
"github.com/casbin/casbin/v2/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func testStringList(t *testing.T, title string, f func() []string, res []string) {
|
||||
t.Helper()
|
||||
myRes := f()
|
||||
t.Log(title+": ", myRes)
|
||||
|
||||
if !util.ArrayEquals(res, myRes) {
|
||||
t.Error(title+": ", myRes, ", supposed to be ", res)
|
||||
}
|
||||
}
|
||||
|
||||
func extractFromArrayReply(reply *pb.ArrayReply) func() []string {
|
||||
return func() []string {
|
||||
return reply.Array
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetList(t *testing.T) {
|
||||
e := newTestEngine(t, "file", "../examples/rbac_policy.csv", "../examples/rbac_model.conf")
|
||||
|
||||
subjects, err := e.s.GetAllSubjects(e.ctx, &pb.EmptyRequest{Handler: e.h})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testStringList(t, "Subjects", extractFromArrayReply(subjects), []string{"alice", "bob", "data2_admin", "data3_admin", "data4_admin"})
|
||||
|
||||
objects, err := e.s.GetAllObjects(e.ctx, &pb.EmptyRequest{Handler: e.h})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testStringList(t, "Objects", extractFromArrayReply(objects), []string{"data1", "data2", "data3", "data4"})
|
||||
|
||||
actions, err := e.s.GetAllActions(e.ctx, &pb.EmptyRequest{Handler: e.h})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testStringList(t, "Actions", extractFromArrayReply(actions), []string{"read", "write", "admin"})
|
||||
|
||||
roles, err := e.s.GetAllRoles(e.ctx, &pb.EmptyRequest{Handler: e.h})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testStringList(t, "Roles", extractFromArrayReply(roles), []string{"data2_admin", "data3_admin", "data4_admin"})
|
||||
}
|
||||
|
||||
func extractFromArray2DReply(reply *pb.Array2DReply) [][]string {
|
||||
array2d := make([][]string, len(reply.D2))
|
||||
for i := 0; i < len(reply.D2); i++ {
|
||||
array2d[i] = reply.D2[i].D1
|
||||
}
|
||||
|
||||
return array2d
|
||||
}
|
||||
|
||||
func testGetPolicy(t *testing.T, e *testEngine, res [][]string) {
|
||||
t.Helper()
|
||||
req := &pb.EmptyRequest{Handler: e.h}
|
||||
reply, err := e.s.GetPolicy(e.ctx, req)
|
||||
assert.NoError(t, err)
|
||||
|
||||
myRes := extractFromArray2DReply(reply)
|
||||
t.Log("Policy: ", myRes)
|
||||
|
||||
if !util.Array2DEquals(res, myRes) {
|
||||
t.Error("Policy: ", myRes, ", supposed to be ", res)
|
||||
}
|
||||
}
|
||||
|
||||
func testGetFilteredPolicy(t *testing.T, e *testEngine, fieldIndex int, res [][]string, fieldValues ...string) {
|
||||
t.Helper()
|
||||
req := &pb.FilteredPolicyRequest{
|
||||
EnforcerHandler: e.h, FieldIndex: int32(fieldIndex), FieldValues: fieldValues}
|
||||
reply, err := e.s.GetFilteredPolicy(e.ctx, req)
|
||||
assert.NoError(t, err)
|
||||
|
||||
myRes := extractFromArray2DReply(reply)
|
||||
t.Log("Policy for ", util.ParamsToString(req.FieldValues...), ": ", myRes)
|
||||
|
||||
if !util.Array2DEquals(res, myRes) {
|
||||
t.Error("Policy for ", util.ParamsToString(req.FieldValues...), ": ", myRes, ", supposed to be ", res)
|
||||
}
|
||||
}
|
||||
|
||||
func testGetGroupingPolicy(t *testing.T, e *testEngine, res [][]string) {
|
||||
t.Helper()
|
||||
req := &pb.EmptyRequest{Handler: e.h}
|
||||
reply, err := e.s.GetGroupingPolicy(e.ctx, req)
|
||||
assert.NoError(t, err)
|
||||
|
||||
myRes := extractFromArray2DReply(reply)
|
||||
t.Log("Grouping policy: ", myRes)
|
||||
|
||||
if !util.Array2DEquals(res, myRes) {
|
||||
t.Error("Grouping policy: ", myRes, ", supposed to be ", res)
|
||||
}
|
||||
}
|
||||
|
||||
func testGetFilteredGroupingPolicy(t *testing.T, e *testEngine, fieldIndex int, res [][]string, fieldValues ...string) {
|
||||
t.Helper()
|
||||
req := &pb.FilteredPolicyRequest{
|
||||
EnforcerHandler: e.h, FieldIndex: int32(fieldIndex), FieldValues: fieldValues}
|
||||
reply, err := e.s.GetFilteredGroupingPolicy(e.ctx, req)
|
||||
assert.NoError(t, err)
|
||||
|
||||
myRes := extractFromArray2DReply(reply)
|
||||
t.Log("Grouping policy for ", util.ParamsToString(fieldValues...), ": ", myRes)
|
||||
|
||||
if !util.Array2DEquals(res, myRes) {
|
||||
t.Error("Grouping policy for ", util.ParamsToString(fieldValues...), ": ", myRes, ", supposed to be ", res)
|
||||
}
|
||||
}
|
||||
|
||||
func testHasPolicy(t *testing.T, e *testEngine, policy []string, res bool) {
|
||||
t.Helper()
|
||||
req := &pb.PolicyRequest{EnforcerHandler: e.h, PType: "p", Params: policy}
|
||||
reply, err := e.s.HasPolicy(e.ctx, req)
|
||||
assert.NoError(t, err)
|
||||
|
||||
myRes := reply.Res
|
||||
t.Log("Has policy ", util.ArrayToString(policy), ": ", myRes)
|
||||
|
||||
if res != myRes {
|
||||
t.Error("Has policy ", util.ArrayToString(policy), ": ", myRes, ", supposed to be ", res)
|
||||
}
|
||||
}
|
||||
|
||||
func testHasGroupingPolicy(t *testing.T, e *testEngine, policy []string, res bool) {
|
||||
t.Helper()
|
||||
req := &pb.PolicyRequest{EnforcerHandler: e.h, PType: "g", Params: policy}
|
||||
reply, err := e.s.HasNamedGroupingPolicy(e.ctx, req)
|
||||
assert.NoError(t, err)
|
||||
|
||||
myRes := reply.Res
|
||||
t.Log("Has grouping policy ", util.ArrayToString(policy), ": ", myRes)
|
||||
|
||||
if res != myRes {
|
||||
t.Error("Has grouping policy ", util.ArrayToString(policy), ": ", myRes, ", supposed to be ", res)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetPolicyAPI(t *testing.T) {
|
||||
e := newTestEngine(t, "file", "../examples/rbac_policy.csv", "../examples/rbac_model.conf")
|
||||
|
||||
testGetPolicy(t, e, [][]string{
|
||||
{"alice", "data1", "read"},
|
||||
{"bob", "data2", "write"},
|
||||
{"data2_admin", "data2", "read"},
|
||||
{"data2_admin", "data2", "write"},
|
||||
{"data3_admin", "data3", "admin"},
|
||||
{"data4_admin", "data4", "read"}})
|
||||
|
||||
testGetFilteredPolicy(t, e, 0, [][]string{{"alice", "data1", "read"}}, "alice")
|
||||
testGetFilteredPolicy(t, e, 0, [][]string{{"bob", "data2", "write"}}, "bob")
|
||||
testGetFilteredPolicy(t, e, 0, [][]string{{"data2_admin", "data2", "read"},
|
||||
{"data2_admin", "data2", "write"}}, "data2_admin")
|
||||
testGetFilteredPolicy(t, e, 1, [][]string{{"alice", "data1", "read"}}, "data1")
|
||||
testGetFilteredPolicy(t, e, 1, [][]string{{"bob", "data2", "write"}, {"data2_admin", "data2", "read"},
|
||||
{"data2_admin", "data2", "write"}}, "data2")
|
||||
testGetFilteredPolicy(t, e, 2, [][]string{{"alice", "data1", "read"}, {"data2_admin", "data2", "read"}, {"data4_admin", "data4", "read"}}, "read")
|
||||
testGetFilteredPolicy(t, e, 2, [][]string{{"bob", "data2", "write"}, {"data2_admin", "data2", "write"}}, "write")
|
||||
|
||||
testGetFilteredPolicy(t, e, 0, [][]string{{"data2_admin", "data2", "read"},
|
||||
{"data2_admin", "data2", "write"}}, "data2_admin", "data2")
|
||||
// Note: "" (empty string) in fieldValues means matching all values.
|
||||
testGetFilteredPolicy(t, e, 0, [][]string{{"data2_admin", "data2", "read"}}, "data2_admin", "", "read")
|
||||
testGetFilteredPolicy(t, e, 1, [][]string{{"bob", "data2", "write"},
|
||||
{"data2_admin", "data2", "write"}}, "data2", "write")
|
||||
|
||||
testHasPolicy(t, e, []string{"alice", "data1", "read"}, true)
|
||||
testHasPolicy(t, e, []string{"bob", "data2", "write"}, true)
|
||||
testHasPolicy(t, e, []string{"alice", "data2", "read"}, false)
|
||||
testHasPolicy(t, e, []string{"bob", "data3", "write"}, false)
|
||||
|
||||
testGetGroupingPolicy(t, e, [][]string{{"alice", "data2_admin"}, {"george", "data3_admin"}, {"data3_admin", "data4_admin"}})
|
||||
|
||||
testGetFilteredGroupingPolicy(t, e, 0, [][]string{{"alice", "data2_admin"}}, "alice")
|
||||
testGetFilteredGroupingPolicy(t, e, 0, [][]string{}, "bob")
|
||||
testGetFilteredGroupingPolicy(t, e, 1, [][]string{}, "data1_admin")
|
||||
testGetFilteredGroupingPolicy(t, e, 1, [][]string{{"alice", "data2_admin"}}, "data2_admin")
|
||||
// Note: "" (empty string) in fieldValues means matching all values.
|
||||
testGetFilteredGroupingPolicy(t, e, 0, [][]string{{"alice", "data2_admin"}}, "", "data2_admin")
|
||||
|
||||
testHasGroupingPolicy(t, e, []string{"alice", "data2_admin"}, true)
|
||||
testHasGroupingPolicy(t, e, []string{"bob", "data2_admin"}, false)
|
||||
}
|
||||
|
||||
func TestModifyPolicyAPI(t *testing.T) {
|
||||
e := newTestEngine(t, "file", "../examples/rbac_policy.csv", "../examples/rbac_model.conf")
|
||||
|
||||
testGetPolicy(t, e, [][]string{
|
||||
{"alice", "data1", "read"},
|
||||
{"bob", "data2", "write"},
|
||||
{"data2_admin", "data2", "read"},
|
||||
{"data2_admin", "data2", "write"},
|
||||
{"data3_admin", "data3", "admin"},
|
||||
{"data4_admin", "data4", "read"}})
|
||||
|
||||
_, err := e.s.RemovePolicy(e.ctx, &pb.PolicyRequest{EnforcerHandler: e.h, Params: []string{"alice", "data1", "read"}})
|
||||
assert.NoError(t, err)
|
||||
_, err = e.s.RemovePolicy(e.ctx, &pb.PolicyRequest{EnforcerHandler: e.h, Params: []string{"bob", "data2", "write"}})
|
||||
assert.NoError(t, err)
|
||||
_, err = e.s.RemovePolicy(e.ctx, &pb.PolicyRequest{EnforcerHandler: e.h, Params: []string{"alice", "data1", "read"}})
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = e.s.AddPolicy(e.ctx, &pb.PolicyRequest{EnforcerHandler: e.h, Params: []string{"eve", "data3", "read"}})
|
||||
assert.NoError(t, err)
|
||||
_, err = e.s.AddPolicy(e.ctx, &pb.PolicyRequest{EnforcerHandler: e.h, Params: []string{"eve", "data3", "read"}})
|
||||
assert.NoError(t, err)
|
||||
|
||||
namedPolicy := []string{"eve", "data3", "read"}
|
||||
_, err = e.s.RemovePolicy(e.ctx, &pb.PolicyRequest{EnforcerHandler: e.h, PType: "p", Params: namedPolicy})
|
||||
assert.NoError(t, err)
|
||||
_, err = e.s.AddNamedPolicy(e.ctx, &pb.PolicyRequest{EnforcerHandler: e.h, PType: "p", Params: namedPolicy})
|
||||
assert.NoError(t, err)
|
||||
|
||||
testGetPolicy(t, e, [][]string{
|
||||
{"data2_admin", "data2", "read"},
|
||||
{"data2_admin", "data2", "write"},
|
||||
{"data3_admin", "data3", "admin"},
|
||||
{"data4_admin", "data4", "read"},
|
||||
{"eve", "data3", "read"}})
|
||||
|
||||
_, err = e.s.RemoveFilteredPolicy(e.ctx, &pb.FilteredPolicyRequest{EnforcerHandler: e.h, FieldIndex: 1, FieldValues: []string{"data2"}})
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = e.s.RemoveFilteredPolicy(e.ctx, &pb.FilteredPolicyRequest{EnforcerHandler: e.h, FieldIndex: 1, FieldValues: []string{"data4"}})
|
||||
assert.NoError(t, err)
|
||||
|
||||
testGetPolicy(t, e, [][]string{{"data3_admin", "data3", "admin"}, {"eve", "data3", "read"}})
|
||||
}
|
||||
|
||||
func TestModifyGroupingPolicyAPI(t *testing.T) {
|
||||
e := newTestEngine(t, "file", "../examples/rbac_policy.csv", "../examples/rbac_model.conf")
|
||||
|
||||
testGetRoles(t, e, "alice", []string{"data2_admin"})
|
||||
testGetRoles(t, e, "bob", []string{})
|
||||
testGetRoles(t, e, "eve", []string{})
|
||||
testGetRoles(t, e, "non_exist", []string{})
|
||||
|
||||
_, err := e.s.RemoveGroupingPolicy(e.ctx,
|
||||
&pb.PolicyRequest{EnforcerHandler: e.h, Params: []string{"alice", "data2_admin"}})
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = e.s.AddGroupingPolicy(e.ctx, &pb.PolicyRequest{EnforcerHandler: e.h, Params: []string{"bob", "data1_admin"}})
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = e.s.AddGroupingPolicy(e.ctx, &pb.PolicyRequest{EnforcerHandler: e.h, Params: []string{"eve", "data3_admin"}})
|
||||
assert.NoError(t, err)
|
||||
|
||||
namedGroupingPolicy := []string{"alice", "data2_admin"}
|
||||
testGetRoles(t, e, "alice", []string{})
|
||||
|
||||
_, err = e.s.AddNamedGroupingPolicy(e.ctx,
|
||||
&pb.PolicyRequest{EnforcerHandler: e.h, PType: "g", Params: namedGroupingPolicy})
|
||||
assert.NoError(t, err)
|
||||
|
||||
testGetRoles(t, e, "alice", []string{"data2_admin"})
|
||||
|
||||
_, err = e.s.RemoveNamedGroupingPolicy(e.ctx,
|
||||
&pb.PolicyRequest{EnforcerHandler: e.h, PType: "g", Params: namedGroupingPolicy})
|
||||
assert.NoError(t, err)
|
||||
|
||||
testGetRoles(t, e, "alice", []string{})
|
||||
testGetRoles(t, e, "bob", []string{"data1_admin"})
|
||||
testGetRoles(t, e, "eve", []string{"data3_admin"})
|
||||
testGetRoles(t, e, "non_exist", []string{})
|
||||
|
||||
testGetUsers(t, e, "data1_admin", []string{"bob"})
|
||||
testGetUsers(t, e, "data2_admin", []string{})
|
||||
testGetUsers(t, e, "data3_admin", []string{"eve", "george"})
|
||||
testGetUsers(t, e, "data4_admin", []string{"data3_admin"})
|
||||
|
||||
_, err = e.s.RemoveFilteredGroupingPolicy(e.ctx,
|
||||
&pb.FilteredPolicyRequest{EnforcerHandler: e.h, FieldIndex: 0, FieldValues: []string{"bob"}})
|
||||
assert.NoError(t, err)
|
||||
|
||||
testGetRoles(t, e, "alice", []string{})
|
||||
testGetRoles(t, e, "bob", []string{})
|
||||
testGetRoles(t, e, "eve", []string{"data3_admin"})
|
||||
testGetRoles(t, e, "non_exist", []string{})
|
||||
|
||||
testGetUsers(t, e, "data1_admin", []string{})
|
||||
testGetUsers(t, e, "data2_admin", []string{})
|
||||
testGetUsers(t, e, "data3_admin", []string{"george", "eve"})
|
||||
}
|
||||
112
components/authz/pkg/server/model_test.go
Normal file
112
components/authz/pkg/server/model_test.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
pb "github.com/RafaySystems/rcloud-base/components/authz/proto/rpc"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func testEnforce(t *testing.T, e *testEngine, sub string, obj string, act string, res bool) {
|
||||
t.Helper()
|
||||
reply, err := e.s.Enforce(e.ctx, &pb.EnforceRequest{EnforcerHandler: e.h, Params: []string{sub, obj, act}})
|
||||
assert.NoError(t, err)
|
||||
|
||||
if reply.Res != res {
|
||||
t.Errorf("%s, %v, %s: %t, supposed to be %t", sub, obj, act, !res, res)
|
||||
} else {
|
||||
t.Logf("Enforce for %s, %s, %s : %v", sub, obj, act, reply.Res)
|
||||
}
|
||||
}
|
||||
|
||||
func testEnforceWithoutUsers(t *testing.T, e *testEngine, obj string, act string, res bool) {
|
||||
t.Helper()
|
||||
reply, err := e.s.Enforce(e.ctx, &pb.EnforceRequest{EnforcerHandler: e.h, Params: []string{obj, act}})
|
||||
assert.NoError(t, err)
|
||||
|
||||
if reply.Res != res {
|
||||
t.Errorf("%s, %s: %t, supposed to be %t", obj, act, !res, res)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRBACModel(t *testing.T) {
|
||||
s := NewServer()
|
||||
ctx := context.Background()
|
||||
|
||||
_, err := s.NewAdapter(ctx, &pb.NewAdapterRequest{DriverName: "file", ConnectString: "../examples/rbac_policy.csv"})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
modelText, err := ioutil.ReadFile("../examples/rbac_model.conf")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
resp, err := s.NewEnforcer(ctx, &pb.NewEnforcerRequest{ModelText: string(modelText), AdapterHandle: 0})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
e := resp.Handler
|
||||
|
||||
sub := "alice"
|
||||
obj := "data1"
|
||||
act := "read"
|
||||
res := true
|
||||
|
||||
resp2, err := s.Enforce(ctx, &pb.EnforceRequest{EnforcerHandler: e, Params: []string{sub, obj, act}})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
myRes := resp2.Res
|
||||
|
||||
if myRes != res {
|
||||
t.Errorf("%s, %s, %s: %t, supposed to be %t", sub, obj, act, myRes, res)
|
||||
}
|
||||
}
|
||||
|
||||
func TestABACModel(t *testing.T) {
|
||||
s := NewServer()
|
||||
ctx := context.Background()
|
||||
|
||||
modelText, err := ioutil.ReadFile("../examples/abac_model.conf")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
resp, err := s.NewEnforcer(ctx, &pb.NewEnforcerRequest{ModelText: string(modelText), AdapterHandle: -1})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
type ABACModel struct {
|
||||
Name string
|
||||
Owner string
|
||||
}
|
||||
e := resp.Handler
|
||||
|
||||
data1, _ := MakeABAC(ABACModel{Name: "data1", Owner: "alice"})
|
||||
data2, _ := MakeABAC(ABACModel{Name: "data2", Owner: "bob"})
|
||||
|
||||
testModel(t, s, e, "alice", data1, "read", true)
|
||||
testModel(t, s, e, "alice", data1, "write", true)
|
||||
testModel(t, s, e, "alice", data2, "read", false)
|
||||
testModel(t, s, e, "alice", data2, "write", false)
|
||||
testModel(t, s, e, "bob", data1, "read", false)
|
||||
testModel(t, s, e, "bob", data1, "write", false)
|
||||
testModel(t, s, e, "bob", data2, "read", true)
|
||||
testModel(t, s, e, "bob", data2, "write", true)
|
||||
|
||||
}
|
||||
|
||||
func testModel(t *testing.T, s *Server, enforcerHandler int32, sub string, obj string, act string, res bool) {
|
||||
t.Helper()
|
||||
|
||||
reply, err := s.Enforce(nil, &pb.EnforceRequest{EnforcerHandler: enforcerHandler, Params: []string{sub, obj, act}})
|
||||
assert.NoError(t, err)
|
||||
|
||||
if reply.Res != res {
|
||||
t.Errorf("%s, %v, %s: %t, supposed to be %t", sub, obj, act, !res, res)
|
||||
}
|
||||
}
|
||||
209
components/authz/pkg/server/rbac_api.go
Normal file
209
components/authz/pkg/server/rbac_api.go
Normal file
@@ -0,0 +1,209 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
pb "github.com/RafaySystems/rcloud-base/components/authz/proto/rpc"
|
||||
)
|
||||
|
||||
// GetRolesForUser gets the roles that a user has.
|
||||
func (s *Server) GetRolesForUser(ctx context.Context, in *pb.UserRoleRequest) (*pb.ArrayReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.ArrayReply{}, err
|
||||
}
|
||||
|
||||
res, _ := e.GetModel()["g"]["g"].RM.GetRoles(in.User)
|
||||
|
||||
return &pb.ArrayReply{Array: res}, nil
|
||||
}
|
||||
|
||||
// GetImplicitPermissionsForUser gets all permissions(including children) for a user or role.
|
||||
func (s *Server) GetImplicitRolesForUser(ctx context.Context, in *pb.UserRoleRequest) (*pb.ArrayReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.ArrayReply{}, err
|
||||
}
|
||||
res, err := e.GetImplicitRolesForUser(in.User)
|
||||
return &pb.ArrayReply{Array: res}, err
|
||||
}
|
||||
|
||||
// GetUsersForRole gets the users that has a role.
|
||||
func (s *Server) GetUsersForRole(ctx context.Context, in *pb.UserRoleRequest) (*pb.ArrayReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.ArrayReply{}, err
|
||||
}
|
||||
|
||||
res, _ := e.GetModel()["g"]["g"].RM.GetUsers(in.Role)
|
||||
|
||||
return &pb.ArrayReply{Array: res}, nil
|
||||
}
|
||||
|
||||
// HasRoleForUser determines whether a user has a role.
|
||||
func (s *Server) HasRoleForUser(ctx context.Context, in *pb.UserRoleRequest) (*pb.BoolReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.BoolReply{}, err
|
||||
}
|
||||
|
||||
roles, err := e.GetRolesForUser(in.User)
|
||||
if err != nil {
|
||||
return &pb.BoolReply{}, err
|
||||
}
|
||||
|
||||
for _, r := range roles {
|
||||
if r == in.Role {
|
||||
return &pb.BoolReply{Res: true}, nil
|
||||
}
|
||||
}
|
||||
|
||||
return &pb.BoolReply{}, nil
|
||||
}
|
||||
|
||||
// AddRoleForUser adds a role for a user.
|
||||
// Returns false if the user already has the role (aka not affected).
|
||||
func (s *Server) AddRoleForUser(ctx context.Context, in *pb.UserRoleRequest) (*pb.BoolReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.BoolReply{}, err
|
||||
}
|
||||
|
||||
ruleAdded, err := e.AddGroupingPolicy(in.User, in.Role)
|
||||
return &pb.BoolReply{Res: ruleAdded}, err
|
||||
}
|
||||
|
||||
// DeleteRoleForUser deletes a role for a user.
|
||||
// Returns false if the user does not have the role (aka not affected).
|
||||
func (s *Server) DeleteRoleForUser(ctx context.Context, in *pb.UserRoleRequest) (*pb.BoolReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.BoolReply{}, err
|
||||
}
|
||||
|
||||
ruleRemoved, err := e.RemoveGroupingPolicy(in.User, in.Role)
|
||||
return &pb.BoolReply{Res: ruleRemoved}, err
|
||||
}
|
||||
|
||||
// DeleteRolesForUser deletes all roles for a user.
|
||||
// Returns false if the user does not have any roles (aka not affected).
|
||||
func (s *Server) DeleteRolesForUser(ctx context.Context, in *pb.UserRoleRequest) (*pb.BoolReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.BoolReply{}, err
|
||||
}
|
||||
|
||||
ruleRemoved, err := e.RemoveFilteredGroupingPolicy(0, in.User)
|
||||
return &pb.BoolReply{Res: ruleRemoved}, err
|
||||
}
|
||||
|
||||
// DeleteUser deletes a user.
|
||||
// Returns false if the user does not exist (aka not affected).
|
||||
func (s *Server) DeleteUser(ctx context.Context, in *pb.UserRoleRequest) (*pb.BoolReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.BoolReply{}, err
|
||||
}
|
||||
|
||||
ruleRemoved, err := e.RemoveFilteredGroupingPolicy(0, in.User)
|
||||
return &pb.BoolReply{Res: ruleRemoved}, err
|
||||
}
|
||||
|
||||
// DeleteRole deletes a role.
|
||||
func (s *Server) DeleteRole(ctx context.Context, in *pb.UserRoleRequest) (*pb.EmptyReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.EmptyReply{}, err
|
||||
}
|
||||
|
||||
_, err = e.DeleteRole(in.Role)
|
||||
return &pb.EmptyReply{}, err
|
||||
}
|
||||
|
||||
// DeletePermission deletes a permission.
|
||||
// Returns false if the permission does not exist (aka not affected).
|
||||
func (s *Server) DeletePermission(ctx context.Context, in *pb.PermissionRequest) (*pb.BoolReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.BoolReply{}, err
|
||||
}
|
||||
|
||||
ruleRemoved, err := e.RemoveFilteredPolicy(1, in.Permissions...)
|
||||
return &pb.BoolReply{Res: ruleRemoved}, err
|
||||
}
|
||||
|
||||
// AddPermissionForUser adds a permission for a user or role.
|
||||
// Returns false if the user or role already has the permission (aka not affected).
|
||||
func (s *Server) AddPermissionForUser(ctx context.Context, in *pb.PermissionRequest) (*pb.BoolReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.BoolReply{}, err
|
||||
}
|
||||
|
||||
ruleAdded, err := e.AddPolicy(s.convertPermissions(in.User, in.Permissions...)...)
|
||||
return &pb.BoolReply{Res: ruleAdded}, err
|
||||
}
|
||||
|
||||
// DeletePermissionForUser deletes a permission for a user or role.
|
||||
// Returns false if the user or role does not have the permission (aka not affected).
|
||||
func (s *Server) DeletePermissionForUser(ctx context.Context, in *pb.PermissionRequest) (*pb.BoolReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.BoolReply{}, err
|
||||
}
|
||||
|
||||
ruleRemoved, err := e.RemovePolicy(s.convertPermissions(in.User, in.Permissions...)...)
|
||||
return &pb.BoolReply{Res: ruleRemoved}, err
|
||||
}
|
||||
|
||||
// DeletePermissionsForUser deletes permissions for a user or role.
|
||||
// Returns false if the user or role does not have any permissions (aka not affected).
|
||||
func (s *Server) DeletePermissionsForUser(ctx context.Context, in *pb.PermissionRequest) (*pb.BoolReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.BoolReply{}, err
|
||||
}
|
||||
|
||||
ruleRemoved, err := e.RemoveFilteredPolicy(0, in.User)
|
||||
return &pb.BoolReply{Res: ruleRemoved}, err
|
||||
}
|
||||
|
||||
// GetPermissionsForUser gets permissions for a user or role.
|
||||
func (s *Server) GetPermissionsForUser(ctx context.Context, in *pb.PermissionRequest) (*pb.Array2DReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.Array2DReply{}, err
|
||||
}
|
||||
|
||||
return s.wrapPlainPolicy(e.GetFilteredPolicy(0, in.User)), nil
|
||||
}
|
||||
|
||||
// GetImplicitPermissionsForUser gets all permissions(including children) for a user or role.
|
||||
func (s *Server) GetImplicitPermissionsForUser(ctx context.Context, in *pb.PermissionRequest) (*pb.Array2DReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.Array2DReply{}, err
|
||||
}
|
||||
resp, err := e.GetImplicitPermissionsForUser(in.User)
|
||||
return s.wrapPlainPolicy(resp), err
|
||||
}
|
||||
|
||||
// HasPermissionForUser determines whether a user has a permission.
|
||||
func (s *Server) HasPermissionForUser(ctx context.Context, in *pb.PermissionRequest) (*pb.BoolReply, error) {
|
||||
e, err := s.getEnforcer(int(in.EnforcerHandler))
|
||||
if err != nil {
|
||||
return &pb.BoolReply{}, err
|
||||
}
|
||||
|
||||
return &pb.BoolReply{Res: e.HasPolicy(s.convertPermissions(in.User, in.Permissions...)...)}, nil
|
||||
}
|
||||
|
||||
func (s *Server) convertPermissions(user string, permissions ...string) []interface{} {
|
||||
params := make([]interface{}, 0, len(permissions)+1)
|
||||
params = append(params, user)
|
||||
for _, perm := range permissions {
|
||||
params = append(params, perm)
|
||||
}
|
||||
|
||||
return params
|
||||
}
|
||||
227
components/authz/pkg/server/rbac_api_test.go
Normal file
227
components/authz/pkg/server/rbac_api_test.go
Normal file
@@ -0,0 +1,227 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
pb "github.com/RafaySystems/rcloud-base/components/authz/proto/rpc"
|
||||
"github.com/casbin/casbin/v2/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func testGetRoles(t *testing.T, e *testEngine, name string, res []string) {
|
||||
t.Helper()
|
||||
reply, err := e.s.GetRolesForUser(e.ctx, &pb.UserRoleRequest{EnforcerHandler: e.h, User: name})
|
||||
assert.NoError(t, err)
|
||||
|
||||
t.Log("Roles for ", name, ": ", reply.Array)
|
||||
|
||||
if !util.SetEquals(res, reply.Array) {
|
||||
t.Error("Roles for ", name, ": ", reply.Array, ", supposed to be ", res)
|
||||
}
|
||||
}
|
||||
|
||||
func testGetImplicitRoles(t *testing.T, e *testEngine, name string, res []string) {
|
||||
t.Helper()
|
||||
reply, err := e.s.GetImplicitRolesForUser(e.ctx, &pb.UserRoleRequest{EnforcerHandler: e.h, User: name})
|
||||
assert.NoError(t, err)
|
||||
|
||||
t.Log("Implicit Roles for ", name, ": ", reply.Array)
|
||||
|
||||
if !util.SetEquals(res, reply.Array) {
|
||||
t.Error("Implicit Roles for ", name, ": ", reply.Array, ", supposed to be ", res)
|
||||
}
|
||||
}
|
||||
|
||||
func testGetUsers(t *testing.T, e *testEngine, name string, res []string) {
|
||||
t.Helper()
|
||||
reply, err := e.s.GetUsersForRole(e.ctx, &pb.UserRoleRequest{EnforcerHandler: e.h, User: name})
|
||||
assert.NoError(t, err)
|
||||
|
||||
t.Log("Users for ", name, ": ", reply.Array)
|
||||
|
||||
if !util.SetEquals(res, reply.Array) {
|
||||
t.Error("Users for ", name, ": ", reply.Array, ", supposed to be ", res)
|
||||
}
|
||||
}
|
||||
|
||||
func testHasRole(t *testing.T, e *testEngine, name string, role string, res bool) {
|
||||
t.Helper()
|
||||
reply, err := e.s.HasRoleForUser(e.ctx, &pb.UserRoleRequest{EnforcerHandler: e.h, User: name, Role: role})
|
||||
assert.NoError(t, err)
|
||||
|
||||
t.Log(name, " has role ", role, ": ", reply.Res)
|
||||
|
||||
if res != reply.Res {
|
||||
t.Error(name, " has role ", role, ": ", reply.Res, ", supposed to be ", res)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoleAPI(t *testing.T) {
|
||||
e := newTestEngine(t, "file", "../examples/rbac_policy.csv", "../examples/rbac_model.conf")
|
||||
|
||||
testGetRoles(t, e, "alice", []string{"data2_admin"})
|
||||
testGetRoles(t, e, "bob", []string{})
|
||||
testGetRoles(t, e, "data2_admin", []string{})
|
||||
testGetRoles(t, e, "non_exist", []string{})
|
||||
|
||||
testHasRole(t, e, "alice", "data1_admin", false)
|
||||
testHasRole(t, e, "alice", "data2_admin", true)
|
||||
|
||||
_, err := e.s.AddRoleForUser(e.ctx, &pb.UserRoleRequest{EnforcerHandler: e.h, User: "alice", Role: "data1_admin"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
testGetRoles(t, e, "alice", []string{"data1_admin", "data2_admin"})
|
||||
testGetRoles(t, e, "bob", []string{})
|
||||
testGetRoles(t, e, "data2_admin", []string{})
|
||||
|
||||
_, err = e.s.DeleteRoleForUser(e.ctx, &pb.UserRoleRequest{EnforcerHandler: e.h, User: "alice", Role: "data1_admin"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
testGetRoles(t, e, "alice", []string{"data2_admin"})
|
||||
testGetRoles(t, e, "bob", []string{})
|
||||
testGetRoles(t, e, "data2_admin", []string{})
|
||||
|
||||
testGetImplicitRoles(t, e, "alice", []string{"data2_admin"})
|
||||
testGetImplicitRoles(t, e, "bob", []string{})
|
||||
testGetImplicitRoles(t, e, "george", []string{"data3_admin", "data4_admin"})
|
||||
|
||||
_, err = e.s.DeleteRolesForUser(e.ctx, &pb.UserRoleRequest{EnforcerHandler: e.h, User: "alice"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
testGetRoles(t, e, "alice", []string{})
|
||||
testGetRoles(t, e, "bob", []string{})
|
||||
testGetRoles(t, e, "data2_admin", []string{})
|
||||
|
||||
_, err = e.s.AddRoleForUser(e.ctx, &pb.UserRoleRequest{EnforcerHandler: e.h, User: "alice", Role: "data1_admin"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = e.s.DeleteUser(e.ctx, &pb.UserRoleRequest{EnforcerHandler: e.h, User: "alice"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
testGetRoles(t, e, "alice", []string{})
|
||||
testGetRoles(t, e, "bob", []string{})
|
||||
testGetRoles(t, e, "data2_admin", []string{})
|
||||
|
||||
_, err = e.s.AddRoleForUser(e.ctx, &pb.UserRoleRequest{EnforcerHandler: e.h, User: "alice", Role: "data2_admin"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
testEnforce(t, e, "alice", "data1", "read", true)
|
||||
testEnforce(t, e, "alice", "data1", "write", false)
|
||||
testEnforce(t, e, "alice", "data2", "read", true)
|
||||
testEnforce(t, e, "alice", "data2", "write", true)
|
||||
testEnforce(t, e, "bob", "data1", "read", false)
|
||||
testEnforce(t, e, "bob", "data1", "write", false)
|
||||
testEnforce(t, e, "bob", "data2", "read", false)
|
||||
testEnforce(t, e, "bob", "data2", "write", true)
|
||||
testEnforce(t, e, "bob", "data4", "read", false)
|
||||
testEnforce(t, e, "george", "data4", "write", false)
|
||||
testEnforce(t, e, "george", "data4", "read", true)
|
||||
|
||||
_, err = e.s.DeleteRole(e.ctx, &pb.UserRoleRequest{EnforcerHandler: e.h, Role: "data2_admin"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
testEnforce(t, e, "alice", "data1", "read", true)
|
||||
testEnforce(t, e, "alice", "data1", "write", false)
|
||||
testEnforce(t, e, "alice", "data2", "read", false)
|
||||
testEnforce(t, e, "alice", "data2", "write", false)
|
||||
testEnforce(t, e, "bob", "data1", "read", false)
|
||||
testEnforce(t, e, "bob", "data1", "write", false)
|
||||
testEnforce(t, e, "bob", "data2", "read", false)
|
||||
testEnforce(t, e, "bob", "data2", "write", true)
|
||||
|
||||
testGetPermissions(t, e, "alice", [][]string{{"alice", "data1", "read"}}) //Added these in this class as it's part of RBAC.
|
||||
testGetPermissions(t, e, "bob", [][]string{{"bob", "data2", "write"}})
|
||||
testGetPermissions(t, e, "george", [][]string{})
|
||||
testGetPermissions(t, e, "data3_admin", [][]string{{"data3_admin", "data3", "admin"}})
|
||||
|
||||
testGetImplicitPermissions(t, e, "bob", [][]string{{"bob", "data2", "write"}})
|
||||
testGetImplicitPermissions(t, e, "data3_admin", [][]string{{"data3_admin", "data3", "admin"}, {"data4_admin", "data4", "read"}})
|
||||
}
|
||||
|
||||
func testGetPermissions(t *testing.T, e *testEngine, name string, res [][]string) {
|
||||
t.Helper()
|
||||
reply, err := e.s.GetPermissionsForUser(e.ctx, &pb.PermissionRequest{EnforcerHandler: e.h, User: name})
|
||||
assert.NoError(t, err)
|
||||
|
||||
myRes := extractFromArray2DReply(reply)
|
||||
t.Log("Permissions for ", name, ": ", myRes)
|
||||
|
||||
if !util.Array2DEquals(res, myRes) {
|
||||
t.Error("Permissions for ", name, ": ", myRes, ", supposed to be ", res)
|
||||
}
|
||||
}
|
||||
|
||||
func testGetImplicitPermissions(t *testing.T, e *testEngine, name string, res [][]string) {
|
||||
t.Helper()
|
||||
reply, err := e.s.GetImplicitPermissionsForUser(e.ctx, &pb.PermissionRequest{EnforcerHandler: e.h, User: name})
|
||||
assert.NoError(t, err)
|
||||
|
||||
myRes := extractFromArray2DReply(reply)
|
||||
t.Log("Implicit Permissions for ", name, ": ", myRes)
|
||||
|
||||
if !util.Array2DEquals(res, myRes) {
|
||||
t.Error("Implicit Permissions for ", name, ": ", myRes, ", supposed to be ", res)
|
||||
}
|
||||
}
|
||||
|
||||
func testHasPermission(t *testing.T, e *testEngine, name string, permission []string, res bool) {
|
||||
t.Helper()
|
||||
reply, err := e.s.HasPermissionForUser(e.ctx, &pb.PermissionRequest{EnforcerHandler: e.h, User: name, Permissions: permission})
|
||||
assert.NoError(t, err)
|
||||
|
||||
t.Log(name, " has permission ", util.ArrayToString(permission), ": ", reply.Res)
|
||||
|
||||
if res != reply.Res {
|
||||
t.Error(name, " has permission ", util.ArrayToString(permission), ": ", reply.Res, ", supposed to be ", res)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPermissionAPI(t *testing.T) {
|
||||
e := newTestEngine(t, "file", "../examples/basic_without_resources_policy.csv",
|
||||
"../examples/basic_without_resources_model.conf")
|
||||
|
||||
testEnforceWithoutUsers(t, e, "alice", "read", true)
|
||||
testEnforceWithoutUsers(t, e, "alice", "write", false)
|
||||
testEnforceWithoutUsers(t, e, "bob", "read", false)
|
||||
testEnforceWithoutUsers(t, e, "bob", "write", true)
|
||||
|
||||
testGetPermissions(t, e, "alice", [][]string{{"alice", "read"}})
|
||||
testGetPermissions(t, e, "bob", [][]string{{"bob", "write"}})
|
||||
|
||||
testHasPermission(t, e, "alice", []string{"read"}, true)
|
||||
testHasPermission(t, e, "alice", []string{"write"}, false)
|
||||
testHasPermission(t, e, "bob", []string{"read"}, false)
|
||||
testHasPermission(t, e, "bob", []string{"write"}, true)
|
||||
|
||||
_, err := e.s.DeletePermission(e.ctx, &pb.PermissionRequest{EnforcerHandler: e.h, Permissions: []string{"read"}})
|
||||
assert.NoError(t, err)
|
||||
|
||||
testEnforceWithoutUsers(t, e, "alice", "read", false)
|
||||
testEnforceWithoutUsers(t, e, "alice", "write", false)
|
||||
testEnforceWithoutUsers(t, e, "bob", "read", false)
|
||||
testEnforceWithoutUsers(t, e, "bob", "write", true)
|
||||
|
||||
_, err = e.s.AddPermissionForUser(e.ctx, &pb.PermissionRequest{EnforcerHandler: e.h, User: "bob", Permissions: []string{"read"}})
|
||||
assert.NoError(t, err)
|
||||
|
||||
testEnforceWithoutUsers(t, e, "alice", "read", false)
|
||||
testEnforceWithoutUsers(t, e, "alice", "write", false)
|
||||
testEnforceWithoutUsers(t, e, "bob", "read", true)
|
||||
testEnforceWithoutUsers(t, e, "bob", "write", true)
|
||||
|
||||
_, err = e.s.DeletePermissionForUser(e.ctx, &pb.PermissionRequest{EnforcerHandler: e.h, User: "bob", Permissions: []string{"read"}})
|
||||
assert.NoError(t, err)
|
||||
|
||||
testEnforceWithoutUsers(t, e, "alice", "read", false)
|
||||
testEnforceWithoutUsers(t, e, "alice", "write", false)
|
||||
testEnforceWithoutUsers(t, e, "bob", "read", false)
|
||||
testEnforceWithoutUsers(t, e, "bob", "write", true)
|
||||
|
||||
_, err = e.s.DeletePermissionsForUser(e.ctx, &pb.PermissionRequest{EnforcerHandler: e.h, User: "bob"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
testEnforceWithoutUsers(t, e, "alice", "read", false)
|
||||
testEnforceWithoutUsers(t, e, "alice", "write", false)
|
||||
testEnforceWithoutUsers(t, e, "bob", "read", false)
|
||||
testEnforceWithoutUsers(t, e, "bob", "write", false)
|
||||
}
|
||||
37
components/authz/pkg/server/test_util.go
Normal file
37
components/authz/pkg/server/test_util.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
pb "github.com/RafaySystems/rcloud-base/components/authz/proto/rpc"
|
||||
)
|
||||
|
||||
type testEngine struct {
|
||||
s *Server
|
||||
ctx context.Context
|
||||
h int32
|
||||
}
|
||||
|
||||
func newTestEngine(t *testing.T, from, connectStr string, modelLoc string) *testEngine {
|
||||
s := NewServer()
|
||||
ctx := context.Background()
|
||||
|
||||
_, err := s.NewAdapter(ctx, &pb.NewAdapterRequest{DriverName: from, ConnectString: connectStr})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
modelText, err := ioutil.ReadFile(modelLoc)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
resp, err := s.NewEnforcer(ctx, &pb.NewEnforcerRequest{ModelText: string(modelText), AdapterHandle: 0})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return &testEngine{s: s, ctx: ctx, h: resp.Handler}
|
||||
}
|
||||
1661
components/authz/proto/rpc/authz.pb.go
Normal file
1661
components/authz/proto/rpc/authz.pb.go
Normal file
File diff suppressed because it is too large
Load Diff
146
components/authz/proto/rpc/authz.proto
Normal file
146
components/authz/proto/rpc/authz.proto
Normal file
@@ -0,0 +1,146 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package rafay.dev.rpc.authz;
|
||||
|
||||
service Authz {
|
||||
rpc NewEnforcer (NewEnforcerRequest) returns (NewEnforcerReply) {}
|
||||
rpc NewAdapter (NewAdapterRequest) returns (NewAdapterReply) {}
|
||||
|
||||
rpc Enforce (EnforceRequest) returns (BoolReply) {}
|
||||
|
||||
rpc LoadPolicy (EmptyRequest) returns (EmptyReply) {}
|
||||
rpc SavePolicy (EmptyRequest) returns (EmptyReply) {}
|
||||
|
||||
rpc AddPolicy (PolicyRequest) returns (BoolReply) {}
|
||||
rpc AddNamedPolicy (PolicyRequest) returns (BoolReply) {}
|
||||
rpc RemovePolicy (PolicyRequest) returns (BoolReply) {}
|
||||
rpc RemoveNamedPolicy (PolicyRequest) returns (BoolReply) {}
|
||||
rpc RemoveFilteredPolicy (FilteredPolicyRequest) returns (BoolReply) {}
|
||||
rpc RemoveFilteredNamedPolicy (FilteredPolicyRequest) returns (BoolReply) {}
|
||||
rpc GetPolicy (EmptyRequest) returns (Array2DReply) {}
|
||||
rpc GetNamedPolicy (PolicyRequest) returns (Array2DReply) {}
|
||||
rpc GetFilteredPolicy (FilteredPolicyRequest) returns (Array2DReply) {}
|
||||
rpc GetFilteredNamedPolicy (FilteredPolicyRequest) returns (Array2DReply) {}
|
||||
|
||||
rpc AddGroupingPolicy (PolicyRequest) returns (BoolReply) {}
|
||||
rpc AddNamedGroupingPolicy (PolicyRequest) returns (BoolReply) {}
|
||||
rpc RemoveGroupingPolicy (PolicyRequest) returns (BoolReply) {}
|
||||
rpc RemoveNamedGroupingPolicy (PolicyRequest) returns (BoolReply) {}
|
||||
rpc RemoveFilteredGroupingPolicy (FilteredPolicyRequest) returns (BoolReply) {}
|
||||
rpc RemoveFilteredNamedGroupingPolicy (FilteredPolicyRequest) returns (BoolReply) {}
|
||||
rpc GetGroupingPolicy (EmptyRequest) returns (Array2DReply) {}
|
||||
rpc GetNamedGroupingPolicy(PolicyRequest) returns (Array2DReply) {}
|
||||
rpc GetFilteredGroupingPolicy (FilteredPolicyRequest) returns (Array2DReply) {}
|
||||
rpc GetFilteredNamedGroupingPolicy (FilteredPolicyRequest) returns (Array2DReply) {}
|
||||
|
||||
rpc GetAllSubjects (EmptyRequest) returns (ArrayReply) {}
|
||||
rpc GetAllNamedSubjects (SimpleGetRequest) returns (ArrayReply) {}
|
||||
rpc GetAllObjects (EmptyRequest) returns (ArrayReply) {}
|
||||
rpc GetAllNamedObjects (SimpleGetRequest) returns (ArrayReply) {}
|
||||
rpc GetAllActions (EmptyRequest) returns (ArrayReply) {}
|
||||
rpc GetAllNamedActions (SimpleGetRequest) returns (ArrayReply) {}
|
||||
rpc GetAllRoles (EmptyRequest) returns (ArrayReply) {}
|
||||
rpc GetAllNamedRoles (SimpleGetRequest) returns (ArrayReply) {}
|
||||
|
||||
rpc HasPolicy (PolicyRequest) returns (BoolReply) {}
|
||||
rpc HasNamedPolicy (PolicyRequest) returns (BoolReply) {}
|
||||
rpc HasGroupingPolicy (PolicyRequest) returns (BoolReply) {}
|
||||
rpc HasNamedGroupingPolicy (PolicyRequest) returns (BoolReply) {}
|
||||
|
||||
rpc GetRolesForUser (UserRoleRequest) returns (ArrayReply) {}
|
||||
rpc GetImplicitRolesForUser (UserRoleRequest) returns (ArrayReply) {}
|
||||
rpc GetUsersForRole (UserRoleRequest) returns (ArrayReply) {}
|
||||
rpc HasRoleForUser (UserRoleRequest) returns (BoolReply) {}
|
||||
rpc AddRoleForUser (UserRoleRequest) returns (BoolReply) {}
|
||||
rpc DeleteRoleForUser (UserRoleRequest) returns (BoolReply) {}
|
||||
rpc DeleteRolesForUser (UserRoleRequest) returns (BoolReply) {}
|
||||
rpc DeleteUser (UserRoleRequest) returns (BoolReply) {}
|
||||
rpc DeleteRole (UserRoleRequest) returns (EmptyReply) {}
|
||||
|
||||
rpc GetPermissionsForUser (PermissionRequest) returns (Array2DReply) {}
|
||||
rpc GetImplicitPermissionsForUser (PermissionRequest) returns (Array2DReply) {}
|
||||
rpc DeletePermission (PermissionRequest) returns (BoolReply) {}
|
||||
rpc AddPermissionForUser (PermissionRequest) returns (BoolReply) {}
|
||||
rpc DeletePermissionForUser (PermissionRequest) returns (BoolReply) {}
|
||||
rpc DeletePermissionsForUser (PermissionRequest) returns (BoolReply) {}
|
||||
rpc HasPermissionForUser (PermissionRequest) returns (BoolReply) {}
|
||||
|
||||
}
|
||||
|
||||
message NewEnforcerRequest {
|
||||
string modelText = 1;
|
||||
int32 adapterHandle = 2;
|
||||
}
|
||||
|
||||
message NewEnforcerReply {
|
||||
int32 handler = 1;
|
||||
}
|
||||
|
||||
message NewAdapterRequest {
|
||||
string adapterName = 1;
|
||||
string driverName = 2;
|
||||
string connectString = 3;
|
||||
bool dbSpecified = 4;
|
||||
}
|
||||
|
||||
message NewAdapterReply {
|
||||
int32 handler = 1;
|
||||
}
|
||||
|
||||
message EnforceRequest {
|
||||
int32 enforcerHandler = 1;
|
||||
repeated string params = 2;
|
||||
}
|
||||
|
||||
message BoolReply {
|
||||
bool res = 1;
|
||||
}
|
||||
|
||||
message EmptyRequest {
|
||||
int32 handler = 1;
|
||||
}
|
||||
|
||||
message EmptyReply {
|
||||
}
|
||||
|
||||
message PolicyRequest {
|
||||
int32 enforcerHandler = 1;
|
||||
string pType = 2;
|
||||
repeated string params = 3;
|
||||
}
|
||||
|
||||
message SimpleGetRequest {
|
||||
int32 enforcerHandler = 1;
|
||||
string pType = 2;
|
||||
}
|
||||
|
||||
message ArrayReply {
|
||||
repeated string array = 1;
|
||||
}
|
||||
|
||||
message FilteredPolicyRequest {
|
||||
int32 enforcerHandler = 1;
|
||||
string pType = 2;
|
||||
int32 fieldIndex = 3;
|
||||
repeated string fieldValues = 4;
|
||||
}
|
||||
|
||||
message UserRoleRequest {
|
||||
int32 enforcerHandler = 1;
|
||||
string user = 2;
|
||||
string role = 3;
|
||||
}
|
||||
|
||||
message PermissionRequest {
|
||||
int32 enforcerHandler = 1;
|
||||
string user = 2;
|
||||
repeated string permissions = 3;
|
||||
}
|
||||
|
||||
message Array2DReply {
|
||||
message d {
|
||||
repeated string d1 = 1;
|
||||
}
|
||||
|
||||
repeated d d2 = 1;
|
||||
}
|
||||
1971
components/authz/proto/rpc/authz_grpc.pb.go
Normal file
1971
components/authz/proto/rpc/authz_grpc.pb.go
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user