From b1bb3f7016c1ad5ac24f8d3752ffffd3461762cd Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Mon, 1 Mar 2021 23:10:33 -0800 Subject: [PATCH] [feat]: implement GetBucketPolicyStatus API (#11673) additionally also add more APIs in notImplemented list, adjust routing rules appropriately --- cmd/api-response.go | 6 ++++ cmd/api-router.go | 14 +++++---- cmd/bucket-handlers.go | 58 +++++++++++++++++++++++++++++++++++++ cmd/generic-handlers.go | 18 +++++++----- cmd/handler-utils.go | 12 ++++---- pkg/bucket/policy/action.go | 6 ++++ pkg/iam/policy/action.go | 4 +++ 7 files changed, 100 insertions(+), 18 deletions(-) diff --git a/cmd/api-response.go b/cmd/api-response.go index 82864eafe..09a83b50c 100644 --- a/cmd/api-response.go +++ b/cmd/api-response.go @@ -48,6 +48,12 @@ type LocationResponse struct { Location string `xml:",chardata"` } +// PolicyStatus captures information returned by GetBucketPolicyStatusHandler +type PolicyStatus struct { + XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ PolicyStatus" json:"-"` + IsPublic string +} + // ListVersionsResponse - format for list bucket versions response. type ListVersionsResponse struct { XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListVersionsResult" json:"-"` diff --git a/cmd/api-router.go b/cmd/api-router.go index b1628fed1..81f3159e8 100644 --- a/cmd/api-router.go +++ b/cmd/api-router.go @@ -185,6 +185,10 @@ func registerAPIRouter(router *mux.Router) { bucket.Methods(http.MethodDelete).Path("/{object:.+}").HandlerFunc( collectAPIStats("deleteobject", maxClients(httpTraceAll(api.DeleteObjectHandler)))) + // PostRestoreObject + bucket.Methods(http.MethodPost).Path("/{object:.+}").HandlerFunc( + collectAPIStats("restoreobject", maxClients(httpTraceAll(api.PostRestoreObjectHandler)))).Queries("restore", "") + /// Bucket operations // GetBucketLocation bucket.Methods(http.MethodGet).HandlerFunc( @@ -262,9 +266,9 @@ func registerAPIRouter(router *mux.Router) { // ListObjectVersions bucket.Methods(http.MethodGet).HandlerFunc( collectAPIStats("listobjectversions", maxClients(httpTraceAll(api.ListObjectVersionsHandler)))).Queries("versions", "") - // ListObjectsV1 (Legacy) + // GetBucketPolicyStatus bucket.Methods(http.MethodGet).HandlerFunc( - collectAPIStats("listobjectsv1", maxClients(httpTraceAll(api.ListObjectsV1Handler)))) + collectAPIStats("getpolicystatus", maxClients(httpTraceAll(api.GetBucketPolicyStatusHandler)))).Queries("policyStatus", "") // PutBucketLifecycle bucket.Methods(http.MethodPut).HandlerFunc( collectAPIStats("putbucketlifecycle", maxClients(httpTraceAll(api.PutBucketLifecycleHandler)))).Queries("lifecycle", "") @@ -320,9 +324,9 @@ func registerAPIRouter(router *mux.Router) { // DeleteBucket bucket.Methods(http.MethodDelete).HandlerFunc( collectAPIStats("deletebucket", maxClients(httpTraceAll(api.DeleteBucketHandler)))) - // PostRestoreObject - bucket.Methods(http.MethodPost).Path("/{object:.+}").HandlerFunc( - collectAPIStats("restoreobject", maxClients(httpTraceAll(api.PostRestoreObjectHandler)))).Queries("restore", "") + // ListObjectsV1 (Legacy) + bucket.Methods(http.MethodGet).HandlerFunc( + collectAPIStats("listobjectsv1", maxClients(httpTraceAll(api.ListObjectsV1Handler)))) } /// Root operation diff --git a/cmd/bucket-handlers.go b/cmd/bucket-handlers.go index 7ef1948e3..66ef57f40 100644 --- a/cmd/bucket-handlers.go +++ b/cmd/bucket-handlers.go @@ -1030,6 +1030,64 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h } } +// GetBucketPolicyStatusHandler - Retrieves the policy status +// for an MinIO bucket, indicating whether the bucket is public. +func (api objectAPIHandlers) GetBucketPolicyStatusHandler(w http.ResponseWriter, r *http.Request) { + ctx := newContext(r, w, "GetBucketPolicyStatus") + + defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r)) + + vars := mux.Vars(r) + bucket := vars["bucket"] + + objectAPI := api.ObjectAPI() + if objectAPI == nil { + writeErrorResponseHeadersOnly(w, errorCodes.ToAPIErr(ErrServerNotInitialized)) + return + } + + if s3Error := checkRequestAuthType(ctx, r, policy.GetBucketPolicyStatusAction, bucket, ""); s3Error != ErrNone { + writeErrorResponseHeadersOnly(w, errorCodes.ToAPIErr(s3Error)) + return + } + + // Check if bucket exists. + if _, err := objectAPI.GetBucketInfo(ctx, bucket); err != nil { + writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) + return + } + + // Check if anonymous (non-owner) has access to list objects. + readable := globalPolicySys.IsAllowed(policy.Args{ + Action: policy.ListBucketAction, + BucketName: bucket, + ConditionValues: getConditionValues(r, "", "", nil), + IsOwner: false, + }) + + // Check if anonymous (non-owner) has access to upload objects. + writable := globalPolicySys.IsAllowed(policy.Args{ + Action: policy.PutObjectAction, + BucketName: bucket, + ConditionValues: getConditionValues(r, "", "", nil), + IsOwner: false, + }) + + encodedSuccessResponse := encodeResponse(PolicyStatus{ + IsPublic: func() string { + // Silly to have special 'boolean' values yes + // but complying with silly implementation + // https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketPolicyStatus.html + if readable && writable { + return "TRUE" + } + return "FALSE" + }(), + }) + + writeSuccessResponseXML(w, encodedSuccessResponse) +} + // HeadBucketHandler - HEAD Bucket // ---------- // This operation is useful to determine if a bucket exists. diff --git a/cmd/generic-handlers.go b/cmd/generic-handlers.go index e86ec9436..e32bcbeb2 100644 --- a/cmd/generic-handlers.go +++ b/cmd/generic-handlers.go @@ -369,13 +369,17 @@ var supportedDummyBucketAPIs = map[string][]string{ // List of not implemented bucket queries var notImplementedBucketResourceNames = map[string]struct{}{ - "cors": {}, - "metrics": {}, - "website": {}, - "logging": {}, - "inventory": {}, - "accelerate": {}, - "requestPayment": {}, + "cors": {}, + "metrics": {}, + "website": {}, + "logging": {}, + "inventory": {}, + "accelerate": {}, + "requestPayment": {}, + "analytics": {}, + "intelligent-tiering": {}, + "ownershipControls": {}, + "publicAccessBlock": {}, } // Checks requests for not implemented Bucket resources diff --git a/cmd/handler-utils.go b/cmd/handler-utils.go index ef7fbd3fa..aabd8e697 100644 --- a/cmd/handler-utils.go +++ b/cmd/handler-utils.go @@ -471,10 +471,10 @@ func methodNotAllowedHandler(api string) func(w http.ResponseWriter, r *http.Req HTTPStatusCode: http.StatusUpgradeRequired, }, r.URL) default: - desc := fmt.Sprintf("Unknown API request at %s", r.URL.Path) writeErrorResponse(r.Context(), w, APIError{ - Code: "XMinioUnknownAPIRequest", - Description: desc, + Code: "BadRequest", + Description: fmt.Sprintf("An error occurred when parsing the HTTP request %s at '%s'", + r.Method, r.URL.Path), HTTPStatusCode: http.StatusBadRequest, }, r.URL, guessIsBrowserReq(r)) } @@ -524,10 +524,10 @@ func errorResponseHandler(w http.ResponseWriter, r *http.Request) { HTTPStatusCode: http.StatusUpgradeRequired, }, r.URL) default: - desc := fmt.Sprintf("Unknown API request at %s", r.URL.Path) writeErrorResponse(r.Context(), w, APIError{ - Code: "XMinioUnknownAPIRequest", - Description: desc, + Code: "BadRequest", + Description: fmt.Sprintf("An error occurred when parsing the HTTP request %s at '%s'", + r.Method, r.URL.Path), HTTPStatusCode: http.StatusBadRequest, }, r.URL, guessIsBrowserReq(r)) } diff --git a/pkg/bucket/policy/action.go b/pkg/bucket/policy/action.go index 1c8a60559..e7c24d35e 100644 --- a/pkg/bucket/policy/action.go +++ b/pkg/bucket/policy/action.go @@ -68,6 +68,9 @@ const ( // ListBucketAction - ListBucket Rest API action. ListBucketAction = "s3:ListBucket" + // GetBucketPolicyStatusAction - Retrieves the policy status for a bucket. + GetBucketPolicyStatusAction = "s3:GetBucketPolicyStatus" + // ListBucketMultipartUploadsAction - ListMultipartUploads Rest API action. ListBucketMultipartUploadsAction = "s3:ListBucketMultipartUploads" @@ -222,6 +225,7 @@ var supportedActions = map[Action]struct{}{ HeadBucketAction: {}, ListAllMyBucketsAction: {}, ListBucketAction: {}, + GetBucketPolicyStatusAction: {}, ListBucketVersionsAction: {}, ListBucketMultipartUploadsAction: {}, ListenNotificationAction: {}, @@ -315,6 +319,8 @@ var actionConditionKeyMap = map[Action]condition.KeySet{ GetBucketLocationAction: condition.NewKeySet(condition.CommonKeys...), + GetBucketPolicyStatusAction: condition.NewKeySet(condition.CommonKeys...), + GetObjectAction: condition.NewKeySet( append([]condition.Key{ condition.S3XAmzServerSideEncryption, diff --git a/pkg/iam/policy/action.go b/pkg/iam/policy/action.go index 3595ecb86..a7adf7cc1 100644 --- a/pkg/iam/policy/action.go +++ b/pkg/iam/policy/action.go @@ -67,6 +67,9 @@ const ( // ListBucketAction - ListBucket Rest API action. ListBucketAction = "s3:ListBucket" + // GetBucketPolicyStatusAction - Retrieves the policy status for a bucket. + GetBucketPolicyStatusAction = "s3:GetBucketPolicyStatus" + // ListBucketVersionsAction - ListBucketVersions Rest API action. ListBucketVersionsAction = "s3:ListBucketVersions" @@ -197,6 +200,7 @@ var supportedActions = map[Action]struct{}{ HeadBucketAction: {}, ListAllMyBucketsAction: {}, ListBucketAction: {}, + GetBucketPolicyStatusAction: {}, ListBucketVersionsAction: {}, ListBucketMultipartUploadsAction: {}, ListenNotificationAction: {},