first prototype of a CS3 permissions service
This commit is contained in:
@@ -1,10 +1,15 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
permissions "github.com/cs3org/go-cs3apis/cs3/permissions/v1beta1"
|
||||
"github.com/owncloud/ocis/ocis-pkg/service/grpc"
|
||||
"github.com/owncloud/ocis/ocis-pkg/version"
|
||||
"github.com/owncloud/ocis/settings/pkg/proto/v0"
|
||||
svc "github.com/owncloud/ocis/settings/pkg/service/v0"
|
||||
"go-micro.dev/v4/api"
|
||||
"go-micro.dev/v4/server"
|
||||
)
|
||||
|
||||
// Server initializes a new go-micro service ready to run
|
||||
@@ -35,5 +40,37 @@ func Server(opts ...Option) grpc.Service {
|
||||
options.Logger.Fatal().Err(err).Msg("could not register Permission service handler")
|
||||
}
|
||||
|
||||
if err := RegisterCS3PermissionsServiceHandler(service.Server(), handle); err != nil {
|
||||
options.Logger.Fatal().Err(err).Msg("could not register CS3 Permission service handler")
|
||||
}
|
||||
|
||||
return service
|
||||
}
|
||||
|
||||
func RegisterCS3PermissionsServiceHandler(s server.Server, hdlr permissions.PermissionsAPIServer, opts ...server.HandlerOption) error {
|
||||
type permissionsService interface {
|
||||
CheckPermission(context.Context, *permissions.CheckPermissionRequest, *permissions.CheckPermissionResponse) error
|
||||
}
|
||||
type PermissionsAPI struct {
|
||||
permissionsService
|
||||
}
|
||||
h := &permissionsServiceHandler{hdlr}
|
||||
opts = append(opts, api.WithEndpoint(&api.Endpoint{
|
||||
Name: "PermissionsService.Checkpermission",
|
||||
Path: []string{"/api/v0/permissions/check-permission"},
|
||||
Method: []string{"POST"},
|
||||
Body: "*",
|
||||
Handler: "rpc",
|
||||
}))
|
||||
return s.Handle(s.NewHandler(&PermissionsAPI{h}, opts...))
|
||||
}
|
||||
|
||||
type permissionsServiceHandler struct {
|
||||
api permissions.PermissionsAPIServer
|
||||
}
|
||||
|
||||
func (h *permissionsServiceHandler) CheckPermission(ctx context.Context, req *permissions.CheckPermissionRequest, res *permissions.CheckPermissionResponse) error {
|
||||
r, err := h.api.CheckPermission(ctx, req)
|
||||
*res = *r
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
permissions "github.com/cs3org/go-cs3apis/cs3/permissions/v1beta1"
|
||||
rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
"github.com/cs3org/reva/pkg/rgrpc/status"
|
||||
"github.com/owncloud/ocis/ocis-pkg/log"
|
||||
"github.com/owncloud/ocis/ocis-pkg/middleware"
|
||||
"github.com/owncloud/ocis/ocis-pkg/roles"
|
||||
@@ -36,6 +39,49 @@ func NewService(cfg *config.Config, logger log.Logger) Service {
|
||||
return service
|
||||
}
|
||||
|
||||
func (g Service) CheckPermission(ctx context.Context, req *permissions.CheckPermissionRequest) (*permissions.CheckPermissionResponse, error) {
|
||||
spec := req.SubjectRef.Spec
|
||||
|
||||
var accountID string
|
||||
switch ref := spec.(type) {
|
||||
case *permissions.SubjectReference_UserId:
|
||||
accountID = ref.UserId.OpaqueId
|
||||
case *permissions.SubjectReference_GroupId:
|
||||
accountID = ref.GroupId.OpaqueId
|
||||
}
|
||||
|
||||
assignments, err := g.manager.ListRoleAssignments(accountID)
|
||||
if err != nil {
|
||||
return &permissions.CheckPermissionResponse{
|
||||
Status: status.NewInternal(ctx, err, err.Error()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
roleIDs := make([]string, 0, len(assignments))
|
||||
for _, a := range assignments {
|
||||
roleIDs = append(roleIDs, a.RoleId)
|
||||
}
|
||||
|
||||
permission, err := g.manager.ReadPermissionByName(req.Permission, roleIDs)
|
||||
if err != nil {
|
||||
return &permissions.CheckPermissionResponse{
|
||||
Status: status.NewInternal(ctx, err, err.Error()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
if permission == nil {
|
||||
return &permissions.CheckPermissionResponse{
|
||||
Status: &rpcv1beta1.Status{
|
||||
Code: rpcv1beta1.Code_CODE_PERMISSION_DENIED,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &permissions.CheckPermissionResponse{
|
||||
Status: status.NewOK(ctx),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// RegisterDefaultRoles composes default roles and saves them. Skipped if the roles already exist.
|
||||
func (g Service) RegisterDefaultRoles() {
|
||||
// FIXME: we're writing default roles per service start (i.e. twice at the moment, for http and grpc server). has to happen only once.
|
||||
|
||||
@@ -50,4 +50,5 @@ type RoleAssignmentManager interface {
|
||||
type PermissionManager interface {
|
||||
ListPermissionsByResource(resource *proto.Resource, roleIDs []string) ([]*proto.Permission, error)
|
||||
ReadPermissionByID(permissionID string, roleIDs []string) (*proto.Permission, error)
|
||||
ReadPermissionByName(name string, roleIDs []string) (*proto.Permission, error)
|
||||
}
|
||||
|
||||
@@ -38,6 +38,25 @@ func (s Store) ReadPermissionByID(permissionID string, roleIDs []string) (*proto
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// ReadPermissionByName finds the permission in the roles, specified by the provided roleIDs
|
||||
func (s Store) ReadPermissionByName(name string, roleIDs []string) (*proto.Permission, error) {
|
||||
for _, roleID := range roleIDs {
|
||||
role, err := s.ReadBundle(roleID)
|
||||
if err != nil {
|
||||
s.Logger.Debug().Str("roleID", roleID).Msg("role not found, skipping")
|
||||
continue
|
||||
}
|
||||
for _, permission := range role.Settings {
|
||||
if permission.Name == name {
|
||||
if value, ok := permission.Value.(*proto.Setting_PermissionValue); ok {
|
||||
return value.PermissionValue, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// extractPermissionsByResource collects all permissions from the provided role that match the requested resource
|
||||
func extractPermissionsByResource(resource *proto.Resource, role *proto.Bundle) []*proto.Permission {
|
||||
permissions := make([]*proto.Permission, 0)
|
||||
|
||||
Reference in New Issue
Block a user