Newer
Older
package server
import (
"context"
"time"
apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac"
rbacInterfaces "code.fbi.h-da.de/danet/gosdn/controller/interfaces/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
roleService rbacInterfaces.RoleService
// NewRoleServer receives a JWTManager and a RoleService and returns a new RoleServer.
func NewRoleServer(jwtManager *rbac.JWTManager, roleService rbacInterfaces.RoleService) *Role {
return &Role{
jwtManager: jwtManager,
roleService: roleService,
}
}
// 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 _, rrole := range request.Roles {
role := rbac.NewRole(uuid.New(), rrole.Name, rrole.Description, rrole.Permissions)
err := r.roleService.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 := r.roleService.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 := r.roleService.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)
for _, role := range request.Roles {
rid, err := uuid.Parse(role.Id)
if err != nil {
return nil, handleRPCError(labels, err)
}
_, err = r.roleService.Get(store.Query{ID: rid})
if err != nil {
return nil, status.Errorf(codes.Canceled, "role not found %v", err)
}
roleToUpdate := rbac.NewRole(rid, role.Name, role.Description, role.Permissions)
err = r.roleService.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 := r.roleService.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 = r.roleService.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 _, role := range request.RoleName {
roleToDelete, err := r.roleService.Get(store.Query{Name: role})
if err != nil {
return nil, status.Errorf(codes.Canceled, "role not found")
}
err = r.roleService.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
}