From 84f427f14afa4b30c99713c477a8a5ace7669a3e Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Thu, 9 Jul 2015 19:34:07 -0700 Subject: [PATCH] All other API's now support signature v4 --- pkg/donut/donut-v1_test.go | 44 ++++++++--------- pkg/donut/donut-v2.go | 73 +++++++++++++++++++++++++--- pkg/donut/donut-v2_test.go | 44 ++++++++--------- pkg/donut/interfaces.go | 20 ++++---- pkg/donut/multipart.go | 49 +++++++++++++++++-- pkg/server/api/bucket-handlers.go | 80 ++++++++++++++++++++++++++++--- pkg/server/api/object-handlers.go | 65 +++++++++++++++++++++++-- pkg/server/api/response.go | 2 +- 8 files changed, 300 insertions(+), 77 deletions(-) diff --git a/pkg/donut/donut-v1_test.go b/pkg/donut/donut-v1_test.go index 41d5ac53b..52f3ed767 100644 --- a/pkg/donut/donut-v1_test.go +++ b/pkg/donut/donut-v1_test.go @@ -74,7 +74,7 @@ func (s *MyDonutSuite) SetUpSuite(c *C) { c.Assert(err, IsNil) // testing empty donut - buckets, err := dd.ListBuckets() + buckets, err := dd.ListBuckets(nil) c.Assert(err, IsNil) c.Assert(len(buckets), Equals, 0) } @@ -86,20 +86,20 @@ func (s *MyDonutSuite) TearDownSuite(c *C) { // test make bucket without name func (s *MyDonutSuite) TestBucketWithoutNameFails(c *C) { // fail to create new bucket without a name - err := dd.MakeBucket("", "private") + err := dd.MakeBucket("", "private", nil) c.Assert(err, Not(IsNil)) - err = dd.MakeBucket(" ", "private") + err = dd.MakeBucket(" ", "private", nil) c.Assert(err, Not(IsNil)) } // test empty bucket func (s *MyDonutSuite) TestEmptyBucket(c *C) { - c.Assert(dd.MakeBucket("foo1", "private"), IsNil) + c.Assert(dd.MakeBucket("foo1", "private", nil), IsNil) // check if bucket is empty var resources BucketResourcesMetadata resources.Maxkeys = 1 - objectsMetadata, resources, err := dd.ListObjects("foo1", resources) + objectsMetadata, resources, err := dd.ListObjects("foo1", resources, nil) c.Assert(err, IsNil) c.Assert(len(objectsMetadata), Equals, 0) c.Assert(resources.CommonPrefixes, DeepEquals, []string{}) @@ -109,11 +109,11 @@ func (s *MyDonutSuite) TestEmptyBucket(c *C) { // test bucket list func (s *MyDonutSuite) TestMakeBucketAndList(c *C) { // create bucket - err := dd.MakeBucket("foo2", "private") + err := dd.MakeBucket("foo2", "private", nil) c.Assert(err, IsNil) // check bucket exists - buckets, err := dd.ListBuckets() + buckets, err := dd.ListBuckets(nil) c.Assert(err, IsNil) c.Assert(len(buckets), Equals, 5) c.Assert(buckets[0].ACL, Equals, BucketACL("private")) @@ -121,33 +121,33 @@ func (s *MyDonutSuite) TestMakeBucketAndList(c *C) { // test re-create bucket func (s *MyDonutSuite) TestMakeBucketWithSameNameFails(c *C) { - err := dd.MakeBucket("foo3", "private") + err := dd.MakeBucket("foo3", "private", nil) c.Assert(err, IsNil) - err = dd.MakeBucket("foo3", "private") + err = dd.MakeBucket("foo3", "private", nil) c.Assert(err, Not(IsNil)) } // test make multiple buckets func (s *MyDonutSuite) TestCreateMultipleBucketsAndList(c *C) { // add a second bucket - err := dd.MakeBucket("foo4", "private") + err := dd.MakeBucket("foo4", "private", nil) c.Assert(err, IsNil) - err = dd.MakeBucket("bar1", "private") + err = dd.MakeBucket("bar1", "private", nil) c.Assert(err, IsNil) - buckets, err := dd.ListBuckets() + buckets, err := dd.ListBuckets(nil) c.Assert(err, IsNil) c.Assert(len(buckets), Equals, 2) c.Assert(buckets[0].Name, Equals, "bar1") c.Assert(buckets[1].Name, Equals, "foo4") - err = dd.MakeBucket("foobar1", "private") + err = dd.MakeBucket("foobar1", "private", nil) c.Assert(err, IsNil) - buckets, err = dd.ListBuckets() + buckets, err = dd.ListBuckets(nil) c.Assert(err, IsNil) c.Assert(len(buckets), Equals, 3) @@ -168,7 +168,7 @@ func (s *MyDonutSuite) TestNewObjectMetadata(c *C) { expectedMd5Sum := base64.StdEncoding.EncodeToString(hasher.Sum(nil)) reader := ioutil.NopCloser(bytes.NewReader([]byte(data))) - err := dd.MakeBucket("foo6", "private") + err := dd.MakeBucket("foo6", "private", nil) c.Assert(err, IsNil) objectMetadata, err := dd.CreateObject("foo6", "obj", expectedMd5Sum, int64(len(data)), reader, map[string]string{"contentType": "application/json"}, nil) @@ -185,7 +185,7 @@ func (s *MyDonutSuite) TestNewObjectFailsWithEmptyName(c *C) { // test create object func (s *MyDonutSuite) TestNewObjectCanBeWritten(c *C) { - err := dd.MakeBucket("foo", "private") + err := dd.MakeBucket("foo", "private", nil) c.Assert(err, IsNil) data := "Hello World" @@ -205,7 +205,7 @@ func (s *MyDonutSuite) TestNewObjectCanBeWritten(c *C) { c.Assert(size, Equals, int64(len(data))) c.Assert(buffer.Bytes(), DeepEquals, []byte(data)) - actualMetadata, err = dd.GetObjectMetadata("foo", "obj") + actualMetadata, err = dd.GetObjectMetadata("foo", "obj", nil) c.Assert(err, IsNil) c.Assert(hex.EncodeToString(hasher.Sum(nil)), Equals, actualMetadata.MD5Sum) c.Assert(int64(len(data)), Equals, actualMetadata.Size) @@ -213,7 +213,7 @@ func (s *MyDonutSuite) TestNewObjectCanBeWritten(c *C) { // test list objects func (s *MyDonutSuite) TestMultipleNewObjects(c *C) { - c.Assert(dd.MakeBucket("foo5", "private"), IsNil) + c.Assert(dd.MakeBucket("foo5", "private", nil), IsNil) one := ioutil.NopCloser(bytes.NewReader([]byte("one"))) @@ -244,7 +244,7 @@ func (s *MyDonutSuite) TestMultipleNewObjects(c *C) { resources.Prefix = "o" resources.Delimiter = "1" resources.Maxkeys = 10 - objectsMetadata, resources, err := dd.ListObjects("foo5", resources) + objectsMetadata, resources, err := dd.ListObjects("foo5", resources, nil) c.Assert(err, IsNil) c.Assert(resources.IsTruncated, Equals, false) c.Assert(resources.CommonPrefixes[0], Equals, "obj1") @@ -253,7 +253,7 @@ func (s *MyDonutSuite) TestMultipleNewObjects(c *C) { resources.Prefix = "" resources.Delimiter = "1" resources.Maxkeys = 10 - objectsMetadata, resources, err = dd.ListObjects("foo5", resources) + objectsMetadata, resources, err = dd.ListObjects("foo5", resources, nil) c.Assert(err, IsNil) c.Assert(objectsMetadata[0].Object, Equals, "obj2") c.Assert(resources.IsTruncated, Equals, false) @@ -263,7 +263,7 @@ func (s *MyDonutSuite) TestMultipleNewObjects(c *C) { resources.Prefix = "o" resources.Delimiter = "" resources.Maxkeys = 10 - objectsMetadata, resources, err = dd.ListObjects("foo5", resources) + objectsMetadata, resources, err = dd.ListObjects("foo5", resources, nil) c.Assert(err, IsNil) c.Assert(resources.IsTruncated, Equals, false) c.Assert(objectsMetadata[0].Object, Equals, "obj1") @@ -283,7 +283,7 @@ func (s *MyDonutSuite) TestMultipleNewObjects(c *C) { resources.Prefix = "o" resources.Delimiter = "" resources.Maxkeys = 2 - objectsMetadata, resources, err = dd.ListObjects("foo5", resources) + objectsMetadata, resources, err = dd.ListObjects("foo5", resources, nil) c.Assert(err, IsNil) c.Assert(resources.IsTruncated, Equals, true) c.Assert(len(objectsMetadata), Equals, 2) diff --git a/pkg/donut/donut-v2.go b/pkg/donut/donut-v2.go index e52fbf73a..c43d781a5 100644 --- a/pkg/donut/donut-v2.go +++ b/pkg/donut/donut-v2.go @@ -180,6 +180,7 @@ func (donut API) GetPartialObject(w io.Writer, bucket, object string, start, len "start": strconv.FormatInt(start, 10), "length": strconv.FormatInt(length, 10), } + if !IsValidBucket(bucket) { return 0, iodine.New(BucketNameInvalid{Bucket: bucket}, errParams) } @@ -226,10 +227,20 @@ func (donut API) GetPartialObject(w io.Writer, bucket, object string, start, len } // GetBucketMetadata - -func (donut API) GetBucketMetadata(bucket string) (BucketMetadata, error) { +func (donut API) GetBucketMetadata(bucket string, signature *Signature) (BucketMetadata, error) { donut.lock.Lock() defer donut.lock.Unlock() + if signature != nil { + ok, err := signature.DoesSignatureMatch("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") + if err != nil { + return BucketMetadata{}, iodine.New(err, nil) + } + if !ok { + return BucketMetadata{}, iodine.New(SignatureDoesNotMatch{}, nil) + } + } + if !IsValidBucket(bucket) { return BucketMetadata{}, iodine.New(BucketNameInvalid{Bucket: bucket}, nil) } @@ -249,10 +260,20 @@ func (donut API) GetBucketMetadata(bucket string) (BucketMetadata, error) { } // SetBucketMetadata - -func (donut API) SetBucketMetadata(bucket string, metadata map[string]string) error { +func (donut API) SetBucketMetadata(bucket string, metadata map[string]string, signature *Signature) error { donut.lock.Lock() defer donut.lock.Unlock() + if signature != nil { + ok, err := signature.DoesSignatureMatch("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") + if err != nil { + return iodine.New(err, nil) + } + if !ok { + return iodine.New(SignatureDoesNotMatch{}, nil) + } + } + if !IsValidBucket(bucket) { return iodine.New(BucketNameInvalid{Bucket: bucket}, nil) } @@ -424,10 +445,20 @@ func (donut API) createObject(bucket, key, contentType, expectedMD5Sum string, s } // MakeBucket - create bucket in cache -func (donut API) MakeBucket(bucketName, acl string) error { +func (donut API) MakeBucket(bucketName, acl string, signature *Signature) error { donut.lock.Lock() defer donut.lock.Unlock() + if signature != nil { + ok, err := signature.DoesSignatureMatch("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") + if err != nil { + return iodine.New(err, nil) + } + if !ok { + return iodine.New(SignatureDoesNotMatch{}, nil) + } + } + if donut.storedBuckets.Stats().Items == totalBuckets { return iodine.New(TooManyBuckets{Bucket: bucketName}, nil) } @@ -463,10 +494,20 @@ func (donut API) MakeBucket(bucketName, acl string) error { } // ListObjects - list objects from cache -func (donut API) ListObjects(bucket string, resources BucketResourcesMetadata) ([]ObjectMetadata, BucketResourcesMetadata, error) { +func (donut API) ListObjects(bucket string, resources BucketResourcesMetadata, signature *Signature) ([]ObjectMetadata, BucketResourcesMetadata, error) { donut.lock.Lock() defer donut.lock.Unlock() + if signature != nil { + ok, err := signature.DoesSignatureMatch("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") + if err != nil { + return nil, BucketResourcesMetadata{}, iodine.New(err, nil) + } + if !ok { + return nil, BucketResourcesMetadata{}, iodine.New(SignatureDoesNotMatch{}, nil) + } + } + if !IsValidBucket(bucket) { return nil, BucketResourcesMetadata{IsTruncated: false}, iodine.New(BucketNameInvalid{Bucket: bucket}, nil) } @@ -556,10 +597,20 @@ func (b byBucketName) Swap(i, j int) { b[i], b[j] = b[j], b[i] } func (b byBucketName) Less(i, j int) bool { return b[i].Name < b[j].Name } // ListBuckets - List buckets from cache -func (donut API) ListBuckets() ([]BucketMetadata, error) { +func (donut API) ListBuckets(signature *Signature) ([]BucketMetadata, error) { donut.lock.Lock() defer donut.lock.Unlock() + if signature != nil { + ok, err := signature.DoesSignatureMatch("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") + if err != nil { + return nil, iodine.New(err, nil) + } + if !ok { + return nil, iodine.New(SignatureDoesNotMatch{}, nil) + } + } + var results []BucketMetadata if len(donut.config.NodeDiskMap) > 0 { buckets, err := donut.listBuckets() @@ -580,10 +631,20 @@ func (donut API) ListBuckets() ([]BucketMetadata, error) { } // GetObjectMetadata - get object metadata from cache -func (donut API) GetObjectMetadata(bucket, key string) (ObjectMetadata, error) { +func (donut API) GetObjectMetadata(bucket, key string, signature *Signature) (ObjectMetadata, error) { donut.lock.Lock() defer donut.lock.Unlock() + if signature != nil { + ok, err := signature.DoesSignatureMatch("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") + if err != nil { + return ObjectMetadata{}, iodine.New(err, nil) + } + if !ok { + return ObjectMetadata{}, iodine.New(SignatureDoesNotMatch{}, nil) + } + } + // check if bucket exists if !IsValidBucket(bucket) { return ObjectMetadata{}, iodine.New(BucketNameInvalid{Bucket: bucket}, nil) diff --git a/pkg/donut/donut-v2_test.go b/pkg/donut/donut-v2_test.go index 259ffdad8..2604c401b 100644 --- a/pkg/donut/donut-v2_test.go +++ b/pkg/donut/donut-v2_test.go @@ -49,7 +49,7 @@ func (s *MyCacheSuite) SetUpSuite(c *C) { c.Assert(err, IsNil) // testing empty cache - buckets, err := dc.ListBuckets() + buckets, err := dc.ListBuckets(nil) c.Assert(err, IsNil) c.Assert(len(buckets), Equals, 0) } @@ -61,20 +61,20 @@ func (s *MyCacheSuite) TearDownSuite(c *C) { // test make bucket without name func (s *MyCacheSuite) TestBucketWithoutNameFails(c *C) { // fail to create new bucket without a name - err := dc.MakeBucket("", "private") + err := dc.MakeBucket("", "private", nil) c.Assert(err, Not(IsNil)) - err = dc.MakeBucket(" ", "private") + err = dc.MakeBucket(" ", "private", nil) c.Assert(err, Not(IsNil)) } // test empty bucket func (s *MyCacheSuite) TestEmptyBucket(c *C) { - c.Assert(dc.MakeBucket("foo1", "private"), IsNil) + c.Assert(dc.MakeBucket("foo1", "private", nil), IsNil) // check if bucket is empty var resources BucketResourcesMetadata resources.Maxkeys = 1 - objectsMetadata, resources, err := dc.ListObjects("foo1", resources) + objectsMetadata, resources, err := dc.ListObjects("foo1", resources, nil) c.Assert(err, IsNil) c.Assert(len(objectsMetadata), Equals, 0) c.Assert(resources.CommonPrefixes, DeepEquals, []string{}) @@ -84,11 +84,11 @@ func (s *MyCacheSuite) TestEmptyBucket(c *C) { // test bucket list func (s *MyCacheSuite) TestMakeBucketAndList(c *C) { // create bucket - err := dc.MakeBucket("foo2", "private") + err := dc.MakeBucket("foo2", "private", nil) c.Assert(err, IsNil) // check bucket exists - buckets, err := dc.ListBuckets() + buckets, err := dc.ListBuckets(nil) c.Assert(err, IsNil) c.Assert(len(buckets), Equals, 5) c.Assert(buckets[0].ACL, Equals, BucketACL("private")) @@ -96,33 +96,33 @@ func (s *MyCacheSuite) TestMakeBucketAndList(c *C) { // test re-create bucket func (s *MyCacheSuite) TestMakeBucketWithSameNameFails(c *C) { - err := dc.MakeBucket("foo3", "private") + err := dc.MakeBucket("foo3", "private", nil) c.Assert(err, IsNil) - err = dc.MakeBucket("foo3", "private") + err = dc.MakeBucket("foo3", "private", nil) c.Assert(err, Not(IsNil)) } // test make multiple buckets func (s *MyCacheSuite) TestCreateMultipleBucketsAndList(c *C) { // add a second bucket - err := dc.MakeBucket("foo4", "private") + err := dc.MakeBucket("foo4", "private", nil) c.Assert(err, IsNil) - err = dc.MakeBucket("bar1", "private") + err = dc.MakeBucket("bar1", "private", nil) c.Assert(err, IsNil) - buckets, err := dc.ListBuckets() + buckets, err := dc.ListBuckets(nil) c.Assert(err, IsNil) c.Assert(len(buckets), Equals, 2) c.Assert(buckets[0].Name, Equals, "bar1") c.Assert(buckets[1].Name, Equals, "foo4") - err = dc.MakeBucket("foobar1", "private") + err = dc.MakeBucket("foobar1", "private", nil) c.Assert(err, IsNil) - buckets, err = dc.ListBuckets() + buckets, err = dc.ListBuckets(nil) c.Assert(err, IsNil) c.Assert(len(buckets), Equals, 3) @@ -143,7 +143,7 @@ func (s *MyCacheSuite) TestNewObjectMetadata(c *C) { expectedMd5Sum := base64.StdEncoding.EncodeToString(hasher.Sum(nil)) reader := ioutil.NopCloser(bytes.NewReader([]byte(data))) - err := dc.MakeBucket("foo6", "private") + err := dc.MakeBucket("foo6", "private", nil) c.Assert(err, IsNil) objectMetadata, err := dc.CreateObject("foo6", "obj", expectedMd5Sum, int64(len(data)), reader, map[string]string{"contentType": "application/json"}, nil) @@ -160,7 +160,7 @@ func (s *MyCacheSuite) TestNewObjectFailsWithEmptyName(c *C) { // test create object func (s *MyCacheSuite) TestNewObjectCanBeWritten(c *C) { - err := dc.MakeBucket("foo", "private") + err := dc.MakeBucket("foo", "private", nil) c.Assert(err, IsNil) data := "Hello World" @@ -180,7 +180,7 @@ func (s *MyCacheSuite) TestNewObjectCanBeWritten(c *C) { c.Assert(size, Equals, int64(len(data))) c.Assert(buffer.Bytes(), DeepEquals, []byte(data)) - actualMetadata, err = dc.GetObjectMetadata("foo", "obj") + actualMetadata, err = dc.GetObjectMetadata("foo", "obj", nil) c.Assert(err, IsNil) c.Assert(hex.EncodeToString(hasher.Sum(nil)), Equals, actualMetadata.MD5Sum) c.Assert(int64(len(data)), Equals, actualMetadata.Size) @@ -188,7 +188,7 @@ func (s *MyCacheSuite) TestNewObjectCanBeWritten(c *C) { // test list objects func (s *MyCacheSuite) TestMultipleNewObjects(c *C) { - c.Assert(dc.MakeBucket("foo5", "private"), IsNil) + c.Assert(dc.MakeBucket("foo5", "private", nil), IsNil) one := ioutil.NopCloser(bytes.NewReader([]byte("one"))) @@ -219,7 +219,7 @@ func (s *MyCacheSuite) TestMultipleNewObjects(c *C) { resources.Prefix = "o" resources.Delimiter = "1" resources.Maxkeys = 10 - objectsMetadata, resources, err := dc.ListObjects("foo5", resources) + objectsMetadata, resources, err := dc.ListObjects("foo5", resources, nil) c.Assert(err, IsNil) c.Assert(resources.IsTruncated, Equals, false) c.Assert(resources.CommonPrefixes[0], Equals, "obj1") @@ -228,7 +228,7 @@ func (s *MyCacheSuite) TestMultipleNewObjects(c *C) { resources.Prefix = "" resources.Delimiter = "1" resources.Maxkeys = 10 - objectsMetadata, resources, err = dc.ListObjects("foo5", resources) + objectsMetadata, resources, err = dc.ListObjects("foo5", resources, nil) c.Assert(err, IsNil) c.Assert(objectsMetadata[0].Object, Equals, "obj2") c.Assert(resources.IsTruncated, Equals, false) @@ -238,7 +238,7 @@ func (s *MyCacheSuite) TestMultipleNewObjects(c *C) { resources.Prefix = "o" resources.Delimiter = "" resources.Maxkeys = 10 - objectsMetadata, resources, err = dc.ListObjects("foo5", resources) + objectsMetadata, resources, err = dc.ListObjects("foo5", resources, nil) c.Assert(err, IsNil) c.Assert(resources.IsTruncated, Equals, false) c.Assert(objectsMetadata[0].Object, Equals, "obj1") @@ -258,7 +258,7 @@ func (s *MyCacheSuite) TestMultipleNewObjects(c *C) { resources.Prefix = "o" resources.Delimiter = "" resources.Maxkeys = 2 - objectsMetadata, resources, err = dc.ListObjects("foo5", resources) + objectsMetadata, resources, err = dc.ListObjects("foo5", resources, nil) c.Assert(err, IsNil) c.Assert(resources.IsTruncated, Equals, true) c.Assert(len(objectsMetadata), Equals, 2) diff --git a/pkg/donut/interfaces.go b/pkg/donut/interfaces.go index 65dfaf4f3..a2870770e 100644 --- a/pkg/donut/interfaces.go +++ b/pkg/donut/interfaces.go @@ -29,18 +29,18 @@ type Interface interface { // ObjectStorage is a donut object storage interface type ObjectStorage interface { // Storage service operations - GetBucketMetadata(bucket string) (BucketMetadata, error) - SetBucketMetadata(bucket string, metadata map[string]string) error - ListBuckets() ([]BucketMetadata, error) - MakeBucket(bucket string, ACL string) error + GetBucketMetadata(bucket string, signature *Signature) (BucketMetadata, error) + SetBucketMetadata(bucket string, metadata map[string]string, signature *Signature) error + ListBuckets(signature *Signature) ([]BucketMetadata, error) + MakeBucket(bucket string, ACL string, signature *Signature) error // Bucket operations - ListObjects(bucket string, resources BucketResourcesMetadata) ([]ObjectMetadata, BucketResourcesMetadata, error) + ListObjects(string, BucketResourcesMetadata, *Signature) ([]ObjectMetadata, BucketResourcesMetadata, error) // Object operations GetObject(w io.Writer, bucket, object string) (int64, error) GetPartialObject(w io.Writer, bucket, object string, start, length int64) (int64, error) - GetObjectMetadata(bucket, object string) (ObjectMetadata, error) + GetObjectMetadata(bucket, object string, signature *Signature) (ObjectMetadata, error) // bucket, object, expectedMD5Sum, size, reader, metadata, signature CreateObject(string, string, string, int64, io.Reader, map[string]string, *Signature) (ObjectMetadata, error) @@ -49,12 +49,12 @@ type ObjectStorage interface { // Multipart API type Multipart interface { - NewMultipartUpload(bucket, key, contentType string) (string, error) - AbortMultipartUpload(bucket, key, uploadID string) error + NewMultipartUpload(bucket, key, contentType string, signature *Signature) (string, error) + AbortMultipartUpload(bucket, key, uploadID string, signature *Signature) error CreateObjectPart(string, string, string, int, string, string, int64, io.Reader, *Signature) (string, error) CompleteMultipartUpload(bucket, key, uploadID string, data io.Reader, signature *Signature) (ObjectMetadata, error) - ListMultipartUploads(bucket string, resources BucketMultipartResourcesMetadata) (BucketMultipartResourcesMetadata, error) - ListObjectParts(bucket, key string, resources ObjectResourcesMetadata) (ObjectResourcesMetadata, error) + ListMultipartUploads(string, BucketMultipartResourcesMetadata, *Signature) (BucketMultipartResourcesMetadata, error) + ListObjectParts(string, string, ObjectResourcesMetadata, *Signature) (ObjectResourcesMetadata, error) } // Management is a donut management system interface diff --git a/pkg/donut/multipart.go b/pkg/donut/multipart.go index 324ca6c4a..25aeb8693 100644 --- a/pkg/donut/multipart.go +++ b/pkg/donut/multipart.go @@ -39,10 +39,20 @@ import ( ) // NewMultipartUpload - initiate a new multipart session -func (donut API) NewMultipartUpload(bucket, key, contentType string) (string, error) { +func (donut API) NewMultipartUpload(bucket, key, contentType string, signature *Signature) (string, error) { donut.lock.Lock() defer donut.lock.Unlock() + if signature != nil { + ok, err := signature.DoesSignatureMatch("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") + if err != nil { + return "", iodine.New(err, nil) + } + if !ok { + return "", iodine.New(SignatureDoesNotMatch{}, nil) + } + } + if !IsValidBucket(bucket) { return "", iodine.New(BucketNameInvalid{Bucket: bucket}, nil) } @@ -74,10 +84,20 @@ func (donut API) NewMultipartUpload(bucket, key, contentType string) (string, er } // AbortMultipartUpload - abort an incomplete multipart session -func (donut API) AbortMultipartUpload(bucket, key, uploadID string) error { +func (donut API) AbortMultipartUpload(bucket, key, uploadID string, signature *Signature) error { donut.lock.Lock() defer donut.lock.Unlock() + if signature != nil { + ok, err := signature.DoesSignatureMatch("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") + if err != nil { + return iodine.New(err, nil) + } + if !ok { + return iodine.New(SignatureDoesNotMatch{}, nil) + } + } + if !IsValidBucket(bucket) { return iodine.New(BucketNameInvalid{Bucket: bucket}, nil) } @@ -313,14 +333,25 @@ func (a byKey) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a byKey) Less(i, j int) bool { return a[i].Key < a[j].Key } // ListMultipartUploads - list incomplete multipart sessions for a given bucket -func (donut API) ListMultipartUploads(bucket string, resources BucketMultipartResourcesMetadata) (BucketMultipartResourcesMetadata, error) { +func (donut API) ListMultipartUploads(bucket string, resources BucketMultipartResourcesMetadata, signature *Signature) (BucketMultipartResourcesMetadata, error) { // TODO handle delimiter donut.lock.Lock() defer donut.lock.Unlock() + if signature != nil { + ok, err := signature.DoesSignatureMatch("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") + if err != nil { + return BucketMultipartResourcesMetadata{}, iodine.New(err, nil) + } + if !ok { + return BucketMultipartResourcesMetadata{}, iodine.New(SignatureDoesNotMatch{}, nil) + } + } + if !donut.storedBuckets.Exists(bucket) { return BucketMultipartResourcesMetadata{}, iodine.New(BucketNotFound{Bucket: bucket}, nil) } + storedBucket := donut.storedBuckets.Get(bucket).(storedBucket) var uploads []*UploadMetadata @@ -376,11 +407,21 @@ func (a partNumber) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a partNumber) Less(i, j int) bool { return a[i].PartNumber < a[j].PartNumber } // ListObjectParts - list parts from incomplete multipart session for a given object -func (donut API) ListObjectParts(bucket, key string, resources ObjectResourcesMetadata) (ObjectResourcesMetadata, error) { +func (donut API) ListObjectParts(bucket, key string, resources ObjectResourcesMetadata, signature *Signature) (ObjectResourcesMetadata, error) { // Verify upload id donut.lock.Lock() defer donut.lock.Unlock() + if signature != nil { + ok, err := signature.DoesSignatureMatch("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") + if err != nil { + return ObjectResourcesMetadata{}, iodine.New(err, nil) + } + if !ok { + return ObjectResourcesMetadata{}, iodine.New(SignatureDoesNotMatch{}, nil) + } + } + if !donut.storedBuckets.Exists(bucket) { return ObjectResourcesMetadata{}, iodine.New(BucketNotFound{Bucket: bucket}, nil) } diff --git a/pkg/server/api/bucket-handlers.go b/pkg/server/api/bucket-handlers.go index 90005e21a..710814619 100644 --- a/pkg/server/api/bucket-handlers.go +++ b/pkg/server/api/bucket-handlers.go @@ -29,7 +29,7 @@ func (api Minio) isValidOp(w http.ResponseWriter, req *http.Request, acceptsCont vars := mux.Vars(req) bucket := vars["bucket"] - bucketMetadata, err := api.Donut.GetBucketMetadata(bucket) + bucketMetadata, err := api.Donut.GetBucketMetadata(bucket, nil) switch iodine.ToError(err).(type) { case donut.BucketNotFound: { @@ -95,7 +95,18 @@ func (api Minio) ListMultipartUploadsHandler(w http.ResponseWriter, req *http.Re vars := mux.Vars(req) bucket := vars["bucket"] - resources, err := api.Donut.ListMultipartUploads(bucket, resources) + var signature *donut.Signature + if _, ok := req.Header["Authorization"]; ok { + // Init signature V4 verification + var err error + signature, err = InitSignatureV4(req) + if err != nil { + writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) + return + } + } + + resources, err := api.Donut.ListMultipartUploads(bucket, resources, signature) switch iodine.ToError(err).(type) { case nil: // success { @@ -153,7 +164,18 @@ func (api Minio) ListObjectsHandler(w http.ResponseWriter, req *http.Request) { vars := mux.Vars(req) bucket := vars["bucket"] - objects, resources, err := api.Donut.ListObjects(bucket, resources) + var signature *donut.Signature + if _, ok := req.Header["Authorization"]; ok { + // Init signature V4 verification + var err error + signature, err = InitSignatureV4(req) + if err != nil { + writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) + return + } + } + + objects, resources, err := api.Donut.ListObjects(bucket, resources, signature) switch iodine.ToError(err).(type) { case nil: // generate response @@ -199,7 +221,18 @@ func (api Minio) ListBucketsHandler(w http.ResponseWriter, req *http.Request) { // return // } - buckets, err := api.Donut.ListBuckets() + var signature *donut.Signature + if _, ok := req.Header["Authorization"]; ok { + // Init signature V4 verification + var err error + signature, err = InitSignatureV4(req) + if err != nil { + writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) + return + } + } + + buckets, err := api.Donut.ListBuckets(signature) switch iodine.ToError(err).(type) { case nil: // generate response @@ -250,7 +283,18 @@ func (api Minio) PutBucketHandler(w http.ResponseWriter, req *http.Request) { vars := mux.Vars(req) bucket := vars["bucket"] - err := api.Donut.MakeBucket(bucket, getACLTypeString(aclType)) + var signature *donut.Signature + if _, ok := req.Header["Authorization"]; ok { + // Init signature V4 verification + var err error + signature, err = InitSignatureV4(req) + if err != nil { + writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) + return + } + } + + err := api.Donut.MakeBucket(bucket, getACLTypeString(aclType), signature) switch iodine.ToError(err).(type) { case nil: // Make sure to add Location information here only for bucket @@ -293,7 +337,18 @@ func (api Minio) PutBucketACLHandler(w http.ResponseWriter, req *http.Request) { vars := mux.Vars(req) bucket := vars["bucket"] - err := api.Donut.SetBucketMetadata(bucket, map[string]string{"acl": getACLTypeString(aclType)}) + var signature *donut.Signature + if _, ok := req.Header["Authorization"]; ok { + // Init signature V4 verification + var err error + signature, err = InitSignatureV4(req) + if err != nil { + writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) + return + } + } + + err := api.Donut.SetBucketMetadata(bucket, map[string]string{"acl": getACLTypeString(aclType)}, signature) switch iodine.ToError(err).(type) { case nil: writeSuccessResponse(w, acceptsContentType) @@ -328,7 +383,18 @@ func (api Minio) HeadBucketHandler(w http.ResponseWriter, req *http.Request) { vars := mux.Vars(req) bucket := vars["bucket"] - _, err := api.Donut.GetBucketMetadata(bucket) + var signature *donut.Signature + if _, ok := req.Header["Authorization"]; ok { + // Init signature V4 verification + var err error + signature, err = InitSignatureV4(req) + if err != nil { + writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) + return + } + } + + _, err := api.Donut.GetBucketMetadata(bucket, signature) switch iodine.ToError(err).(type) { case nil: writeSuccessResponse(w, acceptsContentType) diff --git a/pkg/server/api/object-handlers.go b/pkg/server/api/object-handlers.go index 437ba8f60..8a7cf46c0 100644 --- a/pkg/server/api/object-handlers.go +++ b/pkg/server/api/object-handlers.go @@ -54,7 +54,18 @@ func (api Minio) GetObjectHandler(w http.ResponseWriter, req *http.Request) { bucket = vars["bucket"] object = vars["object"] - metadata, err := api.Donut.GetObjectMetadata(bucket, object) + var signature *donut.Signature + if _, ok := req.Header["Authorization"]; ok { + // Init signature V4 verification + var err error + signature, err = InitSignatureV4(req) + if err != nil { + writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) + return + } + } + + metadata, err := api.Donut.GetObjectMetadata(bucket, object, signature) switch iodine.ToError(err).(type) { case nil: // success { @@ -117,7 +128,18 @@ func (api Minio) HeadObjectHandler(w http.ResponseWriter, req *http.Request) { bucket = vars["bucket"] object = vars["object"] - metadata, err := api.Donut.GetObjectMetadata(bucket, object) + var signature *donut.Signature + if _, ok := req.Header["Authorization"]; ok { + // Init signature V4 verification + var err error + signature, err = InitSignatureV4(req) + if err != nil { + writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) + return + } + } + + metadata, err := api.Donut.GetObjectMetadata(bucket, object, signature) switch iodine.ToError(err).(type) { case nil: setObjectHeaders(w, metadata) @@ -270,7 +292,18 @@ func (api Minio) NewMultipartUploadHandler(w http.ResponseWriter, req *http.Requ bucket = vars["bucket"] object = vars["object"] - uploadID, err := api.Donut.NewMultipartUpload(bucket, object, "") + var signature *donut.Signature + if _, ok := req.Header["Authorization"]; ok { + // Init signature V4 verification + var err error + signature, err = InitSignatureV4(req) + if err != nil { + writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) + return + } + } + + uploadID, err := api.Donut.NewMultipartUpload(bucket, object, req.Header.Get("Content-Type"), signature) switch iodine.ToError(err).(type) { case nil: { @@ -401,7 +434,18 @@ func (api Minio) AbortMultipartUploadHandler(w http.ResponseWriter, req *http.Re objectResourcesMetadata := getObjectResources(req.URL.Query()) - err := api.Donut.AbortMultipartUpload(bucket, object, objectResourcesMetadata.UploadID) + var signature *donut.Signature + if _, ok := req.Header["Authorization"]; ok { + // Init signature V4 verification + var err error + signature, err = InitSignatureV4(req) + if err != nil { + writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) + return + } + } + + err := api.Donut.AbortMultipartUpload(bucket, object, objectResourcesMetadata.UploadID, signature) switch iodine.ToError(err).(type) { case nil: setCommonHeaders(w, getContentTypeString(acceptsContentType), 0) @@ -439,7 +483,18 @@ func (api Minio) ListObjectPartsHandler(w http.ResponseWriter, req *http.Request bucket := vars["bucket"] object := vars["object"] - objectResourcesMetadata, err := api.Donut.ListObjectParts(bucket, object, objectResourcesMetadata) + var signature *donut.Signature + if _, ok := req.Header["Authorization"]; ok { + // Init signature V4 verification + var err error + signature, err = InitSignatureV4(req) + if err != nil { + writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) + return + } + } + + objectResourcesMetadata, err := api.Donut.ListObjectParts(bucket, object, objectResourcesMetadata, signature) switch iodine.ToError(err).(type) { case nil: { diff --git a/pkg/server/api/response.go b/pkg/server/api/response.go index 4e733ef0b..3c83e843e 100644 --- a/pkg/server/api/response.go +++ b/pkg/server/api/response.go @@ -85,7 +85,7 @@ func generateListObjectsResponse(bucket string, objects []donut.ObjectMetadata, continue } content.Key = object.Object - content.LastModified = object.Created.Format(iso8601Format) + content.LastModified = object.Created.Format(rfcFormat) content.ETag = "\"" + object.MD5Sum + "\"" content.Size = object.Size content.StorageClass = "STANDARD"