signature: Rewrite signature handling and move it into a library.

This commit is contained in:
Harshavardhana
2016-02-15 17:42:39 -08:00
parent b531bb31bb
commit 5a9333a67b
30 changed files with 1193 additions and 1215 deletions

View File

@@ -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 {

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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{}

View File

@@ -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()