forked from TrueCloudLab/frostfs-s3-gw
[#306] Save bucket policy as native chain
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
parent
ff15f9f28a
commit
8f89f275bd
6 changed files with 78 additions and 24 deletions
|
@ -681,7 +681,7 @@ func (h *handler) DeleteBucketPolicyHandler(w http.ResponseWriter, r *http.Reque
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = h.ape.DeleteBucketPolicy(reqInfo.Namespace, bktInfo.CID, getBucketChainID(bktInfo)); err != nil {
|
if err = h.ape.DeleteBucketPolicy(reqInfo.Namespace, bktInfo.CID, getBucketChainID(chain.S3, bktInfo)); err != nil {
|
||||||
h.logAndSendError(w, "failed to delete policy from storage", reqInfo, err)
|
h.logAndSendError(w, "failed to delete policy from storage", reqInfo, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -721,15 +721,13 @@ func (h *handler) PutBucketPolicyHandler(w http.ResponseWriter, r *http.Request)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s3Chain, err := engineiam.ConvertToS3Chain(bktPolicy, h.frostfsid)
|
for _, stat := range bktPolicy.Statement {
|
||||||
if err != nil {
|
if len(stat.NotResource) != 0 {
|
||||||
h.logAndSendError(w, "could not convert s3 policy to chain policy", reqInfo, err)
|
h.logAndSendError(w, "policy resource mismatched bucket", reqInfo, errors.GetAPIError(errors.ErrMalformedPolicy))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s3Chain.ID = getBucketChainID(bktInfo)
|
|
||||||
|
|
||||||
for _, rule := range s3Chain.Rules {
|
for _, resource := range stat.Resource {
|
||||||
for _, resource := range rule.Resources.Names {
|
|
||||||
if reqInfo.BucketName != strings.Split(strings.TrimPrefix(resource, arnAwsPrefix), "/")[0] {
|
if reqInfo.BucketName != strings.Split(strings.TrimPrefix(resource, arnAwsPrefix), "/")[0] {
|
||||||
h.logAndSendError(w, "policy resource mismatched bucket", reqInfo, errors.GetAPIError(errors.ErrMalformedPolicy))
|
h.logAndSendError(w, "policy resource mismatched bucket", reqInfo, errors.GetAPIError(errors.ErrMalformedPolicy))
|
||||||
return
|
return
|
||||||
|
@ -737,14 +735,50 @@ func (h *handler) PutBucketPolicyHandler(w http.ResponseWriter, r *http.Request)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = h.ape.PutBucketPolicy(reqInfo.Namespace, bktInfo.CID, jsonPolicy, s3Chain); err != nil {
|
nativeChain, err := engineiam.ConvertToNativeChain(bktPolicy, h.nativeResolver(reqInfo.Namespace, bktInfo))
|
||||||
|
if err != nil {
|
||||||
|
h.logAndSendError(w, "could not convert s3 policy to native chain policy", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
nativeChain.ID = getBucketChainID(chain.Ingress, bktInfo)
|
||||||
|
|
||||||
|
s3Chain, err := engineiam.ConvertToS3Chain(bktPolicy, h.frostfsid)
|
||||||
|
if err != nil {
|
||||||
|
h.logAndSendError(w, "could not convert s3 policy to chain policy", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s3Chain.ID = getBucketChainID(chain.S3, bktInfo)
|
||||||
|
|
||||||
|
if err = h.ape.PutBucketPolicy(reqInfo.Namespace, bktInfo.CID, jsonPolicy, []*chain.Chain{s3Chain, nativeChain}); err != nil {
|
||||||
h.logAndSendError(w, "failed to update policy in contract", reqInfo, err)
|
h.logAndSendError(w, "failed to update policy in contract", reqInfo, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBucketChainID(bktInfo *data.BucketInfo) chain.ID {
|
type nativeResolver struct {
|
||||||
return chain.ID(string(chain.S3) + ":bkt" + string(bktInfo.CID[:]))
|
FrostFSID
|
||||||
|
namespace string
|
||||||
|
bktInfo *data.BucketInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *nativeResolver) GetBucketInfo(bucket string) (*engineiam.BucketInfo, error) {
|
||||||
|
if n.bktInfo.Name != bucket {
|
||||||
|
return nil, fmt.Errorf("invalid bucket %s: %w", bucket, errors.GetAPIError(errors.ErrMalformedPolicy))
|
||||||
|
}
|
||||||
|
|
||||||
|
return &engineiam.BucketInfo{Namespace: n.namespace, Container: n.bktInfo.CID.EncodeToString()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *handler) nativeResolver(ns string, bktInfo *data.BucketInfo) engineiam.NativeResolver {
|
||||||
|
return &nativeResolver{
|
||||||
|
FrostFSID: h.frostfsid,
|
||||||
|
namespace: ns,
|
||||||
|
bktInfo: bktInfo,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBucketChainID(prefix chain.Name, bktInfo *data.BucketInfo) chain.ID {
|
||||||
|
return chain.ID(string(prefix) + ":bkt" + string(bktInfo.CID[:]))
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseACLHeaders(header http.Header, key *keys.PublicKey) (*AccessControlPolicy, error) {
|
func parseACLHeaders(header http.Header, key *keys.PublicKey) (*AccessControlPolicy, error) {
|
||||||
|
|
|
@ -51,11 +51,12 @@ type (
|
||||||
|
|
||||||
FrostFSID interface {
|
FrostFSID interface {
|
||||||
GetUserAddress(account, user string) (string, error)
|
GetUserAddress(account, user string) (string, error)
|
||||||
|
GetUserKey(account, name string) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// APE is Access Policy Engine that needs to save policy and acl info to different places.
|
// APE is Access Policy Engine that needs to save policy and acl info to different places.
|
||||||
APE interface {
|
APE interface {
|
||||||
PutBucketPolicy(ns string, cnrID cid.ID, policy []byte, s3Chain *chain.Chain) error
|
PutBucketPolicy(ns string, cnrID cid.ID, policy []byte, chains []*chain.Chain) error
|
||||||
DeleteBucketPolicy(ns string, cnrID cid.ID, chainID chain.ID) error
|
DeleteBucketPolicy(ns string, cnrID cid.ID, chainID chain.ID) error
|
||||||
GetBucketPolicy(ns string, cnrID cid.ID) ([]byte, error)
|
GetBucketPolicy(ns string, cnrID cid.ID) ([]byte, error)
|
||||||
SaveACLChains(ns string, chains []*chain.Chain) error
|
SaveACLChains(ns string, chains []*chain.Chain) error
|
||||||
|
@ -101,6 +102,10 @@ func (f frostfsIDDisabled) GetUserAddress(_, _ string) (string, error) {
|
||||||
return "", errors.New("frostfsid disabled")
|
return "", errors.New("frostfsid disabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f frostfsIDDisabled) GetUserKey(account, name string) (string, error) {
|
||||||
|
return "", errors.New("frostfsid disabled")
|
||||||
|
}
|
||||||
|
|
||||||
// pickCopiesNumbers chooses the return values following this logic:
|
// pickCopiesNumbers chooses the return values following this logic:
|
||||||
// 1) array of copies numbers sent in request's header has the highest priority.
|
// 1) array of copies numbers sent in request's header has the highest priority.
|
||||||
// 2) array of copies numbers with corresponding location constraint provided in the config file.
|
// 2) array of copies numbers with corresponding location constraint provided in the config file.
|
||||||
|
|
|
@ -261,11 +261,18 @@ func (a *apeMock) DeletePolicy(namespace string, cnrID cid.ID) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *apeMock) PutBucketPolicy(ns string, cnrID cid.ID, policy []byte, s3Chain *chain.Chain) error {
|
func (a *apeMock) PutBucketPolicy(ns string, cnrID cid.ID, policy []byte, chain []*chain.Chain) error {
|
||||||
if err := a.PutPolicy(ns, cnrID, policy); err != nil {
|
if err := a.PutPolicy(ns, cnrID, policy); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return a.AddChain(engine.NamespaceTarget(ns), s3Chain)
|
|
||||||
|
for i := range chain {
|
||||||
|
if err := a.AddChain(engine.NamespaceTarget(ns), chain[i]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *apeMock) DeleteBucketPolicy(ns string, cnrID cid.ID, chainID chain.ID) error {
|
func (a *apeMock) DeleteBucketPolicy(ns string, cnrID cid.ID, chainID chain.ID) error {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package frostfsid
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -100,6 +101,15 @@ func (f *FrostFSID) GetUserAddress(namespace, name string) (string, error) {
|
||||||
return key.Address(), nil
|
return key.Address(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *FrostFSID) GetUserKey(account, name string) (string, error) {
|
||||||
|
key, err := f.cli.GetSubjectKeyByName(account, name)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return hex.EncodeToString(key.Bytes()), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (f *FrostFSID) GetUserGroupIDs(userHash util.Uint160) ([]string, error) {
|
func (f *FrostFSID) GetUserGroupIDs(userHash util.Uint160) ([]string, error) {
|
||||||
subjExt, err := f.cli.GetSubjectExtended(userHash)
|
subjExt, err := f.cli.GetSubjectExtended(userHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -73,13 +73,16 @@ func (c *MorphRuleChainStorage) ListMorphRuleChains(name chain.Name, target engi
|
||||||
return list, nil
|
return list, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MorphRuleChainStorage) PutBucketPolicy(ns string, cnrID cid.ID, policy []byte, s3Chain *chain.Chain) error {
|
func (c *MorphRuleChainStorage) PutBucketPolicy(ns string, cnrID cid.ID, policy []byte, chains []*chain.Chain) error {
|
||||||
c.cache.Delete(cache.MorphPolicyCacheKey{Target: engine.NamespaceTarget(ns), Name: chain.S3})
|
c.cache.Delete(cache.MorphPolicyCacheKey{Target: engine.NamespaceTarget(ns), Name: chain.S3})
|
||||||
|
|
||||||
tx := c.contract.StartTx()
|
tx := c.contract.StartTx()
|
||||||
tx.AddChain(policycontract.Namespace, ns, s3Chain.ID, s3Chain.Bytes())
|
|
||||||
tx.AddChain(policycontract.IAM, ns, getBucketPolicyName(cnrID), policy)
|
tx.AddChain(policycontract.IAM, ns, getBucketPolicyName(cnrID), policy)
|
||||||
|
|
||||||
|
for i := range chains {
|
||||||
|
tx.AddChain(policycontract.Namespace, ns, chains[i].ID, chains[i].Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
return c.contract.SendTx(tx)
|
return c.contract.SendTx(tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,8 +66,8 @@ func (s *Storage) LocalStorage() engine.LocalOverrideStorage {
|
||||||
return s.local
|
return s.local
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Storage) PutBucketPolicy(ns string, cnrID cid.ID, policy []byte, s3Chain *chain.Chain) error {
|
func (s *Storage) PutBucketPolicy(ns string, cnrID cid.ID, policy []byte, policyChains []*chain.Chain) error {
|
||||||
return s.morph.PutBucketPolicy(ns, cnrID, policy, s3Chain)
|
return s.morph.PutBucketPolicy(ns, cnrID, policy, policyChains)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Storage) DeleteBucketPolicy(ns string, cnrID cid.ID, chainID chain.ID) error {
|
func (s *Storage) DeleteBucketPolicy(ns string, cnrID cid.ID, chainID chain.ID) error {
|
||||||
|
@ -81,8 +81,3 @@ func (s *Storage) GetBucketPolicy(ns string, cnrID cid.ID) ([]byte, error) {
|
||||||
func (s *Storage) SaveACLChains(ns string, chains []*chain.Chain) error {
|
func (s *Storage) SaveACLChains(ns string, chains []*chain.Chain) error {
|
||||||
return s.morph.SaveACLChains(ns, chains)
|
return s.morph.SaveACLChains(ns, chains)
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
//func (s *Storage) ListChains(target engine.Target) ([]*chain.Chain, error) {
|
|
||||||
// return s.morph.ListMorphRuleChains(target)
|
|
||||||
//}
|
|
||||||
|
|
Loading…
Reference in a new issue