[#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"
|
"encoding/json"
|
||||||
stderrors "errors"
|
stderrors "errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -24,6 +25,9 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
"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/session"
|
"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"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
@ -485,19 +489,45 @@ func (h *handler) GetBucketPolicyHandler(w http.ResponseWriter, r *http.Request)
|
||||||
return
|
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 {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ast := tableToAst(bucketACL.EACL, reqInfo.BucketName)
|
w.Header().Set(api.ContentType, "application/json")
|
||||||
bktPolicy := astToPolicy(ast)
|
|
||||||
|
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
if err = json.NewEncoder(w).Encode(bktPolicy); err != nil {
|
if _, err = w.Write(jsonPolicy); err != nil {
|
||||||
h.logAndSendError(w, "something went wrong", reqInfo, err)
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
token, err := getSessionTokenSetEACL(r.Context())
|
jsonPolicy, err := io.ReadAll(r.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(w, "couldn't get eacl token", reqInfo, err)
|
h.logAndSendError(w, "read body", reqInfo, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
bktPolicy := &bucketPolicy{Bucket: reqInfo.BucketName}
|
var bktPolicy engineiam.Policy
|
||||||
if err = json.NewDecoder(r.Body).Decode(bktPolicy); err != nil {
|
if err = json.Unmarshal(jsonPolicy, &bktPolicy); err != nil {
|
||||||
h.logAndSendError(w, "could not parse bucket policy", reqInfo, err)
|
h.logAndSendError(w, "could not parse bucket policy", reqInfo, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
astPolicy, err := policyToAst(bktPolicy)
|
s3Chain, err := engineiam.ConvertToS3Chain(bktPolicy, h.frostfsid)
|
||||||
if err != nil {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = h.updateBucketACL(r, astPolicy, bktInfo, token); err != nil {
|
if err = h.ape.PutPolicy(resolvedNamespace, bktInfo.CID, jsonPolicy); err != nil {
|
||||||
h.logAndSendError(w, "could not update bucket acl", reqInfo, err)
|
h.logAndSendError(w, "failed to save policy to storage", reqInfo, err)
|
||||||
return
|
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) {
|
func parseACLHeaders(header http.Header, key *keys.PublicKey) (*AccessControlPolicy, error) {
|
||||||
var err error
|
var err error
|
||||||
acp := &AccessControlPolicy{Owner: Owner{
|
acp := &AccessControlPolicy{Owner: Owner{
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
"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/session"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
||||||
|
engineiam "git.frostfs.info/TrueCloudLab/policy-engine/iam"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -1316,42 +1317,26 @@ func TestBucketPolicy(t *testing.T) {
|
||||||
hc := prepareHandlerContext(t)
|
hc := prepareHandlerContext(t)
|
||||||
bktName := "bucket-for-policy"
|
bktName := "bucket-for-policy"
|
||||||
|
|
||||||
box, key := createAccessBox(t)
|
createTestBucket(hc, bktName)
|
||||||
createBucket(t, hc, bktName, box)
|
|
||||||
|
|
||||||
bktPolicy := getBucketPolicy(hc, bktName)
|
getBucketPolicy(hc, bktName, s3errors.ErrNoSuchBucketPolicy)
|
||||||
for _, st := range bktPolicy.Statement {
|
|
||||||
if st.Effect == "Allow" {
|
|
||||||
require.Equal(t, hex.EncodeToString(key.PublicKey().Bytes()), st.Principal.CanonicalUser)
|
|
||||||
require.Equal(t, []string{arnAwsPrefix + bktName}, st.Resource)
|
|
||||||
} else {
|
|
||||||
require.Equal(t, allUsersWildcard, st.Principal.AWS)
|
|
||||||
require.Equal(t, "Deny", st.Effect)
|
|
||||||
require.Equal(t, []string{arnAwsPrefix + bktName}, st.Resource)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newPolicy := &bucketPolicy{
|
newPolicy := engineiam.Policy{
|
||||||
Statement: []statement{{
|
Statement: []engineiam.Statement{{
|
||||||
Effect: "Allow",
|
Principal: map[engineiam.PrincipalType][]string{engineiam.Wildcard: {}},
|
||||||
Principal: principal{AWS: allUsersWildcard},
|
Effect: engineiam.DenyEffect,
|
||||||
Action: []string{s3GetObject},
|
Action: engineiam.Action{"s3:PutObject"},
|
||||||
Resource: []string{arnAwsPrefix + "dummy"},
|
Resource: engineiam.Resource{"arn:aws:s3:::test/*"},
|
||||||
}},
|
}},
|
||||||
}
|
}
|
||||||
|
|
||||||
putBucketPolicy(hc, bktName, newPolicy, box, http.StatusInternalServerError)
|
putBucketPolicy(hc, bktName, newPolicy, s3errors.ErrMalformedPolicy)
|
||||||
|
|
||||||
newPolicy.Statement[0].Resource[0] = arnAwsPrefix + bktName
|
newPolicy.Statement[0].Resource[0] = arnAwsPrefix + bktName + "/*"
|
||||||
putBucketPolicy(hc, bktName, newPolicy, box, http.StatusOK)
|
putBucketPolicy(hc, bktName, newPolicy)
|
||||||
|
|
||||||
bktPolicy = getBucketPolicy(hc, bktName)
|
bktPolicy := getBucketPolicy(hc, bktName)
|
||||||
for _, st := range bktPolicy.Statement {
|
require.Equal(t, newPolicy, bktPolicy)
|
||||||
if st.Effect == "Allow" && st.Principal.AWS == allUsersWildcard {
|
|
||||||
require.Equal(t, []string{arnAwsPrefix + bktName}, st.Resource)
|
|
||||||
require.ElementsMatch(t, []string{s3GetObject, s3ListBucket}, st.Action)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBucketPolicyUnmarshal(t *testing.T) {
|
func TestBucketPolicyUnmarshal(t *testing.T) {
|
||||||
|
@ -1411,9 +1396,7 @@ func TestPutBucketPolicy(t *testing.T) {
|
||||||
{
|
{
|
||||||
"Version": "2012-10-17",
|
"Version": "2012-10-17",
|
||||||
"Statement": [{
|
"Statement": [{
|
||||||
"Principal": {
|
"Principal": "*",
|
||||||
"AWS": "*"
|
|
||||||
},
|
|
||||||
"Effect": "Deny",
|
"Effect": "Deny",
|
||||||
"Action": "s3:GetObject",
|
"Action": "s3:GetObject",
|
||||||
"Resource": "arn:aws:s3:::bucket-for-policy/*"
|
"Resource": "arn:aws:s3:::bucket-for-policy/*"
|
||||||
|
@ -1423,36 +1406,41 @@ func TestPutBucketPolicy(t *testing.T) {
|
||||||
hc := prepareHandlerContext(t)
|
hc := prepareHandlerContext(t)
|
||||||
bktName := "bucket-for-policy"
|
bktName := "bucket-for-policy"
|
||||||
|
|
||||||
box, _ := createAccessBox(t)
|
createTestBucket(hc, bktName)
|
||||||
createBucket(t, hc, bktName, box)
|
|
||||||
|
|
||||||
w, r := prepareTestPayloadRequest(hc, bktName, "", bytes.NewReader([]byte(bktPolicy)))
|
w, r := prepareTestPayloadRequest(hc, bktName, "", bytes.NewReader([]byte(bktPolicy)))
|
||||||
ctx := middleware.SetBoxData(r.Context(), box)
|
|
||||||
r = r.WithContext(ctx)
|
|
||||||
hc.Handler().PutBucketPolicyHandler(w, r)
|
hc.Handler().PutBucketPolicyHandler(w, r)
|
||||||
assertStatus(hc.t, w, http.StatusOK)
|
assertStatus(hc.t, w, http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBucketPolicy(hc *handlerContext, bktName string) *bucketPolicy {
|
func getBucketPolicy(hc *handlerContext, bktName string, errCode ...s3errors.ErrorCode) engineiam.Policy {
|
||||||
w, r := prepareTestRequest(hc, bktName, "", nil)
|
w, r := prepareTestRequest(hc, bktName, "", nil)
|
||||||
hc.Handler().GetBucketPolicyHandler(w, r)
|
hc.Handler().GetBucketPolicyHandler(w, r)
|
||||||
|
|
||||||
|
var policy engineiam.Policy
|
||||||
|
if len(errCode) == 0 {
|
||||||
assertStatus(hc.t, w, http.StatusOK)
|
assertStatus(hc.t, w, http.StatusOK)
|
||||||
policy := &bucketPolicy{}
|
err := json.NewDecoder(w.Result().Body).Decode(&policy)
|
||||||
err := json.NewDecoder(w.Result().Body).Decode(policy)
|
|
||||||
require.NoError(hc.t, err)
|
require.NoError(hc.t, err)
|
||||||
|
} else {
|
||||||
|
assertS3Error(hc.t, w, s3errors.GetAPIError(errCode[0]))
|
||||||
|
}
|
||||||
|
|
||||||
return policy
|
return policy
|
||||||
}
|
}
|
||||||
|
|
||||||
func putBucketPolicy(hc *handlerContext, bktName string, bktPolicy *bucketPolicy, box *accessbox.Box, status int) {
|
func putBucketPolicy(hc *handlerContext, bktName string, bktPolicy engineiam.Policy, errCode ...s3errors.ErrorCode) {
|
||||||
body, err := json.Marshal(bktPolicy)
|
body, err := json.Marshal(bktPolicy)
|
||||||
require.NoError(hc.t, err)
|
require.NoError(hc.t, err)
|
||||||
|
|
||||||
w, r := prepareTestPayloadRequest(hc, bktName, "", bytes.NewReader(body))
|
w, r := prepareTestPayloadRequest(hc, bktName, "", bytes.NewReader(body))
|
||||||
ctx := middleware.SetBoxData(r.Context(), box)
|
|
||||||
r = r.WithContext(ctx)
|
|
||||||
hc.Handler().PutBucketPolicyHandler(w, r)
|
hc.Handler().PutBucketPolicyHandler(w, r)
|
||||||
assertStatus(hc.t, w, status)
|
|
||||||
|
if len(errCode) == 0 {
|
||||||
|
assertStatus(hc.t, w, http.StatusOK)
|
||||||
|
} else {
|
||||||
|
assertS3Error(hc.t, w, s3errors.GetAPIError(errCode[0]))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkLastRecords(t *testing.T, tc *handlerContext, bktInfo *data.BucketInfo, action eacl.Action) {
|
func checkLastRecords(t *testing.T, tc *handlerContext, bktInfo *data.BucketInfo, action eacl.Action) {
|
||||||
|
|
|
@ -12,7 +12,10 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
||||||
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -22,6 +25,8 @@ type (
|
||||||
obj layer.Client
|
obj layer.Client
|
||||||
notificator Notificator
|
notificator Notificator
|
||||||
cfg Config
|
cfg Config
|
||||||
|
ape APE
|
||||||
|
frostfsid FrostFSID
|
||||||
}
|
}
|
||||||
|
|
||||||
Notificator interface {
|
Notificator interface {
|
||||||
|
@ -42,18 +47,52 @@ type (
|
||||||
IsResolveListAllow() bool
|
IsResolveListAllow() bool
|
||||||
BypassContentEncodingInChunks() bool
|
BypassContentEncodingInChunks() bool
|
||||||
MD5Enabled() bool
|
MD5Enabled() bool
|
||||||
|
ResolveNamespaceAlias(namespace string) string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FrostFSID interface {
|
||||||
|
GetUserAddress(account, user string) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// APE is Access Policy Engine that needs to save policy and acl info to different places.
|
||||||
|
APE interface {
|
||||||
|
MorphRuleChainStorage
|
||||||
|
PolicyStorage
|
||||||
|
}
|
||||||
|
|
||||||
|
// MorphRuleChainStorage is a similar to engine.MorphRuleChainStorage
|
||||||
|
// but doesn't know anything about tx.
|
||||||
|
MorphRuleChainStorage interface {
|
||||||
|
AddChain(target engine.Target, c *chain.Chain) error
|
||||||
|
RemoveChain(target engine.Target, chainID chain.ID) error
|
||||||
|
ListChains(target engine.Target) ([]*chain.Chain, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PolicyStorage is interface to save intact initial user provided policy.
|
||||||
|
PolicyStorage interface {
|
||||||
|
PutPolicy(namespace string, cnrID cid.ID, policy []byte) error
|
||||||
|
GetPolicy(namespace string, cnrID cid.ID) ([]byte, error)
|
||||||
|
DeletePolicy(namespace string, cnrID cid.ID) error
|
||||||
|
}
|
||||||
|
|
||||||
|
frostfsIDDisabled struct{}
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ api.Handler = (*handler)(nil)
|
var _ api.Handler = (*handler)(nil)
|
||||||
|
|
||||||
// New creates new api.Handler using given logger and client.
|
// New creates new api.Handler using given logger and client.
|
||||||
func New(log *zap.Logger, obj layer.Client, notificator Notificator, cfg Config) (api.Handler, error) {
|
func New(log *zap.Logger, obj layer.Client, notificator Notificator, cfg Config, storage APE, ffsid FrostFSID) (api.Handler, error) {
|
||||||
switch {
|
switch {
|
||||||
case obj == nil:
|
case obj == nil:
|
||||||
return nil, errors.New("empty FrostFS Object Layer")
|
return nil, errors.New("empty FrostFS Object Layer")
|
||||||
case log == nil:
|
case log == nil:
|
||||||
return nil, errors.New("empty logger")
|
return nil, errors.New("empty logger")
|
||||||
|
case storage == nil:
|
||||||
|
return nil, errors.New("empty policy storage")
|
||||||
|
}
|
||||||
|
|
||||||
|
if ffsid == nil {
|
||||||
|
ffsid = frostfsIDDisabled{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !cfg.NotificatorEnabled() {
|
if !cfg.NotificatorEnabled() {
|
||||||
|
@ -66,10 +105,16 @@ func New(log *zap.Logger, obj layer.Client, notificator Notificator, cfg Config)
|
||||||
log: log,
|
log: log,
|
||||||
obj: obj,
|
obj: obj,
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
|
ape: storage,
|
||||||
notificator: notificator,
|
notificator: notificator,
|
||||||
|
frostfsid: ffsid,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f frostfsIDDisabled) GetUserAddress(_, _ 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.
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
@ -26,9 +27,12 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
"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"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||||
|
"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"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
type handlerContext struct {
|
type handlerContext struct {
|
||||||
|
@ -116,6 +120,10 @@ func (c *configMock) MD5Enabled() bool {
|
||||||
return c.md5Enabled
|
return c.md5Enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *configMock) ResolveNamespaceAlias(ns string) string {
|
||||||
|
return ns
|
||||||
|
}
|
||||||
|
|
||||||
func prepareHandlerContext(t *testing.T) *handlerContext {
|
func prepareHandlerContext(t *testing.T) *handlerContext {
|
||||||
return prepareHandlerContextBase(t, false)
|
return prepareHandlerContextBase(t, false)
|
||||||
}
|
}
|
||||||
|
@ -167,6 +175,7 @@ func prepareHandlerContextBase(t *testing.T, minCache bool) *handlerContext {
|
||||||
log: l,
|
log: l,
|
||||||
obj: layer.NewLayer(l, tp, layerCfg),
|
obj: layer.NewLayer(l, tp, layerCfg),
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
|
ape: newAPEMock(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return &handlerContext{
|
return &handlerContext{
|
||||||
|
@ -199,6 +208,60 @@ func getMinCacheConfig(logger *zap.Logger) *layer.CachesConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type apeMock struct {
|
||||||
|
chainMap map[engine.Target][]*chain.Chain
|
||||||
|
policyMap map[string][]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAPEMock() *apeMock {
|
||||||
|
return &apeMock{
|
||||||
|
chainMap: map[engine.Target][]*chain.Chain{},
|
||||||
|
policyMap: map[string][]byte{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *apeMock) AddChain(target engine.Target, c *chain.Chain) error {
|
||||||
|
list := a.chainMap[target]
|
||||||
|
|
||||||
|
ind := slices.IndexFunc(list, func(item *chain.Chain) bool { return item.ID == c.ID })
|
||||||
|
if ind != -1 {
|
||||||
|
list[ind] = c
|
||||||
|
} else {
|
||||||
|
list = append(list, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
a.chainMap[target] = list
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *apeMock) RemoveChain(target engine.Target, chainID chain.ID) error {
|
||||||
|
a.chainMap[target] = slices.DeleteFunc(a.chainMap[target], func(item *chain.Chain) bool { return item.ID == chainID })
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *apeMock) ListChains(target engine.Target) ([]*chain.Chain, error) {
|
||||||
|
return a.chainMap[target], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *apeMock) PutPolicy(namespace string, cnrID cid.ID, policy []byte) error {
|
||||||
|
a.policyMap[namespace+cnrID.EncodeToString()] = policy
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *apeMock) GetPolicy(namespace string, cnrID cid.ID) ([]byte, error) {
|
||||||
|
policy, ok := a.policyMap[namespace+cnrID.EncodeToString()]
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return policy, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *apeMock) DeletePolicy(namespace string, cnrID cid.ID) error {
|
||||||
|
delete(a.policyMap, namespace+cnrID.EncodeToString())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func NewTreeServiceMock(t *testing.T) *tree.Tree {
|
func NewTreeServiceMock(t *testing.T) *tree.Tree {
|
||||||
memCli, err := tree.NewTreeServiceClientMemory()
|
memCli, err := tree.NewTreeServiceClientMemory()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
|
@ -7,10 +7,6 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *handler) DeleteBucketPolicyHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
h.logAndSendError(w, "not supported", middleware.GetReqInfo(r.Context()), errors.GetAPIError(errors.ErrNotSupported))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *handler) DeleteBucketLifecycleHandler(w http.ResponseWriter, r *http.Request) {
|
func (h *handler) DeleteBucketLifecycleHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
h.logAndSendError(w, "not supported", middleware.GetReqInfo(r.Context()), errors.GetAPIError(errors.ErrNotSupported))
|
h.logAndSendError(w, "not supported", middleware.GetReqInfo(r.Context()), errors.GetAPIError(errors.ErrNotSupported))
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
apiErr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apiErr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/policy"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
"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"
|
||||||
|
@ -52,7 +51,7 @@ func policyCheck(storage engine.ChainRouter, settings PolicySettings, domains []
|
||||||
|
|
||||||
reqInfo := GetReqInfo(r.Context())
|
reqInfo := GetReqInfo(r.Context())
|
||||||
target := engine.NewRequestTargetWithNamespace(settings.ResolveNamespaceAlias(reqInfo.Namespace))
|
target := engine.NewRequestTargetWithNamespace(settings.ResolveNamespaceAlias(reqInfo.Namespace))
|
||||||
st, found, err := storage.IsAllowed(policy.S3ChainName, target, req)
|
st, found, err := storage.IsAllowed(chain.S3, target, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,7 +111,7 @@ type Config struct {
|
||||||
// FrostfsID optional. If nil middleware.FrostfsIDValidation won't be attached.
|
// FrostfsID optional. If nil middleware.FrostfsIDValidation won't be attached.
|
||||||
FrostfsID s3middleware.FrostFSID
|
FrostfsID s3middleware.FrostFSID
|
||||||
|
|
||||||
PolicyStorage engine.LocalOverrideEngine
|
PolicyChecker engine.ChainRouter
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRouter(cfg Config) *chi.Mux {
|
func NewRouter(cfg Config) *chi.Mux {
|
||||||
|
@ -130,8 +130,8 @@ func NewRouter(cfg Config) *chi.Mux {
|
||||||
api.Use(s3middleware.FrostfsIDValidation(cfg.FrostfsID, cfg.Log))
|
api.Use(s3middleware.FrostfsIDValidation(cfg.FrostfsID, cfg.Log))
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.PolicyStorage != nil {
|
if cfg.PolicyChecker != nil {
|
||||||
api.Use(s3middleware.PolicyCheck(cfg.PolicyStorage, cfg.MiddlewareSettings, cfg.Domains, cfg.Log))
|
api.Use(s3middleware.PolicyCheck(cfg.PolicyChecker, cfg.MiddlewareSettings, cfg.Domains, cfg.Log))
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultRouter := chi.NewRouter()
|
defaultRouter := chi.NewRouter()
|
||||||
|
@ -320,7 +320,7 @@ func bucketRouter(h Handler, log *zap.Logger) chi.Router {
|
||||||
Handler(named(s3middleware.DeleteBucketTaggingOperation, h.DeleteBucketTaggingHandler))).
|
Handler(named(s3middleware.DeleteBucketTaggingOperation, h.DeleteBucketTaggingHandler))).
|
||||||
Add(NewFilter().
|
Add(NewFilter().
|
||||||
Queries(s3middleware.PolicyQuery).
|
Queries(s3middleware.PolicyQuery).
|
||||||
Handler(named(s3middleware.PutBucketPolicyOperation, h.PutBucketPolicyHandler))).
|
Handler(named(s3middleware.DeleteBucketPolicyOperation, h.DeleteBucketPolicyHandler))).
|
||||||
Add(NewFilter().
|
Add(NewFilter().
|
||||||
Queries(s3middleware.LifecycleQuery).
|
Queries(s3middleware.LifecycleQuery).
|
||||||
Handler(named(s3middleware.PutBucketLifecycleOperation, h.PutBucketLifecycleHandler))).
|
Handler(named(s3middleware.PutBucketLifecycleOperation, h.PutBucketLifecycleHandler))).
|
||||||
|
|
|
@ -27,6 +27,7 @@ type routerMock struct {
|
||||||
router *chi.Mux
|
router *chi.Mux
|
||||||
cfg Config
|
cfg Config
|
||||||
middlewareSettings *middlewareSettingsMock
|
middlewareSettings *middlewareSettingsMock
|
||||||
|
policyChecker engine.LocalOverrideEngine
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *routerMock) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (m *routerMock) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -35,6 +36,7 @@ func (m *routerMock) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
func prepareRouter(t *testing.T) *routerMock {
|
func prepareRouter(t *testing.T) *routerMock {
|
||||||
middlewareSettings := &middlewareSettingsMock{}
|
middlewareSettings := &middlewareSettingsMock{}
|
||||||
|
policyChecker := inmemory.NewInMemoryLocalOverrides()
|
||||||
|
|
||||||
cfg := Config{
|
cfg := Config{
|
||||||
Throttle: middleware.ThrottleOpts{
|
Throttle: middleware.ThrottleOpts{
|
||||||
|
@ -46,12 +48,13 @@ func prepareRouter(t *testing.T) *routerMock {
|
||||||
Log: zaptest.NewLogger(t),
|
Log: zaptest.NewLogger(t),
|
||||||
Metrics: &metrics.AppMetrics{},
|
Metrics: &metrics.AppMetrics{},
|
||||||
MiddlewareSettings: middlewareSettings,
|
MiddlewareSettings: middlewareSettings,
|
||||||
PolicyStorage: inmemory.NewInMemoryLocalOverrides(),
|
PolicyChecker: policyChecker,
|
||||||
}
|
}
|
||||||
return &routerMock{
|
return &routerMock{
|
||||||
router: NewRouter(cfg),
|
router: NewRouter(cfg),
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
middlewareSettings: middlewareSettings,
|
middlewareSettings: middlewareSettings,
|
||||||
|
policyChecker: policyChecker,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,7 +167,7 @@ func TestPolicyChecker(t *testing.T) {
|
||||||
}},
|
}},
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err := chiRouter.cfg.PolicyStorage.MorphRuleChainStorage().AddMorphRuleChain(chain.S3, engine.NamespaceTarget(namespace), ruleChain)
|
_, _, err := chiRouter.policyChecker.MorphRuleChainStorage().AddMorphRuleChain(chain.S3, engine.NamespaceTarget(namespace), ruleChain)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// check we can access 'bucket' in default namespace
|
// check we can access 'bucket' in default namespace
|
||||||
|
|
|
@ -43,8 +43,6 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool"
|
||||||
treepool "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool/tree"
|
treepool "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool/tree"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine/inmemory"
|
|
||||||
"github.com/go-chi/chi/v5/middleware"
|
"github.com/go-chi/chi/v5/middleware"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
@ -70,7 +68,7 @@ type (
|
||||||
|
|
||||||
frostfsid *frostfsid.FrostFSID
|
frostfsid *frostfsid.FrostFSID
|
||||||
|
|
||||||
policyStorage engine.LocalOverrideEngine
|
policyStorage *policy.Storage
|
||||||
|
|
||||||
servers []Server
|
servers []Server
|
||||||
|
|
||||||
|
@ -144,11 +142,11 @@ func newApp(ctx context.Context, log *Logger, v *viper.Viper) *App {
|
||||||
|
|
||||||
func (a *App) init(ctx context.Context) {
|
func (a *App) init(ctx context.Context) {
|
||||||
a.setRuntimeParameters()
|
a.setRuntimeParameters()
|
||||||
a.initAPI(ctx)
|
|
||||||
a.initPolicyStorage(ctx)
|
|
||||||
a.initControlAPI()
|
|
||||||
a.initMetrics()
|
|
||||||
a.initFrostfsID(ctx)
|
a.initFrostfsID(ctx)
|
||||||
|
a.initPolicyStorage(ctx)
|
||||||
|
a.initAPI(ctx)
|
||||||
|
a.initMetrics()
|
||||||
|
a.initControlAPI()
|
||||||
a.initServers(ctx)
|
a.initServers(ctx)
|
||||||
a.initTracing(ctx)
|
a.initTracing(ctx)
|
||||||
}
|
}
|
||||||
|
@ -452,12 +450,13 @@ func (a *App) initFrostfsID(ctx context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) initPolicyStorage(ctx context.Context) {
|
func (a *App) initPolicyStorage(ctx context.Context) {
|
||||||
if !a.cfg.GetBool(cfgPolicyEnabled) {
|
var (
|
||||||
a.policyStorage = inmemory.NewInMemoryLocalOverrides()
|
err error
|
||||||
return
|
policyContract policy.Contract
|
||||||
}
|
)
|
||||||
|
|
||||||
policyClient, err := contract.New(ctx, contract.Config{
|
if a.cfg.GetBool(cfgPolicyEnabled) {
|
||||||
|
policyContract, err = contract.New(ctx, contract.Config{
|
||||||
RPCAddress: a.cfg.GetString(cfgRPCEndpoint),
|
RPCAddress: a.cfg.GetString(cfgRPCEndpoint),
|
||||||
Contract: a.cfg.GetString(cfgPolicyContract),
|
Contract: a.cfg.GetString(cfgPolicyContract),
|
||||||
Key: a.key,
|
Key: a.key,
|
||||||
|
@ -465,14 +464,15 @@ func (a *App) initPolicyStorage(ctx context.Context) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.log.Fatal(logs.InitPolicyContractFailed, zap.Error(err))
|
a.log.Fatal(logs.InitPolicyContractFailed, zap.Error(err))
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
policyContract = contract.NewInMemoryContract()
|
||||||
|
}
|
||||||
|
|
||||||
cachedMorph := policy.NewCachedMorph(policy.CachedMorphConfig{
|
a.policyStorage = policy.NewStorage(policy.StorageConfig{
|
||||||
Morph: policyClient,
|
Contract: policyContract,
|
||||||
Cache: cache.NewMorphPolicyCache(getMorphPolicyCacheConfig(a.cfg, a.log)),
|
Cache: cache.NewMorphPolicyCache(getMorphPolicyCacheConfig(a.cfg, a.log)),
|
||||||
Log: a.log,
|
Log: a.log,
|
||||||
})
|
})
|
||||||
|
|
||||||
a.policyStorage = policy.NewStorage(cachedMorph)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) initResolver() {
|
func (a *App) initResolver() {
|
||||||
|
@ -672,7 +672,7 @@ func (a *App) Serve(ctx context.Context) {
|
||||||
Domains: domains,
|
Domains: domains,
|
||||||
|
|
||||||
MiddlewareSettings: a.settings,
|
MiddlewareSettings: a.settings,
|
||||||
PolicyStorage: a.policyStorage,
|
PolicyChecker: a.policyStorage,
|
||||||
}
|
}
|
||||||
|
|
||||||
// We cannot make direct assignment if frostfsid.FrostFSID is nil
|
// We cannot make direct assignment if frostfsid.FrostFSID is nil
|
||||||
|
@ -943,8 +943,16 @@ func getMorphPolicyCacheConfig(v *viper.Viper, l *zap.Logger) *cache.Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) initHandler() {
|
func (a *App) initHandler() {
|
||||||
var err error
|
var (
|
||||||
a.api, err = handler.New(a.log, a.obj, a.nc, a.settings)
|
err error
|
||||||
|
ffsid handler.FrostFSID
|
||||||
|
)
|
||||||
|
|
||||||
|
if a.frostfsid != nil {
|
||||||
|
ffsid = a.frostfsid
|
||||||
|
}
|
||||||
|
|
||||||
|
a.api, err = handler.New(a.log, a.obj, a.nc, a.settings, a.policyStorage, ffsid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.log.Fatal(logs.CouldNotInitializeAPIHandler, zap.Error(err))
|
a.log.Fatal(logs.CouldNotInitializeAPIHandler, zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,10 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
|
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/handler"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/authmate"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/authmate"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/util"
|
frostfsutil "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
|
@ -33,11 +34,12 @@ type Config struct {
|
||||||
var (
|
var (
|
||||||
_ middleware.FrostFSID = (*FrostFSID)(nil)
|
_ middleware.FrostFSID = (*FrostFSID)(nil)
|
||||||
_ authmate.FrostFSID = (*FrostFSID)(nil)
|
_ authmate.FrostFSID = (*FrostFSID)(nil)
|
||||||
|
_ handler.FrostFSID = (*FrostFSID)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
// New creates new FrostfsID contract wrapper that implements auth.FrostFSID interface.
|
// New creates new FrostfsID contract wrapper that implements auth.FrostFSID interface.
|
||||||
func New(ctx context.Context, cfg Config) (*FrostFSID, error) {
|
func New(ctx context.Context, cfg Config) (*FrostFSID, error) {
|
||||||
contractHash, err := util.ResolveContractHash(cfg.Contract, cfg.RPCAddress)
|
contractHash, err := frostfsutil.ResolveContractHash(cfg.Contract, cfg.RPCAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("resolve frostfs contract hash: %w", err)
|
return nil, fmt.Errorf("resolve frostfs contract hash: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -77,3 +79,12 @@ func (f *FrostFSID) RegisterPublicKey(key *keys.PublicKey) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *FrostFSID) GetUserAddress(namespace, name string) (string, error) {
|
||||||
|
key, err := f.cli.GetSubjectKeyByName(namespace, name)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return key.Address(), nil
|
||||||
|
}
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
package policy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/cache"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CachedMorph struct {
|
|
||||||
morph engine.MorphRuleChainStorage
|
|
||||||
cache *cache.MorphPolicyCache
|
|
||||||
log *zap.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
type CachedMorphConfig struct {
|
|
||||||
Morph engine.MorphRuleChainStorage
|
|
||||||
Cache *cache.MorphPolicyCache
|
|
||||||
Log *zap.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ engine.MorphRuleChainStorage = (*CachedMorph)(nil)
|
|
||||||
|
|
||||||
func NewCachedMorph(config CachedMorphConfig) *CachedMorph {
|
|
||||||
return &CachedMorph{
|
|
||||||
morph: config.Morph,
|
|
||||||
cache: config.Cache,
|
|
||||||
log: config.Log,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CachedMorph) AddMorphRuleChain(name chain.Name, target engine.Target, policyChain *chain.Chain) (util.Uint256, uint32, error) {
|
|
||||||
c.cache.Delete(cache.MorphPolicyCacheKey{Target: target, Name: name})
|
|
||||||
return c.morph.AddMorphRuleChain(name, target, policyChain)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CachedMorph) RemoveMorphRuleChain(name chain.Name, target engine.Target, chainID chain.ID) (util.Uint256, uint32, error) {
|
|
||||||
c.cache.Delete(cache.MorphPolicyCacheKey{Target: target, Name: name})
|
|
||||||
return c.morph.RemoveMorphRuleChain(name, target, chainID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CachedMorph) ListMorphRuleChains(name chain.Name, target engine.Target) ([]*chain.Chain, error) {
|
|
||||||
key := cache.MorphPolicyCacheKey{Target: target, Name: name}
|
|
||||||
list := c.cache.Get(key)
|
|
||||||
if list != nil {
|
|
||||||
return list, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
list, err := c.morph.ListMorphRuleChains(name, target)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = c.cache.Put(key, list); err != nil {
|
|
||||||
c.log.Warn(logs.CouldntCacheListPolicyChains)
|
|
||||||
}
|
|
||||||
|
|
||||||
return list, nil
|
|
||||||
}
|
|
|
@ -7,9 +7,8 @@ import (
|
||||||
|
|
||||||
policycontract "git.frostfs.info/TrueCloudLab/frostfs-contract/policy"
|
policycontract "git.frostfs.info/TrueCloudLab/frostfs-contract/policy"
|
||||||
policyclient "git.frostfs.info/TrueCloudLab/frostfs-contract/rpcclient/policy"
|
policyclient "git.frostfs.info/TrueCloudLab/frostfs-contract/rpcclient/policy"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/policy"
|
||||||
frostfsutil "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/util"
|
frostfsutil "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/util"
|
||||||
"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"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
||||||
|
@ -34,7 +33,7 @@ type Config struct {
|
||||||
Key *keys.PrivateKey
|
Key *keys.PrivateKey
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ engine.MorphRuleChainStorage = (*Client)(nil)
|
var _ policy.Contract = (*Client)(nil)
|
||||||
|
|
||||||
// New creates new Policy contract wrapper.
|
// New creates new Policy contract wrapper.
|
||||||
func New(ctx context.Context, cfg Config) (*Client, error) {
|
func New(ctx context.Context, cfg Config) (*Client, error) {
|
||||||
|
@ -67,45 +66,36 @@ func New(ctx context.Context, cfg Config) (*Client, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) AddMorphRuleChain(name chain.Name, target engine.Target, policyChain *chain.Chain) (util.Uint256, uint32, error) {
|
func (c *Client) AddChain(kind policycontract.Kind, entity string, name []byte, chain []byte) (util.Uint256, uint32, error) {
|
||||||
chainName := append([]byte(name), []byte(policyChain.ID)...)
|
return c.policyContract.AddChain(big.NewInt(int64(kind)), entity, name, chain)
|
||||||
return c.policyContract.AddChain(getKind(target), target.Name, chainName, policyChain.Bytes())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) RemoveMorphRuleChain(name chain.Name, target engine.Target, chainID chain.ID) (util.Uint256, uint32, error) {
|
func (c *Client) GetChain(kind policycontract.Kind, entity string, name []byte) ([]byte, error) {
|
||||||
chainName := append([]byte(name), []byte(chainID)...)
|
return c.policyContract.GetChain(big.NewInt(int64(kind)), entity, name)
|
||||||
return c.policyContract.RemoveChain(getKind(target), target.Name, chainName)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) ListMorphRuleChains(name chain.Name, target engine.Target) ([]*chain.Chain, error) {
|
func (c *Client) RemoveChain(kind policycontract.Kind, entity string, name []byte) (util.Uint256, uint32, error) {
|
||||||
items, err := c.policyContract.ListChainsByPrefix(getKind(target), target.Name, []byte(name))
|
return c.policyContract.RemoveChain(big.NewInt(int64(kind)), entity, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListChains(kind policycontract.Kind, entity string, name []byte) ([][]byte, error) {
|
||||||
|
items, err := c.policyContract.ListChainsByPrefix(big.NewInt(int64(kind)), entity, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
res := make([]*chain.Chain, len(items))
|
res := make([][]byte, len(items))
|
||||||
for i, item := range items {
|
for i, item := range items {
|
||||||
data, err := item.TryBytes()
|
res[i], err = item.TryBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var policyChain chain.Chain
|
|
||||||
if err = policyChain.DecodeBytes(data); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
res[i] = &policyChain
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getKind(target engine.Target) *big.Int {
|
func (c *Client) Wait(tx util.Uint256, vub uint32, err error) error {
|
||||||
var kind int64 = policycontract.Container
|
_, err = c.actor.Wait(tx, vub, err)
|
||||||
if target.Type != engine.Container {
|
return err
|
||||||
kind = policycontract.Namespace
|
|
||||||
}
|
|
||||||
|
|
||||||
return big.NewInt(kind)
|
|
||||||
}
|
}
|
||||||
|
|
97
internal/frostfs/policy/contract/inmemory.go
Normal file
97
internal/frostfs/policy/contract/inmemory.go
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
package contract
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
policycontract "git.frostfs.info/TrueCloudLab/frostfs-contract/policy"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/policy"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type InMemoryContract struct {
|
||||||
|
iamChains *syncedMap
|
||||||
|
containerChains *syncedMap
|
||||||
|
namespaceChains *syncedMap
|
||||||
|
}
|
||||||
|
|
||||||
|
type syncedMap struct {
|
||||||
|
mu sync.RWMutex
|
||||||
|
data map[string][]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ policy.Contract = (*InMemoryContract)(nil)
|
||||||
|
|
||||||
|
var ErrChainNotFound = errors.New("chain not found")
|
||||||
|
|
||||||
|
// NewInMemoryContract creates new inmemory Policy contract wrapper.
|
||||||
|
func NewInMemoryContract() *InMemoryContract {
|
||||||
|
return &InMemoryContract{
|
||||||
|
iamChains: &syncedMap{data: map[string][]byte{}},
|
||||||
|
containerChains: &syncedMap{data: map[string][]byte{}},
|
||||||
|
namespaceChains: &syncedMap{data: map[string][]byte{}},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *InMemoryContract) AddChain(kind policycontract.Kind, entity string, name []byte, chain []byte) (util.Uint256, uint32, error) {
|
||||||
|
syncMap := c.getMap(kind)
|
||||||
|
syncMap.mu.Lock()
|
||||||
|
syncMap.data[entity+string(name)] = chain
|
||||||
|
syncMap.mu.Unlock()
|
||||||
|
|
||||||
|
return util.Uint256{}, 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *InMemoryContract) GetChain(kind policycontract.Kind, entity string, name []byte) ([]byte, error) {
|
||||||
|
syncMap := c.getMap(kind)
|
||||||
|
syncMap.mu.RLock()
|
||||||
|
defer syncMap.mu.RUnlock()
|
||||||
|
|
||||||
|
val, ok := syncMap.data[entity+string(name)]
|
||||||
|
if !ok {
|
||||||
|
return nil, ErrChainNotFound
|
||||||
|
}
|
||||||
|
return val, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *InMemoryContract) RemoveChain(kind policycontract.Kind, entity string, name []byte) (util.Uint256, uint32, error) {
|
||||||
|
syncMap := c.getMap(kind)
|
||||||
|
syncMap.mu.Lock()
|
||||||
|
delete(syncMap.data, entity+string(name))
|
||||||
|
syncMap.mu.Unlock()
|
||||||
|
|
||||||
|
return util.Uint256{}, 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *InMemoryContract) ListChains(kind policycontract.Kind, entity string, name []byte) ([][]byte, error) {
|
||||||
|
syncMap := c.getMap(kind)
|
||||||
|
syncMap.mu.RLock()
|
||||||
|
defer syncMap.mu.RUnlock()
|
||||||
|
|
||||||
|
var res [][]byte
|
||||||
|
for key, val := range syncMap.data {
|
||||||
|
if strings.HasPrefix(key, entity+string(name)) {
|
||||||
|
res = append(res, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *InMemoryContract) Wait(_ util.Uint256, _ uint32, err error) error {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *InMemoryContract) getMap(kind policycontract.Kind) *syncedMap {
|
||||||
|
switch kind {
|
||||||
|
case policycontract.IAM:
|
||||||
|
return c.iamChains
|
||||||
|
case policycontract.Container:
|
||||||
|
return c.containerChains
|
||||||
|
case policycontract.Namespace:
|
||||||
|
return c.namespaceChains
|
||||||
|
default:
|
||||||
|
return &syncedMap{data: map[string][]byte{}}
|
||||||
|
}
|
||||||
|
}
|
46
internal/frostfs/policy/morph_policy_storage.go
Normal file
46
internal/frostfs/policy/morph_policy_storage.go
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
package policy
|
||||||
|
|
||||||
|
import (
|
||||||
|
policycontract "git.frostfs.info/TrueCloudLab/frostfs-contract/policy"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/handler"
|
||||||
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MorphPolicyStorage struct {
|
||||||
|
contract Contract
|
||||||
|
}
|
||||||
|
|
||||||
|
type MorphPolicyStorageConfig struct {
|
||||||
|
Contract Contract
|
||||||
|
Log *zap.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ handler.PolicyStorage = (*MorphPolicyStorage)(nil)
|
||||||
|
|
||||||
|
const policyStoragePrefix = 'b'
|
||||||
|
|
||||||
|
func NewMorphPolicyStorage(config *MorphPolicyStorageConfig) *MorphPolicyStorage {
|
||||||
|
return &MorphPolicyStorage{
|
||||||
|
contract: config.Contract,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MorphPolicyStorage) PutPolicy(namespace string, cnrID cid.ID, policy []byte) error {
|
||||||
|
name := getPolicyStorageName(cnrID)
|
||||||
|
return c.contract.Wait(c.contract.AddChain(policycontract.IAM, namespace, name, policy))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MorphPolicyStorage) GetPolicy(namespace string, cnrID cid.ID) ([]byte, error) {
|
||||||
|
name := getPolicyStorageName(cnrID)
|
||||||
|
return c.contract.GetChain(policycontract.IAM, namespace, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MorphPolicyStorage) DeletePolicy(namespace string, cnrID cid.ID) error {
|
||||||
|
name := getPolicyStorageName(cnrID)
|
||||||
|
return c.contract.Wait(c.contract.RemoveChain(policycontract.IAM, namespace, name))
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPolicyStorageName(cnrID cid.ID) []byte {
|
||||||
|
return append([]byte{policyStoragePrefix}, cnrID[:]...)
|
||||||
|
}
|
102
internal/frostfs/policy/morph_rule_chain_storage.go
Normal file
102
internal/frostfs/policy/morph_rule_chain_storage.go
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
package policy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
policycontract "git.frostfs.info/TrueCloudLab/frostfs-contract/policy"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/cache"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/handler"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MorphRuleChainStorage struct {
|
||||||
|
contract Contract
|
||||||
|
cache *cache.MorphPolicyCache
|
||||||
|
log *zap.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
type MorphRuleChainStorageConfig struct {
|
||||||
|
Contract Contract
|
||||||
|
Cache *cache.MorphPolicyCache
|
||||||
|
Log *zap.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ engine.MorphRuleChainStorage = (*MorphRuleChainStorage)(nil)
|
||||||
|
_ handler.MorphRuleChainStorage = (*MorphRuleChainStorage)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewMorphRuleChainStorage(config *MorphRuleChainStorageConfig) *MorphRuleChainStorage {
|
||||||
|
return &MorphRuleChainStorage{
|
||||||
|
contract: config.Contract,
|
||||||
|
cache: config.Cache,
|
||||||
|
log: config.Log,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MorphRuleChainStorage) AddChain(target engine.Target, policyChain *chain.Chain) error {
|
||||||
|
return c.contract.Wait(c.AddMorphRuleChain(chain.S3, target, policyChain))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MorphRuleChainStorage) RemoveChain(target engine.Target, chainID chain.ID) error {
|
||||||
|
return c.contract.Wait(c.RemoveMorphRuleChain(chain.S3, target, chainID))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MorphRuleChainStorage) ListChains(target engine.Target) ([]*chain.Chain, error) {
|
||||||
|
return c.ListMorphRuleChains(chain.S3, target)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MorphRuleChainStorage) AddMorphRuleChain(name chain.Name, target engine.Target, policyChain *chain.Chain) (util.Uint256, uint32, error) {
|
||||||
|
c.cache.Delete(cache.MorphPolicyCacheKey{Target: target, Name: name})
|
||||||
|
return c.contract.AddChain(getKind(target), target.Name, getName(name, policyChain.ID), policyChain.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MorphRuleChainStorage) RemoveMorphRuleChain(name chain.Name, target engine.Target, chainID chain.ID) (util.Uint256, uint32, error) {
|
||||||
|
c.cache.Delete(cache.MorphPolicyCacheKey{Target: target, Name: name})
|
||||||
|
return c.contract.RemoveChain(getKind(target), target.Name, getName(name, chainID))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MorphRuleChainStorage) ListMorphRuleChains(name chain.Name, target engine.Target) ([]*chain.Chain, error) {
|
||||||
|
key := cache.MorphPolicyCacheKey{Target: target, Name: name}
|
||||||
|
list := c.cache.Get(key)
|
||||||
|
if list != nil {
|
||||||
|
return list, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
listChains, err := c.contract.ListChains(getKind(target), target.Name, []byte(name))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
list = make([]*chain.Chain, len(listChains))
|
||||||
|
for i, listChain := range listChains {
|
||||||
|
var item chain.Chain
|
||||||
|
if err = json.Unmarshal(listChain, &item); err != nil {
|
||||||
|
return nil, fmt.Errorf("unmarshal chain: %w", err)
|
||||||
|
}
|
||||||
|
list[i] = &item
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = c.cache.Put(key, list); err != nil {
|
||||||
|
c.log.Warn(logs.CouldntCacheListPolicyChains)
|
||||||
|
}
|
||||||
|
|
||||||
|
return list, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getKind(target engine.Target) policycontract.Kind {
|
||||||
|
var kind policycontract.Kind = policycontract.Container
|
||||||
|
if target.Type != engine.Container {
|
||||||
|
kind = policycontract.Namespace
|
||||||
|
}
|
||||||
|
|
||||||
|
return kind
|
||||||
|
}
|
||||||
|
func getName(name chain.Name, chainID chain.ID) []byte {
|
||||||
|
return append([]byte(name), []byte(chainID)...)
|
||||||
|
}
|
|
@ -1,42 +1,95 @@
|
||||||
package policy
|
package policy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
policycontract "git.frostfs.info/TrueCloudLab/frostfs-contract/policy"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/cache"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/handler"
|
||||||
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
"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/pkg/resource"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/resource"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
const S3ChainName chain.Name = "s3"
|
|
||||||
|
|
||||||
type Storage struct {
|
type Storage struct {
|
||||||
router engine.ChainRouter
|
router engine.ChainRouter
|
||||||
|
|
||||||
morph engine.MorphRuleChainStorage
|
morph handler.MorphRuleChainStorage
|
||||||
|
|
||||||
local engine.LocalOverrideStorage
|
local engine.LocalOverrideStorage
|
||||||
|
|
||||||
|
policy handler.PolicyStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ engine.LocalOverrideEngine = (*Storage)(nil)
|
type StorageConfig struct {
|
||||||
|
Contract Contract
|
||||||
|
Cache *cache.MorphPolicyCache
|
||||||
|
Log *zap.Logger
|
||||||
|
}
|
||||||
|
|
||||||
func NewStorage(morph engine.MorphRuleChainStorage) *Storage {
|
type Contract interface {
|
||||||
|
AddChain(kind policycontract.Kind, entity string, name []byte, chain []byte) (util.Uint256, uint32, error)
|
||||||
|
GetChain(kind policycontract.Kind, entity string, name []byte) ([]byte, error)
|
||||||
|
RemoveChain(kind policycontract.Kind, entity string, name []byte) (util.Uint256, uint32, error)
|
||||||
|
ListChains(kind policycontract.Kind, entity string, name []byte) ([][]byte, error)
|
||||||
|
Wait(tx util.Uint256, vub uint32, err error) error
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ handler.APE = (*Storage)(nil)
|
||||||
|
|
||||||
|
func NewStorage(cfg StorageConfig) *Storage {
|
||||||
|
// todo use thread safe inmemory https://git.frostfs.info/TrueCloudLab/policy-engine/issues/35
|
||||||
local := inmemory.NewInmemoryLocalStorage()
|
local := inmemory.NewInmemoryLocalStorage()
|
||||||
|
|
||||||
|
morph := NewMorphRuleChainStorage(&MorphRuleChainStorageConfig{
|
||||||
|
Contract: cfg.Contract,
|
||||||
|
Cache: cfg.Cache,
|
||||||
|
Log: cfg.Log,
|
||||||
|
})
|
||||||
|
|
||||||
|
policyStorage := NewMorphPolicyStorage(&MorphPolicyStorageConfig{
|
||||||
|
Contract: cfg.Contract,
|
||||||
|
Log: cfg.Log,
|
||||||
|
})
|
||||||
|
|
||||||
return &Storage{
|
return &Storage{
|
||||||
router: engine.NewDefaultChainRouterWithLocalOverrides(morph, local),
|
router: engine.NewDefaultChainRouterWithLocalOverrides(morph, local),
|
||||||
morph: morph,
|
morph: morph,
|
||||||
local: local,
|
local: local,
|
||||||
|
policy: policyStorage,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s Storage) IsAllowed(name chain.Name, target engine.RequestTarget, r resource.Request) (status chain.Status, found bool, err error) {
|
func (s *Storage) IsAllowed(name chain.Name, target engine.RequestTarget, r resource.Request) (status chain.Status, found bool, err error) {
|
||||||
return s.router.IsAllowed(name, target, r)
|
return s.router.IsAllowed(name, target, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s Storage) MorphRuleChainStorage() engine.MorphRuleChainStorage {
|
func (s *Storage) LocalStorage() engine.LocalOverrideStorage {
|
||||||
return s.morph
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Storage) LocalStorage() engine.LocalOverrideStorage {
|
|
||||||
return s.local
|
return s.local
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Storage) AddChain(target engine.Target, policyChain *chain.Chain) error {
|
||||||
|
return s.morph.AddChain(target, policyChain)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Storage) RemoveChain(target engine.Target, chainID chain.ID) error {
|
||||||
|
return s.morph.RemoveChain(target, chainID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Storage) ListChains(target engine.Target) ([]*chain.Chain, error) {
|
||||||
|
return s.morph.ListChains(target)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Storage) PutPolicy(namespace string, cnrID cid.ID, policy []byte) error {
|
||||||
|
return s.policy.PutPolicy(namespace, cnrID, policy)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Storage) GetPolicy(namespace string, cnrID cid.ID) ([]byte, error) {
|
||||||
|
return s.policy.GetPolicy(namespace, cnrID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Storage) DeletePolicy(namespace string, cnrID cid.ID) error {
|
||||||
|
return s.policy.DeletePolicy(namespace, cnrID)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue