[#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 committed by Evgenii Stratonikov
parent 0f064b7962
commit 47d9ce71be
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 - `/*` all containers in the `root` namespace
Actions is a regular operations upon FrostFS containers/objects. Like `Object.Put`, `Container.Get` etc. 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. In status section it is possible to use `allow`, `deny` or `deny:QuotaLimitReached` actions.

View file

@ -102,6 +102,8 @@ func ParseAPEChain(chain *apechain.Chain, rules []string) error {
// allow Object.Get Object.Resource:Department=HR Object.Request:Actor=ownerA * // allow Object.Get Object.Resource:Department=HR Object.Request:Actor=ownerA *
// allow Object.Get any Object.Resource:Department=HR Object.Request:Actor=ownerA * // allow Object.Get any Object.Resource:Department=HR Object.Request:Actor=ownerA *
// allow Object.Get all Object.Resource:Department=HR Object.Request:Actor=ownerA * // allow Object.Get all Object.Resource:Department=HR Object.Request:Actor=ownerA *
// allow Object.* *
// allow Container.* *
// //
//nolint:godot //nolint:godot
func ParseAPERule(r *apechain.Rule, rule string) error { func ParseAPERule(r *apechain.Rule, rule string) error {
@ -112,6 +114,18 @@ func ParseAPERule(r *apechain.Rule, rule string) error {
return parseRuleLexemes(r, lexemes) 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 { func parseRuleLexemes(r *apechain.Rule, lexemes []string) error {
if len(lexemes) < 2 { if len(lexemes) < 2 {
return errInvalidStatementFormat return errInvalidStatementFormat
@ -131,9 +145,9 @@ func parseRuleLexemes(r *apechain.Rule, lexemes []string) error {
continue continue
} }
var name string var names []string
var actionType bool var actionType bool
name, actionType, err = parseAction(lexeme) names, actionType, err = parseAction(lexeme)
if err != nil { if err != nil {
condition, errCond := parseCondition(lexeme) condition, errCond := parseCondition(lexeme)
if errCond != nil { if errCond != nil {
@ -144,7 +158,7 @@ func parseRuleLexemes(r *apechain.Rule, lexemes []string) error {
actionType = condition.Object == apechain.ObjectResource || condition.Object == apechain.ObjectRequest actionType = condition.Object == apechain.ObjectResource || condition.Object == apechain.ObjectRequest
r.Condition = append(r.Condition, *condition) r.Condition = append(r.Condition, *condition)
} else { } else {
r.Actions.Names = append(r.Actions.Names, name) r.Actions.Names = append(r.Actions.Names, names...)
} }
if isObject == nil { if isObject == nil {
isObject = &actionType isObject = &actionType
@ -152,6 +166,7 @@ func parseRuleLexemes(r *apechain.Rule, lexemes []string) error {
return errMixedTypesInRule return errMixedTypesInRule
} }
} }
r.Actions.Names = unique(r.Actions.Names)
if len(r.Actions.Names) == 0 { if len(r.Actions.Names) == 0 {
return fmt.Errorf("%w:%w", err, errNoActionsInRule) return fmt.Errorf("%w:%w", err, errNoActionsInRule)
} }
@ -198,35 +213,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) { switch strings.ToLower(lexeme) {
case "object.put": case "object.put":
return nativeschema.MethodPutObject, true, nil return []string{nativeschema.MethodPutObject}, true, nil
case "object.get": case "object.get":
return nativeschema.MethodGetObject, true, nil return []string{nativeschema.MethodGetObject}, true, nil
case "object.head": case "object.head":
return nativeschema.MethodHeadObject, true, nil return []string{nativeschema.MethodHeadObject}, true, nil
case "object.delete": case "object.delete":
return nativeschema.MethodDeleteObject, true, nil return []string{nativeschema.MethodDeleteObject}, true, nil
case "object.search": case "object.search":
return nativeschema.MethodSearchObject, true, nil return []string{nativeschema.MethodSearchObject}, true, nil
case "object.range": case "object.range":
return nativeschema.MethodRangeObject, true, nil return []string{nativeschema.MethodRangeObject}, true, nil
case "object.hash": 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": case "container.put":
return nativeschema.MethodPutContainer, false, nil return []string{nativeschema.MethodPutContainer}, false, nil
case "container.delete": case "container.delete":
return nativeschema.MethodDeleteContainer, false, nil return []string{nativeschema.MethodDeleteContainer}, false, nil
case "container.get": case "container.get":
return nativeschema.MethodGetContainer, false, nil return []string{nativeschema.MethodGetContainer}, false, nil
case "container.setcontainereacl": case "container.setcontainereacl":
return nativeschema.MethodSetContainerEACL, false, nil return []string{nativeschema.MethodSetContainerEACL}, false, nil
case "container.getcontainereacl": 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: 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) { func parseResource(lexeme string, isObj bool) (string, error) {