relax validation when loading lifecycle document from the backend (#9612)

This commit is contained in:
Anis Elleuch 2020-05-18 16:33:43 +01:00 committed by GitHub
parent de9b391db3
commit 96009975d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 61 additions and 31 deletions

View File

@ -72,6 +72,12 @@ func (api objectAPIHandlers) PutBucketLifecycleHandler(w http.ResponseWriter, r
return return
} }
// Validate the received bucket policy document
if err = bucketLifecycle.Validate(); err != nil {
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
return
}
if err = objAPI.SetBucketLifecycle(ctx, bucket, bucketLifecycle); err != nil { if err = objAPI.SetBucketLifecycle(ctx, bucket, bucketLifecycle); err != nil {
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
return return

View File

@ -23,6 +23,7 @@ import (
"path" "path"
"sync" "sync"
"github.com/minio/minio/cmd/logger"
"github.com/minio/minio/pkg/bucket/lifecycle" "github.com/minio/minio/pkg/bucket/lifecycle"
) )
@ -148,9 +149,15 @@ func (sys *LifecycleSys) load(buckets []BucketInfo, objAPI ObjectLayer) error {
return err return err
} }
// Do not load the lifecycle configuration if it is not valid
err = config.Validate()
if err != nil {
logger.LogIf(context.Background(), err)
continue
}
sys.Set(bucket.Name, config) sys.Set(bucket.Name, config)
} }
return nil return nil
} }

View File

@ -18,15 +18,13 @@ package lifecycle
import ( import (
"encoding/xml" "encoding/xml"
"github.com/minio/minio-go/v6/pkg/tags"
) )
// And - a tag to combine a prefix and multiple tags for lifecycle configuration rule. // And - a tag to combine a prefix and multiple tags for lifecycle configuration rule.
type And struct { type And struct {
XMLName xml.Name `xml:"And"` XMLName xml.Name `xml:"And"`
Prefix string `xml:"Prefix,omitempty"` Prefix string `xml:"Prefix,omitempty"`
Tags []tags.Tag `xml:"Tag,omitempty"` Tags []Tag `xml:"Tag,omitempty"`
} }
var errDuplicateTagKey = Errorf("Duplicate Tag Keys are not allowed") var errDuplicateTagKey = Errorf("Duplicate Tag Keys are not allowed")

View File

@ -18,8 +18,6 @@ package lifecycle
import ( import (
"encoding/xml" "encoding/xml"
"github.com/minio/minio-go/v6/pkg/tags"
) )
var ( var (
@ -31,7 +29,7 @@ type Filter struct {
XMLName xml.Name `xml:"Filter"` XMLName xml.Name `xml:"Filter"`
Prefix string Prefix string
And And And And
Tag tags.Tag Tag Tag
} }
// MarshalXML - produces the xml representation of the Filter struct // MarshalXML - produces the xml representation of the Filter struct

View File

@ -57,9 +57,6 @@ func ParseLifecycleConfig(reader io.Reader) (*Lifecycle, error) {
if err := xml.NewDecoder(reader).Decode(&lc); err != nil { if err := xml.NewDecoder(reader).Decode(&lc); err != nil {
return nil, err return nil, err
} }
if err := lc.Validate(); err != nil {
return nil, err
}
return &lc, nil return &lc, nil
} }

View File

