forked from TrueCloudLab/policy-engine
[#26] schema: Add resource name validation method
Close #26 Signed-off-by: Airat Arifullin <aarifullin@yadro.com>
This commit is contained in:
parent
156018bcba
commit
e4e381b8a4
3 changed files with 162 additions and 0 deletions
20
docs/resource.md
Normal file
20
docs/resource.md
Normal 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.
|
45
schema/native/util/validation.go
Normal file
45
schema/native/util/validation.go
Normal 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
|
||||||
|
}
|
97
schema/native/util/validation_test.go
Normal file
97
schema/native/util/validation_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue