Files
paralus/pkg/service/authz.go
nirav-rafay c66bdc25cd restructure rcloud-base as a single base controller (#37)
* restructure rcloud-base as a single base controller
* updated master.rest
* moved sentry from internal to pkg as it is used by relay
* removing unused rpc and it's dependencies
* Fix usermgmt tests
* Don't redefine variables in rest file
Co-authored-by: Abin Simon <abin.simon@rafay.co>
2022-03-03 17:59:06 +05:30

264 lines
8.5 KiB
Go

package service
import (
"context"
"fmt"
authzpbv1 "github.com/RafaySystems/rcloud-base/proto/types/authz"
"github.com/casbin/casbin/v2"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"gorm.io/gorm"
)
type AuthzService interface {
Enforce(context.Context, *authzpbv1.EnforceRequest) (*authzpbv1.BoolReply, error)
ListPolicies(context.Context, *authzpbv1.Policy) (*authzpbv1.Policies, error)
CreatePolicies(context.Context, *authzpbv1.Policies) (*authzpbv1.BoolReply, error)
DeletePolicies(context.Context, *authzpbv1.Policy) (*authzpbv1.BoolReply, error)
ListUserGroups(context.Context, *authzpbv1.UserGroup) (*authzpbv1.UserGroups, error)
CreateUserGroups(ctx context.Context, p *authzpbv1.UserGroups) (*authzpbv1.BoolReply, error)
DeleteUserGroups(ctx context.Context, p *authzpbv1.UserGroup) (*authzpbv1.BoolReply, error)
ListRolePermissionMappings(ctx context.Context, p *authzpbv1.FilteredRolePermissionMapping) (*authzpbv1.RolePermissionMappingList, error)
CreateRolePermissionMappings(ctx context.Context, p *authzpbv1.RolePermissionMappingList) (*authzpbv1.BoolReply, error)
DeleteRolePermissionMappings(ctx context.Context, p *authzpbv1.FilteredRolePermissionMapping) (*authzpbv1.BoolReply, error)
}
type authzService struct {
db *gorm.DB
enforcer *casbin.CachedEnforcer
}
func NewAuthzService(db *gorm.DB, en *casbin.CachedEnforcer) AuthzService {
return &authzService{
db: db,
enforcer: en,
}
}
const (
groupGtype = "g2"
roleGtype = "g"
)
func (s *authzService) toPolicies(policies [][]string) *authzpbv1.Policies {
if len(policies) == 0 {
return &authzpbv1.Policies{}
}
res := &authzpbv1.Policies{}
res.Policies = make([]*authzpbv1.Policy, len(policies))
for i := range policies {
res.Policies[i] = &authzpbv1.Policy{
Sub: policies[i][0],
Ns: policies[i][1],
Proj: policies[i][2],
Org: policies[i][3],
Obj: policies[i][4],
Act: policies[i][5],
}
}
return res
}
func (s *authzService) fromPolicies(policies *authzpbv1.Policies) ([][]string, error) {
res := [][]string{}
for i, p := range policies.GetPolicies() {
rule := []string{p.GetSub(), p.GetNs(), p.GetProj(), p.GetOrg(), p.GetObj(), p.GetAct()}
for _, field := range rule {
if field == "" {
return res, fmt.Errorf(fmt.Sprintf("index %d: policy elements do not meet definition", i))
}
}
res = append(res, rule)
}
return res, nil
}
func (s *authzService) toUserGroups(ug [][]string) *authzpbv1.UserGroups {
if len(ug) == 0 {
return &authzpbv1.UserGroups{}
}
res := &authzpbv1.UserGroups{}
res.UserGroups = make([]*authzpbv1.UserGroup, len(ug))
for i := range ug {
res.UserGroups[i] = &authzpbv1.UserGroup{
User: ug[i][0],
Grp: ug[i][1],
}
}
return res
}
func (s *authzService) fromUserGroups(ugs *authzpbv1.UserGroups) ([][]string, error) {
res := [][]string{}
for i, p := range ugs.GetUserGroups() {
rule := []string{p.GetUser(), p.GetGrp()}
for _, field := range rule {
if field == "" {
return res, fmt.Errorf(fmt.Sprintf("index %d: request elements do not meet definition", i))
}
}
res = append(res, rule)
}
return res, nil
}
func (s *authzService) toRolePermissionMappingList(r [][]string) *authzpbv1.RolePermissionMappingList {
if len(r) == 0 {
return &authzpbv1.RolePermissionMappingList{}
}
rpms := make(map[string][]string)
for _, rpm := range r {
rpms[rpm[1]] = append(rpms[rpm[1]], rpm[0])
}
res := &authzpbv1.RolePermissionMappingList{}
res.RolePermissionMappingList = make([]*authzpbv1.RolePermissionMapping, len(rpms))
var i int
for k, v := range rpms {
i++
res.RolePermissionMappingList[i] = &authzpbv1.RolePermissionMapping{
Role: k,
Permission: v,
}
}
return res
}
func (s *authzService) fromRolePermissionMappingList(r *authzpbv1.RolePermissionMappingList) ([][]string, error) {
res := [][]string{}
for i, mapping := range r.GetRolePermissionMappingList() {
for _, permission := range mapping.GetPermission() {
rule := []string{permission, mapping.Role}
for _, field := range rule {
if field == "" {
return res, fmt.Errorf(fmt.Sprintf("index %d: mapping elements do not meet definition", i))
}
}
res = append(res, rule)
}
}
return res, nil
}
func (s *authzService) Enforce(ctx context.Context, req *authzpbv1.EnforceRequest) (*authzpbv1.BoolReply, error) {
var param interface{}
params := make([]interface{}, 0, len(req.Params))
for index := range req.Params {
param = req.Params[index]
params = append(params, param)
}
res, err := s.enforcer.Enforce(params...)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, err.Error())
}
return &authzpbv1.BoolReply{Res: res}, nil
}
func (s *authzService) ListPolicies(ctx context.Context, p *authzpbv1.Policy) (*authzpbv1.Policies, error) {
return s.toPolicies(s.enforcer.GetFilteredPolicy(0, p.GetSub(), p.GetNs(), p.GetProj(), p.GetOrg(), p.GetObj(), p.GetAct())), nil
}
func (s *authzService) CreatePolicies(ctx context.Context, p *authzpbv1.Policies) (*authzpbv1.BoolReply, error) {
if len(p.GetPolicies()) == 0 {
return &authzpbv1.BoolReply{Res: false}, nil
}
policies, err := s.fromPolicies(p)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, err.Error())
}
// err could be from db, policy assertions; dispatcher, watcher updates (not pertinent)
res, err := s.enforcer.AddPolicies(policies)
if err != nil {
return nil, status.Errorf(codes.Internal, err.Error())
}
return &authzpbv1.BoolReply{Res: res}, nil
}
func (s *authzService) DeletePolicies(ctx context.Context, p *authzpbv1.Policy) (*authzpbv1.BoolReply, error) {
// err could be from db, policy assertions, cache; dispatcher, watcher updates (not pertinent)
res, err := s.enforcer.RemoveFilteredPolicy(0, p.GetSub(), p.GetNs(), p.GetProj(), p.GetOrg(), p.GetObj(), p.GetAct())
if err != nil {
return nil, status.Errorf(codes.Internal, err.Error())
}
return &authzpbv1.BoolReply{Res: res}, nil
}
func (s *authzService) ListUserGroups(ctx context.Context, p *authzpbv1.UserGroup) (*authzpbv1.UserGroups, error) {
return s.toUserGroups(s.enforcer.GetFilteredNamedGroupingPolicy(groupGtype, 0, p.GetUser(), p.GetGrp())), nil
}
func (s *authzService) CreateUserGroups(ctx context.Context, p *authzpbv1.UserGroups) (*authzpbv1.BoolReply, error) {
if len(p.GetUserGroups()) == 0 {
return &authzpbv1.BoolReply{Res: false}, nil
}
ugs, err := s.fromUserGroups(p)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, err.Error())
}
// err could be from db, policy assertions; dispatcher, watcher updates (not pertinent)
res, err := s.enforcer.AddNamedGroupingPolicies(groupGtype, ugs)
if err != nil {
return nil, status.Errorf(codes.Internal, err.Error())
}
return &authzpbv1.BoolReply{Res: res}, nil
}
func (s *authzService) DeleteUserGroups(ctx context.Context, p *authzpbv1.UserGroup) (*authzpbv1.BoolReply, error) {
// err could be from db, policy assertions, cache; dispatcher, watcher updates (not pertinent)
res, err := s.enforcer.RemoveFilteredNamedGroupingPolicy(groupGtype, 0, p.GetUser(), p.GetGrp())
if err != nil {
return nil, status.Errorf(codes.Internal, err.Error())
}
return &authzpbv1.BoolReply{Res: res}, nil
}
// NOTE: might need identifier per permission in list if inheritance is needed
func (s *authzService) ListRolePermissionMappings(ctx context.Context, p *authzpbv1.FilteredRolePermissionMapping) (*authzpbv1.RolePermissionMappingList, error) {
// TODO: Change list of urls to permissions (many to one)
return s.toRolePermissionMappingList(s.enforcer.GetFilteredNamedGroupingPolicy(roleGtype, 0, p.GetRole())), nil
}
func (s *authzService) CreateRolePermissionMappings(ctx context.Context, p *authzpbv1.RolePermissionMappingList) (*authzpbv1.BoolReply, error) {
// TODO: Change permissions to a list of urls (one to many)
if len(p.GetRolePermissionMappingList()) == 0 {
return &authzpbv1.BoolReply{Res: false}, nil
}
rpms, err := s.fromRolePermissionMappingList(p)
if err != nil {
return nil, status.Errorf(codes.Internal, err.Error())
}
res, err := s.enforcer.AddNamedGroupingPolicies(roleGtype, rpms)
if err != nil {
return nil, status.Errorf(codes.Internal, err.Error())
}
return &authzpbv1.BoolReply{Res: res}, nil
}
func (s *authzService) DeleteRolePermissionMappings(ctx context.Context, p *authzpbv1.FilteredRolePermissionMapping) (*authzpbv1.BoolReply, error) {
// TODO: Change permissions to a list of urls (one to many)
res, err := s.enforcer.RemoveFilteredNamedGroupingPolicy(roleGtype, 1, p.GetRole())
if err != nil {
return nil, status.Errorf(codes.Internal, err.Error())
}
return &authzpbv1.BoolReply{Res: res}, nil
}