Add permission endpoint for extracting one permission from a set of roleIds

This commit is contained in:
Benedikt Kulmann
2020-08-26 11:44:41 +02:00
parent 2ae00e877a
commit 5d89f7db8a
9 changed files with 849 additions and 458 deletions

View File

File diff suppressed because it is too large Load Diff

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)
}

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.

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: "*"
};
}
}
// ---
@@ -259,6 +265,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
// ---

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": {

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)
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)
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,31 @@ 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
}
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 {

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 {

View File

@@ -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)
}

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)
}
}
}