Compare commits

...

1 commit

Author SHA1 Message Date
aarifullin
e4e381b8a4 [#26] schema: Add resource name validation method
All checks were successful
DCO action / DCO (pull_request) Successful in 1m6s
Tests and linters / Tests (1.21) (pull_request) Successful in 1m13s
Tests and linters / Tests (1.20) (pull_request) Successful in 1m38s
Tests and linters / Tests with -race (pull_request) Successful in 1m29s
Tests and linters / Staticcheck (pull_request) Successful in 1m35s
Tests and linters / Lint (pull_request) Successful in 2m17s
Close #26

Signed-off-by: Airat Arifullin <aarifullin@yadro.com>
2023-12-18 10:58:24 +03:00
3 changed files with 162 additions and 0 deletions

20
docs/resource.md Normal file
View file

@ -0,0 +1,20 @@
# Resource
From the point of the access policy engine, a resource is an object to which a request is being performed.
This can be an object in a container within a namespace, or all objects in a container,
or all containers within the root namespace etc.
A resource can be viewed from two sides:
- As part of a [request](../pkg/resource/resource.go). In this case a resource has a name and properties.
- As part of rule [chain](../pkg/chain/chain.go): a resource has just a name.
## Resource name
A resource name must have a such format that can be processed by a chain router that matches a request
either with local overrides or with rules within policy contract to get if this request is allowed to be performed.
The main idea of this format is for the chain router to match by full name (`native:object//cnrID/objID`) or
wildcard (`native:object//cnrID/*`).
Check out formats that are defined in the schema: [native formats](../schema/native/consts.go), [s3 formats](../schema/s3/consts.go).
You should validate a resource name using [util](../schema/native/util/validation.go) before instantiating a request or
before putting it to either to local override storage or the policy contract storage.

View file

@ -0,0 +1,45 @@
package util
import (
"strings"
"git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
)
var nativePatterns = []string{
native.ResourceFormatNamespaceObjects, native.ResourceFormatNamespaceContainerObjects,
native.ResourceFormatNamespaceContainerObject, native.ResourceFormatRootObjects,
native.ResourceFormatRootContainerObjects, native.ResourceFormatRootContainerObject,
native.ResourceFormatAllObjects, native.ResourceFormatNamespaceContainer,
native.ResourceFormatNamespaceContainers, native.ResourceFormatRootContainer,
native.ResourceFormatRootContainers, native.ResourceFormatAllContainers,
}
func match(resource, pattern string) bool {
rTokens := strings.Split(resource, "/")
pToken := strings.Split(pattern, "/")
if len(rTokens) != len(pToken) {
return false
}
for i := range rTokens {
if pToken[i] == "%s" {
continue
}
if pToken[i] != rTokens[i] {
return false
}
}
return true
}
func IsNativeResourceNameValid(resource string) bool {
for _, pattern := range nativePatterns {
if match(resource, pattern) {
return true
}
}
return false
}

View file

@ -0,0 +1,97 @@
package util
import (
"testing"
"github.com/stretchr/testify/require"
)
var tests = []struct {
name string
expected bool
resource string
}{
{
name: "ResourceFormatNamespaceObjects",
expected: true,
resource: "native:object/RootNamespace/*",
},
{
name: "ResourceFormatNamespaceContainerObjects",
expected: true,
resource: "native:object/RootNamespace/BzQw5HH3feoxFDD5tCT87Y1726qzgLfxEE7wgtoRzB3R/*",
},
{
name: "ResourceFormatNamespaceContainerObject",
expected: true,
resource: "native:object/RootNamespace/BzQw5HH3feoxFDD5tCT87Y1726qzgLfxEE7wgtoRzB3R/AeZa5HH3feoxFDD5tCT87Y1726qzgLfxEE7wgtoRzB4E",
},
{
name: "ResourceFormatRootObjects",
expected: true,
resource: "native:object//*",
},
{
name: "ResourceFormatRootContainerObjects",
expected: true,
resource: "native:object//BzQw5HH3feoxFDD5tCT87Y1726qzgLfxEE7wgtoRzB3R/*",
},
{
name: "ResourceFormatRootContainerObject",
expected: true,
resource: "native:object//BzQw5HH3feoxFDD5tCT87Y1726qzgLfxEE7wgtoRzB3R/AeZa5HH3feoxFDD5tCT87Y1726qzgLfxEE7wgtoRzB4E",
},
{
name: "ResourceFormatAllObjects",
expected: true,
resource: "native:object/*",
},
{
name: "ResourceFormatNamespaceContainer",
expected: true,
resource: "native:container/RootNamespace/BzQw5HH3feoxFDD5tCT87Y1726qzgLfxEE7wgtoRzB3R",
},
{
name: "ResourceFormatNamespaceContainers",
expected: true,
resource: "native:container/RootNamespace/*",
},
{
name: "ResourceFormatRootContainers",
expected: true,
resource: "native:container//*",
},
{
name: "ResourceFormatAllContainers",
expected: true,
resource: "native:container/*",
},
{
name: "Invalid resource 1",
expected: false,
resource: "native:::container/*",
},
{
name: "Invalid resource 2",
expected: false,
resource: "native:container/RootNamespace/w5HH3feoxFDD5tCTtoRzB3R/Bz726qzgLfxEE7wgtoRzB3R/RootNamespace",
},
}
func TestIsNativeResourceNameValid(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
require.Equal(t, test.expected, IsNativeResourceNameValid(test.resource))
})
}
}
func BenchmarkIsNativeResourceNameValid(b *testing.B) {
for _, test := range tests {
b.Run(test.name, func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = IsNativeResourceNameValid(test.resource)
}
})
}
}