web: add handlers for set/get bucket policy. (#2486)

Refer #1858
This commit is contained in:
Bala FA
2016-08-30 22:34:50 +05:30
committed by Harshavardhana
parent 2f9975c76c
commit 7431acb2c4
6 changed files with 904 additions and 4 deletions

View File

@@ -116,9 +116,9 @@ func getOldBucketsConfigPath() (string, error) {
return path.Join(configPath, "buckets"), nil
}
// readBucketPolicy - reads bucket policy for an input bucket, returns BucketPolicyNotFound
// if bucket policy is not found. This function also parses the bucket policy into an object.
func readBucketPolicy(bucket string, objAPI ObjectLayer) (*bucketPolicy, error) {
// readBucketPolicyJSON - reads bucket policy for an input bucket, returns BucketPolicyNotFound
// if bucket policy is not found.
func readBucketPolicyJSON(bucket string, objAPI ObjectLayer) (bucketPolicyReader io.Reader, err error) {
// Verify bucket is valid.
if !IsValidBucketName(bucket) {
return nil, BucketNameInvalid{Bucket: bucket}
@@ -139,9 +139,22 @@ func readBucketPolicy(bucket string, objAPI ObjectLayer) (*bucketPolicy, error)
}
return nil, err
}
return &buffer, nil
}
// readBucketPolicy - reads bucket policy for an input bucket, returns BucketPolicyNotFound
// if bucket policy is not found. This function also parses the bucket policy into an object.
func readBucketPolicy(bucket string, objAPI ObjectLayer) (*bucketPolicy, error) {
// Read bucket policy JSON.
bucketPolicyReader, err := readBucketPolicyJSON(bucket, objAPI)
if err != nil {
return nil, err
}
// Parse the saved policy.
var policy = &bucketPolicy{}
err = parseBucketPolicy(&buffer, policy)
err = parseBucketPolicy(bucketPolicyReader, policy)
if err != nil {
return nil, err

View File

@@ -17,7 +17,10 @@
package cmd
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"path"
@@ -30,6 +33,7 @@ import (
"github.com/dustin/go-humanize"
"github.com/gorilla/mux"
"github.com/gorilla/rpc/v2/json2"
"github.com/minio/minio-go/pkg/policy"
"github.com/minio/miniobrowser"
)
@@ -482,3 +486,98 @@ func writeWebErrorResponse(w http.ResponseWriter, err error) {
w.WriteHeader(apiErr.HTTPStatusCode)
w.Write([]byte(apiErr.Description))
}
// GetBucketPolicyArgs - get bucket policy args.
type GetBucketPolicyArgs struct {
BucketName string `json:"bucketName"`
Prefix string `json:"prefix"`
}
// GetBucketPolicyRep - get bucket policy reply.
type GetBucketPolicyRep struct {
UIVersion string `json:"uiVersion"`
Policy policy.BucketPolicy `json:"policy"`
}
func readBucketAccessPolicy(objAPI ObjectLayer, bucketName string) (policy.BucketAccessPolicy, error) {
bucketPolicyReader, err := readBucketPolicyJSON(bucketName, objAPI)
if err != nil {
if _, ok := err.(BucketPolicyNotFound); ok {
return policy.BucketAccessPolicy{}, nil
}
return policy.BucketAccessPolicy{}, err
}
bucketPolicyBuf, err := ioutil.ReadAll(bucketPolicyReader)
if err != nil {
return policy.BucketAccessPolicy{}, err
}
policyInfo := policy.BucketAccessPolicy{}
err = json.Unmarshal(bucketPolicyBuf, &policyInfo)
if err != nil {
return policy.BucketAccessPolicy{}, err
}
return policyInfo, nil
}
// GetBucketPolicy - get bucket policy.
func (web *webAPIHandlers) GetBucketPolicy(r *http.Request, args *GetBucketPolicyArgs, reply *GetBucketPolicyRep) error {
if !isJWTReqAuthenticated(r) {
return &json2.Error{Message: "Unauthorized request"}
}
policyInfo, err := readBucketAccessPolicy(web.ObjectAPI, args.BucketName)
if err != nil {
return &json2.Error{Message: err.Error()}
}
bucketPolicy := policy.GetPolicy(policyInfo.Statements, args.BucketName, args.Prefix)
reply.UIVersion = miniobrowser.UIVersion
reply.Policy = bucketPolicy
return nil
}
// SetBucketPolicyArgs - set bucket policy args.
type SetBucketPolicyArgs struct {
BucketName string `json:"bucketName"`
Prefix string `json:"prefix"`
Policy string `json:"policy"`
}
// SetBucketPolicy - set bucket policy.
func (web *webAPIHandlers) SetBucketPolicy(r *http.Request, args *SetBucketPolicyArgs, reply *WebGenericRep) error {
if !isJWTReqAuthenticated(r) {
return &json2.Error{Message: "Unauthorized request"}
}
bucketPolicy := policy.BucketPolicy(args.Policy)
if !bucketPolicy.IsValidBucketPolicy() {
return &json2.Error{Message: "Invalid policy " + args.Policy}
}
policyInfo, err := readBucketAccessPolicy(web.ObjectAPI, args.BucketName)
if err != nil {
return &json2.Error{Message: err.Error()}
}
policyInfo.Statements = policy.SetPolicy(policyInfo.Statements, bucketPolicy, args.BucketName, args.Prefix)
data, err := json.Marshal(policyInfo)
if err != nil {
return &json2.Error{Message: err.Error()}
}
// TODO: update policy statements according to bucket name, prefix and policy arguments.
if err := writeBucketPolicy(args.BucketName, web.ObjectAPI, bytes.NewReader(data), int64(len(data))); err != nil {
return &json2.Error{Message: err.Error()}
}
reply.UIVersion = miniobrowser.UIVersion
return nil
}

View File

@@ -24,6 +24,8 @@ import (
"net/http/httptest"
"strconv"
"testing"
"github.com/minio/minio-go/pkg/policy"
)
// Authenticate and get JWT token - will be called before every webrpc handler invocation
@@ -711,3 +713,60 @@ func testDownloadWebHandler(obj ObjectLayer, instanceType string, t TestErrHandl
t.Fatalf("The downloaded file is corrupted")
}
}
// Wrapper for calling GetBucketPolicy Handler
func TestWebHandlerGetBucketPolicyHandler(t *testing.T) {
ExecObjectLayerTest(t, testWebGetBucketPolicyHandler)
}
// testWebGetBucketPolicyHandler - Test GetBucketPolicy web handler
func testWebGetBucketPolicyHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
// Register the API end points with XL/FS object layer.
apiRouter := initTestWebRPCEndPoint(obj)
// initialize the server and obtain the credentials and root.
// credentials are necessary to sign the HTTP request.
rootPath, err := newTestConfig("us-east-1")
if err != nil {
t.Fatalf("Init Test config failed")
}
// remove the root folder after the test ends.
defer removeAll(rootPath)
credentials := serverConfig.GetCredential()
authorization, err := getWebRPCToken(apiRouter, credentials.AccessKeyID, credentials.SecretAccessKey)
if err != nil {
t.Fatal("Cannot authenticate")
}
rec := httptest.NewRecorder()
bucketName := getRandomBucketName()
testCases := []struct {
bucketName string
prefix string
expectedResult policy.BucketPolicy
}{
{bucketName, "", policy.BucketPolicyNone},
}
for i, testCase := range testCases {
args := &GetBucketPolicyArgs{BucketName: testCase.bucketName, Prefix: testCase.prefix}
reply := &GetBucketPolicyRep{}
req, err := newTestWebRPCRequest("Web.GetBucketPolicy", authorization, args)
if err != nil {
t.Fatalf("Test %d: Failed to create HTTP request: <ERROR> %v", i+1, err)
}
apiRouter.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("Test %d: Expected the response status to be 200, but instead found `%d`", i+1, rec.Code)
}
if err = getTestWebRPCResponse(rec, &reply); err != nil {
t.Fatalf("Test %d: Should succeed but it didn't, %v", i+1, err)
}
if testCase.expectedResult != reply.Policy {
t.Fatalf("Test %d: expected: %v, got: %v", i+1, testCase.expectedResult, reply.Policy)
}
}
}