[#365] Include iam user tags in query #365
4 changed files with 33 additions and 10 deletions
|
@ -51,7 +51,7 @@ type PolicySettings interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type FrostFSIDInformer interface {
|
type FrostFSIDInformer interface {
|
||||||
GetUserGroupIDs(userHash util.Uint160) ([]string, error)
|
GetUserGroupIDsAndClaims(userHash util.Uint160) ([]string, map[string]string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type XMLDecoder interface {
|
type XMLDecoder interface {
|
||||||
|
@ -149,6 +149,7 @@ func getPolicyRequest(r *http.Request, cfg PolicyConfig, reqType ReqType, bktNam
|
||||||
var (
|
var (
|
||||||
owner string
|
owner string
|
||||||
groups []string
|
groups []string
|
||||||
|
tags map[string]string
|
||||||
)
|
)
|
||||||
|
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
|
@ -160,7 +161,7 @@ func getPolicyRequest(r *http.Request, cfg PolicyConfig, reqType ReqType, bktNam
|
||||||
}
|
}
|
||||||
owner = pk.Address()
|
owner = pk.Address()
|
||||||
|
|
||||||
groups, err = cfg.FrostfsID.GetUserGroupIDs(pk.GetScriptHash())
|
groups, tags, err = cfg.FrostfsID.GetUserGroupIDsAndClaims(pk.GetScriptHash())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("get group ids: %w", err)
|
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)
|
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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("determine properties: %w", err)
|
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,
|
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{
|
res := map[string]string{
|
||||||
s3.PropertyKeyOwner: owner,
|
s3.PropertyKeyOwner: owner,
|
||||||
common.PropertyKeyFrostFSIDGroupID: chain.FormCondSliceContainsValue(groups),
|
common.PropertyKeyFrostFSIDGroupID: chain.FormCondSliceContainsValue(groups),
|
||||||
}
|
}
|
||||||
queries := GetReqInfo(r.Context()).URL.Query()
|
queries := GetReqInfo(r.Context()).URL.Query()
|
||||||
|
|
||||||
|
for k, v := range tags {
|
||||||
|
res[fmt.Sprintf(common.PropertyKeyFormatFrostFSIDUserClaim, k)] = v
|
||||||
|
}
|
||||||
|
|
||||||
if reqType == objectType {
|
if reqType == objectType {
|
||||||
if versionID := queries.Get(QueryVersionID); len(versionID) > 0 {
|
if versionID := queries.Get(QueryVersionID); len(versionID) > 0 {
|
||||||
res[s3.PropertyKeyVersionID] = versionID
|
res[s3.PropertyKeyVersionID] = versionID
|
||||||
|
|
|
@ -85,14 +85,15 @@ func (r *middlewareSettingsMock) ACLEnabled() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
type frostFSIDMock struct {
|
type frostFSIDMock struct {
|
||||||
|
tags map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *frostFSIDMock) ValidatePublicKey(*keys.PublicKey) error {
|
func (f *frostFSIDMock) ValidatePublicKey(*keys.PublicKey) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *frostFSIDMock) GetUserGroupIDs(util.Uint160) ([]string, error) {
|
func (f *frostFSIDMock) GetUserGroupIDsAndClaims(util.Uint160) ([]string, map[string]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, f.tags, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type xmlMock struct {
|
type xmlMock struct {
|
||||||
|
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine/inmemory"
|
"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"
|
"git.frostfs.info/TrueCloudLab/policy-engine/schema/s3"
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/go-chi/chi/v5/middleware"
|
"github.com/go-chi/chi/v5/middleware"
|
||||||
|
@ -256,6 +257,22 @@ func TestDefaultBehaviorPolicyChecker(t *testing.T) {
|
||||||
createBucketErr(chiRouter, ns, bktName, apiErrors.ErrAccessDenied)
|
createBucketErr(chiRouter, ns, bktName, apiErrors.ErrAccessDenied)
|
||||||
}
|
}
|
||||||
dkirillov marked this conversation as resolved
Outdated
|
|||||||
|
|
||||||
|
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) {
|
func TestACLAPE(t *testing.T) {
|
||||||
t.Run("acl disabled, ape deny by default", func(t *testing.T) {
|
t.Run("acl disabled, ape deny by default", func(t *testing.T) {
|
||||||
router := prepareRouter(t)
|
router := prepareRouter(t)
|
||||||
|
|
|
@ -57,14 +57,14 @@ func (f *FrostFSID) ValidatePublicKey(key *keys.PublicKey) error {
|
||||||
return err
|
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)
|
subj, err := f.getSubject(userHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "not found") {
|
if strings.Contains(err.Error(), "not found") {
|
||||||
f.log.Debug(logs.UserGroupsListIsEmpty, zap.Error(err))
|
f.log.Debug(logs.UserGroupsListIsEmpty, zap.Error(err))
|
||||||
return nil, nil
|
return nil, nil, nil
|
||||||
dkirillov marked this conversation as resolved
Outdated
dkirillov
commented
We must not return error We must not return error
|
|||||||
}
|
}
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
res := make([]string, len(subj.Groups))
|
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)
|
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) {
|
func (f *FrostFSID) getSubject(addr util.Uint160) (*client.SubjectExtended, error) {
|
||||||
|
|
Loading…
Reference in a new issue
The logic should be the following:
true
AccessDenied
must be got)FrostFSIDMock
so it return appropriate tag for user