first prototype of a CS3 permissions service

This commit is contained in:
David Christofas
2022-01-27 16:56:15 +01:00
parent 22555e20e7
commit 29f4f49e1c
9 changed files with 116 additions and 6 deletions
+1 -1
View File
@@ -19,7 +19,7 @@ require (
github.com/asim/go-micro/plugins/wrapper/trace/opencensus/v4 v4.0.0-20211220083148-8e52761edb49
github.com/blevesearch/bleve/v2 v2.3.0
github.com/coreos/go-oidc/v3 v3.1.0
github.com/cs3org/go-cs3apis v0.0.0-20211214102047-7ce3134d7bf8
github.com/cs3org/go-cs3apis v0.0.0-20211214102128-4e8745ab1654
github.com/cs3org/reva v1.16.1-0.20220121134812-59d1aa30eb60
github.com/disintegration/imaging v1.6.2
github.com/glauth/glauth/v2 v2.0.0-20211021011345-ef3151c28733
+2 -1
View File
@@ -322,8 +322,9 @@ github.com/crewjam/httperr v0.2.0/go.mod h1:Jlz+Sg/XqBQhyMjdDiC+GNNRzZTD7x39Gu3p
github.com/crewjam/saml v0.4.5 h1:H9u+6CZAESUKHxMyxUbVn0IawYvKZn4nt3d4ccV4O/M=
github.com/crewjam/saml v0.4.5/go.mod h1:qCJQpUtZte9R1ZjUBcW8qtCNlinbO363ooNl02S68bk=
github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e/go.mod h1:XJEZ3/EQuI3BXTp/6DUzFr850vlxq11I6satRtz0YQ4=
github.com/cs3org/go-cs3apis v0.0.0-20211214102047-7ce3134d7bf8 h1:PqOprF37OvwCbAN5W23znknGk6N/LMayqLAeP904FHE=
github.com/cs3org/go-cs3apis v0.0.0-20211214102047-7ce3134d7bf8/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/cs3org/go-cs3apis v0.0.0-20211214102128-4e8745ab1654 h1:ha5tiuuFyDrwKUrVEc3TrRDFgTKVQ9NGDRmEP0PRPno=
github.com/cs3org/go-cs3apis v0.0.0-20211214102128-4e8745ab1654/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/cs3org/reva v1.16.1-0.20220121134812-59d1aa30eb60 h1:XaraDDlNXPv5GREzwkP7+8IEMDXbzzeHsekfUQABJzc=
github.com/cs3org/reva v1.16.1-0.20220121134812-59d1aa30eb60/go.mod h1:/BofcMJgfqTIHNiCp1uXr9ABcgylp27U2W4fjYUR6Fg=
github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8 h1:Z9lwXumT5ACSmJ7WGnFl+OMLLjpz5uR2fyz7dC255FI=
+37
View File
@@ -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
}
+46
View File
@@ -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.
+1
View File
@@ -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)
+1
View File
@@ -140,6 +140,7 @@ func gatewayConfigFromStruct(c *cli.Context, cfg *config.Config, logger log.Logg
"preferencessvc": cfg.Reva.Users.Endpoint,
"userprovidersvc": cfg.Reva.Users.Endpoint,
"groupprovidersvc": cfg.Reva.Groups.Endpoint,
"permissionssvc": cfg.Reva.Permissions.Endpoint,
// sharing is located on the sharing service
"usershareprovidersvc": cfg.Reva.Sharing.Endpoint,
"publicshareprovidersvc": cfg.Reva.Sharing.Endpoint,
+6 -4
View File
@@ -199,10 +199,11 @@ type StoragePort struct {
DataServerURL string `ocisConfig:"data_server_url"`
// for HTTP ports with only one http service
HTTPPrefix string `ocisConfig:"http_prefix"`
TempFolder string `ocisConfig:"temp_folder"`
ReadOnly bool `ocisConfig:"read_only"`
DataProvider DataProvider `ocisConfig:"data_provider"`
HTTPPrefix string `ocisConfig:"http_prefix"`
TempFolder string `ocisConfig:"temp_folder"`
ReadOnly bool `ocisConfig:"read_only"`
DataProvider DataProvider `ocisConfig:"data_provider"`
GatewayEndpoint string `ocisConfig:"gateway_endpoint"`
}
// PublicStorage configures a public storage provider
@@ -474,6 +475,7 @@ type Reva struct {
StoragePublicLink PublicStorage `ocisConfig:"storage_public_link"`
StorageMetadata StoragePort `ocisConfig:"storage_metadata"`
AppProvider AppProvider `ocisConfig:"app_provider"`
Permissions Port `ocisConfig:"permissions"`
// Configs can be used to configure the reva instance.
// Services and Ports will be ignored if this is used
Configs map[string]interface{} `ocisConfig:"configs"`
+3
View File
@@ -421,6 +421,9 @@ func DefaultConfig() *Config {
OpenURL: "/app/open",
NewURL: "/app/new",
},
Permissions: Port{
Endpoint: "localhost:9191",
},
Configs: nil,
UploadMaxChunkSize: 1e+8,
UploadHTTPMethodOverride: "",