1
0
Эх сурвалжийг харах

feat(permset): apply permission checking using permsets

Mustafa Arici 8 жил өмнө
parent
commit
9c34a5fcb1
4 өөрчлөгдсөн 266 нэмэгдсэн , 14 устгасан
  1. 11 0
      api/auth.go
  2. 4 0
      api/interceptor.go
  3. 198 13
      api/rpc.go
  4. 53 1
      perms.go

+ 11 - 0
api/auth.go

@@ -6,6 +6,7 @@ import (
 
 	"github.com/Sirupsen/logrus"
 	"github.com/cad/ovpm"
+	"github.com/cad/ovpm/permset"
 	gcontext "golang.org/x/net/context"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/codes"
@@ -24,7 +25,17 @@ func authRequired(ctx gcontext.Context, req interface{}, handler grpc.UnaryHandl
 		logrus.Debugln("rpc: auth denied because user with this token can not be found")
 		return nil, grpc.Errorf(codes.Unauthenticated, "access denied")
 	}
+
+	// Set user's permissions according to it's criterias.
+	var permissions permset.Permset
+	if user.IsAdmin() {
+		permissions = permset.New(ovpm.AdminPerms()...)
+	} else {
+		permissions = permset.New(ovpm.UserPerms()...)
+	}
+
 	newCtx := NewUsernameContext(ctx, user.GetUsername())
+	newCtx = permset.NewContext(newCtx, permissions)
 	return handler(newCtx, req)
 }
 

+ 4 - 0
api/interceptor.go

