Skip to content

Commit

Permalink
additional test for negative case, test coverage for policy, remove c…
Browse files Browse the repository at this point in the history
…omment
  • Loading branch information
marktheunissen committed Nov 20, 2024
1 parent 4971ce6 commit 301e5dc
Show file tree
Hide file tree
Showing 3 changed files with 640 additions and 31 deletions.
210 changes: 181 additions & 29 deletions functional_tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -5643,9 +5643,6 @@ func testPresignedPostPolicy() {
"policy": "",
}

// Seed random based on current time.
rand.Seed(time.Now().Unix())

// Instantiate new minio client object
c, err := minio.New(os.Getenv(serverEndpoint),
&minio.Options{
Expand Down Expand Up @@ -5692,32 +5689,6 @@ func testPresignedPostPolicy() {
}

policy := minio.NewPostPolicy()

if err := policy.SetBucket(""); err == nil {
logError(testName, function, args, startTime, "", "SetBucket did not fail for invalid conditions", err)
return
}
if err := policy.SetKey(""); err == nil {
logError(testName, function, args, startTime, "", "SetKey did not fail for invalid conditions", err)
return
}
if err := policy.SetExpires(time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC)); err == nil {
logError(testName, function, args, startTime, "", "SetExpires did not fail for invalid conditions", err)
return
}
if err := policy.SetContentType(""); err == nil {
logError(testName, function, args, startTime, "", "SetContentType did not fail for invalid conditions", err)
return
}
if err := policy.SetContentLengthRange(1024*1024, 1024); err == nil {
logError(testName, function, args, startTime, "", "SetContentLengthRange did not fail for invalid conditions", err)
return
}
if err := policy.SetUserMetadata("", ""); err == nil {
logError(testName, function, args, startTime, "", "SetUserMetadata did not fail for invalid conditions", err)
return
}

policy.SetBucket(bucketName)
policy.SetKey(objectName)
policy.SetExpires(time.Now().UTC().AddDate(0, 0, 10)) // expires in 10 days
Expand Down Expand Up @@ -5865,6 +5836,186 @@ func testPresignedPostPolicy() {
logSuccess(testName, function, args, startTime)
}

// testPresignedPostPolicyWrongFile tests that when we have a policy with a checksum, we cannot POST the wrong file
func testPresignedPostPolicyWrongFile() {
// initialize logging params
startTime := time.Now()
testName := getFuncName()
function := "PresignedPostPolicy(policy)"
args := map[string]interface{}{
"policy": "",
}

// Instantiate new minio client object
c, err := minio.New(os.Getenv(serverEndpoint),
&minio.Options{
Creds: credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
Transport: createHTTPTransport(),
Secure: mustParseBool(os.Getenv(enableHTTPS)),
})
if err != nil {
logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
return
}

// Enable tracing, write to stderr.
// c.TraceOn(os.Stderr)

// Set user agent.
c.SetAppInfo("MinIO-go-FunctionalTest", appVersion)

// Generate a new random bucket name.
bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")

// Make a new bucket in 'us-east-1' (source bucket).
err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
if err != nil {
logError(testName, function, args, startTime, "", "MakeBucket failed", err)
return
}

defer cleanupBucket(bucketName, c)

// Generate 33K of data.
reader := getDataReader("datafile-33-kB")
defer reader.Close()

objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
// Azure requires the key to not start with a number
metadataKey := randString(60, rand.NewSource(time.Now().UnixNano()), "user")
metadataValue := randString(60, rand.NewSource(time.Now().UnixNano()), "")

buf, err := io.ReadAll(reader)
if err != nil {
logError(testName, function, args, startTime, "", "ReadAll failed", err)
return
}

policy := minio.NewPostPolicy()
policy.SetBucket(bucketName)
policy.SetKey(objectName)
policy.SetExpires(time.Now().UTC().AddDate(0, 0, 10)) // expires in 10 days
policy.SetContentType("binary/octet-stream")
policy.SetContentLengthRange(10, 1024*1024)
policy.SetUserMetadata(metadataKey, metadataValue)

// Add CRC32C of the 33kB file that the policy will explicitly allow.
checksum := minio.ChecksumCRC32C.ChecksumBytes(buf)
err = policy.SetChecksum(checksum)
if err != nil {
logError(testName, function, args, startTime, "", "SetChecksum failed", err)
return
}

args["policy"] = policy.String()

presignedPostPolicyURL, formData, err := c.PresignedPostPolicy(context.Background(), policy)
if err != nil {
logError(testName, function, args, startTime, "", "PresignedPostPolicy failed", err)
return
}

// At this stage, we have a policy that allows us to upload datafile-33-kB.
// Test that uploading datafile-10-kB, with a different checksum, fails as expected
filePath := getMintDataDirFilePath("datafile-10-kB")
if filePath == "" {
// Make a temp file with 10 KB data.
file, err := os.CreateTemp(os.TempDir(), "PresignedPostPolicyTest")
if err != nil {
logError(testName, function, args, startTime, "", "TempFile creation failed", err)
return
}
if _, err = io.Copy(file, getDataReader("datafile-10-kB")); err != nil {
logError(testName, function, args, startTime, "", "Copy failed", err)
return
}
if err = file.Close(); err != nil {
logError(testName, function, args, startTime, "", "File Close failed", err)
return
}
filePath = file.Name()
}
fileReader := getDataReader("datafile-10-kB")
defer fileReader.Close()
buf10k, err := io.ReadAll(fileReader)
if err != nil {
logError(testName, function, args, startTime, "", "ReadAll failed", err)
return
}
otherChecksum := minio.ChecksumCRC32C.ChecksumBytes(buf10k)

var formBuf bytes.Buffer
writer := multipart.NewWriter(&formBuf)
for k, v := range formData {
if k == "x-amz-checksum-crc32c" {
v = otherChecksum.Encoded()
}
writer.WriteField(k, v)
}

// Add file to post request
f, err := os.Open(filePath)
defer f.Close()
if err != nil {
logError(testName, function, args, startTime, "", "File open failed", err)
return
}
w, err := writer.CreateFormFile("file", filePath)
if err != nil {
logError(testName, function, args, startTime, "", "CreateFormFile failed", err)
return
}
_, err = io.Copy(w, f)
if err != nil {
logError(testName, function, args, startTime, "", "Copy failed", err)
return
}
writer.Close()

httpClient := &http.Client{
Timeout: 30 * time.Second,
Transport: createHTTPTransport(),
}
args["url"] = presignedPostPolicyURL.String()

req, err := http.NewRequest(http.MethodPost, presignedPostPolicyURL.String(), bytes.NewReader(formBuf.Bytes()))
if err != nil {
logError(testName, function, args, startTime, "", "HTTP request failed", err)
return
}

req.Header.Set("Content-Type", writer.FormDataContentType())

// Make the POST request with the form data.
res, err := httpClient.Do(req)
if err != nil {
logError(testName, function, args, startTime, "", "HTTP request failed", err)
return
}
defer res.Body.Close()
if res.StatusCode != http.StatusForbidden {
logError(testName, function, args, startTime, "", "HTTP request unexpected status", errors.New(res.Status))
return
}

// Read the response body, ensure it has checksum failure message
resBody, err := io.ReadAll(res.Body)
if err != nil {
logError(testName, function, args, startTime, "", "ReadAll failed", err)
return
}

// Normalize the response body, because S3 uses quotes around the policy condition components
// in the error message, MinIO does not.
resBodyStr := strings.ReplaceAll(string(resBody), `"`, "")
if !strings.Contains(resBodyStr, "Policy Condition failed: [eq, $x-amz-checksum-crc32c, aHnJMw==]") {
logError(testName, function, args, startTime, "", "Unexpected response body", errors.New(resBodyStr))
return
}

logSuccess(testName, function, args, startTime)
}

// Tests copy object
func testCopyObject() {
// initialize logging params
Expand Down Expand Up @@ -14977,6 +15128,7 @@ func main() {
testGetObjectReadAtFunctional()
testGetObjectReadAtWhenEOFWasReached()
testPresignedPostPolicy()
testPresignedPostPolicyWrongFile()
testCopyObject()
testComposeObjectErrorCases()
testCompose10KSources()
Expand Down
2 changes: 0 additions & 2 deletions post-policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,8 +326,6 @@ func (p *PostPolicy) SetChecksum(c Checksum) error {
p.formData[amzChecksumAlgo] = c.Type.String()
p.formData[c.Type.Key()] = c.Encoded()

// Needed for S3 compatibility. MinIO ignores the checksum keys in the policy.
// https://github.com/minio/minio/blob/RELEASE.2024-08-29T01-40-52Z/cmd/postpolicyform.go#L60-L65
policyCond := policyCondition{
matchType: "eq",
condition: fmt.Sprintf("$%s", amzChecksumAlgo),
Expand Down
Loading

0 comments on commit 301e5dc

Please sign in to comment.