Further fixes for ACL support, currently code is disabled in all the handlers

Disabled because due to lack of testing support. Once we get that in we can
uncomment them back.
This commit is contained in:
Harshavardhana 2015-04-22 19:29:39 -07:00
parent 1c0ff2c758
commit 848c4ee31c
8 changed files with 91 additions and 68 deletions

View File

@ -16,10 +16,7 @@
package api package api
import ( import "net/http"
"net/http"
"strings"
)
// Please read for more information - http://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl // Please read for more information - http://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl
// //
@ -41,16 +38,20 @@ const (
// Get acl type requested from 'x-amz-acl' header // Get acl type requested from 'x-amz-acl' header
func getACLType(req *http.Request) ACLType { func getACLType(req *http.Request) ACLType {
aclHeader := req.Header.Get("x-amz-acl") aclHeader := req.Header.Get("x-amz-acl")
if aclHeader != "" {
switch { switch {
case strings.HasPrefix(aclHeader, "private"): case aclHeader == "private":
return privateACLType return privateACLType
case strings.HasPrefix(aclHeader, "public-read"): case aclHeader == "public-read":
return publicReadACLType return publicReadACLType
case strings.HasPrefix(aclHeader, "public-read-write"): case aclHeader == "public-read-write":
return publicReadWriteACLType return publicReadWriteACLType
default: default:
return unsupportedACLType return unsupportedACLType
} }
}
// make it default private
return privateACLType
} }
// ACL type to human readable string // ACL type to human readable string
@ -68,7 +69,11 @@ func getACLTypeString(acl ACLType) string {
{ {
return "public-read-write" return "public-read-write"
} }
default: case unsupportedACLType:
{
return "" return ""
} }
default:
return "private"
}
} }

View File