@@ -6,6 +6,8 @@ import (
 
 	"github.com/Sirupsen/logrus"
 	"github.com/asaskevich/govalidator"
+	"github.com/cad/ovpm"
+	"github.com/cad/ovpm/permset"
 	gcontext "golang.org/x/net/context"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/metadata"
@@ -50,6 +52,8 @@ func AuthUnaryInterceptor(ctx gcontext.Context, req interface{}, info *grpc.Unar
 	if !enableAuthCheck {
 		logrus.Debugf("rpc: auth-check not enabled: %s", md["x-forwarded-for"])
 		ctx = NewUsernameContext(ctx, "root")
+		permissions := permset.New(ovpm.AdminPerms()...)
+		ctx = permset.NewContext(ctx, permissions)
 	}
 
 	if enableAuthCheck {

+ 198 - 13
api/rpc.go

@@ -9,6 +9,7 @@ import (
 	"github.com/Sirupsen/logrus"
 	"github.com/cad/ovpm"
 	"github.com/cad/ovpm/api/pb"
+	"github.com/cad/ovpm/permset"
 	"golang.org/x/net/context"
 )
 
@@ -66,6 +67,16 @@ type UserService struct{}
 
 func (s *UserService) List(ctx context.Context, req *pb.UserListRequest) (*pb.UserResponse, error) {
 	logrus.Debug("rpc call: user list")
+	perms, err := permset.FromContext(ctx)
+	if err != nil {
+		return nil, grpc.Errorf(codes.Unauthenticated, "permset not found within the context")
+	}
+
+	// Check perms.
+	if !perms.Contains(ovpm.GetAnyUserPerm) {
+		return nil, grpc.Errorf(codes.PermissionDenied, "ovpm.GetAnyUserPerm is required for this operation")
+	}
+
 	var ut []*pb.UserResponse_User
 
 	users, err := ovpm.GetAllUsers()
@@ -91,6 +102,16 @@ func (s *UserService) List(ctx context.Context, req *pb.UserListRequest) (*pb.Us
 
 func (s *UserService) Create(ctx context.Context, req *pb.UserCreateRequest) (*pb.UserResponse, error) {
 	logrus.Debugf("rpc call: user create: %s", req.Username)
+	perms, err := permset.FromContext(ctx)
+	if err != nil {
+		return nil, grpc.Errorf(codes.Unauthenticated, "permset not found within the context")
+	}
+
+	// Check perms.
+	if !perms.Contains(ovpm.CreateUserPerm) {
+		return nil, grpc.Errorf(codes.PermissionDenied, "ovpm.CreateUserPerm is required for this operation")
+	}
+
 	var ut []*pb.UserResponse_User
 	user, err := ovpm.CreateNewUser(req.Username, req.Password, req.NoGw, req.HostId, req.IsAdmin)
 	if err != nil {
@@ -139,21 +160,53 @@ func (s *UserService) Update(ctx context.Context, req *pb.UserUpdateRequest) (*p
 		admin = user.IsAdmin()
 	}
 
-	err = user.Update(req.Password, noGW, req.HostId, admin)
+	perms, err := permset.FromContext(ctx)
 	if err != nil {
-		return nil, err
+		return nil, grpc.Errorf(codes.Unauthenticated, "permset not found within the context")
 	}
-	pbUser := pb.UserResponse_User{
-		Username:           user.GetUsername(),
-		ServerSerialNumber: user.GetServerSerialNumber(),
-		NoGw:               user.IsNoGW(),
-		HostId:             user.GetHostID(),
-		IsAdmin:            user.IsAdmin(),
+
+	username, err := GetUsernameFromContext(ctx)
+	if err != nil {
+		logrus.Debugln(err)
+		return nil, grpc.Errorf(codes.Unauthenticated, "username not found with the provided credentials")
 	}
 
-	ut = append(ut, &pbUser)
+	// User has admin perms?
+	if perms.Contains(ovpm.UpdateAnyUserPerm) {
+		err = user.Update(req.Password, noGW, req.HostId, admin)
+		if err != nil {
+			return nil, err
+		}
+		ut = append(ut, &pb.UserResponse_User{
+			Username:           user.GetUsername(),
+			ServerSerialNumber: user.GetServerSerialNumber(),
+			NoGw:               user.IsNoGW(),
+			HostId:             user.GetHostID(),
+			IsAdmin:            user.IsAdmin(),
+		})
+		return &pb.UserResponse{Users: ut}, nil
+	}
 
-	return &pb.UserResponse{Users: ut}, nil
+	// User has self update perms?
+	if perms.Contains(ovpm.UpdateSelfPerm) {
+		if user.GetUsername() != username {
+			return nil, grpc.Errorf(codes.PermissionDenied, "Caller can only update their user with ovpm.UpdateSelfPerm")
+		}
+
+		err = user.Update(req.Password, noGW, req.HostId, admin)
+		if err != nil {
+			return nil, err
+		}
+		ut = append(ut, &pb.UserResponse_User{
+			Username:           user.GetUsername(),
+			ServerSerialNumber: user.GetServerSerialNumber(),
+			NoGw:               user.IsNoGW(),
+			HostId:             user.GetHostID(),
+			IsAdmin:            user.IsAdmin(),
+		})
+		return &pb.UserResponse{Users: ut}, nil
+	}
+	return nil, grpc.Errorf(codes.PermissionDenied, "Permissions are required for this operation.")
 }
 
 func (s *UserService) Delete(ctx context.Context, req *pb.UserDeleteRequest) (*pb.UserResponse, error) {
@@ -164,6 +217,15 @@ func (s *UserService) Delete(ctx context.Context, req *pb.UserDeleteRequest) (*p
 		return nil, err
 	}
 
+	perms, err := permset.FromContext(ctx)
+	if err != nil {
+		return nil, grpc.Errorf(codes.Unauthenticated, "Can't get permset from context")
+	}
+
+	if !perms.Contains(ovpm.DeleteAnyUserPerm) {
+		return nil, grpc.Errorf(codes.PermissionDenied, "ovpm.DeleteAnyUserPerm is required for this operation.")
+	}
+
 	pbUser := pb.UserResponse_User{
 		Username:           user.GetUsername(),
 		ServerSerialNumber: user.GetServerSerialNumber(),
@@ -196,6 +258,15 @@ func (s *UserService) Renew(ctx context.Context, req *pb.UserRenewRequest) (*pb.
 	}
 	ut = append(ut, &pbUser)
 
+	perms, err := permset.FromContext(ctx)
+	if err != nil {
+		return nil, grpc.Errorf(codes.Unauthenticated, "Can't get permset from context")
+	}
+
+	if !perms.Contains(ovpm.RenewAnyUserPerm) {
+		return nil, grpc.Errorf(codes.PermissionDenied, "ovpm.RenewAnyUserPerm is required for this operation.")
+	}
+
 	err = user.Renew()
 	if err != nil {
 		return nil, err
@@ -210,12 +281,37 @@ func (s *UserService) GenConfig(ctx context.Context, req *pb.UserGenConfigReques
 	if err != nil {
 		return nil, err
 	}
-	configBlob, err := ovpm.DumpsClientConfig(user.GetUsername())
+	username, err := GetUsernameFromContext(ctx)
 	if err != nil {
-		return nil, err
+		logrus.Debugln(err)
+		return nil, grpc.Errorf(codes.Unauthenticated, "username not found with the provided credentials")
 	}
 
-	return &pb.UserGenConfigResponse{ClientConfig: configBlob}, nil
+	perms, err := permset.FromContext(ctx)
+	if err != nil {
+		return nil, grpc.Errorf(codes.Unauthenticated, "Can't get permset from context")
+	}
+
+	if perms.Contains(ovpm.GenConfigAnyUserPerm) {
+		configBlob, err := ovpm.DumpsClientConfig(user.GetUsername())
+		if err != nil {
+			return nil, err
+		}
+		return &pb.UserGenConfigResponse{ClientConfig: configBlob}, nil
+	}
+
+	if perms.Contains(ovpm.GenConfigSelfPerm) {
+		if user.GetUsername() != username {
+			return nil, grpc.Errorf(codes.PermissionDenied, "Caller can only genconfig for their user.")
+		}
+		configBlob, err := ovpm.DumpsClientConfig(user.GetUsername())
+		if err != nil {
+			return nil, err
+		}
+		return &pb.UserGenConfigResponse{ClientConfig: configBlob}, nil
+	}
+
+	return nil, grpc.Errorf(codes.PermissionDenied, "Permissions are required for this operation.")
 }
 
 type VPNService struct{}
@@ -227,6 +323,15 @@ func (s *VPNService) Status(ctx context.Context, req *pb.VPNStatusRequest) (*pb.
 		return nil, err
 	}
 
+	perms, err := permset.FromContext(ctx)
+	if err != nil {
+		return nil, grpc.Errorf(codes.Unauthenticated, "Can't get permset from context")
+	}
+
+	if !perms.Contains(ovpm.GetVPNStatusPerm) {
+		return nil, grpc.Errorf(codes.PermissionDenied, "ovpm.GetVPNStatusPerm is required for this operation.")
+	}
+
 	response := pb.VPNStatusResponse{
 		Name:         server.GetServerName(),
 		SerialNumber: server.GetSerialNumber(),
@@ -255,6 +360,15 @@ func (s *VPNService) Init(ctx context.Context, req *pb.VPNInitRequest) (*pb.VPNI
 		proto = ovpm.UDPProto
 	}
 
+	perms, err := permset.FromContext(ctx)
+	if err != nil {
+		return nil, grpc.Errorf(codes.Unauthenticated, "Can't get permset from context")
+	}
+
+	if !perms.Contains(ovpm.InitVPNPerm) {
+		return nil, grpc.Errorf(codes.PermissionDenied, "ovpm.InitVPNPerm is required for this operation.")
+	}
+
 	if err := ovpm.Init(req.Hostname, req.Port, proto, req.IpBlock, req.Dns); err != nil {
 		logrus.Errorf("server can not be created: %v", err)
 	}
@@ -263,6 +377,15 @@ func (s *VPNService) Init(ctx context.Context, req *pb.VPNInitRequest) (*pb.VPNI
 
 func (s *VPNService) Update(ctx context.Context, req *pb.VPNUpdateRequest) (*pb.VPNUpdateResponse, error) {
 	logrus.Debugf("rpc call: vpn update")
+	perms, err := permset.FromContext(ctx)
+	if err != nil {
+		return nil, grpc.Errorf(codes.Unauthenticated, "Can't get permset from context")
+	}
+
+	if !perms.Contains(ovpm.UpdateVPNPerm) {
+		return nil, grpc.Errorf(codes.PermissionDenied, "ovpm.UpdateVPNPerm is required for this operation.")
+	}
+
 	if err := ovpm.Update(req.IpBlock, req.Dns); err != nil {
 		logrus.Errorf("server can not be updated: %v", err)
 	}
@@ -275,6 +398,15 @@ func (s *NetworkService) List(ctx context.Context, req *pb.NetworkListRequest) (
 	logrus.Debug("rpc call: network list")
 	var nt []*pb.Network
 
+	perms, err := permset.FromContext(ctx)
+	if err != nil {
+		return nil, grpc.Errorf(codes.Unauthenticated, "Can't get permset from context")
+	}
+
+	if !perms.Contains(ovpm.ListNetworksPerm) {
+		return nil, grpc.Errorf(codes.PermissionDenied, "ovpm.ListNetworksPerm is required for this operation.")
+	}
+
 	networks := ovpm.GetAllNetworks()
 	for _, network := range networks {
 		nt = append(nt, &pb.Network{
@@ -292,6 +424,15 @@ func (s *NetworkService) List(ctx context.Context, req *pb.NetworkListRequest) (
 
 func (s *NetworkService) Create(ctx context.Context, req *pb.NetworkCreateRequest) (*pb.NetworkCreateResponse, error) {
 	logrus.Debugf("rpc call: network create: %s", req.Name)
+	perms, err := permset.FromContext(ctx)
+	if err != nil {
+		return nil, grpc.Errorf(codes.Unauthenticated, "Can't get permset from context")
+	}
+
+	if !perms.Contains(ovpm.CreateNetworkPerm) {
+		return nil, grpc.Errorf(codes.PermissionDenied, "ovpm.CreateNetworkPerm is required for this operation.")
+	}
+
 	network, err := ovpm.CreateNewNetwork(req.Name, req.Cidr, ovpm.NetworkTypeFromString(req.Type), req.Via)
 	if err != nil {
 		return nil, err
@@ -311,6 +452,15 @@ func (s *NetworkService) Create(ctx context.Context, req *pb.NetworkCreateReques
 
 func (s *NetworkService) Delete(ctx context.Context, req *pb.NetworkDeleteRequest) (*pb.NetworkDeleteResponse, error) {
 	logrus.Debugf("rpc call: network delete: %s", req.Name)
+	perms, err := permset.FromContext(ctx)
+	if err != nil {
+		return nil, grpc.Errorf(codes.Unauthenticated, "Can't get permset from context")
+	}
+
+	if !perms.Contains(ovpm.DeleteNetworkPerm) {
+		return nil, grpc.Errorf(codes.PermissionDenied, "ovpm.DeleteNetworkPerm is required for this operation.")
+	}
+
 	network, err := ovpm.GetNetwork(req.Name)
 	if err != nil {
 		return nil, err
@@ -336,6 +486,16 @@ func (s *NetworkService) Delete(ctx context.Context, req *pb.NetworkDeleteReques
 func (s *NetworkService) GetAllTypes(ctx context.Context, req *pb.NetworkGetAllTypesRequest) (*pb.NetworkGetAllTypesResponse, error) {
 	logrus.Debugf("rpc call: network get-types")
 	var networkTypes []*pb.NetworkType
+
+	perms, err := permset.FromContext(ctx)
+	if err != nil {
+		return nil, grpc.Errorf(codes.Unauthenticated, "Can't get permset from context")
+	}
+
+	if !perms.Contains(ovpm.GetNetworkTypesPerm) {
+		return nil, grpc.Errorf(codes.PermissionDenied, "ovpm.GetNetworkTypesPerm is required for this operation.")
+	}
+
 	for _, nt := range ovpm.GetAllNetworkTypes() {
 		if nt == ovpm.UNDEFINEDNET {
 			continue
@@ -348,6 +508,15 @@ func (s *NetworkService) GetAllTypes(ctx context.Context, req *pb.NetworkGetAllT
 
 func (s *NetworkService) GetAssociatedUsers(ctx context.Context, req *pb.NetworkGetAssociatedUsersRequest) (*pb.NetworkGetAssociatedUsersResponse, error) {
 	logrus.Debugf("rpc call: network get-associated-users")
+	perms, err := permset.FromContext(ctx)
+	if err != nil {
+		return nil, grpc.Errorf(codes.Unauthenticated, "Can't get permset from context")
+	}
+
+	if !perms.Contains(ovpm.GetNetworkAssociatedUsersPerm) {
+		return nil, grpc.Errorf(codes.PermissionDenied, "ovpm.GetNetworkAssociatedUsersPerm is required for this operation.")
+	}
+
 	network, err := ovpm.GetNetwork(req.Name)
 	if err != nil {
 		return nil, err
@@ -358,6 +527,14 @@ func (s *NetworkService) GetAssociatedUsers(ctx context.Context, req *pb.Network
 
 func (s *NetworkService) Associate(ctx context.Context, req *pb.NetworkAssociateRequest) (*pb.NetworkAssociateResponse, error) {
 	logrus.Debugf("rpc call: network associate")
+	perms, err := permset.FromContext(ctx)
+	if err != nil {
+		return nil, grpc.Errorf(codes.Unauthenticated, "Can't get permset from context")
+	}
+
+	if !perms.Contains(ovpm.AssociateNetworkUserPerm) {
+		return nil, grpc.Errorf(codes.PermissionDenied, "ovpm.AssociateNetworkUserPerm is required for this operation.")
+	}
 
 	network, err := ovpm.GetNetwork(req.Name)
 	if err != nil {
@@ -373,6 +550,14 @@ func (s *NetworkService) Associate(ctx context.Context, req *pb.NetworkAssociate
 
 func (s *NetworkService) Dissociate(ctx context.Context, req *pb.NetworkDissociateRequest) (*pb.NetworkDissociateResponse, error) {
 	logrus.Debugf("rpc call: network dissociate")
+	perms, err := permset.FromContext(ctx)
+	if err != nil {
+		return nil, grpc.Errorf(codes.Unauthenticated, "Can't get permset from context")
+	}
+
+	if !perms.Contains(ovpm.DissociateNetworkUserPerm) {
+		return nil, grpc.Errorf(codes.PermissionDenied, "ovpm.DissociateNetworkUserPerm is required for this operation.")
+	}
 
 	network, err := ovpm.GetNetwork(req.Name)
 	if err != nil {

+ 53 - 1
perms.go

@@ -2,12 +2,64 @@ package ovpm
 
 import "github.com/cad/ovpm/permset"
 
-// OVPM defined permissions.
+// OVPM available permissions.
 const (
+	// User permissions
 	CreateUserPerm permset.Perm = iota
 	GetAnyUserPerm
 	GetSelfPerm
 	UpdateAnyUserPerm
 	UpdateSelfPerm
 	DeleteAnyUserPerm
+	RenewAnyUserPerm
+	GenConfigAnyUserPerm
+	GenConfigSelfPerm
+
+	// VPN permissions
+	GetVPNStatusPerm
+	InitVPNPerm
+	UpdateVPNPerm
+
+	// Network permissions
+	ListNetworksPerm
+	CreateNetworkPerm
+	DeleteNetworkPerm
+	GetNetworkTypesPerm
+	GetNetworkAssociatedUsersPerm
+	AssociateNetworkUserPerm
+	DissociateNetworkUserPerm
 )
+
+// AdminPerms is a collection of permissions for Admin.
+func AdminPerms() []permset.Perm {
+	return []permset.Perm{
+		CreateUserPerm,
+		GetAnyUserPerm,
+		GetSelfPerm,
+		UpdateAnyUserPerm,
+		UpdateSelfPerm,
+		DeleteAnyUserPerm,
+		RenewAnyUserPerm,
+		GenConfigAnyUserPerm,
+		GenConfigSelfPerm,
+		GetVPNStatusPerm,
+		InitVPNPerm,
+		UpdateVPNPerm,
+		ListNetworksPerm,
+		CreateNetworkPerm,
+		DeleteAnyUserPerm,
+		GetNetworkTypesPerm,
+		GetNetworkAssociatedUsersPerm,
+		AssociateNetworkUserPerm,
+		DissociateNetworkUserPerm,
+	}
+}
+
+// UserPerms is a collection of permissions for User.
+func UserPerms() []permset.Perm {
+	return []permset.Perm{
+		GetSelfPerm,
+		UpdateSelfPerm,
+		GenConfigSelfPerm,
+	}
+}