-
Andre Sterba authored
See merge request !298
Andre Sterba authoredSee merge request !298
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
role.go 6.34 KiB
package server
import (
"context"
"time"
apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac"
"code.fbi.h-da.de/danet/gosdn/controller/metrics"
"code.fbi.h-da.de/danet/gosdn/controller/rbac"
"code.fbi.h-da.de/danet/gosdn/controller/store"
"github.com/google/uuid"
"github.com/prometheus/client_golang/prometheus"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// Role holds a JWTManager and represents a RoleServiceServer.
type Role struct {
apb.UnimplementedRoleServiceServer
jwtManager *rbac.JWTManager
}
// NewRoleServer receives a JWTManager and returns a new Role.
func NewRoleServer(jwtManager *rbac.JWTManager) *Role {
return &Role{
jwtManager: jwtManager,
}
}
// CreateRoles creates one are multiple new roles.
func (r Role) CreateRoles(ctx context.Context, request *apb.CreateRolesRequest) (*apb.CreateRolesResponse, error) {
labels := prometheus.Labels{"service": "auth", "rpc": "post"}
start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
for _, r := range request.Roles {
role := rbac.NewRole(uuid.New(), r.Name, r.Description, r.Permissions)
err := rolec.Add(role)
if err != nil {
log.Error(err)
return nil, status.Errorf(codes.Aborted, "%v", err)
}
}
return &apb.CreateRolesResponse{
Timestamp: time.Now().UnixNano(),
Status: apb.Status_STATUS_OK,
}, nil
}
// GetRole returns one role with its permissions found by name.
func (r Role) GetRole(ctx context.Context, request *apb.GetRoleRequest) (*apb.GetRoleResponse, error) {
labels := prometheus.Labels{"service": "auth", "rpc": "get"}
start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
roleData, err := rolec.Get(store.Query{Name: request.RoleName})
if err != nil {
return nil, err
}
role := &apb.Role{
Id: roleData.ID().String(),
Name: roleData.Name(),
Description: roleData.GetDescription(),
Permissions: roleData.GetPermissions(),
}
return &apb.GetRoleResponse{
Timestamp: time.Now().UnixNano(),
Status: apb.Status_STATUS_OK,
Role: role,
}, nil
}
// GetRoles returns all roles with their permissions.
func (r Role) GetRoles(ctx context.Context, request *apb.GetRolesRequest) (*apb.GetRolesResponse, error) {
labels := prometheus.Labels{"service": "auth", "rpc": "get"}
start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
roleList, err := rolec.GetAll()
if err != nil {
return nil, err
}
roles := []*apb.Role{}
for _, r := range roleList {
roles = append(roles, &apb.Role{
Id: r.ID().String(),
Name: r.Name(),
Description: r.GetDescription(),
Permissions: r.GetPermissions(),
})
}
return &apb.GetRolesResponse{
Timestamp: time.Now().UnixNano(),
Status: apb.Status_STATUS_OK,
Roles: roles,
}, nil
}
// UpdateRoles updates data of the provided roles.
func (r Role) UpdateRoles(ctx context.Context, request *apb.UpdateRolesRequest) (*apb.UpdateRolesResponse, error) {
labels := prometheus.Labels{"service": "auth", "rpc": "post"}
start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
// TODO: check if current user is allowed to update the role they try to update; only their own if not admin
for _, r := range request.Roles {
rid, err := uuid.Parse(r.Id)
if err != nil {
return nil, handleRPCError(labels, err)
}
_, err = rolec.Get(store.Query{ID: rid})
if err != nil {
return nil, status.Errorf(codes.Canceled, "role not found %v", err)
}
roleToUpdate := rbac.NewRole(rid, r.Name, r.Description, r.Permissions)
err = rolec.Update(roleToUpdate)
if err != nil {
return nil, status.Errorf(codes.Aborted, "could not update role %v", err)
}
}
return &apb.UpdateRolesResponse{
Timestamp: time.Now().UnixNano(),
Status: apb.Status_STATUS_OK,
}, nil
}
// DeletePermissionsForRole deletes the provided permissions from one role found by name.
func (r Role) DeletePermissionsForRole(ctx context.Context, request *apb.DeletePermissionsForRoleRequest) (*apb.DeletePermissionsForRoleResponse, error) {
labels := prometheus.Labels{"service": "auth", "rpc": "delete"}
start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
roleToUpdate, err := rolec.Get(store.Query{Name: request.RoleName})
if err != nil {
return nil, status.Errorf(codes.Canceled, "role not found %v", err)
}
// checks if there is at least one valid permission to delete
// in the provided set of permissions to delete
nonFound := true
for _, perm := range roleToUpdate.GetPermissions() {
for _, permToDelete := range request.PermissionsToDelete {
if perm == permToDelete {
nonFound = false
break
}
}
if !nonFound {
break
}
}
if nonFound {
return nil, status.Errorf(codes.Canceled, "no fitting permissions")
}
// updates the existing role with the trimmed set of permissions
roleToUpdate.RemovePermissionsFromRole(request.PermissionsToDelete)
err = rolec.Update(roleToUpdate)
if err != nil {
return nil, status.Errorf(codes.Aborted, "could not update role %v", err)
}
return &apb.DeletePermissionsForRoleResponse{
Timestamp: time.Now().UnixNano(),
Status: apb.Status_STATUS_OK,
}, nil
}
// DeleteRoles deletes all the provided roles with their permissions.
func (r Role) DeleteRoles(ctx context.Context, request *apb.DeleteRolesRequest) (*apb.DeleteRolesResponse, error) {
labels := prometheus.Labels{"service": "auth", "rpc": "delete"}
start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
for _, r := range request.RoleName {
roleToDelete, err := rolec.Get(store.Query{Name: r})
if err != nil {
return nil, status.Errorf(codes.Canceled, "role not found")
}
err = rolec.Delete(roleToDelete)
if err != nil {
return nil, status.Errorf(codes.Aborted, "error deleting role %v", err)
}
}
return &apb.DeleteRolesResponse{
Timestamp: time.Now().UnixNano(),
Status: apb.Status_STATUS_OK,
}, nil
}