Repository: minio/minio (language: go)

Issue:
minio inconsistent with Amazon S3
Hello,

I use AWS JavaScript SDK v3 and I've just found that minio behaves differently from Amazon S3 (and two other "S3-like" cloud providers).
See the minimal code sample at "Steps to Reproduce" section.

## Expected Behavior
I expect minio to return `200 OK` in response to `PutObject` command performed using presigned URL. Like any tested S3 cloud provider does.

## Current Behavior
minio responses with `AccessDenied`: `There were headers present in the request which were not signed`.


## Steps to Reproduce (for bugs)
0. Setup node.js environment with `@aws-sdk/client-s3@3.431.0`, `@aws-sdk/s3-request-presigner@3.431.0`, and `node-fetch@2.0`.
1. Try to run the following node.js code with appropriate minio credentials (`node index.js`):
```javascript
const fetch = require('node-fetch');
const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3');
const { getSignedUrl } = require('@aws-sdk/s3-request-presigner');

const minioParams = {
  region: // ...
  endpoint: // ...
    credentials: {
    accessKeyId: // ...
    secretAccessKey: // ...
  },
};

const bucket = "test";
const key = "hello.txt";
const metadata = {
  "Id": "42",
};

async function getUrl(params) {
  const client = new S3Client(params);
  const command = new PutObjectCommand({ Bucket: bucket, Key: key, Metadata: metadata });
  const url = getSignedUrl(client, command, { expiresIn: 3600 });

  return url;
}

async function run(params) {
  const url = await getUrl(params);

  console.log(url);

  const response = await fetch(url, {
    method: "PUT",
    body: "Hello, World!",
  });

  if (response.ok) {
    console.log("Ok");
  } else {
    console.log(response.statusText);

    const body = await response.text();

    console.log(body);
  }
}

run(minioParams);
```
2. See the error.

## Context
I am trying to PUT the object using presigned URL and I also want to provide some metadata for this object.
I am also sure that my minio credentials are correct, since
```javascript
const metadata = {};
```
fixes the issue. Replacing the `params` with the valid credentials of any S3 cloud provided also fixes the issue.

## Regression
Not sure

## Your Environment
* Version used (`minio --version`):
```
minio version RELEASE.2023-10-07T15:07:38Z (commit-id=DEVELOPMENT.GOGET)
Runtime: go1.21.3 linux/amd64
License: GNU AGPLv3 <https://www.gnu.org/licenses/agpl-3.0.html>
Copyright: 2015-0000 MinIO, Inc.
```
* Server setup and configuration: testing virtual machine with single disk.
* Operating System and version (`uname -a`):
```
Linux linux 5.14.21-150400.24.88-default #1 SMP PREEMPT_DYNAMIC Thu Sep 21 12:45:42 UTC 2023 (2cab595) x86_64 x86_64 x86_64 GNU/Linux
```



Discussion / hints:
I will check and get back.

Fix patch:
diff --git a/cmd/signature-v4-utils.go b/cmd/signature-v4-utils.go
index 94e879cca3b8f..b520b23dd0110 100644
--- a/cmd/signature-v4-utils.go
+++ b/cmd/signature-v4-utils.go
@@ -273,15 +273,5 @@ func checkMetaHeaders(signedHeadersMap http.Header, r *http.Request) APIErrorCod
 		}
 	}
 
-	// check values from url, if no http header
-	for k, val := range r.Form {
-		if stringsHasPrefixFold(k, "x-amz-meta-") {
-			if signedHeadersMap.Get(http.CanonicalHeaderKey(k)) == val[0] {
-				continue
-			}
-			return ErrUnsignedHeaders
-		}
-	}
-
 	return ErrNone
 }


Test patch:
diff --git a/cmd/signature-v4-utils_test.go b/cmd/signature-v4-utils_test.go
index b5893cc71461c..be724ec35cd22 100644
--- a/cmd/signature-v4-utils_test.go
+++ b/cmd/signature-v4-utils_test.go
@@ -394,17 +394,4 @@ func TestCheckMetaHeaders(t *testing.T) {
 	if errCode != ErrNone {
 		t.Fatalf("Expected the APIErrorCode to be %d, but got %d", ErrNone, errCode)
 	}
-
-	// Add extra metadata in url values
-	r, err = http.NewRequest(http.MethodPut, "http://play.min.io:9000?x-amz-meta-test=test&x-amz-meta-extension=png&x-amz-meta-name=imagepng&x-amz-meta-clone=fail", nil)
-	if err != nil {
-		t.Fatal("Unable to create http.Request :", err)
-	}
-
-	r.ParseForm()
-	// calling the function being tested.
-	errCode = checkMetaHeaders(signedHeadersMap, r)
-	if errCode != ErrUnsignedHeaders {
-		t.Fatalf("Expected the APIErrorCode to be %d, but got %d", ErrUnsignedHeaders, errCode)
-	}
 }