github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/cmd/postpolicyform_test.go (about)

     1  // Copyright (c) 2015-2021 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package cmd
    19  
    20  import (
    21  	"bytes"
    22  	"encoding/base64"
    23  	"fmt"
    24  	"net/http"
    25  	"strings"
    26  	"testing"
    27  
    28  	minio "github.com/minio/minio-go/v7"
    29  )
    30  
    31  func TestParsePostPolicyForm(t *testing.T) {
    32  	testCases := []struct {
    33  		policy  string
    34  		success bool
    35  	}{
    36  		// missing expiration, will fail.
    37  		{
    38  			policy:  `{"conditions":[["eq","$bucket","asdf"],["eq","$key","hello.txt"]],"conditions":[["eq","$success_action_status","201"],["eq","$Content-Type","plain/text"],["eq","$success_action_status","201"],["eq","$x-amz-algorithm","AWS4-HMAC-SHA256"],["eq","$x-amz-credential","Q3AM3UQ867SPQQA43P2F/20210315/us-east-1/s3/aws4_request"],["eq","$x-amz-date","20210315T091621Z"]]}`,
    39  			success: false,
    40  		},
    41  		// invalid json.
    42  		{
    43  			policy:  `{"conditions":[["eq","$bucket","asdf"],["eq","$key","hello.txt"]],"conditions":[["eq","$success_action_status","201"],["eq","$Content-Type","plain/text"],["eq","$success_action_status","201"],["eq","$x-amz-algorithm","AWS4-HMAC-SHA256"],["eq","$x-amz-credential","Q3AM3UQ867SPQQA43P2F/20210315/us-east-1/s3/aws4_request"],["eq","$x-amz-date","20210315T091621Z"]]`,
    44  			success: false,
    45  		},
    46  		// duplicate 'expiration' reject
    47  		{
    48  			policy: `{"expiration":"2021-03-22T09:16:21.310Z","expiration":"2021-03-22T09:16:21.310Z","conditions":[["eq","$bucket","evil"],["eq","$key","hello.txt"],["eq","$success_action_status","201"],["eq","$Content-Type","plain/text"],["eq","$success_action_status","201"],["eq","$x-amz-algorithm","AWS4-HMAC-SHA256"],["eq","$x-amz-credential","Q3AM3UQ867SPQQA43P2F/20210315/us-east-1/s3/aws4_request"],["eq","$x-amz-date","20210315T091621Z"]]}`,
    49  		},
    50  		// duplicate '$bucket' reject
    51  		{
    52  			policy:  `{"expiration":"2021-03-22T09:16:21.310Z","conditions":[["eq","$bucket","good"],["eq","$key","hello.txt"]],"conditions":[["eq","$bucket","evil"],["eq","$key","hello.txt"],["eq","$success_action_status","201"],["eq","$Content-Type","plain/text"],["eq","$success_action_status","201"],["eq","$x-amz-algorithm","AWS4-HMAC-SHA256"],["eq","$x-amz-credential","Q3AM3UQ867SPQQA43P2F/20210315/us-east-1/s3/aws4_request"],["eq","$x-amz-date","20210315T091621Z"]]}`,
    53  			success: false,
    54  		},
    55  		// duplicate conditions, reject
    56  		{
    57  			policy:  `{"expiration":"2021-03-22T09:16:21.310Z","conditions":[["eq","$bucket","asdf"],["eq","$key","hello.txt"]],"conditions":[["eq","$success_action_status","201"],["eq","$Content-Type","plain/text"],["eq","$success_action_status","201"],["eq","$x-amz-algorithm","AWS4-HMAC-SHA256"],["eq","$x-amz-credential","Q3AM3UQ867SPQQA43P2F/20210315/us-east-1/s3/aws4_request"],["eq","$x-amz-date","20210315T091621Z"]]}`,
    58  			success: false,
    59  		},
    60  		// no duplicates, shall be parsed properly.
    61  		{
    62  			policy:  `{"expiration":"2021-03-27T20:35:28.458Z","conditions":[["eq","$bucket","testbucket"],["eq","$key","wtf.txt"],["eq","$x-amz-date","20210320T203528Z"],["eq","$x-amz-algorithm","AWS4-HMAC-SHA256"],["eq","$x-amz-credential","Q3AM3UQ867SPQQA43P2F/20210320/us-east-1/s3/aws4_request"]]}`,
    63  			success: true,
    64  		},
    65  	}
    66  
    67  	for _, testCase := range testCases {
    68  		testCase := testCase
    69  		t.Run("", func(t *testing.T) {
    70  			_, err := parsePostPolicyForm(strings.NewReader(testCase.policy))
    71  			if testCase.success && err != nil {
    72  				t.Errorf("Expected success but failed with %s", err)
    73  			}
    74  			if !testCase.success && err == nil {
    75  				t.Errorf("Expected failed but succeeded")
    76  			}
    77  		})
    78  	}
    79  }
    80  
    81  // Test Post Policy parsing and checking conditions
    82  func TestPostPolicyForm(t *testing.T) {
    83  	pp := minio.NewPostPolicy()
    84  	pp.SetBucket("testbucket")
    85  	pp.SetContentType("image/jpeg")
    86  	pp.SetUserMetadata("uuid", "14365123651274")
    87  	pp.SetKeyStartsWith("user/user1/filename")
    88  	pp.SetContentLengthRange(1048579, 10485760)
    89  	pp.SetSuccessStatusAction("201")
    90  
    91  	type testCase struct {
    92  		Bucket              string
    93  		Key                 string
    94  		XAmzDate            string
    95  		XAmzAlgorithm       string
    96  		XAmzCredential      string
    97  		XAmzMetaUUID        string
    98  		ContentType         string
    99  		SuccessActionStatus string
   100  		Policy              string
   101  		Expired             bool
   102  		expectedErr         error
   103  	}
   104  
   105  	testCases := []testCase{
   106  		// Everything is fine with this test
   107  		{Bucket: "testbucket", Key: "user/user1/filename/${filename}/myfile.txt", XAmzMetaUUID: "14365123651274", SuccessActionStatus: "201", XAmzCredential: "KVGKMDUQ23TCZXTLTHLP/20160727/us-east-1/s3/aws4_request", XAmzDate: "20160727T000000Z", XAmzAlgorithm: "AWS4-HMAC-SHA256", ContentType: "image/jpeg", expectedErr: nil},
   108  		// Expired policy document
   109  		{Bucket: "testbucket", Key: "user/user1/filename/${filename}/myfile.txt", XAmzMetaUUID: "14365123651274", SuccessActionStatus: "201", XAmzCredential: "KVGKMDUQ23TCZXTLTHLP/20160727/us-east-1/s3/aws4_request", XAmzDate: "20160727T000000Z", XAmzAlgorithm: "AWS4-HMAC-SHA256", ContentType: "image/jpeg", Expired: true, expectedErr: fmt.Errorf("Invalid according to Policy: Policy expired")},
   110  		// Different AMZ date
   111  		{Bucket: "testbucket", Key: "user/user1/filename/${filename}/myfile.txt", XAmzMetaUUID: "14365123651274", XAmzDate: "2017T000000Z", XAmzAlgorithm: "AWS4-HMAC-SHA256", ContentType: "image/jpeg", expectedErr: fmt.Errorf("Invalid according to Policy: Policy Condition failed")},
   112  		// Key which doesn't start with user/user1/filename
   113  		{Bucket: "testbucket", Key: "myfile.txt", XAmzDate: "20160727T000000Z", XAmzMetaUUID: "14365123651274", XAmzAlgorithm: "AWS4-HMAC-SHA256", ContentType: "image/jpeg", expectedErr: fmt.Errorf("Invalid according to Policy: Policy Condition failed")},
   114  		// Incorrect bucket name.
   115  		{Bucket: "incorrect", Key: "user/user1/filename/myfile.txt", XAmzMetaUUID: "14365123651274", XAmzDate: "20160727T000000Z", XAmzAlgorithm: "AWS4-HMAC-SHA256", ContentType: "image/jpeg", expectedErr: fmt.Errorf("Invalid according to Policy: Policy Condition failed")},
   116  		// Incorrect key name
   117  		{Bucket: "testbucket", Key: "incorrect", XAmzDate: "20160727T000000Z", XAmzMetaUUID: "14365123651274", XAmzAlgorithm: "AWS4-HMAC-SHA256", ContentType: "image/jpeg", expectedErr: fmt.Errorf("Invalid according to Policy: Policy Condition failed")},
   118  		// Incorrect date
   119  		{Bucket: "testbucket", Key: "user/user1/filename/${filename}/myfile.txt", XAmzMetaUUID: "14365123651274", XAmzDate: "incorrect", XAmzAlgorithm: "AWS4-HMAC-SHA256", ContentType: "image/jpeg", expectedErr: fmt.Errorf("Invalid according to Policy: Policy Condition failed")},
   120  		// Incorrect ContentType
   121  		{Bucket: "testbucket", Key: "user/user1/filename/${filename}/myfile.txt", XAmzMetaUUID: "14365123651274", XAmzDate: "20160727T000000Z", XAmzAlgorithm: "AWS4-HMAC-SHA256", ContentType: "incorrect", expectedErr: fmt.Errorf("Invalid according to Policy: Policy Condition failed")},
   122  		// Incorrect Metadata
   123  		{Bucket: "testbucket", Key: "user/user1/filename/${filename}/myfile.txt", XAmzMetaUUID: "151274", SuccessActionStatus: "201", XAmzCredential: "KVGKMDUQ23TCZXTLTHLP/20160727/us-east-1/s3/aws4_request", XAmzDate: "20160727T000000Z", XAmzAlgorithm: "AWS4-HMAC-SHA256", ContentType: "image/jpeg", expectedErr: fmt.Errorf("Invalid according to Policy: Policy Condition failed: [eq, $x-amz-meta-uuid, 14365123651274]")},
   124  	}
   125  	// Validate all the test cases.
   126  	for i, tt := range testCases {
   127  		formValues := make(http.Header)
   128  		formValues.Set("Bucket", tt.Bucket)
   129  		formValues.Set("Key", tt.Key)
   130  		formValues.Set("Content-Type", tt.ContentType)
   131  		formValues.Set("X-Amz-Date", tt.XAmzDate)
   132  		formValues.Set("X-Amz-Meta-Uuid", tt.XAmzMetaUUID)
   133  		formValues.Set("X-Amz-Algorithm", tt.XAmzAlgorithm)
   134  		formValues.Set("X-Amz-Credential", tt.XAmzCredential)
   135  		if tt.Expired {
   136  			// Expired already.
   137  			pp.SetExpires(UTCNow().AddDate(0, 0, -10))
   138  		} else {
   139  			// Expires in 10 days.
   140  			pp.SetExpires(UTCNow().AddDate(0, 0, 10))
   141  		}
   142  
   143  		formValues.Set("Policy", base64.StdEncoding.EncodeToString([]byte(pp.String())))
   144  		formValues.Set("Success_action_status", tt.SuccessActionStatus)
   145  		policyBytes, err := base64.StdEncoding.DecodeString(base64.StdEncoding.EncodeToString([]byte(pp.String())))
   146  		if err != nil {
   147  			t.Fatal(err)
   148  		}
   149  
   150  		postPolicyForm, err := parsePostPolicyForm(bytes.NewReader(policyBytes))
   151  		if err != nil {
   152  			t.Fatal(err)
   153  		}
   154  
   155  		err = checkPostPolicy(formValues, postPolicyForm)
   156  		if err != nil && tt.expectedErr != nil && err.Error() != tt.expectedErr.Error() {
   157  			t.Fatalf("Test %d:, Expected %s, got %s", i+1, tt.expectedErr.Error(), err.Error())
   158  		}
   159  	}
   160  }