[#1047] object: Set container owner ID property to ape request

* Introduce ContainerOwner field in RequestContext.
* Set ContainerOwner in aclv2 middleware.
* Set PropertyKeyContainerOwnerID for object ape request.

Signed-off-by: Airat Arifullin <a.arifullin@yadro.com>
This commit is contained in:
Airat Arifullin 2024-03-15 15:16:52 +03:00 committed by Evgenii Stratonikov
parent 7278201753
commit 6959e617c4
6 changed files with 142 additions and 100 deletions

View file

@ -113,10 +113,11 @@ type wrappedGetObjectStream struct {
func (w *wrappedGetObjectStream) Context() context.Context { func (w *wrappedGetObjectStream) Context() context.Context {
return context.WithValue(w.GetObjectStream.Context(), object.RequestContextKey, &object.RequestContext{ return context.WithValue(w.GetObjectStream.Context(), object.RequestContextKey, &object.RequestContext{
Namespace: w.requestInfo.ContainerNamespace(), Namespace: w.requestInfo.ContainerNamespace(),
SenderKey: w.requestInfo.SenderKey(), ContainerOwner: w.requestInfo.ContainerOwner(),
Role: w.requestInfo.RequestRole(), SenderKey: w.requestInfo.SenderKey(),
SoftAPECheck: w.requestInfo.IsSoftAPECheck(), Role: w.requestInfo.RequestRole(),
SoftAPECheck: w.requestInfo.IsSoftAPECheck(),
}) })
} }
@ -137,10 +138,11 @@ type wrappedRangeStream struct {
func (w *wrappedRangeStream) Context() context.Context { func (w *wrappedRangeStream) Context() context.Context {
return context.WithValue(w.GetObjectRangeStream.Context(), object.RequestContextKey, &object.RequestContext{ return context.WithValue(w.GetObjectRangeStream.Context(), object.RequestContextKey, &object.RequestContext{
Namespace: w.requestInfo.ContainerNamespace(), Namespace: w.requestInfo.ContainerNamespace(),
SenderKey: w.requestInfo.SenderKey(), ContainerOwner: w.requestInfo.ContainerOwner(),
Role: w.requestInfo.RequestRole(), SenderKey: w.requestInfo.SenderKey(),
SoftAPECheck: w.requestInfo.IsSoftAPECheck(), Role: w.requestInfo.RequestRole(),
SoftAPECheck: w.requestInfo.IsSoftAPECheck(),
}) })
} }
@ -161,10 +163,11 @@ type wrappedSearchStream struct {
func (w *wrappedSearchStream) Context() context.Context { func (w *wrappedSearchStream) Context() context.Context {
return context.WithValue(w.SearchStream.Context(), object.RequestContextKey, &object.RequestContext{ return context.WithValue(w.SearchStream.Context(), object.RequestContextKey, &object.RequestContext{
Namespace: w.requestInfo.ContainerNamespace(), Namespace: w.requestInfo.ContainerNamespace(),
SenderKey: w.requestInfo.SenderKey(), ContainerOwner: w.requestInfo.ContainerOwner(),
Role: w.requestInfo.RequestRole(), SenderKey: w.requestInfo.SenderKey(),
SoftAPECheck: w.requestInfo.IsSoftAPECheck(), Role: w.requestInfo.RequestRole(),
SoftAPECheck: w.requestInfo.IsSoftAPECheck(),
}) })
} }
@ -471,10 +474,11 @@ func (b Service) GetRange(request *objectV2.GetRangeRequest, stream object.GetOb
func requestContext(ctx context.Context, reqInfo RequestInfo) context.Context { func requestContext(ctx context.Context, reqInfo RequestInfo) context.Context {
return context.WithValue(ctx, object.RequestContextKey, &object.RequestContext{ return context.WithValue(ctx, object.RequestContextKey, &object.RequestContext{
Namespace: reqInfo.ContainerNamespace(), Namespace: reqInfo.ContainerNamespace(),
SenderKey: reqInfo.SenderKey(), ContainerOwner: reqInfo.ContainerOwner(),
Role: reqInfo.RequestRole(), SenderKey: reqInfo.SenderKey(),
SoftAPECheck: reqInfo.IsSoftAPECheck(), Role: reqInfo.RequestRole(),
SoftAPECheck: reqInfo.IsSoftAPECheck(),
}) })
} }

View file

@ -8,6 +8,7 @@ import (
objectV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" objectV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain" apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
policyengine "git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine" policyengine "git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
nativeschema "git.frostfs.info/TrueCloudLab/policy-engine/schema/native" nativeschema "git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
@ -48,6 +49,9 @@ type Prm struct {
// An encoded sender's public key string. // An encoded sender's public key string.
SenderKey string SenderKey string
// An encoded container's owner user ID.
ContainerOwner user.ID
// If SoftAPECheck is set to true, then NoRuleFound is interpreted as allow. // If SoftAPECheck is set to true, then NoRuleFound is interpreted as allow.
SoftAPECheck bool SoftAPECheck bool
} }

View file

@ -10,6 +10,7 @@ import (
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
aperesource "git.frostfs.info/TrueCloudLab/policy-engine/pkg/resource" aperesource "git.frostfs.info/TrueCloudLab/policy-engine/pkg/resource"
nativeschema "git.frostfs.info/TrueCloudLab/policy-engine/schema/native" nativeschema "git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
) )
@ -78,11 +79,13 @@ func resourceName(cid cid.ID, oid *oid.ID, namespace string) string {
} }
// objectProperties collects object properties from address parameters and a header if it is passed. // objectProperties collects object properties from address parameters and a header if it is passed.
func objectProperties(cnr cid.ID, oid *oid.ID, header *objectV2.Header) map[string]string { func objectProperties(cnr cid.ID, oid *oid.ID, cnrOwner user.ID, header *objectV2.Header) map[string]string {
objectProps := map[string]string{ objectProps := map[string]string{
nativeschema.PropertyKeyObjectContainerID: cnr.EncodeToString(), nativeschema.PropertyKeyObjectContainerID: cnr.EncodeToString(),
} }
objectProps[nativeschema.PropertyKeyContainerOwnerID] = cnrOwner.EncodeToString()
if oid != nil { if oid != nil {
objectProps[nativeschema.PropertyKeyObjectID] = oid.String() objectProps[nativeschema.PropertyKeyObjectID] = oid.String()
} }
@ -149,7 +152,7 @@ func (c *checkerImpl) newAPERequest(ctx context.Context, prm Prm) (*request, err
operation: prm.Method, operation: prm.Method,
resource: &resource{ resource: &resource{
name: resourceName(prm.Container, prm.Object, prm.Namespace), name: resourceName(prm.Container, prm.Object, prm.Namespace),
properties: objectProperties(prm.Container, prm.Object, header), properties: objectProperties(prm.Container, prm.Object, prm.ContainerOwner, header),
}, },
properties: map[string]string{ properties: map[string]string{
nativeschema.PropertyKeyActorPublicKey: prm.SenderKey, nativeschema.PropertyKeyActorPublicKey: prm.SenderKey,

View file

@ -8,11 +8,16 @@ import (
objectV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" objectV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
checksumtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/checksum/test" checksumtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/checksum/test"
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
usertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user/test" usertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user/test"
nativeschema "git.frostfs.info/TrueCloudLab/policy-engine/schema/native" nativeschema "git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
const (
testOwnerID = "FPPtmAi9TCX329"
)
func TestObjectProperties(t *testing.T) { func TestObjectProperties(t *testing.T) {
for _, test := range []struct { for _, test := range []struct {
name string name string
@ -82,8 +87,12 @@ func TestObjectProperties(t *testing.T) {
obj := newObjectIDSDK(t, test.object) obj := newObjectIDSDK(t, test.object)
header := newHeaderObjectSDK(cnr, obj, test.header) header := newHeaderObjectSDK(cnr, obj, test.header)
props := objectProperties(cnr, obj, header.ToV2().GetHeader()) var testCnrOwner user.ID
require.NoError(t, testCnrOwner.DecodeString(testOwnerID))
props := objectProperties(cnr, obj, testCnrOwner, header.ToV2().GetHeader())
require.Equal(t, test.container, props[nativeschema.PropertyKeyObjectContainerID]) require.Equal(t, test.container, props[nativeschema.PropertyKeyObjectContainerID])
require.Equal(t, testOwnerID, props[nativeschema.PropertyKeyContainerOwnerID])
if obj != nil { if obj != nil {
require.Equal(t, *test.object, props[nativeschema.PropertyKeyObjectID]) require.Equal(t, *test.object, props[nativeschema.PropertyKeyObjectID])
@ -210,13 +219,17 @@ func TestNewAPERequest(t *testing.T) {
cnr := newContainerIDSDK(t, test.container) cnr := newContainerIDSDK(t, test.container)
obj := newObjectIDSDK(t, test.object) obj := newObjectIDSDK(t, test.object)
var testCnrOwner user.ID
require.NoError(t, testCnrOwner.DecodeString(testOwnerID))
prm := Prm{ prm := Prm{
Namespace: test.namespace, Namespace: test.namespace,
Method: method, Method: method,
Container: cnr, Container: cnr,
Object: obj, Object: obj,
Role: role, Role: role,
SenderKey: senderKey, SenderKey: senderKey,
ContainerOwner: testCnrOwner,
} }
headerSource := newHeaderProviderMock() headerSource := newHeaderProviderMock()
@ -247,7 +260,7 @@ func TestNewAPERequest(t *testing.T) {
operation: method, operation: method,
resource: &resource{ resource: &resource{
name: resourceName(cnr, obj, prm.Namespace), name: resourceName(cnr, obj, prm.Namespace),
properties: objectProperties(cnr, obj, func() *objectV2.Header { properties: objectProperties(cnr, obj, testCnrOwner, func() *objectV2.Header {
if headerObjSDK != nil { if headerObjSDK != nil {
return headerObjSDK.ToV2().GetHeader() return headerObjSDK.ToV2().GetHeader()
} }

View file

@ -14,6 +14,7 @@ import (
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
nativeschema "git.frostfs.info/TrueCloudLab/policy-engine/schema/native" nativeschema "git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
) )
@ -67,6 +68,8 @@ type getStreamBasicChecker struct {
senderKey []byte senderKey []byte
containerOwner user.ID
role string role string
softAPECheck bool softAPECheck bool
@ -80,14 +83,15 @@ func (g *getStreamBasicChecker) Send(resp *objectV2.GetResponse) error {
} }
prm := Prm{ prm := Prm{
Namespace: g.namespace, Namespace: g.namespace,
Container: cnrID, Container: cnrID,
Object: objID, Object: objID,
Header: partInit.GetHeader(), Header: partInit.GetHeader(),
Method: nativeschema.MethodGetObject, Method: nativeschema.MethodGetObject,
SenderKey: hex.EncodeToString(g.senderKey), SenderKey: hex.EncodeToString(g.senderKey),
Role: g.role, ContainerOwner: g.containerOwner,
SoftAPECheck: g.softAPECheck, Role: g.role,
SoftAPECheck: g.softAPECheck,
} }
if err := g.apeChecker.CheckAPE(g.Context(), prm); err != nil { if err := g.apeChecker.CheckAPE(g.Context(), prm); err != nil {
@ -121,13 +125,14 @@ func (c *Service) Get(request *objectV2.GetRequest, stream objectSvc.GetObjectSt
} }
err = c.apeChecker.CheckAPE(stream.Context(), Prm{ err = c.apeChecker.CheckAPE(stream.Context(), Prm{
Namespace: reqCtx.Namespace, Namespace: reqCtx.Namespace,
Container: cnrID, Container: cnrID,
Object: objID, Object: objID,
Method: nativeschema.MethodGetObject, Method: nativeschema.MethodGetObject,
Role: nativeSchemaRole(reqCtx.Role), Role: nativeSchemaRole(reqCtx.Role),
SenderKey: hex.EncodeToString(reqCtx.SenderKey), SenderKey: hex.EncodeToString(reqCtx.SenderKey),
SoftAPECheck: reqCtx.SoftAPECheck, ContainerOwner: reqCtx.ContainerOwner,
SoftAPECheck: reqCtx.SoftAPECheck,
}) })
if err != nil { if err != nil {
return toStatusErr(err) return toStatusErr(err)
@ -162,14 +167,15 @@ func (p *putStreamBasicChecker) Send(ctx context.Context, request *objectV2.PutR
} }
prm := Prm{ prm := Prm{
Namespace: reqCtx.Namespace, Namespace: reqCtx.Namespace,
Container: cnrID, Container: cnrID,
Object: objID, Object: objID,
Header: partInit.GetHeader(), Header: partInit.GetHeader(),
Method: nativeschema.MethodPutObject, Method: nativeschema.MethodPutObject,
SenderKey: hex.EncodeToString(reqCtx.SenderKey), SenderKey: hex.EncodeToString(reqCtx.SenderKey),
Role: nativeSchemaRole(reqCtx.Role), ContainerOwner: reqCtx.ContainerOwner,
SoftAPECheck: reqCtx.SoftAPECheck, Role: nativeSchemaRole(reqCtx.Role),
SoftAPECheck: reqCtx.SoftAPECheck,
} }
if err := p.apeChecker.CheckAPE(ctx, prm); err != nil { if err := p.apeChecker.CheckAPE(ctx, prm); err != nil {
@ -205,13 +211,14 @@ func (c *Service) Head(ctx context.Context, request *objectV2.HeadRequest) (*obj
} }
err = c.apeChecker.CheckAPE(ctx, Prm{ err = c.apeChecker.CheckAPE(ctx, Prm{
Namespace: reqCtx.Namespace, Namespace: reqCtx.Namespace,
Container: cnrID, Container: cnrID,
Object: objID, Object: objID,
Method: nativeschema.MethodHeadObject, Method: nativeschema.MethodHeadObject,
Role: nativeSchemaRole(reqCtx.Role), Role: nativeSchemaRole(reqCtx.Role),
SenderKey: hex.EncodeToString(reqCtx.SenderKey), SenderKey: hex.EncodeToString(reqCtx.SenderKey),
SoftAPECheck: reqCtx.SoftAPECheck, ContainerOwner: reqCtx.ContainerOwner,
SoftAPECheck: reqCtx.SoftAPECheck,
}) })
if err != nil { if err != nil {
return nil, toStatusErr(err) return nil, toStatusErr(err)
@ -242,14 +249,15 @@ func (c *Service) Head(ctx context.Context, request *objectV2.HeadRequest) (*obj
} }
err = c.apeChecker.CheckAPE(ctx, Prm{ err = c.apeChecker.CheckAPE(ctx, Prm{
Namespace: reqCtx.Namespace, Namespace: reqCtx.Namespace,
Container: cnrID, Container: cnrID,
Object: objID, Object: objID,
Header: header, Header: header,
Method: nativeschema.MethodHeadObject, Method: nativeschema.MethodHeadObject,
Role: nativeSchemaRole(reqCtx.Role), Role: nativeSchemaRole(reqCtx.Role),
SenderKey: hex.EncodeToString(reqCtx.SenderKey), SenderKey: hex.EncodeToString(reqCtx.SenderKey),
SoftAPECheck: reqCtx.SoftAPECheck, ContainerOwner: reqCtx.ContainerOwner,
SoftAPECheck: reqCtx.SoftAPECheck,
}) })
if err != nil { if err != nil {
return nil, toStatusErr(err) return nil, toStatusErr(err)
@ -271,12 +279,13 @@ func (c *Service) Search(request *objectV2.SearchRequest, stream objectSvc.Searc
} }
err = c.apeChecker.CheckAPE(stream.Context(), Prm{ err = c.apeChecker.CheckAPE(stream.Context(), Prm{
Namespace: reqCtx.Namespace, Namespace: reqCtx.Namespace,
Container: cnrID, Container: cnrID,
Method: nativeschema.MethodSearchObject, Method: nativeschema.MethodSearchObject,
Role: nativeSchemaRole(reqCtx.Role), Role: nativeSchemaRole(reqCtx.Role),
SenderKey: hex.EncodeToString(reqCtx.SenderKey), SenderKey: hex.EncodeToString(reqCtx.SenderKey),
SoftAPECheck: reqCtx.SoftAPECheck, ContainerOwner: reqCtx.ContainerOwner,
SoftAPECheck: reqCtx.SoftAPECheck,
}) })
if err != nil { if err != nil {
return toStatusErr(err) return toStatusErr(err)
@ -297,13 +306,14 @@ func (c *Service) Delete(ctx context.Context, request *objectV2.DeleteRequest) (
} }
err = c.apeChecker.CheckAPE(ctx, Prm{ err = c.apeChecker.CheckAPE(ctx, Prm{
Namespace: reqCtx.Namespace, Namespace: reqCtx.Namespace,
Container: cnrID, Container: cnrID,
Object: objID, Object: objID,
Method: nativeschema.MethodDeleteObject, Method: nativeschema.MethodDeleteObject,
Role: nativeSchemaRole(reqCtx.Role), Role: nativeSchemaRole(reqCtx.Role),
SenderKey: hex.EncodeToString(reqCtx.SenderKey), SenderKey: hex.EncodeToString(reqCtx.SenderKey),
SoftAPECheck: reqCtx.SoftAPECheck, ContainerOwner: reqCtx.ContainerOwner,
SoftAPECheck: reqCtx.SoftAPECheck,
}) })
if err != nil { if err != nil {
return nil, toStatusErr(err) return nil, toStatusErr(err)
@ -329,13 +339,14 @@ func (c *Service) GetRange(request *objectV2.GetRangeRequest, stream objectSvc.G
} }
err = c.apeChecker.CheckAPE(stream.Context(), Prm{ err = c.apeChecker.CheckAPE(stream.Context(), Prm{
Namespace: reqCtx.Namespace, Namespace: reqCtx.Namespace,
Container: cnrID, Container: cnrID,
Object: objID, Object: objID,
Method: nativeschema.MethodRangeObject, Method: nativeschema.MethodRangeObject,
Role: nativeSchemaRole(reqCtx.Role), Role: nativeSchemaRole(reqCtx.Role),
SenderKey: hex.EncodeToString(reqCtx.SenderKey), SenderKey: hex.EncodeToString(reqCtx.SenderKey),
SoftAPECheck: reqCtx.SoftAPECheck, ContainerOwner: reqCtx.ContainerOwner,
SoftAPECheck: reqCtx.SoftAPECheck,
}) })
if err != nil { if err != nil {
return toStatusErr(err) return toStatusErr(err)
@ -356,13 +367,14 @@ func (c *Service) GetRangeHash(ctx context.Context, request *objectV2.GetRangeHa
} }
prm := Prm{ prm := Prm{
Namespace: reqCtx.Namespace, Namespace: reqCtx.Namespace,
Container: cnrID, Container: cnrID,
Object: objID, Object: objID,
Method: nativeschema.MethodHashObject, Method: nativeschema.MethodHashObject,
Role: nativeSchemaRole(reqCtx.Role), Role: nativeSchemaRole(reqCtx.Role),
SenderKey: hex.EncodeToString(reqCtx.SenderKey), SenderKey: hex.EncodeToString(reqCtx.SenderKey),
SoftAPECheck: reqCtx.SoftAPECheck, ContainerOwner: reqCtx.ContainerOwner,
SoftAPECheck: reqCtx.SoftAPECheck,
} }
if err = c.apeChecker.CheckAPE(ctx, prm); err != nil { if err = c.apeChecker.CheckAPE(ctx, prm); err != nil {
@ -392,14 +404,15 @@ func (c *Service) PutSingle(ctx context.Context, request *objectV2.PutSingleRequ
} }
prm := Prm{ prm := Prm{
Namespace: reqCtx.Namespace, Namespace: reqCtx.Namespace,
Container: cnrID, Container: cnrID,
Object: objID, Object: objID,
Header: request.GetBody().GetObject().GetHeader(), Header: request.GetBody().GetObject().GetHeader(),
Method: nativeschema.MethodPutObject, Method: nativeschema.MethodPutObject,
Role: nativeSchemaRole(reqCtx.Role), Role: nativeSchemaRole(reqCtx.Role),
SenderKey: hex.EncodeToString(reqCtx.SenderKey), SenderKey: hex.EncodeToString(reqCtx.SenderKey),
SoftAPECheck: reqCtx.SoftAPECheck, ContainerOwner: reqCtx.ContainerOwner,
SoftAPECheck: reqCtx.SoftAPECheck,
} }
if err = c.apeChecker.CheckAPE(ctx, prm); err != nil { if err = c.apeChecker.CheckAPE(ctx, prm); err != nil {

View file

@ -1,6 +1,9 @@
package object package object
import "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl" import (
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
)
type RequestContextKeyT struct{} type RequestContextKeyT struct{}
@ -12,6 +15,8 @@ type RequestContext struct {
SenderKey []byte SenderKey []byte
ContainerOwner user.ID
Role acl.Role Role acl.Role
SoftAPECheck bool SoftAPECheck bool