forked from TrueCloudLab/frostfs-s3-gw
[#261] Make PutBucketPolicy handler use policy contract
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
parent
6dbb07f0fa
commit
8273af8bf8
16 changed files with 594 additions and 202 deletions
|
@ -8,6 +8,7 @@ import (
|
|||
"encoding/json"
|
||||
stderrors "errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
@ -24,6 +25,9 @@ import (
|
|||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
||||
engineiam "git.frostfs.info/TrueCloudLab/policy-engine/iam"
|
||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
@ -485,19 +489,45 @@ func (h *handler) GetBucketPolicyHandler(w http.ResponseWriter, r *http.Request)
|
|||
return
|
||||
}
|
||||
|
||||
bucketACL, err := h.obj.GetBucketACL(r.Context(), bktInfo)
|
||||
resolvedNamespace := h.cfg.ResolveNamespaceAlias(reqInfo.Namespace)
|
||||
jsonPolicy, err := h.ape.GetPolicy(resolvedNamespace, bktInfo.CID)
|
||||
if err != nil {
|
||||
h.logAndSendError(w, "could not fetch bucket acl", reqInfo, err)
|
||||
if strings.Contains(err.Error(), "not found") {
|
||||
err = fmt.Errorf("%w: %s", errors.GetAPIError(errors.ErrNoSuchBucketPolicy), err.Error())
|
||||
}
|
||||
h.logAndSendError(w, "failed to get policy from storage", reqInfo, err)
|
||||
return
|
||||
}
|
||||
|
||||
ast := tableToAst(bucketACL.EACL, reqInfo.BucketName)
|
||||
bktPolicy := astToPolicy(ast)
|
||||
|
||||
w.Header().Set(api.ContentType, "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
if err = json.NewEncoder(w).Encode(bktPolicy); err != nil {
|
||||
h.logAndSendError(w, "something went wrong", reqInfo, err)
|
||||
if _, err = w.Write(jsonPolicy); err != nil {
|
||||
h.logAndSendError(w, "write json policy to client", reqInfo, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *handler) DeleteBucketPolicyHandler(w http.ResponseWriter, r *http.Request) {
|
||||
reqInfo := middleware.GetReqInfo(r.Context())
|
||||
|
||||
bktInfo, err := h.getBucketAndCheckOwner(r, reqInfo.BucketName)
|
||||
if err != nil {
|
||||
h.logAndSendError(w, "could not get bucket info", reqInfo, err)
|
||||
return
|
||||
}
|
||||
|
||||
resolvedNamespace := h.cfg.ResolveNamespaceAlias(reqInfo.Namespace)
|
||||
|
||||
target := engine.NamespaceTarget(resolvedNamespace)
|
||||
chainID := getBucketChainID(bktInfo)
|
||||
if err = h.ape.RemoveChain(target, chainID); err != nil {
|
||||
h.logAndSendError(w, "failed to remove morph rule chain", reqInfo, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err = h.ape.DeletePolicy(resolvedNamespace, bktInfo.CID); err != nil {
|
||||
h.logAndSendError(w, "failed to delete policy from storage", reqInfo, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -523,30 +553,52 @@ func (h *handler) PutBucketPolicyHandler(w http.ResponseWriter, r *http.Request)
|
|||
return
|
||||
}
|
||||
|
||||
token, err := getSessionTokenSetEACL(r.Context())
|
||||
jsonPolicy, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
h.logAndSendError(w, "couldn't get eacl token", reqInfo, err)
|
||||
h.logAndSendError(w, "read body", reqInfo, err)
|
||||
return
|
||||
}
|
||||
|
||||
bktPolicy := &bucketPolicy{Bucket: reqInfo.BucketName}
|
||||
if err = json.NewDecoder(r.Body).Decode(bktPolicy); err != nil {
|
||||
var bktPolicy engineiam.Policy
|
||||
if err = json.Unmarshal(jsonPolicy, &bktPolicy); err != nil {
|
||||
h.logAndSendError(w, "could not parse bucket policy", reqInfo, err)
|
||||
return
|
||||
}
|
||||
|
||||
astPolicy, err := policyToAst(bktPolicy)
|
||||
s3Chain, err := engineiam.ConvertToS3Chain(bktPolicy, h.frostfsid)
|
||||
if err != nil {
|
||||
h.logAndSendError(w, "could not translate policy to ast", reqInfo, err)
|
||||
h.logAndSendError(w, "could not convert s3 policy to chain policy", reqInfo, err)
|
||||
return
|
||||
}
|
||||
s3Chain.ID = getBucketChainID(bktInfo)
|
||||
|
||||
for _, rule := range s3Chain.Rules {
|
||||
for _, resource := range rule.Resources.Names {
|
||||
if reqInfo.BucketName != strings.Split(resource, "/")[0] {
|
||||
h.logAndSendError(w, "policy resource mismatched bucket", reqInfo, errors.GetAPIError(errors.ErrMalformedPolicy))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resolvedNamespace := h.cfg.ResolveNamespaceAlias(reqInfo.Namespace)
|
||||
|
||||
target := engine.NamespaceTarget(resolvedNamespace)
|
||||
if err = h.ape.AddChain(target, s3Chain); err != nil {
|
||||
h.logAndSendError(w, "failed to add morph rule chain", reqInfo, err)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = h.updateBucketACL(r, astPolicy, bktInfo, token); err != nil {
|
||||
h.logAndSendError(w, "could not update bucket acl", reqInfo, err)
|
||||
if err = h.ape.PutPolicy(resolvedNamespace, bktInfo.CID, jsonPolicy); err != nil {
|
||||
h.logAndSendError(w, "failed to save policy to storage", reqInfo, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func getBucketChainID(bktInfo *data.BucketInfo) chain.ID {
|
||||
return chain.ID("bkt" + string(bktInfo.CID[:]))
|
||||
}
|
||||
|
||||
func parseACLHeaders(header http.Header, key *keys.PublicKey) (*AccessControlPolicy, error) {
|
||||
var err error
|
||||
acp := &AccessControlPolicy{Owner: Owner{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue