[#535] Support public access block operations

Signed-off-by: Marina Biryukova <m.biryukova@yadro.com>
This commit is contained in:
Marina Biryukova 2025-04-03 13:51:16 +03:00 committed by Alexey Vanin
parent 4f0f2ca7bd
commit a7ce40d745
23 changed files with 940 additions and 87 deletions

View file

@ -88,7 +88,7 @@ func Auth(center Center, log *zap.Logger) Func {
}
type FrostFSIDValidator interface {
ValidatePublicKey(key *keys.PublicKey) error
GetUserNamespace(key *keys.PublicKey) (string, error)
}
func FrostfsIDValidation(frostfsID FrostFSIDValidator, log *zap.Logger) Func {
@ -104,7 +104,8 @@ func FrostfsIDValidation(frostfsID FrostFSIDValidator, log *zap.Logger) Func {
return
}
if err = validateBearerToken(frostfsID, bd.Gate.BearerToken); err != nil {
namespace, err := getNamespaceFromBearerToken(frostfsID, bd.Gate.BearerToken)
if err != nil {
reqLogOrDefault(ctx, log).Error(logs.FrostfsIDValidationFailed, zap.Error(err), logs.TagField(logs.TagDatapath))
if _, wrErr := WriteErrorResponse(w, GetReqInfo(ctx), err); wrErr != nil {
reqLogOrDefault(ctx, log).Error(logs.FailedToWriteResponse, zap.Error(wrErr), logs.TagField(logs.TagDatapath))
@ -112,25 +113,58 @@ func FrostfsIDValidation(frostfsID FrostFSIDValidator, log *zap.Logger) Func {
span.End()
return
}
reqInfo := GetReqInfo(r.Context())
reqInfo.UserNamespace = &namespace
span.End()
h.ServeHTTP(w, r)
})
}
}
func getNamespaceFromBearerToken(frostfsID FrostFSIDValidator, bt *bearer.Token) (string, error) {
m := new(acl.BearerToken)
bt.WriteToV2(m)
pk, err := keys.NewPublicKeyFromBytes(m.GetSignature().GetKey(), elliptic.P256())
if err != nil {
return "", fmt.Errorf("invalid bearer token public key: %w", err)
}
namespace, err := frostfsID.GetUserNamespace(pk)
if err != nil {
return "", fmt.Errorf("get user namespace: %w", err)
}
return namespace, nil
}
type PublicAccessBlockChecker interface {
CheckRestrictPublicBuckets(context.Context) error
}
func RestrictPublicBuckets(checker PublicAccessBlockChecker, log *zap.Logger) Func {
return func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx, span := tracing.StartSpanFromContext(r.Context(), "middleware.RestrictPublicBuckets")
if r.Method == http.MethodOptions {
span.End()
h.ServeHTTP(w, r)
return
}
if err := checker.CheckRestrictPublicBuckets(ctx); err != nil {
reqLogOrDefault(ctx, log).Error(logs.RestrictPublicBucketsCheckFailed, zap.Error(err), logs.TagField(logs.TagDatapath))
if _, wrErr := WriteErrorResponse(w, GetReqInfo(ctx), err); wrErr != nil {
reqLogOrDefault(ctx, log).Error(logs.FailedToWriteResponse, zap.Error(wrErr), logs.TagField(logs.TagDatapath))
}
span.End()
return
}
span.End()
h.ServeHTTP(w, r)
})
}
}
func validateBearerToken(frostfsID FrostFSIDValidator, bt *bearer.Token) error {
m := new(acl.BearerToken)
bt.WriteToV2(m)
pk, err := keys.NewPublicKeyFromBytes(m.GetSignature().GetKey(), elliptic.P256())
if err != nil {
return fmt.Errorf("invalid bearer token public key: %w", err)
}
if err = frostfsID.ValidatePublicKey(pk); err != nil {
return fmt.Errorf("validation data user key failed: %w", err)
}
return nil
}