Bring in full fledged acl support

This commit is contained in:
Harshavardhana 2015-04-22 18:19:20 -07:00
parent 2c1455af1b
commit c8713fd650
5 changed files with 82 additions and 61 deletions

View file

@ -27,6 +27,8 @@ import (
// http://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#setting-acls // http://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#setting-acls
// Minio only supports three types for now i.e 'private, public-read, public-read-write' // Minio only supports three types for now i.e 'private, public-read, public-read-write'
// ACLType - different acl types
type ACLType int type ACLType int
const ( const (

View file

@ -128,7 +128,7 @@ func (server *minioAPI) putBucketHandler(w http.ResponseWriter, req *http.Reques
vars := mux.Vars(req) vars := mux.Vars(req)
bucket := vars["bucket"] bucket := vars["bucket"]
err := server.driver.CreateBucket(bucket) err := server.driver.CreateBucket(bucket, getACLTypeString(aclType))
switch err.(type) { switch err.(type) {
case nil: case nil:
{ {

View file

@ -20,11 +20,14 @@ import (
"net/http" "net/http"
"strings" "strings"
"github.com/gorilla/mux"
"github.com/minio-io/minio/pkg/api/config" "github.com/minio-io/minio/pkg/api/config"
"github.com/minio-io/minio/pkg/storage/drivers"
) )
type vHandler struct { type vHandler struct {
conf config.Config conf config.Config
driver drivers.Driver
handler http.Handler handler http.Handler
} }
@ -47,43 +50,56 @@ func stripAccessKey(r *http.Request) string {
// Validate handler is wrapper handler used for API request validation with authorization header. // Validate handler is wrapper handler used for API request validation with authorization header.
// Current authorization layer supports S3's standard HMAC based signature request. // Current authorization layer supports S3's standard HMAC based signature request.
func validateHandler(conf config.Config, h http.Handler) http.Handler { func validateHandler(conf config.Config, driver drivers.Driver, h http.Handler) http.Handler {
return vHandler{conf, h} return vHandler{
conf: conf,
driver: driver,
handler: h,
}
} }
// Validate handler ServeHTTP() wrapper // Validate handler ServeHTTP() wrapper
func (h vHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (h vHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
accessKey := stripAccessKey(r) accessKey := stripAccessKey(r)
acceptsContentType := getContentType(r) acceptsContentType := getContentType(r)
if accessKey != "" { if acceptsContentType == unknownContentType {
if err := h.conf.ReadConfig(); err != nil { writeErrorResponse(w, r, NotAcceptable, acceptsContentType, r.URL.Path)
error := getErrorCode(InternalError) return
errorResponse := getErrorResponse(error, "") }
setCommonHeaders(w, getContentTypeString(acceptsContentType)) // verify for if bucket is private or public
w.WriteHeader(error.HTTPStatusCode) vars := mux.Vars(r)
w.Write(encodeErrorResponse(errorResponse, acceptsContentType)) bucket, ok := vars["bucket"]
} else { if ok {
user, ok := h.conf.Users[accessKey] bucketMetadata, err := h.driver.GetBucketMetadata(bucket)
if ok == false { if err != nil {
error := getErrorCode(AccessDenied) writeErrorResponse(w, r, AccessDenied, acceptsContentType, r.URL.Path)
errorResponse := getErrorResponse(error, "") return
setCommonHeaders(w, getContentTypeString(acceptsContentType))
w.WriteHeader(error.HTTPStatusCode)
w.Write(encodeErrorResponse(errorResponse, acceptsContentType))
} else {
ok, _ = ValidateRequest(user, r)
if ok {
h.handler.ServeHTTP(w, r)
} else {
error := getErrorCode(AccessDenied)
errorResponse := getErrorResponse(error, "")
setCommonHeaders(w, getContentTypeString(acceptsContentType))
w.WriteHeader(error.HTTPStatusCode)
w.Write(encodeErrorResponse(errorResponse, acceptsContentType))
}
}
} }
} else { if accessKey == "" && bucketMetadata.ACL.IsPrivate() {
writeErrorResponse(w, r, AccessDenied, acceptsContentType, r.URL.Path)
return
}
}
switch true {
case accessKey != "":
if err := h.conf.ReadConfig(); err != nil {
writeErrorResponse(w, r, InternalError, acceptsContentType, r.URL.Path)
return
}
user, ok := h.conf.Users[accessKey]
if !ok {
writeErrorResponse(w, r, AccessDenied, acceptsContentType, r.URL.Path)
return
}
ok, _ = ValidateRequest(user, r)
if !ok {
writeErrorResponse(w, r, AccessDenied, acceptsContentType, r.URL.Path)
return
}
// Success
h.handler.ServeHTTP(w, r)
default:
// Control reaches when no access key is found, ideally we would // Control reaches when no access key is found, ideally we would
// like to throw back `403`. But for now with our tests lacking // like to throw back `403`. But for now with our tests lacking
// this functionality it is better for us to be serving anonymous // this functionality it is better for us to be serving anonymous

View file

@ -89,5 +89,5 @@ func HTTPHandler(domain string, driver drivers.Driver) http.Handler {
log.Fatal(iodine.New(err, map[string]string{"domain": domain})) log.Fatal(iodine.New(err, map[string]string{"domain": domain}))
} }
return validateHandler(conf, ignoreResourcesHandler(mux)) return validateHandler(conf, api.driver, ignoreResourcesHandler(mux))
} }

View file

@ -142,7 +142,7 @@ func (s *MySuite) TestEmptyObject(c *C) {
Md5: "d41d8cd98f00b204e9800998ecf8427e", Md5: "d41d8cd98f00b204e9800998ecf8427e",
Size: 0, Size: 0,
} }
typedDriver.On("CreateBucket", "bucket").Return(nil).Once() typedDriver.On("CreateBucket", "bucket", "private").Return(nil).Once()
typedDriver.On("CreateObject", "bucket", "object", "", "", mock.Anything).Return(nil).Once() typedDriver.On("CreateObject", "bucket", "object", "", "", mock.Anything).Return(nil).Once()
typedDriver.On("GetObjectMetadata", "bucket", "object", "").Return(metadata, nil).Once() typedDriver.On("GetObjectMetadata", "bucket", "object", "").Return(metadata, nil).Once()
typedDriver.On("GetObject", mock.Anything, "bucket", "object").Return(int64(0), nil).Once() typedDriver.On("GetObject", mock.Anything, "bucket", "object").Return(int64(0), nil).Once()
@ -152,7 +152,7 @@ func (s *MySuite) TestEmptyObject(c *C) {
defer testServer.Close() defer testServer.Close()
buffer := bytes.NewBufferString("") buffer := bytes.NewBufferString("")
driver.CreateBucket("bucket") driver.CreateBucket("bucket", "private")
driver.CreateObject("bucket", "object", "", "", buffer) driver.CreateObject("bucket", "object", "", "", buffer)
response, err := http.Get(testServer.URL + "/bucket/object") response, err := http.Get(testServer.URL + "/bucket/object")
@ -181,14 +181,14 @@ func (s *MySuite) TestBucket(c *C) {
Name: "bucket", Name: "bucket",
Created: time.Now(), Created: time.Now(),
} }
typedDriver.On("CreateBucket", "bucket").Return(nil).Once() typedDriver.On("CreateBucket", "bucket", "private").Return(nil).Once()
typedDriver.On("GetBucketMetadata", "bucket").Return(metadata, nil).Twice() typedDriver.On("GetBucketMetadata", "bucket").Return(metadata, nil).Twice()
httpHandler := api.HTTPHandler("", driver) httpHandler := api.HTTPHandler("", driver)
testServer := httptest.NewServer(httpHandler) testServer := httptest.NewServer(httpHandler)
defer testServer.Close() defer testServer.Close()
driver.CreateBucket("bucket") driver.CreateBucket("bucket", "private")
response, err := http.Head(testServer.URL + "/bucket") response, err := http.Head(testServer.URL + "/bucket")
c.Assert(err, IsNil) c.Assert(err, IsNil)
@ -212,7 +212,7 @@ func (s *MySuite) TestObject(c *C) {
Md5: "5eb63bbbe01eeed093cb22bb8f5acdc3", Md5: "5eb63bbbe01eeed093cb22bb8f5acdc3",
Size: 11, Size: 11,
} }
typedDriver.On("CreateBucket", "bucket").Return(nil).Once() typedDriver.On("CreateBucket", "bucket", "private").Return(nil).Once()
typedDriver.On("CreateObject", "bucket", "object", "", "", mock.Anything).Return(nil).Once() typedDriver.On("CreateObject", "bucket", "object", "", "", mock.Anything).Return(nil).Once()
typedDriver.On("GetObjectMetadata", "bucket", "object", "").Return(metadata, nil).Twice() typedDriver.On("GetObjectMetadata", "bucket", "object", "").Return(metadata, nil).Twice()
typedDriver.SetGetObjectWriter("bucket", "object", []byte("hello world")) typedDriver.SetGetObjectWriter("bucket", "object", []byte("hello world"))
@ -223,7 +223,7 @@ func (s *MySuite) TestObject(c *C) {
defer testServer.Close() defer testServer.Close()
buffer := bytes.NewBufferString("hello world") buffer := bytes.NewBufferString("hello world")
driver.CreateBucket("bucket") driver.CreateBucket("bucket", "private")
driver.CreateObject("bucket", "object", "", "", buffer) driver.CreateObject("bucket", "object", "", "", buffer)
response, err := http.Get(testServer.URL + "/bucket/object") response, err := http.Get(testServer.URL + "/bucket/object")
@ -280,8 +280,8 @@ func (s *MySuite) TestMultipleObjects(c *C) {
buffer2 := bytes.NewBufferString("hello two") buffer2 := bytes.NewBufferString("hello two")
buffer3 := bytes.NewBufferString("hello three") buffer3 := bytes.NewBufferString("hello three")
typedDriver.On("CreateBucket", "bucket").Return(nil).Once() typedDriver.On("CreateBucket", "bucket", "private").Return(nil).Once()
driver.CreateBucket("bucket") driver.CreateBucket("bucket", "private")
typedDriver.On("CreateObject", "bucket", "object1", "", "", mock.Anything).Return(nil).Once() typedDriver.On("CreateObject", "bucket", "object1", "", "", mock.Anything).Return(nil).Once()
driver.CreateObject("bucket", "object1", "", "", buffer1) driver.CreateObject("bucket", "object1", "", "", buffer1)
typedDriver.On("CreateObject", "bucket", "object2", "", "", mock.Anything).Return(nil).Once() typedDriver.On("CreateObject", "bucket", "object2", "", "", mock.Anything).Return(nil).Once()
@ -397,8 +397,8 @@ func (s *MySuite) TestHeader(c *C) {
testServer := httptest.NewServer(httpHandler) testServer := httptest.NewServer(httpHandler)
defer testServer.Close() defer testServer.Close()
typedDriver.On("CreateBucket", "bucket").Return(nil).Once() typedDriver.On("CreateBucket", "bucket", "private").Return(nil).Once()
driver.CreateBucket("bucket") driver.CreateBucket("bucket", "private")
typedDriver.On("GetObjectMetadata", "bucket", "object", "").Return(drivers.ObjectMetadata{}, drivers.ObjectNotFound{}).Once() typedDriver.On("GetObjectMetadata", "bucket", "object", "").Return(drivers.ObjectMetadata{}, drivers.ObjectNotFound{}).Once()
response, err := http.Get(testServer.URL + "/bucket/object") response, err := http.Get(testServer.URL + "/bucket/object")
@ -450,7 +450,7 @@ func (s *MySuite) TestPutBucket(c *C) {
c.Assert(len(buckets), Equals, 0) c.Assert(len(buckets), Equals, 0)
c.Assert(err, IsNil) c.Assert(err, IsNil)
typedDriver.On("CreateBucket", "bucket").Return(nil).Once() typedDriver.On("CreateBucket", "bucket", "private").Return(nil).Once()
request, err := http.NewRequest("PUT", testServer.URL+"/bucket", bytes.NewBufferString("")) request, err := http.NewRequest("PUT", testServer.URL+"/bucket", bytes.NewBufferString(""))
c.Assert(err, IsNil) c.Assert(err, IsNil)
request.Header.Add("x-amz-acl", "private") request.Header.Add("x-amz-acl", "private")
@ -497,7 +497,7 @@ func (s *MySuite) TestPutObject(c *C) {
date1 := time.Now().Add(-time.Second) date1 := time.Now().Add(-time.Second)
// Put Bucket before - Put Object into a bucket // Put Bucket before - Put Object into a bucket
typedDriver.On("CreateBucket", "bucket").Return(nil).Once() typedDriver.On("CreateBucket", "bucket", "private").Return(nil).Once()
request, err := http.NewRequest("PUT", testServer.URL+"/bucket", bytes.NewBufferString("")) request, err := http.NewRequest("PUT", testServer.URL+"/bucket", bytes.NewBufferString(""))
c.Assert(err, IsNil) c.Assert(err, IsNil)
request.Header.Add("x-amz-acl", "private") request.Header.Add("x-amz-acl", "private")
@ -575,8 +575,9 @@ func (s *MySuite) TestListBuckets(c *C) {
c.Assert(err, IsNil) c.Assert(err, IsNil)
c.Assert(len(listResponse.Buckets.Bucket), Equals, 0) c.Assert(len(listResponse.Buckets.Bucket), Equals, 0)
typedDriver.On("CreateBucket", "foo").Return(nil).Once() typedDriver.On("CreateBucket", "foo", "private").Return(nil).Once()
driver.CreateBucket("foo") err = driver.CreateBucket("foo", "private")
c.Assert(err, IsNil)
bucketMetadata := []drivers.BucketMetadata{ bucketMetadata := []drivers.BucketMetadata{
{Name: "foo", Created: time.Now()}, {Name: "foo", Created: time.Now()},
@ -592,8 +593,9 @@ func (s *MySuite) TestListBuckets(c *C) {
c.Assert(len(listResponse.Buckets.Bucket), Equals, 1) c.Assert(len(listResponse.Buckets.Bucket), Equals, 1)
c.Assert(listResponse.Buckets.Bucket[0].Name, Equals, "foo") c.Assert(listResponse.Buckets.Bucket[0].Name, Equals, "foo")
typedDriver.On("CreateBucket", "bar").Return(nil).Once() typedDriver.On("CreateBucket", "bar", "private").Return(nil).Once()
driver.CreateBucket("bar") err = driver.CreateBucket("bar", "private")
c.Assert(err, IsNil)
bucketMetadata = []drivers.BucketMetadata{ bucketMetadata = []drivers.BucketMetadata{
{Name: "bar", Created: time.Now()}, {Name: "bar", Created: time.Now()},
@ -689,8 +691,8 @@ func (s *MySuite) TestXMLNameNotInBucketListJson(c *C) {
testServer := httptest.NewServer(httpHandler) testServer := httptest.NewServer(httpHandler)
defer testServer.Close() defer testServer.Close()
typedDriver.On("CreateBucket", "foo").Return(nil).Once() typedDriver.On("CreateBucket", "foo", "private").Return(nil).Once()
err := driver.CreateBucket("foo") err := driver.CreateBucket("foo", "private")
c.Assert(err, IsNil) c.Assert(err, IsNil)
typedDriver.On("ListBuckets").Return([]drivers.BucketMetadata{{Name: "foo", Created: time.Now()}}, nil) typedDriver.On("ListBuckets").Return([]drivers.BucketMetadata{{Name: "foo", Created: time.Now()}}, nil)
@ -723,8 +725,8 @@ func (s *MySuite) TestXMLNameNotInObjectListJson(c *C) {
testServer := httptest.NewServer(httpHandler) testServer := httptest.NewServer(httpHandler)
defer testServer.Close() defer testServer.Close()
typedDriver.On("CreateBucket", "foo").Return(nil).Once() typedDriver.On("CreateBucket", "foo", "private").Return(nil).Once()
err := driver.CreateBucket("foo") err := driver.CreateBucket("foo", "private")
c.Assert(err, IsNil) c.Assert(err, IsNil)
typedDriver.On("ListObjects", "foo", mock.Anything).Return([]drivers.ObjectMetadata{}, drivers.BucketResourcesMetadata{}, nil).Once() typedDriver.On("ListObjects", "foo", mock.Anything).Return([]drivers.ObjectMetadata{}, drivers.BucketResourcesMetadata{}, nil).Once()
@ -758,8 +760,8 @@ func (s *MySuite) TestContentTypePersists(c *C) {
testServer := httptest.NewServer(httpHandler) testServer := httptest.NewServer(httpHandler)
defer testServer.Close() defer testServer.Close()
typedDriver.On("CreateBucket", "bucket").Return(nil).Once() typedDriver.On("CreateBucket", "bucket", "private").Return(nil).Once()
err := driver.CreateBucket("bucket") err := driver.CreateBucket("bucket", "private")
c.Assert(err, IsNil) c.Assert(err, IsNil)
client := http.Client{} client := http.Client{}
@ -849,10 +851,11 @@ func (s *MySuite) TestPartialContent(c *C) {
Size: 11, Size: 11,
} }
typedDriver.On("CreateBucket", "foo").Return(nil).Once() typedDriver.On("CreateBucket", "foo", "private").Return(nil).Once()
typedDriver.On("CreateObject", "foo", "bar", "", "", mock.Anything).Return(nil).Once() typedDriver.On("CreateObject", "foo", "bar", "", "", mock.Anything).Return(nil).Once()
driver.CreateBucket("foo") err := driver.CreateBucket("foo", "private")
c.Assert(err, IsNil)
driver.CreateObject("foo", "bar", "", "", bytes.NewBufferString("hello world")) driver.CreateObject("foo", "bar", "", "", bytes.NewBufferString("hello world"))
// prepare for GET on range request // prepare for GET on range request
@ -969,7 +972,7 @@ func (s *MySuite) TestPutBucketErrors(c *C) {
defer testServer.Close() defer testServer.Close()
client := http.Client{} client := http.Client{}
typedDriver.On("CreateBucket", "foo").Return(drivers.BucketNameInvalid{}).Once() typedDriver.On("CreateBucket", "foo", "private").Return(drivers.BucketNameInvalid{}).Once()
request, err := http.NewRequest("PUT", testServer.URL+"/foo", bytes.NewBufferString("")) request, err := http.NewRequest("PUT", testServer.URL+"/foo", bytes.NewBufferString(""))
c.Assert(err, IsNil) c.Assert(err, IsNil)
request.Header.Add("x-amz-acl", "private") request.Header.Add("x-amz-acl", "private")
@ -978,7 +981,7 @@ func (s *MySuite) TestPutBucketErrors(c *C) {
c.Assert(err, IsNil) c.Assert(err, IsNil)
verifyError(c, response, "InvalidBucketName", "The specified bucket is not valid.", http.StatusBadRequest) verifyError(c, response, "InvalidBucketName", "The specified bucket is not valid.", http.StatusBadRequest)
typedDriver.On("CreateBucket", "foo").Return(drivers.BucketExists{}).Once() typedDriver.On("CreateBucket", "foo", "private").Return(drivers.BucketExists{}).Once()
request, err = http.NewRequest("PUT", testServer.URL+"/foo", bytes.NewBufferString("")) request, err = http.NewRequest("PUT", testServer.URL+"/foo", bytes.NewBufferString(""))
c.Assert(err, IsNil) c.Assert(err, IsNil)
request.Header.Add("x-amz-acl", "private") request.Header.Add("x-amz-acl", "private")
@ -987,7 +990,7 @@ func (s *MySuite) TestPutBucketErrors(c *C) {
c.Assert(err, IsNil) c.Assert(err, IsNil)
verifyError(c, response, "BucketAlreadyExists", "The requested bucket name is not available.", http.StatusConflict) verifyError(c, response, "BucketAlreadyExists", "The requested bucket name is not available.", http.StatusConflict)
typedDriver.On("CreateBucket", "foo").Return(drivers.BackendCorrupted{}).Once() typedDriver.On("CreateBucket", "foo", "private").Return(drivers.BackendCorrupted{}).Once()
request, err = http.NewRequest("PUT", testServer.URL+"/foo", bytes.NewBufferString("")) request, err = http.NewRequest("PUT", testServer.URL+"/foo", bytes.NewBufferString(""))
c.Assert(err, IsNil) c.Assert(err, IsNil)
request.Header.Add("x-amz-acl", "private") request.Header.Add("x-amz-acl", "private")
@ -996,7 +999,7 @@ func (s *MySuite) TestPutBucketErrors(c *C) {
c.Assert(err, IsNil) c.Assert(err, IsNil)
verifyError(c, response, "InternalError", "We encountered an internal error, please try again.", http.StatusInternalServerError) verifyError(c, response, "InternalError", "We encountered an internal error, please try again.", http.StatusInternalServerError)
typedDriver.On("CreateBucket", "foo").Return(nil).Once() typedDriver.On("CreateBucket", "foo", "unknown").Return(nil).Once()
request, err = http.NewRequest("PUT", testServer.URL+"/foo", bytes.NewBufferString("")) request, err = http.NewRequest("PUT", testServer.URL+"/foo", bytes.NewBufferString(""))
c.Assert(err, IsNil) c.Assert(err, IsNil)
request.Header.Add("x-amz-acl", "unknown") request.Header.Add("x-amz-acl", "unknown")