@ -24,7 +24,7 @@ import (
"time" "time"
) )
func TestParseLifecycleConfig(t *testing.T) { func TestParseAndValidateLifecycleConfig(t *testing.T) {
// Test for lifecycle config with more than 1000 rules // Test for lifecycle config with more than 1000 rules
var manyRules []Rule var manyRules []Rule
rule := Rule{ rule := Rule{
@ -64,8 +64,9 @@ func TestParseLifecycleConfig(t *testing.T) {
} }
testCases := []struct { testCases := []struct {
inputConfig string inputConfig string
expectedErr error expectedParsingErr error
expectedValidationErr error
}{ }{
{ // Valid lifecycle config { // Valid lifecycle config
inputConfig: `<LifecycleConfiguration> inputConfig: `<LifecycleConfiguration>
@ -84,28 +85,36 @@ func TestParseLifecycleConfig(t *testing.T) {
<Expiration><Days>3</Days></Expiration> <Expiration><Days>3</Days></Expiration>
</Rule> </Rule>
</LifecycleConfiguration>`, </LifecycleConfiguration>`,
expectedErr: nil, expectedParsingErr: nil,
expectedValidationErr: nil,
}, },
{ // lifecycle config with no rules { // lifecycle config with no rules
inputConfig: `<LifecycleConfiguration> inputConfig: `<LifecycleConfiguration>
</LifecycleConfiguration>`, </LifecycleConfiguration>`,
expectedErr: errLifecycleNoRule, expectedParsingErr: nil,
expectedValidationErr: errLifecycleNoRule,
}, },
{ // lifecycle config with more than 1000 rules { // lifecycle config with more than 1000 rules
inputConfig: string(manyRuleLcConfig), inputConfig: string(manyRuleLcConfig),
expectedErr: errLifecycleTooManyRules, expectedParsingErr: nil,
expectedValidationErr: errLifecycleTooManyRules,
}, },
{ // lifecycle config with rules having overlapping prefix { // lifecycle config with rules having overlapping prefix
inputConfig: string(overlappingLcConfig), inputConfig: string(overlappingLcConfig),
expectedErr: errLifecycleOverlappingPrefix, expectedParsingErr: nil,
expectedValidationErr: errLifecycleOverlappingPrefix,
}, },
} }
for i, tc := range testCases { for i, tc := range testCases {
t.Run(fmt.Sprintf("Test %d", i+1), func(t *testing.T) { t.Run(fmt.Sprintf("Test %d", i+1), func(t *testing.T) {
var err error lc, err := ParseLifecycleConfig(bytes.NewReader([]byte(tc.inputConfig)))
if _, err = ParseLifecycleConfig(bytes.NewReader([]byte(tc.inputConfig))); err != tc.expectedErr { if err != tc.expectedParsingErr {
t.Fatalf("%d: Expected %v but got %v", i+1, tc.expectedErr, err) t.Fatalf("%d: Expected %v during parsing but got %v", i+1, tc.expectedParsingErr, err)
}
err = lc.Validate()
if err != tc.expectedValidationErr {
t.Fatalf("%d: Expected %v during parsing but got %v", i+1, tc.expectedValidationErr, err)
} }
}) })
} }

View File

@ -18,6 +18,7 @@ package lifecycle
import ( import (
"encoding/xml" "encoding/xml"
"unicode/utf8"
) )
// Tag - a tag for a lifecycle configuration Rule filter. // Tag - a tag for a lifecycle configuration Rule filter.
@ -27,15 +28,29 @@ type Tag struct {
Value string `xml:"Value,omitempty"` Value string `xml:"Value,omitempty"`
} }
var errTagUnsupported = Errorf("Specifying <Tag></Tag> is not supported") var (
errInvalidTagKey = Errorf("The TagKey you have provided is invalid")
errInvalidTagValue = Errorf("The TagValue you have provided is invalid")
)
// UnmarshalXML is extended to indicate lack of support for Tag func (tag Tag) String() string {
// xml tag in object lifecycle configuration return tag.Key + "=" + tag.Value
func (t Tag) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
return errTagUnsupported
} }
// MarshalXML is extended to leave out <Tag></Tag> tags // IsEmpty returns whether this tag is empty or not.
func (t Tag) MarshalXML(e *xml.Encoder, start xml.StartElement) error { func (tag Tag) IsEmpty() bool {
return tag.Key == ""
}
// Validate checks this tag.
func (tag Tag) Validate() error {
if len(tag.Key) == 0 || utf8.RuneCountInString(tag.Key) > 128 {
return errInvalidTagKey
}
if utf8.RuneCountInString(tag.Value) > 256 {
return errInvalidTagValue
}
return nil return nil
} }