Merge pull request #59 from owncloud/permission-endpoints

Add permission endpoint for extracting one permission from a set of roleIDs
This commit is contained in:
Benedikt Kulmann
2020-08-27 21:26:08 +02:00
committed by GitHub
16 changed files with 1065 additions and 574 deletions
@@ -0,0 +1,6 @@
Change: Add filter option for bundle ids in ListBundles and ListRoles
We added bundle ids as filter option for ListBundles and ListRoles and a new endpoint for fetching a permission by ID.
https://github.com/owncloud/ocis-settings/pull/59
+2 -2
View File
@@ -1,5 +1,5 @@
// Code generated by fileb0x at "2020-08-26 18:01:22.299544 +0200 CEST m=+0.042142555" from config file "embed.yml" DO NOT EDIT.
// modification hash(b166c77fcc0c0fbd95b4ebb476d86f32.8058aec596c5fb73022d09bb97af796e)
// Code generated by fileb0x at "2020-08-27 15:42:12.738259 +0200 CEST m=+0.038980633" from config file "embed.yml" DO NOT EDIT.
// modification hash(72fc92ee28815272b98623a481d7cc37.8058aec596c5fb73022d09bb97af796e)
package assets
File diff suppressed because it is too large Load Diff
+31
View File
@@ -579,6 +579,13 @@ func NewPermissionServiceEndpoints() []*api.Endpoint {
Body: "*",
Handler: "rpc",
},
&api.Endpoint{
Name: "PermissionService.GetPermissionByID",
Path: []string{"/api/v0/settings/permissions-get-by-id"},
Method: []string{"POST"},
Body: "*",
Handler: "rpc",
},
}
}
@@ -586,6 +593,7 @@ func NewPermissionServiceEndpoints() []*api.Endpoint {
type PermissionService interface {
ListPermissionsByResource(ctx context.Context, in *ListPermissionsByResourceRequest, opts ...client.CallOption) (*ListPermissionsByResourceResponse, error)
GetPermissionByID(ctx context.Context, in *GetPermissionByIDRequest, opts ...client.CallOption) (*GetPermissionByIDResponse, error)
}
type permissionService struct {
@@ -610,15 +618,27 @@ func (c *permissionService) ListPermissionsByResource(ctx context.Context, in *L
return out, nil
}
func (c *permissionService) GetPermissionByID(ctx context.Context, in *GetPermissionByIDRequest, opts ...client.CallOption) (*GetPermissionByIDResponse, error) {
req := c.c.NewRequest(c.name, "PermissionService.GetPermissionByID", in)
out := new(GetPermissionByIDResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for PermissionService service
type PermissionServiceHandler interface {
ListPermissionsByResource(context.Context, *ListPermissionsByResourceRequest, *ListPermissionsByResourceResponse) error
GetPermissionByID(context.Context, *GetPermissionByIDRequest, *GetPermissionByIDResponse) error
}
func RegisterPermissionServiceHandler(s server.Server, hdlr PermissionServiceHandler, opts ...server.HandlerOption) error {
type permissionService interface {
ListPermissionsByResource(ctx context.Context, in *ListPermissionsByResourceRequest, out *ListPermissionsByResourceResponse) error
GetPermissionByID(ctx context.Context, in *GetPermissionByIDRequest, out *GetPermissionByIDResponse) error
}
type PermissionService struct {
permissionService
@@ -631,6 +651,13 @@ func RegisterPermissionServiceHandler(s server.Server, hdlr PermissionServiceHan
Body: "*",
Handler: "rpc",
}))
opts = append(opts, api.WithEndpoint(&api.Endpoint{
Name: "PermissionService.GetPermissionByID",
Path: []string{"/api/v0/settings/permissions-get-by-id"},
Method: []string{"POST"},
Body: "*",
Handler: "rpc",
}))
return s.Handle(s.NewHandler(&PermissionService{h}, opts...))
}
@@ -641,3 +668,7 @@ type permissionServiceHandler struct {
func (h *permissionServiceHandler) ListPermissionsByResource(ctx context.Context, in *ListPermissionsByResourceRequest, out *ListPermissionsByResourceResponse) error {
return h.PermissionServiceHandler.ListPermissionsByResource(ctx, in, out)
}
func (h *permissionServiceHandler) GetPermissionByID(ctx context.Context, in *GetPermissionByIDRequest, out *GetPermissionByIDResponse) error {
return h.PermissionServiceHandler.GetPermissionByID(ctx, in, out)
}
+97
View File
@@ -422,6 +422,30 @@ func (h *webPermissionServiceHandler) ListPermissionsByResource(w http.ResponseW
render.JSON(w, r, resp)
}
func (h *webPermissionServiceHandler) GetPermissionByID(w http.ResponseWriter, r *http.Request) {
req := &GetPermissionByIDRequest{}
resp := &GetPermissionByIDResponse{}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusPreconditionFailed)
return
}
if err := h.h.GetPermissionByID(
r.Context(),
req,
resp,
); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
render.Status(r, http.StatusCreated)
render.JSON(w, r, resp)
}
func RegisterPermissionServiceWeb(r chi.Router, i PermissionServiceHandler, middlewares ...func(http.Handler) http.Handler) {
handler := &webPermissionServiceHandler{
r: r,
@@ -429,6 +453,7 @@ func RegisterPermissionServiceWeb(r chi.Router, i PermissionServiceHandler, midd
}
r.MethodFunc("POST", "/api/v0/settings/permissions-list-by-resource", handler.ListPermissionsByResource)
r.MethodFunc("POST", "/api/v0/settings/permissions-get-by-id", handler.GetPermissionByID)
}
// SaveBundleRequestJSONMarshaler describes the default jsonpb.Marshaler used by all
@@ -1367,6 +1392,78 @@ func (m *ListPermissionsByResourceResponse) UnmarshalJSON(b []byte) error {
var _ json.Unmarshaler = (*ListPermissionsByResourceResponse)(nil)
// GetPermissionByIDRequestJSONMarshaler describes the default jsonpb.Marshaler used by all
// instances of GetPermissionByIDRequest. This struct is safe to replace or modify but
// should not be done so concurrently.
var GetPermissionByIDRequestJSONMarshaler = new(jsonpb.Marshaler)
// MarshalJSON satisfies the encoding/json Marshaler interface. This method
// uses the more correct jsonpb package to correctly marshal the message.
func (m *GetPermissionByIDRequest) MarshalJSON() ([]byte, error) {
if m == nil {
return json.Marshal(nil)
}
buf := &bytes.Buffer{}
if err := GetPermissionByIDRequestJSONMarshaler.Marshal(buf, m); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
var _ json.Marshaler = (*GetPermissionByIDRequest)(nil)
// GetPermissionByIDRequestJSONUnmarshaler describes the default jsonpb.Unmarshaler used by all
// instances of GetPermissionByIDRequest. This struct is safe to replace or modify but
// should not be done so concurrently.
var GetPermissionByIDRequestJSONUnmarshaler = new(jsonpb.Unmarshaler)
// UnmarshalJSON satisfies the encoding/json Unmarshaler interface. This method
// uses the more correct jsonpb package to correctly unmarshal the message.
func (m *GetPermissionByIDRequest) UnmarshalJSON(b []byte) error {
return GetPermissionByIDRequestJSONUnmarshaler.Unmarshal(bytes.NewReader(b), m)
}
var _ json.Unmarshaler = (*GetPermissionByIDRequest)(nil)
// GetPermissionByIDResponseJSONMarshaler describes the default jsonpb.Marshaler used by all
// instances of GetPermissionByIDResponse. This struct is safe to replace or modify but
// should not be done so concurrently.
var GetPermissionByIDResponseJSONMarshaler = new(jsonpb.Marshaler)
// MarshalJSON satisfies the encoding/json Marshaler interface. This method
// uses the more correct jsonpb package to correctly marshal the message.
func (m *GetPermissionByIDResponse) MarshalJSON() ([]byte, error) {
if m == nil {
return json.Marshal(nil)
}
buf := &bytes.Buffer{}
if err := GetPermissionByIDResponseJSONMarshaler.Marshal(buf, m); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
var _ json.Marshaler = (*GetPermissionByIDResponse)(nil)
// GetPermissionByIDResponseJSONUnmarshaler describes the default jsonpb.Unmarshaler used by all
// instances of GetPermissionByIDResponse. This struct is safe to replace or modify but
// should not be done so concurrently.
var GetPermissionByIDResponseJSONUnmarshaler = new(jsonpb.Unmarshaler)
// UnmarshalJSON satisfies the encoding/json Unmarshaler interface. This method
// uses the more correct jsonpb package to correctly unmarshal the message.
func (m *GetPermissionByIDResponse) UnmarshalJSON(b []byte) error {
return GetPermissionByIDResponseJSONUnmarshaler.Unmarshal(bytes.NewReader(b), m)
}
var _ json.Unmarshaler = (*GetPermissionByIDResponse)(nil)
// ResourceJSONMarshaler describes the default jsonpb.Marshaler used by all
// instances of Resource. This struct is safe to replace or modify but
// should not be done so concurrently.
+16
View File
@@ -125,6 +125,12 @@ service PermissionService {
body: "*"
};
}
rpc GetPermissionByID(GetPermissionByIDRequest) returns (GetPermissionByIDResponse) {
option (google.api.http) = {
post: "/api/v0/settings/permissions-get-by-id",
body: "*"
};
}
}
// ---
@@ -147,6 +153,7 @@ message GetBundleResponse {
}
message ListBundlesRequest {
repeated string bundle_ids = 1;
}
message ListBundlesResponse {
@@ -259,6 +266,15 @@ message ListPermissionsByResourceResponse {
repeated Permission permissions = 1;
}
message GetPermissionByIDRequest {
string permission_id = 1;
repeated string role_ids = 2;
}
message GetPermissionByIDResponse {
Permission permission = 1;
}
// ---
// resource payloads
// ---
+63 -1
View File
@@ -280,6 +280,38 @@
]
}
},
"/api/v0/settings/permissions-get-by-id": {
"post": {
"operationId": "PermissionService_GetPermissionByID",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/protoGetPermissionByIDResponse"
}
},
"default": {
"description": "An unexpected error response",
"schema": {
"$ref": "#/definitions/runtimeError"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/protoGetPermissionByIDRequest"
}
}
],
"tags": [
"PermissionService"
]
}
},
"/api/v0/settings/permissions-list-by-resource": {
"post": {
"operationId": "PermissionService_ListPermissionsByResource",
@@ -589,6 +621,28 @@
}
}
},
"protoGetPermissionByIDRequest": {
"type": "object",
"properties": {
"permission_id": {
"type": "string"
},
"role_ids": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"protoGetPermissionByIDResponse": {
"type": "object",
"properties": {
"permission": {
"$ref": "#/definitions/protoPermission"
}
}
},
"protoGetValueByUniqueIdentifiersRequest": {
"type": "object",
"properties": {
@@ -655,7 +709,15 @@
}
},
"protoListBundlesRequest": {
"type": "object"
"type": "object",
"properties": {
"bundle_ids": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"protoListBundlesResponse": {
"type": "object",
+6 -3
View File
@@ -23,13 +23,16 @@ func Server(opts ...Option) grpc.Service {
handle := svc.NewService(options.Config, options.Logger)
if err := proto.RegisterBundleServiceHandler(service.Server(), handle); err != nil {
options.Logger.Fatal().Err(err).Msg("could not register SettingsBundles service handler")
options.Logger.Fatal().Err(err).Msg("could not register Bundle service handler")
}
if err := proto.RegisterValueServiceHandler(service.Server(), handle); err != nil {
options.Logger.Fatal().Err(err).Msg("could not register SettingsValues service handler")
options.Logger.Fatal().Err(err).Msg("could not register Value service handler")
}
if err := proto.RegisterRoleServiceHandler(service.Server(), handle); err != nil {
options.Logger.Fatal().Err(err).Msg("could not register SettingsRoles service handler")
options.Logger.Fatal().Err(err).Msg("could not register Role service handler")
}
if err := proto.RegisterPermissionServiceHandler(service.Server(), handle); err != nil {
options.Logger.Fatal().Err(err).Msg("could not register Permission service handler")
}
service.Init()
+1
View File
@@ -66,6 +66,7 @@ func Server(opts ...Option) http.Service {
proto.RegisterBundleServiceWeb(r, handle)
proto.RegisterValueServiceWeb(r, handle)
proto.RegisterRoleServiceWeb(r, handle)
proto.RegisterPermissionServiceWeb(r, handle)
})
service.Handle(
+51 -33
View File
@@ -17,6 +17,7 @@ import (
// Service represents a service.
type Service struct {
id string
config *config.Config
logger log.Logger
manager settings.Manager
@@ -25,6 +26,7 @@ type Service struct {
// NewService returns a service implementation for Service.
func NewService(cfg *config.Config, logger log.Logger) Service {
service := Service{
id: "ocis-settings",
config: cfg,
logger: logger,
manager: store.New(cfg),
@@ -59,11 +61,11 @@ func (g Service) RegisterDefaultRoles() {
func (g Service) SaveBundle(c context.Context, req *proto.SaveBundleRequest, res *proto.SaveBundleResponse) error {
cleanUpResource(c, req.Bundle.Resource)
if validationError := validateSaveBundle(req); validationError != nil {
return merrors.BadRequest("ocis-settings", "%s", validationError)
return merrors.BadRequest(g.id, "%s", validationError)
}
r, err := g.manager.WriteBundle(req.Bundle)
if err != nil {
return merrors.BadRequest("ocis-settings", "%s", err)
return merrors.BadRequest(g.id, "%s", err)
}
res.Bundle = r
return nil
@@ -73,17 +75,17 @@ func (g Service) SaveBundle(c context.Context, req *proto.SaveBundleRequest, res
func (g Service) GetBundle(c context.Context, req *proto.GetBundleRequest, res *proto.GetBundleResponse) error {
accountUUID := getValidatedAccountUUID(c, "me")
if validationError := validateGetBundle(req); validationError != nil {
return merrors.BadRequest("ocis-settings", "%s", validationError)
return merrors.BadRequest(g.id, "%s", validationError)
}
bundle, err := g.manager.ReadBundle(req.BundleId)
if err != nil {
return merrors.NotFound("ocis-settings", "%s", err)
return merrors.NotFound(g.id, "%s", err)
}
roleIDs := g.getRoleIDs(c, accountUUID)
filteredBundle := g.getFilteredBundle(roleIDs, bundle)
if len(filteredBundle.Settings) == 0 {
err = fmt.Errorf("could not read bundle: %s", req.BundleId)
return merrors.NotFound("ocis-settings", "%s", err)
return merrors.NotFound(g.id, "%s", err)
}
res.Bundle = filteredBundle
return nil
@@ -94,11 +96,11 @@ func (g Service) ListBundles(c context.Context, req *proto.ListBundlesRequest, r
// fetch all bundles
accountUUID := getValidatedAccountUUID(c, "me")
if validationError := validateListBundles(req); validationError != nil {
return merrors.BadRequest("ocis-settings", "%s", validationError)
return merrors.BadRequest(g.id, "%s", validationError)
}
bundles, err := g.manager.ListBundles(proto.Bundle_TYPE_DEFAULT)
bundles, err := g.manager.ListBundles(proto.Bundle_TYPE_DEFAULT, req.BundleIds)
if err != nil {
return merrors.NotFound("ocis-settings", "%s", err)
return merrors.NotFound(g.id, "%s", err)
}
roleIDs := g.getRoleIDs(c, accountUUID)
@@ -154,11 +156,11 @@ func (g Service) getFilteredBundle(roleIDs []string, bundle *proto.Bundle) *prot
func (g Service) AddSettingToBundle(c context.Context, req *proto.AddSettingToBundleRequest, res *proto.AddSettingToBundleResponse) error {
cleanUpResource(c, req.Setting.Resource)
if validationError := validateAddSettingToBundle(req); validationError != nil {
return merrors.BadRequest("ocis-settings", "%s", validationError)
return merrors.BadRequest(g.id, "%s", validationError)
}
r, err := g.manager.AddSettingToBundle(req.BundleId, req.Setting)
if err != nil {
return merrors.BadRequest("ocis-settings", "%s", err)
return merrors.BadRequest(g.id, "%s", err)
}
res.Setting = r
return nil
@@ -167,10 +169,10 @@ func (g Service) AddSettingToBundle(c context.Context, req *proto.AddSettingToBu
// RemoveSettingFromBundle implements the BundleServiceHandler interface
func (g Service) RemoveSettingFromBundle(c context.Context, req *proto.RemoveSettingFromBundleRequest, _ *empty.Empty) error {
if validationError := validateRemoveSettingFromBundle(req); validationError != nil {
return merrors.BadRequest("ocis-settings", "%s", validationError)
return merrors.BadRequest(g.id, "%s", validationError)
}
if err := g.manager.RemoveSettingFromBundle(req.BundleId, req.SettingId); err != nil {
return merrors.BadRequest("ocis-settings", "%s", err)
return merrors.BadRequest(g.id, "%s", err)
}
return nil
@@ -182,15 +184,15 @@ func (g Service) SaveValue(c context.Context, req *proto.SaveValueRequest, res *
cleanUpResource(c, req.Value.Resource)
// TODO: we need to check, if the authenticated user has permission to write the value for the specified resource (e.g. global, file with id xy, ...)
if validationError := validateSaveValue(req); validationError != nil {
return merrors.BadRequest("ocis-settings", "%s", validationError)
return merrors.BadRequest(g.id, "%s", validationError)
}
r, err := g.manager.WriteValue(req.Value)
if err != nil {
return merrors.BadRequest("ocis-settings", "%s", err)
return merrors.BadRequest(g.id, "%s", err)
}
valueWithIdentifier, err := g.getValueWithIdentifier(r)
if err != nil {
return merrors.NotFound("ocis-settings", "%s", err)
return merrors.NotFound(g.id, "%s", err)
}
res.Value = valueWithIdentifier
return nil
@@ -199,15 +201,15 @@ func (g Service) SaveValue(c context.Context, req *proto.SaveValueRequest, res *
// GetValue implements the ValueServiceHandler interface
func (g Service) GetValue(c context.Context, req *proto.GetValueRequest, res *proto.GetValueResponse) error {
if validationError := validateGetValue(req); validationError != nil {
return merrors.BadRequest("ocis-settings", "%s", validationError)
return merrors.BadRequest(g.id, "%s", validationError)
}
r, err := g.manager.ReadValue(req.Id)
if err != nil {
return merrors.NotFound("ocis-settings", "%s", err)
return merrors.NotFound(g.id, "%s", err)
}
valueWithIdentifier, err := g.getValueWithIdentifier(r)
if err != nil {
return merrors.NotFound("ocis-settings", "%s", err)
return merrors.NotFound(g.id, "%s", err)
}
res.Value = valueWithIdentifier
return nil
@@ -217,13 +219,13 @@ func (g Service) GetValue(c context.Context, req *proto.GetValueRequest, res *pr
func (g Service) GetValueByUniqueIdentifiers(ctx context.Context, in *proto.GetValueByUniqueIdentifiersRequest, res *proto.GetValueResponse) error {
v, err := g.manager.ReadValueByUniqueIdentifiers(in.AccountUuid, in.SettingId)
if err != nil {
return merrors.NotFound("ocis-settings", "%s", err)
return merrors.NotFound(g.id, "%s", err)
}
if v.BundleId != "" {
valueWithIdentifier, err := g.getValueWithIdentifier(v)
if err != nil {
return merrors.NotFound("ocis-settings", "%s", err)
return merrors.NotFound(g.id, "%s", err)
}
res.Value = valueWithIdentifier
@@ -235,11 +237,11 @@ func (g Service) GetValueByUniqueIdentifiers(ctx context.Context, in *proto.GetV
func (g Service) ListValues(c context.Context, req *proto.ListValuesRequest, res *proto.ListValuesResponse) error {
req.AccountUuid = getValidatedAccountUUID(c, req.AccountUuid)
if validationError := validateListValues(req); validationError != nil {
return merrors.BadRequest("ocis-settings", "%s", validationError)
return merrors.BadRequest(g.id, "%s", validationError)
}
r, err := g.manager.ListValues(req.BundleId, req.AccountUuid)
if err != nil {
return merrors.NotFound("ocis-settings", "%s", err)
return merrors.NotFound(g.id, "%s", err)
}
var result []*proto.ValueWithIdentifier
for _, value := range r {
@@ -256,11 +258,11 @@ func (g Service) ListValues(c context.Context, req *proto.ListValuesRequest, res
func (g Service) ListRoles(c context.Context, req *proto.ListBundlesRequest, res *proto.ListBundlesResponse) error {
//accountUUID := getValidatedAccountUUID(c, "me")
if validationError := validateListRoles(req); validationError != nil {
return merrors.BadRequest("ocis-settings", "%s", validationError)
return merrors.BadRequest(g.id, "%s", validationError)
}
r, err := g.manager.ListBundles(proto.Bundle_TYPE_ROLE)
r, err := g.manager.ListBundles(proto.Bundle_TYPE_ROLE, req.BundleIds)
if err != nil {
return merrors.NotFound("ocis-settings", "%s", err)
return merrors.NotFound(g.id, "%s", err)
}
// TODO: only allow to list roles when user has account management permissions
res.Bundles = r
@@ -271,11 +273,11 @@ func (g Service) ListRoles(c context.Context, req *proto.ListBundlesRequest, res
func (g Service) ListRoleAssignments(c context.Context, req *proto.ListRoleAssignmentsRequest, res *proto.ListRoleAssignmentsResponse) error {
req.AccountUuid = getValidatedAccountUUID(c, req.AccountUuid)
if validationError := validateListRoleAssignments(req); validationError != nil {
return merrors.BadRequest("ocis-settings", "%s", validationError)
return merrors.BadRequest(g.id, "%s", validationError)
}
r, err := g.manager.ListRoleAssignments(req.AccountUuid)
if err != nil {
return merrors.NotFound("ocis-settings", "%s", err)
return merrors.NotFound(g.id, "%s", err)
}
res.Assignments = r
return nil
@@ -285,11 +287,11 @@ func (g Service) ListRoleAssignments(c context.Context, req *proto.ListRoleAssig
func (g Service) AssignRoleToUser(c context.Context, req *proto.AssignRoleToUserRequest, res *proto.AssignRoleToUserResponse) error {
req.AccountUuid = getValidatedAccountUUID(c, req.AccountUuid)
if validationError := validateAssignRoleToUser(req); validationError != nil {
return merrors.BadRequest("ocis-settings", "%s", validationError)
return merrors.BadRequest(g.id, "%s", validationError)
}
r, err := g.manager.WriteRoleAssignment(req.AccountUuid, req.RoleId)
if err != nil {
return merrors.BadRequest("ocis-settings", "%s", err)
return merrors.BadRequest(g.id, "%s", err)
}
res.Assignment = r
return nil
@@ -298,10 +300,10 @@ func (g Service) AssignRoleToUser(c context.Context, req *proto.AssignRoleToUser
// RemoveRoleFromUser implements the RoleServiceHandler interface
func (g Service) RemoveRoleFromUser(c context.Context, req *proto.RemoveRoleFromUserRequest, _ *empty.Empty) error {
if validationError := validateRemoveRoleFromUser(req); validationError != nil {
return merrors.BadRequest("ocis-settings", "%s", validationError)
return merrors.BadRequest(g.id, "%s", validationError)
}
if err := g.manager.RemoveRoleAssignment(req.Id); err != nil {
return merrors.BadRequest("ocis-settings", "%s", err)
return merrors.BadRequest(g.id, "%s", err)
}
return nil
}
@@ -309,16 +311,32 @@ func (g Service) RemoveRoleFromUser(c context.Context, req *proto.RemoveRoleFrom
// ListPermissionsByResource implements the PermissionServiceHandler interface
func (g Service) ListPermissionsByResource(c context.Context, req *proto.ListPermissionsByResourceRequest, res *proto.ListPermissionsByResourceResponse) error {
if validationError := validateListPermissionsByResource(req); validationError != nil {
return merrors.BadRequest("ocis-settings", "%s", validationError)
return merrors.BadRequest(g.id, "%s", validationError)
}
permissions, err := g.manager.ListPermissionsByResource(req.Resource, req.RoleIds)
if err != nil {
return merrors.BadRequest("ocis-settings", "%s", err)
return merrors.BadRequest(g.id, "%s", err)
}
res.Permissions = permissions
return nil
}
// GetPermissionByID implements the PermissionServiceHandler interface
func (g Service) GetPermissionByID(c context.Context, req *proto.GetPermissionByIDRequest, res *proto.GetPermissionByIDResponse) error {
if validationError := validateGetPermissionByID(req); validationError != nil {
return merrors.BadRequest(g.id, "%s", validationError)
}
permission, err := g.manager.ReadPermissionByID(req.PermissionId, req.RoleIds)
if err != nil {
return merrors.BadRequest(g.id, "%s", err)
}
if permission == nil {
return merrors.NotFound(g.id, "%s", fmt.Errorf("permission %s not found in roles", req.PermissionId))
}
res.Permission = permission
return nil
}
// cleanUpResource makes sure that the account uuid of the authenticated user is injected if needed.
func cleanUpResource(c context.Context, resource *proto.Resource) {
if resource != nil && resource.Type == proto.Resource_TYPE_USER {
+8
View File
@@ -132,6 +132,14 @@ func validateListPermissionsByResource(req *proto.ListPermissionsByResourceReque
)
}
func validateGetPermissionByID(req *proto.GetPermissionByIDRequest) error {
return validation.ValidateStruct(
req,
validation.Field(&req.PermissionId, requireAlphanumeric...),
validation.Field(&req.RoleIds, validation.Each(requireAlphanumeric...)),
)
}
// validateResource is an internal helper for validating the content of a resource.
func validateResource(resource *proto.Resource) error {
if err := validation.Validate(&resource, validation.Required); err != nil {
+2 -1
View File
@@ -23,7 +23,7 @@ type Manager interface {
// BundleManager is a bundle service interface for abstraction of storage implementations
type BundleManager interface {
ListBundles(bundleType proto.Bundle_Type) ([]*proto.Bundle, error)
ListBundles(bundleType proto.Bundle_Type, bundleIDs []string) ([]*proto.Bundle, error)
ReadBundle(bundleID string) (*proto.Bundle, error)
WriteBundle(bundle *proto.Bundle) (*proto.Bundle, error)
ReadSetting(settingID string) (*proto.Setting, error)
@@ -49,4 +49,5 @@ type RoleAssignmentManager interface {
// PermissionManager is a permissions service interface for abstraction of storage implementations
type PermissionManager interface {
ListPermissionsByResource(resource *proto.Resource, roleIDs []string) ([]*proto.Permission, error)
ReadPermissionByID(permissionID string, roleIDs []string) (*proto.Permission, error)
}
+15 -2
View File
@@ -14,7 +14,7 @@ import (
var m = &sync.RWMutex{}
// ListBundles returns all bundles in the dataPath folder that match the given type.
func (s Store) ListBundles(bundleType proto.Bundle_Type) ([]*proto.Bundle, error) {
func (s Store) ListBundles(bundleType proto.Bundle_Type, bundleIDs []string) ([]*proto.Bundle, error) {
// FIXME: list requests should be ran against a cache, not FS
m.RLock()
defer m.RUnlock()
@@ -36,12 +36,25 @@ func (s Store) ListBundles(bundleType proto.Bundle_Type) ([]*proto.Bundle, error
if record.Type != bundleType {
continue
}
if len(bundleIDs) > 0 && !containsStr(record.Id, bundleIDs) {
continue
}
records = append(records, &record)
}
return records, nil
}
// containsStr checks if the strs slice contains str
func containsStr(str string, strs []string) bool {
for _, s := range strs {
if s == str {
return true
}
}
return false
}
// ReadBundle tries to find a bundle by the given id within the dataPath.
func (s Store) ReadBundle(bundleID string) (*proto.Bundle, error) {
m.RLock()
@@ -62,7 +75,7 @@ func (s Store) ReadSetting(settingID string) (*proto.Setting, error) {
m.RLock()
defer m.RUnlock()
bundles, err := s.ListBundles(proto.Bundle_TYPE_DEFAULT)
bundles, err := s.ListBundles(proto.Bundle_TYPE_DEFAULT, []string{})
if err != nil {
return nil, err
}
+12 -2
View File
@@ -124,7 +124,7 @@ func TestBundles(t *testing.T) {
}
// check that ListBundles only returns bundles with type DEFAULT
bundles, err := s.ListBundles(proto.Bundle_TYPE_DEFAULT)
bundles, err := s.ListBundles(proto.Bundle_TYPE_DEFAULT, []string{})
if err != nil {
t.Error(err)
}
@@ -132,8 +132,18 @@ func TestBundles(t *testing.T) {
assert.Equal(t, proto.Bundle_TYPE_DEFAULT, bundles[i].Type)
}
// check that ListBundles filtered by an id only returns that bundle
filteredBundles, err := s.ListBundles(proto.Bundle_TYPE_DEFAULT, []string{bundle2})
if err != nil {
t.Error(err)
}
assert.Equal(t, 1, len(filteredBundles))
if len(filteredBundles) == 1 {
assert.Equal(t, bundle2, filteredBundles[0].Id)
}
// check that ListRoles only returns bundles with type ROLE
roles, err := s.ListBundles(proto.Bundle_TYPE_ROLE)
roles, err := s.ListBundles(proto.Bundle_TYPE_ROLE, []string{})
if err != nil {
t.Error(err)
}
+21 -3
View File
@@ -19,14 +19,32 @@ func (s Store) ListPermissionsByResource(resource *proto.Resource, roleIDs []str
return records, nil
}
// ReadPermissionByID finds the permission in the roles, specified by the provided roleIDs
func (s Store) ReadPermissionByID(permissionID 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.Id == permissionID {
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)
for _, setting := range role.Settings {
if _, ok := setting.Value.(*proto.Setting_PermissionValue); ok {
value := setting.Value.(*proto.Setting_PermissionValue).PermissionValue
if value, ok := setting.Value.(*proto.Setting_PermissionValue); ok {
if util.IsResourceMatched(setting.Resource, resource) {
permissions = append(permissions, value)
permissions = append(permissions, value.PermissionValue)
}
}
}
+46
View File
@@ -395,6 +395,52 @@ export const BundleService_RemoveSettingFromBundleURL = function(parameters = {}
let keys = Object.keys(queryParameters)
return domain + path + (keys.length > 0 ? '?' + (keys.map(key => key + '=' + encodeURIComponent(queryParameters[key])).join('&')) : '')
}
/**
*
* request: PermissionService_GetPermissionById
* url: PermissionService_GetPermissionByIdURL
* method: PermissionService_GetPermissionById_TYPE
* raw_url: PermissionService_GetPermissionById_RAW_URL
* @param body -
*/
export const PermissionService_GetPermissionById = function(parameters = {}) {
const domain = parameters.$domain ? parameters.$domain : getDomain()
const config = parameters.$config
let path = '/api/v0/settings/permissions-get-by-id'
let body
let queryParameters = {}
let form = {}
if (parameters['body'] !== undefined) {
body = parameters['body']
}
if (parameters['body'] === undefined) {
return Promise.reject(new Error('Missing required parameter: body'))
}
if (parameters.$queryParameters) {
Object.keys(parameters.$queryParameters).forEach(function(parameterName) {
queryParameters[parameterName] = parameters.$queryParameters[parameterName]
});
}
return request('post', domain + path, body, queryParameters, form, config)
}
export const PermissionService_GetPermissionById_RAW_URL = function() {
return '/api/v0/settings/permissions-get-by-id'
}
export const PermissionService_GetPermissionById_TYPE = function() {
return 'post'
}
export const PermissionService_GetPermissionByIdURL = function(parameters = {}) {
let queryParameters = {}
const domain = parameters.$domain ? parameters.$domain : getDomain()
let path = '/api/v0/settings/permissions-get-by-id'
if (parameters.$queryParameters) {
Object.keys(parameters.$queryParameters).forEach(function(parameterName) {
queryParameters[parameterName] = parameters.$queryParameters[parameterName]
})
}
let keys = Object.keys(queryParameters)
return domain + path + (keys.length > 0 ? '?' + (keys.map(key => key + '=' + encodeURIComponent(queryParameters[key])).join('&')) : '')
}
/**
*
* request: PermissionService_ListPermissionsByResource