cubefs/objectnode/object_lock.go
yhjiango 4401624f96 feat(objectnode): s3 sts and signature auth
1. sts federation token
2. signature auth code refactor

Signed-off-by: yhjiango <jiangyunhua@oppo.com>
2023-08-30 20:05:32 +08:00

208 lines
5.9 KiB
Go

// Copyright 2023 The CubeFS Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
package objectnode
import (
"encoding/xml"
"errors"
"strconv"
"time"
"github.com/cubefs/cubefs/util/log"
)
var (
InvalidModeErr = errors.New("Invalid Retention Mode")
RetentionPeriodsTooLargeErr = errors.New("Default retention period is too large")
NonPositiveRetentionPeriodsErr = errors.New("Default retention period must be a positive integer value")
BothDaysAndYearsSpecifiedErr = errors.New("Either Days or Years must be specified, cannot be specified both at the same time")
EitherDaysOrYearsSpecifiedErr = errors.New("Either Days or Years must be specified")
InvalidObjectLockEnabledErr = errors.New("Only Enabled value is allowd to ObjectLockEnabled element")
NilDefaultRetentionErr = errors.New("Default retention cannot be nil")
NilDefaultRuleErr = errors.New("Default rule cannot be nil")
)
const (
ComplianceMode = "COMPLIANCE"
Enabled = "Enabled"
MaxObjectLockSize = 1 << 12 // 16KB
maximumRetentionDays = 70 * 365
maximumRetentionYears = 70
nanosecondsPerDay = 24 * 60 * 60 * 1e9
)
type ObjectLockConfig struct {
XMLNS string `xml:"xmlns,attr,omitempty" json:"-" `
XMLName *xml.Name `xml:"ObjectLockConfiguration" json:"-" `
ObjectLockEnabled string `xml:"ObjectLockEnabled" json:"object_lock_enabled,omitempty" `
Rule *ObjectLockRule `xml:"Rule,omitempty" json:"rule,omitempty"`
}
type ObjectLockRule struct {
DefaultRetention *DefaultRetention `xml:"DefaultRetention" json:"default_retention" `
}
type DefaultRetention struct {
XMLName *xml.Name `xml:"DefaultRetention" json:"-"`
Mode string `xml:"Mode" json:"mode"`
Days *int64 `xml:"Days,omitempty" json:"days,omitempty" `
Years *int64 `xml:"Years,omitempty" json:"years,omitempty"`
}
func (c *ObjectLockConfig) CheckValid() error {
if c.IsEmpty() {
return nil
}
if c.ObjectLockEnabled != Enabled {
return InvalidObjectLockEnabledErr
}
if c.Rule == nil {
return NilDefaultRuleErr
}
if c.Rule != nil && c.Rule.DefaultRetention == nil {
return NilDefaultRetentionErr
}
if err := c.Rule.DefaultRetention.isValid(); err != nil {
return err
}
return nil
}
type Retention struct {
Mode string
Duration time.Duration
}
func (c ObjectLockConfig) ToRetention() (r *Retention) {
if c.Rule != nil {
r = &Retention{}
r.Mode = c.Rule.DefaultRetention.Mode
if c.Rule.DefaultRetention.Days != nil {
r.Duration = time.Duration(nanosecondsPerDay * (*c.Rule.DefaultRetention.Days))
} else {
r.Duration = time.Duration(nanosecondsPerDay*(*c.Rule.DefaultRetention.Years)) * 365
}
}
return
}
// check whether ObjectLockConfig is empty
func (c ObjectLockConfig) IsEmpty() bool {
return c.ObjectLockEnabled == "" && c.Rule == nil
}
// parse ObjectLockConfig from xml
func ParseObjectLockConfigFromXML(data []byte) (*ObjectLockConfig, error) {
config := ObjectLockConfig{}
if err := xml.Unmarshal(data, &config); err != nil {
return nil, NewError("InvalidObjectLockConfiguration", err.Error(), 400)
}
err := config.CheckValid()
if err != nil {
return nil, NewError("InvalidObjectLockConfiguration", err.Error(), 400)
}
return &config, nil
}
// check valid of DefaultRetention
func (d DefaultRetention) isValid() error {
switch d.Mode {
case ComplianceMode:
default:
return InvalidModeErr
}
if d.Days == nil && d.Years == nil {
return EitherDaysOrYearsSpecifiedErr
}
if d.Days != nil && d.Years != nil {
return BothDaysAndYearsSpecifiedErr
}
if d.Days != nil {
if *d.Days <= 0 {
return NonPositiveRetentionPeriodsErr
}
if *d.Days > maximumRetentionDays {
return RetentionPeriodsTooLargeErr
}
}
if d.Years != nil {
if *d.Years <= 0 {
return NonPositiveRetentionPeriodsErr
}
if *d.Years > maximumRetentionYears {
return RetentionPeriodsTooLargeErr
}
}
return nil
}
type ObjectRetention struct {
XMLNS string `xml:"xmlns,attr,omitempty"`
XMLName xml.Name `xml:"Retention"`
Mode string `xml:"Mode,omitempty"`
RetainUntilDate RetentionDate `xml:"RetainUntilDate,omitempty"`
}
type RetentionDate struct {
time.Time
}
func (r RetentionDate) MarshalXML(e *xml.Encoder, startElement xml.StartElement) error {
if r == (RetentionDate{time.Time{}}) {
return nil
}
return e.EncodeElement(r.Format(ISO8601Layout), startElement)
}
func storeObjectLock(bytes []byte, vol *Volume) (err error) {
return vol.store.Put(vol.name, bucketRootPath, XAttrKeyOSSLock, bytes)
}
func isObjectLocked(v *Volume, inode uint64, name, path string) error {
xattrInfo, err := v.mw.XAttrGet_ll(inode, XAttrKeyOSSLock)
if err != nil {
log.LogErrorf("isObjectLocked: check ObjectLock err(%v) volume(%v) path(%v) name(%v)",
err, v.name, path, name)
return err
}
retainUntilDate := xattrInfo.Get(XAttrKeyOSSLock)
if len(retainUntilDate) > 0 {
retainUntilDateInt64, err := strconv.ParseInt(string(retainUntilDate), 10, 64)
if err != nil {
return err
}
if retainUntilDateInt64 > time.Now().UnixNano() {
log.LogWarnf("isObjectLocked: object is locked, retainUntilDate(%v) volume(%v) path(%v) name(%v)",
retainUntilDateInt64, v.name, path, name)
return AccessDenied
}
}
return nil
}
func formatRetentionDateStr(modifyTime time.Time, retention *Retention) string {
retentionDateUnixNano := modifyTime.Add(retention.Duration).UnixNano()
return strconv.FormatInt(retentionDateUnixNano, 10)
}