From aa579bbc20936cb8d7f359bfd78cec3ab3df31c8 Mon Sep 17 00:00:00 2001 From: Bala FA Date: Thu, 22 Sep 2016 23:06:45 -0700 Subject: [PATCH] web: add method to get all policies for given bucket name. (#2756) Refer #1858 --- cmd/web-handlers.go | 34 ++++++++++ cmd/web-handlers_test.go | 67 +++++++++++++++++++ .../minio-go/pkg/policy/bucket-policy.go | 27 ++++++++ vendor/vendor.json | 6 +- 4 files changed, 131 insertions(+), 3 deletions(-) diff --git a/cmd/web-handlers.go b/cmd/web-handlers.go index d6e1a7161..0aed38594 100644 --- a/cmd/web-handlers.go +++ b/cmd/web-handlers.go @@ -582,6 +582,40 @@ func (web *webAPIHandlers) GetBucketPolicy(r *http.Request, args *GetBucketPolic return nil } +// GetAllBucketPolicyArgs - get all bucket policy args. +type GetAllBucketPolicyArgs struct { + BucketName string `json:"bucketName"` +} + +// GetAllBucketPolicyRep - get all bucket policy reply. +type GetAllBucketPolicyRep struct { + UIVersion string `json:"uiVersion"` + Policies map[string]policy.BucketPolicy `json:"policies"` +} + +// GetAllBucketPolicy - get all bucket policy. +func (web *webAPIHandlers) GetAllBucketPolicy(r *http.Request, args *GetAllBucketPolicyArgs, reply *GetAllBucketPolicyRep) error { + if !isJWTReqAuthenticated(r) { + return &json2.Error{Message: "Unauthorized request"} + } + + objectAPI := web.ObjectAPI() + if objectAPI == nil { + return &json2.Error{Message: "Server not initialized"} + } + policyInfo, err := readBucketAccessPolicy(objectAPI, args.BucketName) + if err != nil { + return &json2.Error{Message: err.Error()} + } + + policies := policy.GetPolicies(policyInfo.Statements, args.BucketName) + + reply.UIVersion = miniobrowser.UIVersion + reply.Policies = policies + + return nil +} + // SetBucketPolicyArgs - set bucket policy args. type SetBucketPolicyArgs struct { BucketName string `json:"bucketName"` diff --git a/cmd/web-handlers_test.go b/cmd/web-handlers_test.go index f9e09c137..83189226f 100644 --- a/cmd/web-handlers_test.go +++ b/cmd/web-handlers_test.go @@ -22,6 +22,7 @@ import ( "io/ioutil" "net/http" "net/http/httptest" + "reflect" "strconv" "strings" "testing" @@ -781,6 +782,72 @@ func testWebGetBucketPolicyHandler(obj ObjectLayer, instanceType string, t TestE } } +// Wrapper for calling GetAllBucketPolicy Handler +func TestWebHandlerGetAllBucketPolicyHandler(t *testing.T) { + ExecObjectLayerTest(t, testWebGetAllBucketPolicyHandler) +} + +// testWebGetAllBucketPolicyHandler - Test GetAllBucketPolicy web handler +func testWebGetAllBucketPolicyHandler(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() + if err := obj.MakeBucket(bucketName); err != nil { + t.Fatal("Unexpected error: ", err) + } + + policyDoc := `{"Version":"2012-10-17","Statement":[{"Action":["s3:GetBucketLocation"],"Effect":"Allow","Principal":{"AWS":["*"]},"Resource":["arn:aws:s3:::` + bucketName + `"],"Sid":""},{"Action":["s3:ListBucket"],"Condition":{"StringEquals":{"s3:prefix":["hello"]}},"Effect":"Allow","Principal":{"AWS":["*"]},"Resource":["arn:aws:s3:::` + bucketName + `"],"Sid":""},{"Action":["s3:ListBucketMultipartUploads"],"Effect":"Allow","Principal":{"AWS":["*"]},"Resource":["arn:aws:s3:::` + bucketName + `"],"Sid":""},{"Action":["s3:AbortMultipartUpload","s3:DeleteObject","s3:GetObject","s3:ListMultipartUploadParts","s3:PutObject"],"Effect":"Allow","Principal":{"AWS":["*"]},"Resource":["arn:aws:s3:::` + bucketName + `/hello*"],"Sid":""}]}` + if err := writeBucketPolicy(bucketName, obj, bytes.NewReader([]byte(policyDoc)), int64(len(policyDoc))); err != nil { + t.Fatal("Unexpected error: ", err) + } + + testCaseResult1 := make(map[string]policy.BucketPolicy) + testCaseResult1[bucketName+"/hello*"] = policy.BucketPolicyReadWrite + testCases := []struct { + bucketName string + expectedResult map[string]policy.BucketPolicy + }{ + {bucketName, testCaseResult1}, + } + + for i, testCase := range testCases { + args := &GetAllBucketPolicyArgs{BucketName: testCase.bucketName} + reply := &GetAllBucketPolicyRep{} + req, err := newTestWebRPCRequest("Web.GetAllBucketPolicy", authorization, args) + if err != nil { + t.Fatalf("Test %d: Failed to create HTTP request: %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 !reflect.DeepEqual(testCase.expectedResult, reply.Policies) { + t.Fatalf("Test %d: expected: %v, got: %v", i+1, testCase.expectedResult, reply.Policies) + } + } +} + // Wrapper for calling SetBucketPolicy Handler func TestWebHandlerSetBucketPolicyHandler(t *testing.T) { ExecObjectLayerTest(t, testWebSetBucketPolicyHandler) diff --git a/vendor/github.com/minio/minio-go/pkg/policy/bucket-policy.go b/vendor/github.com/minio/minio-go/pkg/policy/bucket-policy.go index 067f9d63d..f618059cf 100644 --- a/vendor/github.com/minio/minio-go/pkg/policy/bucket-policy.go +++ b/vendor/github.com/minio/minio-go/pkg/policy/bucket-policy.go @@ -563,6 +563,33 @@ func GetPolicy(statements []Statement, bucketName string, prefix string) BucketP return policy } +// GetPolicies returns a map of policies rules of given bucket name, prefix in given statements. +func GetPolicies(statements []Statement, bucketName string) map[string]BucketPolicy { + policyRules := map[string]BucketPolicy{} + objResources := set.NewStringSet() + // Search all resources related to objects policy + for _, s := range statements { + for r := range s.Resources { + if strings.HasPrefix(r, awsResourcePrefix+bucketName+"/") { + objResources.Add(r) + } + } + } + // Pretend that policy resource as an actual object and fetch its policy + for r := range objResources { + // Put trailing * if exists in asterisk + asterisk := "" + if strings.HasSuffix(r, "*") { + r = r[:len(r)-1] + asterisk = "*" + } + objectPath := r[len(awsResourcePrefix+bucketName)+1 : len(r)] + p := GetPolicy(statements, bucketName, objectPath) + policyRules[bucketName+"/"+objectPath+asterisk] = p + } + return policyRules +} + // Returns new statements containing policy of given bucket name and // prefix are appended. func SetPolicy(statements []Statement, policy BucketPolicy, bucketName string, prefix string) []Statement { diff --git a/vendor/vendor.json b/vendor/vendor.json index e83afd795..af2692c44 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -114,10 +114,10 @@ "revisionTime": "2016-02-29T08:42:30-08:00" }, { - "checksumSHA1": "0OZaeJPgMlA2Txn+1yeAIwEpJvM=", + "checksumSHA1": "qTxOBp3GVxCC70ykb7Hxg6UgWwA=", "path": "github.com/minio/minio-go/pkg/policy", - "revision": "a2e27c84cd20b86cd781b76639781d6366235d0c", - "revisionTime": "2016-08-23T00:31:21Z" + "revision": "40505f5d08c721dfe5a6450fbdef3bcd6567aa97", + "revisionTime": "2016-09-04T08:12:15Z" }, { "checksumSHA1": "A8QOw1aWwc+RtjGozY0XeS5varo=",