From 927a8790523e9df9c793b9cee833ce2898adc3af Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Fri, 7 Oct 2022 21:45:53 -0700 Subject: [PATCH] authenticate the request first for headObject() (#15820) --- cmd/admin-handlers-users_test.go | 13 ++++++ cmd/object-handlers.go | 69 +++++++++++++++++++------------- cmd/sts-handlers_test.go | 1 + 3 files changed, 55 insertions(+), 28 deletions(-) diff --git a/cmd/admin-handlers-users_test.go b/cmd/admin-handlers-users_test.go index 4b66b7b78..97437df28 100644 --- a/cmd/admin-handlers-users_test.go +++ b/cmd/admin-handlers-users_test.go @@ -1231,6 +1231,19 @@ func (c *check) mustGetObject(ctx context.Context, client *minio.Client, bucket, } } +func (c *check) mustHeadObject(ctx context.Context, client *minio.Client, bucket, object string, tagCount int) { + c.Helper() + + oinfo, err := client.StatObject(ctx, bucket, object, minio.StatObjectOptions{}) + if err != nil { + c.Fatalf("user was unable to download the object: %v", err) + } + + if oinfo.UserTagCount != tagCount { + c.Fatalf("expected tagCount: %d, got %d", tagCount, oinfo.UserTagCount) + } +} + func (c *check) mustListObjects(ctx context.Context, client *minio.Client, bucket string) { c.Helper() res := client.ListObjects(ctx, bucket, minio.ListObjectsOptions{}) diff --git a/cmd/object-handlers.go b/cmd/object-handlers.go index be1011e0a..92dd3373a 100644 --- a/cmd/object-handlers.go +++ b/cmd/object-handlers.go @@ -651,6 +651,44 @@ func (api objectAPIHandlers) headObjectHandler(ctx context.Context, objectAPI Ob return } + // Check for auth type to return S3 compatible error. + // type to return the correct error (NoSuchKey vs AccessDenied) + if s3Error := authenticateRequest(ctx, r, policy.GetObjectAction); s3Error != ErrNone { + if getRequestAuthType(r) == authTypeAnonymous { + // As per "Permission" section in + // https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectHEAD.html + // If the object you request does not exist, + // the error Amazon S3 returns depends on + // whether you also have the s3:ListBucket + // permission. + // * If you have the s3:ListBucket permission + // on the bucket, Amazon S3 will return an + // HTTP status code 404 ("no such key") + // error. + // * if you don’t have the s3:ListBucket + // permission, Amazon S3 will return an HTTP + // status code 403 ("access denied") error.` + if globalPolicySys.IsAllowed(policy.Args{ + Action: policy.ListBucketAction, + BucketName: bucket, + ConditionValues: getConditionValues(r, "", "", nil), + IsOwner: false, + }) { + getObjectInfo := objectAPI.GetObjectInfo + if api.CacheAPI() != nil { + getObjectInfo = api.CacheAPI().GetObjectInfo + } + + _, err = getObjectInfo(ctx, bucket, object, opts) + if toAPIError(ctx, err).Code == "NoSuchKey" { + s3Error = ErrNoSuchKey + } + } + } + writeErrorResponseHeadersOnly(w, errorCodes.ToAPIErr(s3Error)) + return + } + // Get request range. var rs *HTTPRangeSpec rangeHeader := r.Header.Get(xhttp.Range) @@ -676,38 +714,13 @@ func (api objectAPIHandlers) headObjectHandler(ctx context.Context, objectAPI Ob } } - if err == nil && objInfo.UserTags != "" { + if objInfo.UserTags != "" { // Set this such that authorization policies can be applied on the object tags. r.Header.Set(xhttp.AmzObjectTagging, objInfo.UserTags) } - if s3Error := checkRequestAuthType(ctx, r, policy.GetObjectAction, bucket, object); s3Error != ErrNone { - if getRequestAuthType(r) == authTypeAnonymous { - // As per "Permission" section in - // https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectHEAD.html - // If the object you request does not exist, - // the error Amazon S3 returns depends on - // whether you also have the s3:ListBucket - // permission. - // * If you have the s3:ListBucket permission - // on the bucket, Amazon S3 will return an - // HTTP status code 404 ("no such key") - // error. - // * if you don’t have the s3:ListBucket - // permission, Amazon S3 will return an HTTP - // status code 403 ("access denied") error.` - if globalPolicySys.IsAllowed(policy.Args{ - Action: policy.ListBucketAction, - BucketName: bucket, - ConditionValues: getConditionValues(r, "", "", nil), - IsOwner: false, - }) { - if toAPIError(ctx, err).Code == "NoSuchKey" { - s3Error = ErrNoSuchKey - } - } - } - writeErrorResponseHeadersOnly(w, errorCodes.ToAPIErr(s3Error)) + if s3Error := authorizeRequest(ctx, r, policy.GetObjectAction); s3Error != ErrNone { + writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Error), r.URL) return } diff --git a/cmd/sts-handlers_test.go b/cmd/sts-handlers_test.go index dd3ad6132..899edc2e6 100644 --- a/cmd/sts-handlers_test.go +++ b/cmd/sts-handlers_test.go @@ -173,6 +173,7 @@ func (s *TestSuiteIAM) TestSTSWithTags(c *check) { // Validate sts creds can access the object c.mustPutObjectWithTags(ctx, uClient, bucket, object) c.mustGetObject(ctx, uClient, bucket, object) + c.mustHeadObject(ctx, uClient, bucket, object, 2) // Validate that the client can remove objects if err = minioClient.RemoveObjectTagging(ctx, bucket, object, minio.RemoveObjectTaggingOptions{}); err != nil {