package engine import ( "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain" "git.frostfs.info/TrueCloudLab/policy-engine/pkg/resource" ) type defaultChainRouter struct { morph MorphRuleChainStorageReader local LocalOverrideStorage } func NewDefaultChainRouter(morph MorphRuleChainStorageReader) ChainRouter { return &defaultChainRouter{ morph: morph, } } func NewDefaultChainRouterWithLocalOverrides(morph MorphRuleChainStorageReader, local LocalOverrideStorage) ChainRouter { return &defaultChainRouter{ morph: morph, local: local, } } func (dr *defaultChainRouter) IsAllowed(name chain.Name, rt RequestTarget, r resource.Request) (status chain.Status, ruleFound bool, err error) { status, ruleFound, err = dr.checkLocal(name, rt, r) if err != nil { return chain.NoRuleFound, false, err } else if ruleFound { // The local overrides have the highest priority and thus // morph rules are not considered if a local one is found. return } status, ruleFound, err = dr.checkMorph(name, rt, r) return } func (dr *defaultChainRouter) checkLocal(name chain.Name, rt RequestTarget, r resource.Request) (status chain.Status, ruleFound bool, err error) { if dr.local == nil { return } var hasAllow bool for _, target := range rt.Targets() { status, ruleFound, err = dr.matchLocalOverrides(name, target, r) if err != nil || ruleFound && status != chain.Allow { return } hasAllow = hasAllow || ruleFound } status = chain.NoRuleFound if hasAllow { status = chain.Allow } return } func (dr *defaultChainRouter) checkMorph(name chain.Name, rt RequestTarget, r resource.Request) (status chain.Status, ruleFound bool, err error) { var hasAllow bool for _, target := range rt.Targets() { status, ruleFound, err = dr.matchMorphRuleChains(name, target, r) if err != nil || ruleFound && status != chain.Allow { return } hasAllow = hasAllow || ruleFound } status = chain.NoRuleFound if hasAllow { status = chain.Allow } return } func (dr *defaultChainRouter) matchLocalOverrides(name chain.Name, target Target, r resource.Request) (status chain.Status, ruleFound bool, err error) { localOverrides, err := dr.local.ListOverrides(name, target) if err != nil { return } status, ruleFound = dr.getStatusFromChains(localOverrides, r) return } func (dr *defaultChainRouter) matchMorphRuleChains(name chain.Name, target Target, r resource.Request) (status chain.Status, ruleFound bool, err error) { namespaceChains, err := dr.morph.ListMorphRuleChains(name, target) if err != nil { return chain.NoRuleFound, false, err } status, ruleFound = dr.getStatusFromChains(namespaceChains, r) return } func (dr *defaultChainRouter) getStatusFromChains(chains []*chain.Chain, r resource.Request) (chain.Status, bool) { var allow bool for _, c := range chains { if status, found := c.Match(r); found { if status != chain.Allow { return status, true } allow = true } } if allow { return chain.Allow, true } return chain.NoRuleFound, false }