[#986] cli: Allow add-rule command to parse new actions

* Introduce Object.* and Container.* actions that
  span all methods for services.

Signed-off-by: Airat Arifullin <a.arifullin@yadro.com>
This commit is contained in:
Airat Arifullin 2024-02-14 17:57:19 +03:00
parent b48270bed0
commit eac2f9f7b9
2 changed files with 53 additions and 17 deletions

View file

@ -27,6 +27,7 @@ For container it can be represented as:
- `/*` all containers in the `root` namespace
Actions is a regular operations upon FrostFS containers/objects. Like `Object.Put`, `Container.Get` etc.
You can use `Object.*`, `Container.*` that implies all actions.
In status section it is possible to use `allow`, `deny` or `deny:QuotaLimitReached` actions.

View file

@ -82,6 +82,8 @@ func ParseAPEChain(chain *apechain.Chain, rules []string) error {
// deny:QuotaLimitReached Object.Put *
// allow Object.Put *
// allow Object.Get Object.Resource:Department=HR Object.Request:Actor=ownerA *
// allow Object.* *
// allow Container.* *
//
//nolint:godot
func ParseAPERule(r *apechain.Rule, rule string) error {
@ -92,6 +94,18 @@ func ParseAPERule(r *apechain.Rule, rule string) error {
return parseRuleLexemes(r, lexemes)
}
func unique(inputSlice []string) []string {
uniqueSlice := make([]string, 0, len(inputSlice))
seen := make(map[string]bool, len(inputSlice))
for _, element := range inputSlice {
if !seen[element] {
uniqueSlice = append(uniqueSlice, element)
seen[element] = true
}
}
return uniqueSlice
}
func parseRuleLexemes(r *apechain.Rule, lexemes []string) error {
if len(lexemes) < 2 {
return errInvalidStatementFormat
@ -105,9 +119,9 @@ func parseRuleLexemes(r *apechain.Rule, lexemes []string) error {
var isObject *bool
for i, lexeme := range lexemes[1:] {
var name string
var names []string
var actionType bool
name, actionType, err = parseAction(lexeme)
names, actionType, err = parseAction(lexeme)
if err != nil {
condition, errCond := parseCondition(lexeme)
if errCond != nil {
@ -118,7 +132,7 @@ func parseRuleLexemes(r *apechain.Rule, lexemes []string) error {
actionType = condition.Object == apechain.ObjectResource || condition.Object == apechain.ObjectRequest
r.Condition = append(r.Condition, *condition)
} else {
r.Actions.Names = append(r.Actions.Names, name)
r.Actions.Names = append(r.Actions.Names, names...)
}
if isObject == nil {
isObject = &actionType
@ -126,6 +140,7 @@ func parseRuleLexemes(r *apechain.Rule, lexemes []string) error {
return errMixedTypesInRule
}
}
r.Actions.Names = unique(r.Actions.Names)
if len(r.Actions.Names) == 0 {
return fmt.Errorf("%w:%w", err, errNoActionsInRule)
}
@ -161,35 +176,55 @@ func parseStatus(lexeme string) (apechain.Status, error) {
}
}
func parseAction(lexeme string) (string, bool, error) {
func parseAction(lexeme string) ([]string, bool, error) {
switch strings.ToLower(lexeme) {
case "object.put":
return nativeschema.MethodPutObject, true, nil
return []string{nativeschema.MethodPutObject}, true, nil
case "object.get":
return nativeschema.MethodGetObject, true, nil
return []string{nativeschema.MethodGetObject}, true, nil
case "object.head":
return nativeschema.MethodHeadObject, true, nil
return []string{nativeschema.MethodHeadObject}, true, nil
case "object.delete":
return nativeschema.MethodDeleteObject, true, nil
return []string{nativeschema.MethodDeleteObject}, true, nil
case "object.search":
return nativeschema.MethodSearchObject, true, nil
return []string{nativeschema.MethodSearchObject}, true, nil
case "object.range":
return nativeschema.MethodRangeObject, true, nil
return []string{nativeschema.MethodRangeObject}, true, nil
case "object.hash":
return nativeschema.MethodHashObject, true, nil
return []string{nativeschema.MethodHashObject}, true, nil
case "object.*":
return []string{
nativeschema.MethodPutObject,
nativeschema.MethodGetObject,
nativeschema.MethodHeadObject,
nativeschema.MethodDeleteObject,
nativeschema.MethodSearchObject,
nativeschema.MethodHashObject,
}, true, nil
case "container.put":
return nativeschema.MethodPutContainer, false, nil
return []string{nativeschema.MethodPutContainer}, false, nil
case "container.delete":
return nativeschema.MethodDeleteContainer, false, nil
return []string{nativeschema.MethodDeleteContainer}, false, nil
case "container.get":
return nativeschema.MethodGetContainer, false, nil
return []string{nativeschema.MethodGetContainer}, false, nil
case "container.setcontainereacl":
return nativeschema.MethodSetContainerEACL, false, nil
return []string{nativeschema.MethodSetContainerEACL}, false, nil
case "container.getcontainereacl":
return nativeschema.MethodGetContainerEACL, false, nil
return []string{nativeschema.MethodGetContainerEACL}, false, nil
case "container.list":
return []string{nativeschema.MethodListContainers}, false, nil
case "container.*":
return []string{
nativeschema.MethodPutContainer,
nativeschema.MethodDeleteContainer,
nativeschema.MethodGetContainer,
nativeschema.MethodSetContainerEACL,
nativeschema.MethodGetContainerEACL,
nativeschema.MethodListContainers,
}, false, nil
default:
}
return "", false, fmt.Errorf("%w: %s", errUnknownAction, lexeme)
return nil, false, fmt.Errorf("%w: %s", errUnknownAction, lexeme)
}
func parseResource(lexeme string, isObj bool) (string, error) {