mirror of
https://github.com/minio/minio.git
synced 2025-11-11 06:20:14 -05:00
signature: Rewrite signature handling and move it into a library.
This commit is contained in:
@@ -19,7 +19,6 @@ package fs
|
||||
import (
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
)
|
||||
@@ -167,7 +166,7 @@ var validBucket = regexp.MustCompile(`^[a-z0-9][a-z0-9\.\-]{1,61}[a-z0-9]$`)
|
||||
// IsValidBucketName - verify bucket name in accordance with
|
||||
// - http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html
|
||||
func IsValidBucketName(bucket string) bool {
|
||||
if strings.TrimSpace(bucket) == "" {
|
||||
if bucket == "" {
|
||||
return false
|
||||
}
|
||||
if len(bucket) < 3 || len(bucket) > 63 {
|
||||
@@ -182,7 +181,7 @@ func IsValidBucketName(bucket string) bool {
|
||||
// IsValidObjectName - verify object name in accordance with
|
||||
// - http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html
|
||||
func IsValidObjectName(object string) bool {
|
||||
if strings.TrimSpace(object) == "" {
|
||||
if object == "" {
|
||||
return true
|
||||
}
|
||||
if len(object) > 1024 || len(object) == 0 {
|
||||
|
||||
@@ -18,25 +18,11 @@ package fs
|
||||
|
||||
import "fmt"
|
||||
|
||||
// MissingDateHeader date header missing
|
||||
type MissingDateHeader struct{}
|
||||
// SignDoesNotMatch - signature does not match.
|
||||
type SignDoesNotMatch struct{}
|
||||
|
||||
func (e MissingDateHeader) Error() string {
|
||||
return "Missing date header"
|
||||
}
|
||||
|
||||
// MissingExpiresQuery expires query string missing
|
||||
type MissingExpiresQuery struct{}
|
||||
|
||||
func (e MissingExpiresQuery) Error() string {
|
||||
return "Missing expires query string"
|
||||
}
|
||||
|
||||
// ExpiredPresignedRequest request already expired
|
||||
type ExpiredPresignedRequest struct{}
|
||||
|
||||
func (e ExpiredPresignedRequest) Error() string {
|
||||
return "Presigned request already expired"
|
||||
func (e SignDoesNotMatch) Error() string {
|
||||
return "Signature does not match."
|
||||
}
|
||||
|
||||
// InvalidArgument invalid argument
|
||||
@@ -156,30 +142,8 @@ func (e BadDigest) Error() string {
|
||||
return "Bad digest"
|
||||
}
|
||||
|
||||
// ParityOverflow parity over flow
|
||||
type ParityOverflow struct{}
|
||||
|
||||
func (e ParityOverflow) Error() string {
|
||||
return "Parity overflow"
|
||||
}
|
||||
|
||||
// ChecksumMismatch checksum mismatch
|
||||
type ChecksumMismatch struct{}
|
||||
|
||||
func (e ChecksumMismatch) Error() string {
|
||||
return "Checksum mismatch"
|
||||
}
|
||||
|
||||
// MissingPOSTPolicy missing post policy
|
||||
type MissingPOSTPolicy struct{}
|
||||
|
||||
func (e MissingPOSTPolicy) Error() string {
|
||||
return "Missing POST policy in multipart form"
|
||||
}
|
||||
|
||||
// InternalError - generic internal error
|
||||
type InternalError struct {
|
||||
}
|
||||
type InternalError struct{}
|
||||
|
||||
// BackendError - generic disk backend error
|
||||
type BackendError struct {
|
||||
@@ -237,13 +201,6 @@ type BucketNameInvalid GenericBucketError
|
||||
|
||||
/// Object related errors
|
||||
|
||||
// EntityTooLarge - object size exceeds maximum limit
|
||||
type EntityTooLarge struct {
|
||||
GenericObjectError
|
||||
Size string
|
||||
MaxSize string
|
||||
}
|
||||
|
||||
// ObjectNameInvalid - object name provided is invalid
|
||||
type ObjectNameInvalid GenericObjectError
|
||||
|
||||
@@ -292,11 +249,6 @@ func (e ObjectNameInvalid) Error() string {
|
||||
return "Object name invalid: " + e.Bucket + "#" + e.Object
|
||||
}
|
||||
|
||||
// Return string an error formatted as the given text
|
||||
func (e EntityTooLarge) Error() string {
|
||||
return e.Bucket + "#" + e.Object + "with " + e.Size + "reached maximum allowed size limit " + e.MaxSize
|
||||
}
|
||||
|
||||
// IncompleteBody You did not provide the number of bytes specified by the Content-Length HTTP header
|
||||
type IncompleteBody GenericObjectError
|
||||
|
||||
|
||||
@@ -68,9 +68,11 @@ func (fs Filesystem) listObjects(bucket, prefix, marker, delimiter string, maxKe
|
||||
// Bucket path prefix should always end with a separator.
|
||||
bucketPathPrefix := bucketPath + string(os.PathSeparator)
|
||||
prefixPath := bucketPathPrefix + prefix
|
||||
st, err := os.Stat(prefixPath)
|
||||
if err != nil && os.IsNotExist(err) {
|
||||
walkPath = bucketPath
|
||||
st, e := os.Stat(prefixPath)
|
||||
if e != nil {
|
||||
if os.IsNotExist(e) {
|
||||
walkPath = bucketPath
|
||||
}
|
||||
} else {
|
||||
if st.IsDir() && !strings.HasSuffix(prefix, delimiter) {
|
||||
walkPath = bucketPath
|
||||
|
||||
@@ -152,7 +152,7 @@ func (fs Filesystem) MakeBucket(bucket, acl string) *probe.Error {
|
||||
}
|
||||
return probe.NewError(e)
|
||||
}
|
||||
if strings.TrimSpace(acl) == "" {
|
||||
if acl == "" {
|
||||
acl = "private"
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@ func (fs Filesystem) SetBucketMetadata(bucket string, metadata map[string]string
|
||||
if !IsValidBucketACL(acl) {
|
||||
return probe.NewError(InvalidACL{ACL: acl})
|
||||
}
|
||||
if strings.TrimSpace(acl) == "" {
|
||||
if acl == "" {
|
||||
acl = "private"
|
||||
}
|
||||
bucket = fs.denormalizeBucket(bucket)
|
||||
|
||||
@@ -174,7 +174,15 @@ func saveParts(partPathPrefix string, mw io.Writer, parts []CompletePart) *probe
|
||||
md5Sum = strings.TrimSuffix(md5Sum, "\"")
|
||||
partFile, e := os.OpenFile(partPathPrefix+md5Sum+fmt.Sprintf("$%d-$multiparts", part.PartNumber), os.O_RDONLY, 0600)
|
||||
if e != nil {
|
||||
return probe.NewError(e)
|
||||
if !os.IsNotExist(e) {
|
||||
return probe.NewError(e)
|
||||
}
|
||||
// Some clients do not set Content-MD5, so we would have
|
||||
// created part files without 'ETag' in them.
|
||||
partFile, e = os.OpenFile(partPathPrefix+fmt.Sprintf("$%d-$multiparts", part.PartNumber), os.O_RDONLY, 0600)
|
||||
if e != nil {
|
||||
return probe.NewError(e)
|
||||
}
|
||||
}
|
||||
partReaders = append(partReaders, partFile)
|
||||
partClosers = append(partClosers, partFile)
|
||||
@@ -322,9 +330,9 @@ func (fs Filesystem) CreateObjectPart(bucket, object, uploadID, expectedMD5Sum s
|
||||
return "", probe.NewError(InvalidUploadID{UploadID: uploadID})
|
||||
}
|
||||
|
||||
if strings.TrimSpace(expectedMD5Sum) != "" {
|
||||
if expectedMD5Sum != "" {
|
||||
var expectedMD5SumBytes []byte
|
||||
expectedMD5SumBytes, err = base64.StdEncoding.DecodeString(strings.TrimSpace(expectedMD5Sum))
|
||||
expectedMD5SumBytes, err = base64.StdEncoding.DecodeString(expectedMD5Sum)
|
||||
if err != nil {
|
||||
// Pro-actively close the connection
|
||||
return "", probe.NewError(InvalidDigest{MD5: expectedMD5Sum})
|
||||
@@ -361,8 +369,8 @@ func (fs Filesystem) CreateObjectPart(bucket, object, uploadID, expectedMD5Sum s
|
||||
md5sum := hex.EncodeToString(md5Hasher.Sum(nil))
|
||||
// Verify if the written object is equal to what is expected, only
|
||||
// if it is requested as such.
|
||||
if strings.TrimSpace(expectedMD5Sum) != "" {
|
||||
if !isMD5SumEqual(strings.TrimSpace(expectedMD5Sum), md5sum) {
|
||||
if expectedMD5Sum != "" {
|
||||
if !isMD5SumEqual(expectedMD5Sum, md5sum) {
|
||||
partFile.CloseAndPurge()
|
||||
return "", probe.NewError(BadDigest{MD5: expectedMD5Sum, Bucket: bucket, Object: object})
|
||||
}
|
||||
@@ -375,7 +383,7 @@ func (fs Filesystem) CreateObjectPart(bucket, object, uploadID, expectedMD5Sum s
|
||||
}
|
||||
if !ok {
|
||||
partFile.CloseAndPurge()
|
||||
return "", probe.NewError(signV4.SigDoesNotMatch{})
|
||||
return "", probe.NewError(SignDoesNotMatch{})
|
||||
}
|
||||
}
|
||||
partFile.Close()
|
||||
@@ -472,7 +480,7 @@ func (fs Filesystem) CompleteMultipartUpload(bucket, object, uploadID string, da
|
||||
}
|
||||
if !ok {
|
||||
file.CloseAndPurge()
|
||||
return ObjectMetadata{}, probe.NewError(signV4.SigDoesNotMatch{})
|
||||
return ObjectMetadata{}, probe.NewError(SignDoesNotMatch{})
|
||||
}
|
||||
}
|
||||
completeMultipartUpload := &CompleteMultipartUpload{}
|
||||
|
||||
@@ -178,7 +178,7 @@ func getMetadata(rootPath, bucket, object string) (ObjectMetadata, *probe.Error)
|
||||
// isMD5SumEqual - returns error if md5sum mismatches, success its `nil`
|
||||
func isMD5SumEqual(expectedMD5Sum, actualMD5Sum string) bool {
|
||||
// Verify the md5sum.
|
||||
if strings.TrimSpace(expectedMD5Sum) != "" && strings.TrimSpace(actualMD5Sum) != "" {
|
||||
if expectedMD5Sum != "" && actualMD5Sum != "" {
|
||||
// Decode md5sum to bytes from their hexadecimal
|
||||
// representations.
|
||||
expectedMD5SumBytes, err := hex.DecodeString(expectedMD5Sum)
|
||||
@@ -199,7 +199,7 @@ func isMD5SumEqual(expectedMD5Sum, actualMD5Sum string) bool {
|
||||
}
|
||||
|
||||
// CreateObject - create an object.
|
||||
func (fs Filesystem) CreateObject(bucket, object, expectedMD5Sum string, size int64, data io.Reader, signature *signV4.Signature) (ObjectMetadata, *probe.Error) {
|
||||
func (fs Filesystem) CreateObject(bucket, object, expectedMD5Sum string, size int64, data io.Reader, sig *signV4.Signature) (ObjectMetadata, *probe.Error) {
|
||||
di, e := disk.GetInfo(fs.path)
|
||||
if e != nil {
|
||||
return ObjectMetadata{}, probe.NewError(e)
|
||||
@@ -233,9 +233,9 @@ func (fs Filesystem) CreateObject(bucket, object, expectedMD5Sum string, size in
|
||||
|
||||
// Get object path.
|
||||
objectPath := filepath.Join(bucketPath, object)
|
||||
if strings.TrimSpace(expectedMD5Sum) != "" {
|
||||
if expectedMD5Sum != "" {
|
||||
var expectedMD5SumBytes []byte
|
||||
expectedMD5SumBytes, e = base64.StdEncoding.DecodeString(strings.TrimSpace(expectedMD5Sum))
|
||||
expectedMD5SumBytes, e = base64.StdEncoding.DecodeString(expectedMD5Sum)
|
||||
if e != nil {
|
||||
// Pro-actively close the connection.
|
||||
return ObjectMetadata{}, probe.NewError(InvalidDigest{MD5: expectedMD5Sum})
|
||||
@@ -244,7 +244,7 @@ func (fs Filesystem) CreateObject(bucket, object, expectedMD5Sum string, size in
|
||||
}
|
||||
|
||||
// Write object.
|
||||
file, e := atomic.FileCreateWithPrefix(objectPath, "$tmpobject")
|
||||
file, e := atomic.FileCreateWithPrefix(objectPath, expectedMD5Sum+"$tmpobject")
|
||||
if e != nil {
|
||||
switch e := e.(type) {
|
||||
case *os.PathError:
|
||||
@@ -279,22 +279,22 @@ func (fs Filesystem) CreateObject(bucket, object, expectedMD5Sum string, size in
|
||||
md5Sum := hex.EncodeToString(md5Hasher.Sum(nil))
|
||||
// Verify if the written object is equal to what is expected, only
|
||||
// if it is requested as such.
|
||||
if strings.TrimSpace(expectedMD5Sum) != "" {
|
||||
if !isMD5SumEqual(strings.TrimSpace(expectedMD5Sum), md5Sum) {
|
||||
if expectedMD5Sum != "" {
|
||||
if !isMD5SumEqual(expectedMD5Sum, md5Sum) {
|
||||
file.CloseAndPurge()
|
||||
return ObjectMetadata{}, probe.NewError(BadDigest{MD5: expectedMD5Sum, Bucket: bucket, Object: object})
|
||||
}
|
||||
}
|
||||
sha256Sum := hex.EncodeToString(sha256Hasher.Sum(nil))
|
||||
if signature != nil {
|
||||
ok, err := signature.DoesSignatureMatch(sha256Sum)
|
||||
if sig != nil {
|
||||
ok, err := sig.DoesSignatureMatch(sha256Sum)
|
||||
if err != nil {
|
||||
file.CloseAndPurge()
|
||||
return ObjectMetadata{}, err.Trace()
|
||||
}
|
||||
if !ok {
|
||||
file.CloseAndPurge()
|
||||
return ObjectMetadata{}, probe.NewError(signV4.SigDoesNotMatch{})
|
||||
return ObjectMetadata{}, signV4.ErrSignDoesNotMath("Signature does not match")
|
||||
}
|
||||
}
|
||||
file.Close()
|
||||
|
||||
Reference in New Issue
Block a user