@ -45,6 +45,15 @@ func (server *minioAPI) listObjectsHandler(w http.ResponseWriter, req *http.Requ
vars := mux.Vars(req) vars := mux.Vars(req)
bucket := vars["bucket"] bucket := vars["bucket"]
// Enable this after tests supports them
// verify for if bucket is private or public
// bucketMetadata, err := server.driver.GetBucketMetadata(bucket)
// if err != nil || (stripAccessKey(req) == "" && bucketMetadata.ACL.IsPrivate()) {
// writeErrorResponse(w, req, AccessDenied, acceptsContentType, req.URL.Path)
// return
// }
objects, resources, err := server.driver.ListObjects(bucket, resources) objects, resources, err := server.driver.ListObjects(bucket, resources)
switch err.(type) { switch err.(type) {
case nil: // success case nil: // success
@ -167,6 +176,15 @@ func (server *minioAPI) headBucketHandler(w http.ResponseWriter, req *http.Reque
vars := mux.Vars(req) vars := mux.Vars(req)
bucket := vars["bucket"] bucket := vars["bucket"]
// Enable this after tests supports them
// verify for if bucket is private or public
// bucketMetadata, err := server.driver.GetBucketMetadata(bucket)
// if err != nil || (stripAccessKey(req) == "" && bucketMetadata.ACL.IsPrivate()) {
// writeErrorResponse(w, req, AccessDenied, acceptsContentType, req.URL.Path)
// return
// }
_, err := server.driver.GetBucketMetadata(bucket) _, err := server.driver.GetBucketMetadata(bucket)
switch err.(type) { switch err.(type) {
case nil: case nil:

View File

@ -20,14 +20,11 @@ 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
} }
@ -50,10 +47,9 @@ 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, driver drivers.Driver, h http.Handler) http.Handler { func validateHandler(conf config.Config, h http.Handler) http.Handler {
return vHandler{ return vHandler{
conf: conf, conf: conf,
driver: driver,
handler: h, handler: h,
} }
} }
@ -66,25 +62,6 @@ func (h vHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
writeErrorResponse(w, r, NotAcceptable, acceptsContentType, r.URL.Path) writeErrorResponse(w, r, NotAcceptable, acceptsContentType, r.URL.Path)
return return
} }
// verify for if bucket is private or public
vars := mux.Vars(r)
bucket, ok := vars["bucket"]
if ok {
bucketMetadata, err := h.driver.GetBucketMetadata(bucket)
if err != nil {
writeErrorResponse(w, r, AccessDenied, acceptsContentType, r.URL.Path)
return
}
if accessKey == "" && bucketMetadata.ACL.IsPrivate() {
writeErrorResponse(w, r, AccessDenied, acceptsContentType, r.URL.Path)
return
}
if r.Method == "PUT" && bucketMetadata.ACL.IsPublicRead() {
writeErrorResponse(w, r, AccessDenied, acceptsContentType, r.URL.Path)
return
}
}
switch true { switch true {
case accessKey != "": case accessKey != "":
if err := h.conf.ReadConfig(); err != nil { if err := h.conf.ReadConfig(); err != nil {

View File

@ -40,6 +40,16 @@ func (server *minioAPI) getObjectHandler(w http.ResponseWriter, req *http.Reques
vars := mux.Vars(req) vars := mux.Vars(req)
bucket = vars["bucket"] bucket = vars["bucket"]
object = vars["object"] object = vars["object"]
// Enable this after tests supports them
// verify for if bucket is private or public
// bucketMetadata, err := server.driver.GetBucketMetadata(bucket)
// if err != nil || (stripAccessKey(req) == "" && bucketMetadata.ACL.IsPrivate()) {
// writeErrorResponse(w, req, AccessDenied, acceptsContentType, req.URL.Path)
// return
// }
metadata, err := server.driver.GetObjectMetadata(bucket, object, "") metadata, err := server.driver.GetObjectMetadata(bucket, object, "")
switch err := err.(type) { switch err := err.(type) {
case nil: // success case nil: // success
@ -51,26 +61,21 @@ func (server *minioAPI) getObjectHandler(w http.ResponseWriter, req *http.Reques
} }
switch httpRange.start == 0 && httpRange.length == 0 { switch httpRange.start == 0 && httpRange.length == 0 {
case true: case true:
{
setObjectHeaders(w, metadata) setObjectHeaders(w, metadata)
if _, err := server.driver.GetObject(w, bucket, object); err != nil { if _, err := server.driver.GetObject(w, bucket, object); err != nil {
// unable to write headers, we've already printed data. Just close the connection. // unable to write headers, we've already printed data. Just close the connection.
log.Error.Println(err) log.Error.Println(err)
} }
}
case false: case false:
{
metadata.Size = httpRange.length metadata.Size = httpRange.length
setRangeObjectHeaders(w, metadata, httpRange) setRangeObjectHeaders(w, metadata, httpRange)
w.WriteHeader(http.StatusPartialContent) w.WriteHeader(http.StatusPartialContent)
_, err := server.driver.GetPartialObject(w, bucket, object, httpRange.start, httpRange.length) if _, err := server.driver.GetPartialObject(w, bucket, object, httpRange.start, httpRange.length); err != nil {
if err != nil {
// unable to write headers, we've already printed data. Just close the connection. // unable to write headers, we've already printed data. Just close the connection.
log.Error.Println(iodine.New(err, nil)) log.Error.Println(iodine.New(err, nil))
} }
} }
} }
}
case drivers.ObjectNotFound: case drivers.ObjectNotFound:
{ {
writeErrorResponse(w, req, NoSuchKey, acceptsContentType, req.URL.Path) writeErrorResponse(w, req, NoSuchKey, acceptsContentType, req.URL.Path)
@ -109,6 +114,15 @@ func (server *minioAPI) headObjectHandler(w http.ResponseWriter, req *http.Reque
vars := mux.Vars(req) vars := mux.Vars(req)
bucket = vars["bucket"] bucket = vars["bucket"]
object = vars["object"] object = vars["object"]
// verify for if bucket is private or public
// verify for if bucket is private or public
// bucketMetadata, err := server.driver.GetBucketMetadata(bucket)
// if err != nil || (stripAccessKey(req) == "" && bucketMetadata.ACL.IsPrivate()) {
// writeErrorResponse(w, req, AccessDenied, acceptsContentType, req.URL.Path)
// return
// }
metadata, err := server.driver.GetObjectMetadata(bucket, object, "") metadata, err := server.driver.GetObjectMetadata(bucket, object, "")
switch err := err.(type) { switch err := err.(type) {
case nil: case nil:
@ -146,6 +160,15 @@ func (server *minioAPI) putObjectHandler(w http.ResponseWriter, req *http.Reques
vars := mux.Vars(req) vars := mux.Vars(req)
bucket = vars["bucket"] bucket = vars["bucket"]
object = vars["object"] object = vars["object"]
// verify for if bucket is private or public
// verify for if bucket is private or public
// bucketMetadata, err := server.driver.GetBucketMetadata(bucket)
// if err != nil || (stripAccessKey(req) == "" && bucketMetadata.ACL.IsPrivate()) || bucketMetadtata.ACL.IsPublicRead() {
// writeErrorResponse(w, req, AccessDenied, acceptsContentType, req.URL.Path)
// return
// }
// get Content-MD5 sent by client and verify if valid // get Content-MD5 sent by client and verify if valid
md5 := req.Header.Get("Content-MD5") md5 := req.Header.Get("Content-MD5")
if !isValidMD5(md5) { if !isValidMD5(md5) {

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, api.driver, ignoreResourcesHandler(mux)) return validateHandler(conf, ignoreResourcesHandler(mux))
} }

View File

@ -115,11 +115,11 @@ func (s *MySuite) TestNonExistantObject(c *C) {
} }
} }
driver := s.Driver driver := s.Driver
s.MockDriver.On("GetObjectMetadata", "bucket", "object", "").Return(drivers.ObjectMetadata{}, drivers.BucketNotFound{Bucket: "bucket"}).Once()
httpHandler := api.HTTPHandler("", driver) httpHandler := api.HTTPHandler("", driver)
testServer := httptest.NewServer(httpHandler) testServer := httptest.NewServer(httpHandler)
defer testServer.Close() defer testServer.Close()
s.MockDriver.On("GetObjectMetadata", "bucket", "object", "").Return(drivers.ObjectMetadata{}, drivers.BucketNotFound{Bucket: "bucket"}).Once()
response, err := http.Get(testServer.URL + "/bucket/object") response, err := http.Get(testServer.URL + "/bucket/object")
c.Assert(err, IsNil) c.Assert(err, IsNil)
c.Assert(response.StatusCode, Equals, http.StatusNotFound) c.Assert(response.StatusCode, Equals, http.StatusNotFound)

View File

@ -29,17 +29,18 @@ const (
// Get content type requested from 'Accept' header // Get content type requested from 'Accept' header
func getContentType(req *http.Request) contentType { func getContentType(req *http.Request) contentType {
acceptHeader := req.Header.Get("Accept") acceptHeader := req.Header.Get("Accept")
if acceptHeader != "" {
switch { switch {
case acceptHeader == "application/json": case acceptHeader == "application/json":
return jsonContentType return jsonContentType
case acceptHeader == "application/xml": case acceptHeader == "application/xml":
return xmlContentType return xmlContentType
default: case acceptHeader == "*/*":
return unknownContentType
}
}
return xmlContentType return xmlContentType
case acceptHeader != "":
return unknownContentType
default:
return xmlContentType
}
} }
// Content type to human readable string // Content type to human readable string

View File

@ -177,8 +177,7 @@ var errorCodeResponse = map[int]Error{
}, },
NotAcceptable: { NotAcceptable: {
Code: "NotAcceptable", Code: "NotAcceptable",
Description: `The requested resource is only capable of generating content Description: "The requested resource is only capable of generating content not acceptable according to the Accept headers sent in the request.",
not acceptable according to the Accept headers sent in the request.`,
HTTPStatusCode: http.StatusNotAcceptable, HTTPStatusCode: http.StatusNotAcceptable,
}, },
} }