From 3c436d8de99fe03e7b1d5683748fb1f8b12c667b Mon Sep 17 00:00:00 2001
From: Pavel Pogodaev
Date: Fri, 12 Apr 2024 11:59:05 +0300
Subject: [PATCH] [#365] Include iam user tags in query
Signed-off-by: Pavel Pogodaev
---
api/middleware/policy.go | 13 +++++++++----
api/router_mock_test.go | 5 +++--
api/router_test.go | 17 +++++++++++++++++
internal/frostfs/frostfsid/frostfsid.go | 8 ++++----
4 files changed, 33 insertions(+), 10 deletions(-)
diff --git a/api/middleware/policy.go b/api/middleware/policy.go
index 3af3fd58..615e3235 100644
--- a/api/middleware/policy.go
+++ b/api/middleware/policy.go
@@ -51,7 +51,7 @@ type PolicySettings interface {
}
type FrostFSIDInformer interface {
- GetUserGroupIDs(userHash util.Uint160) ([]string, error)
+ GetUserGroupIDsAndClaims(userHash util.Uint160) ([]string, map[string]string, error)
}
type XMLDecoder interface {
@@ -149,6 +149,7 @@ func getPolicyRequest(r *http.Request, cfg PolicyConfig, reqType ReqType, bktNam
var (
owner string
groups []string
+ tags map[string]string
)
ctx := r.Context()
@@ -160,7 +161,7 @@ func getPolicyRequest(r *http.Request, cfg PolicyConfig, reqType ReqType, bktNam
}
owner = pk.Address()
- groups, err = cfg.FrostfsID.GetUserGroupIDs(pk.GetScriptHash())
+ groups, tags, err = cfg.FrostfsID.GetUserGroupIDsAndClaims(pk.GetScriptHash())
if err != nil {
return nil, fmt.Errorf("get group ids: %w", err)
}
@@ -175,7 +176,7 @@ func getPolicyRequest(r *http.Request, cfg PolicyConfig, reqType ReqType, bktNam
res = fmt.Sprintf(s3.ResourceFormatS3Bucket, bktName)
}
- properties, err := determineProperties(r, cfg.Decoder, cfg.BucketResolver, cfg.Tagging, reqType, op, bktName, objName, owner, groups)
+ properties, err := determineProperties(r, cfg.Decoder, cfg.BucketResolver, cfg.Tagging, reqType, op, bktName, objName, owner, groups, tags)
if err != nil {
return nil, fmt.Errorf("determine properties: %w", err)
}
@@ -410,13 +411,17 @@ func determineGeneralOperation(r *http.Request) string {
}
func determineProperties(r *http.Request, decoder XMLDecoder, resolver BucketResolveFunc, tagging ResourceTagging, reqType ReqType,
- op, bktName, objName, owner string, groups []string) (map[string]string, error) {
+ op, bktName, objName, owner string, groups []string, tags map[string]string) (map[string]string, error) {
res := map[string]string{
s3.PropertyKeyOwner: owner,
common.PropertyKeyFrostFSIDGroupID: chain.FormCondSliceContainsValue(groups),
}
queries := GetReqInfo(r.Context()).URL.Query()
+ for k, v := range tags {
+ res[fmt.Sprintf(common.PropertyKeyFormatFrostFSIDUserClaim, k)] = v
+ }
+
if reqType == objectType {
if versionID := queries.Get(QueryVersionID); len(versionID) > 0 {
res[s3.PropertyKeyVersionID] = versionID
diff --git a/api/router_mock_test.go b/api/router_mock_test.go
index 8c996da7..6b410020 100644
--- a/api/router_mock_test.go
+++ b/api/router_mock_test.go
@@ -85,14 +85,15 @@ func (r *middlewareSettingsMock) ACLEnabled() bool {
}
type frostFSIDMock struct {
+ tags map[string]string
}
func (f *frostFSIDMock) ValidatePublicKey(*keys.PublicKey) error {
return nil
}
-func (f *frostFSIDMock) GetUserGroupIDs(util.Uint160) ([]string, error) {
- return []string{}, nil
+func (f *frostFSIDMock) GetUserGroupIDsAndClaims(util.Uint160) ([]string, map[string]string, error) {
+ return []string{}, f.tags, nil
}
type xmlMock struct {
diff --git a/api/router_test.go b/api/router_test.go
index fdeb851d..ed895a81 100644
--- a/api/router_test.go
+++ b/api/router_test.go
@@ -22,6 +22,7 @@ import (
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine/inmemory"
+ "git.frostfs.info/TrueCloudLab/policy-engine/schema/common"
"git.frostfs.info/TrueCloudLab/policy-engine/schema/s3"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
@@ -256,6 +257,22 @@ func TestDefaultBehaviorPolicyChecker(t *testing.T) {
createBucketErr(chiRouter, ns, bktName, apiErrors.ErrAccessDenied)
}
+func TestDefaultPolicyCheckerWithUserTags(t *testing.T) {
+ router := prepareRouter(t)
+ ns, bktName := "", "bucket"
+ router.middlewareSettings.denyByDefault = true
+
+ allowOperations(router, ns, []string{"s3:CreateBucket"}, engineiam.Conditions{
+ engineiam.CondStringEquals: engineiam.Condition{fmt.Sprintf(common.PropertyKeyFormatFrostFSIDUserClaim, "tag-test"): []string{"test"}},
+ })
+ createBucketErr(router, ns, bktName, apiErrors.ErrAccessDenied)
+
+ tags := make(map[string]string)
+ tags["tag-test"] = "test"
+ router.cfg.FrostfsID.(*frostFSIDMock).tags = tags
+ createBucket(router, ns, bktName)
+}
+
func TestACLAPE(t *testing.T) {
t.Run("acl disabled, ape deny by default", func(t *testing.T) {
router := prepareRouter(t)
diff --git a/internal/frostfs/frostfsid/frostfsid.go b/internal/frostfs/frostfsid/frostfsid.go
index a7eaf48b..26e4f624 100644
--- a/internal/frostfs/frostfsid/frostfsid.go
+++ b/internal/frostfs/frostfsid/frostfsid.go
@@ -57,14 +57,14 @@ func (f *FrostFSID) ValidatePublicKey(key *keys.PublicKey) error {
return err
}
-func (f *FrostFSID) GetUserGroupIDs(userHash util.Uint160) ([]string, error) {
+func (f *FrostFSID) GetUserGroupIDsAndClaims(userHash util.Uint160) ([]string, map[string]string, error) {
subj, err := f.getSubject(userHash)
if err != nil {
if strings.Contains(err.Error(), "not found") {
f.log.Debug(logs.UserGroupsListIsEmpty, zap.Error(err))
- return nil, nil
+ return nil, nil, nil
}
- return nil, err
+ return nil, nil, err
}
res := make([]string, len(subj.Groups))
@@ -72,7 +72,7 @@ func (f *FrostFSID) GetUserGroupIDs(userHash util.Uint160) ([]string, error) {
res[i] = strconv.FormatInt(group.ID, 10)
}
- return res, nil
+ return res, subj.KV, nil
}
func (f *FrostFSID) getSubject(addr util.Uint160) (*client.SubjectExtended, error) {