storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/web-handlers_test.go (about)

     1  /*
     2   * MinIO Cloud Storage, (C) 2016, 2017, 2018 MinIO, Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package cmd
    18  
    19  import (
    20  	"archive/zip"
    21  	"bytes"
    22  	"context"
    23  	"crypto/md5"
    24  	"encoding/hex"
    25  	"encoding/json"
    26  	"fmt"
    27  	"io"
    28  	"io/ioutil"
    29  	"net/http"
    30  	"net/http/httptest"
    31  	"reflect"
    32  	"strconv"
    33  	"strings"
    34  	"testing"
    35  
    36  	jwtgo "github.com/dgrijalva/jwt-go"
    37  	humanize "github.com/dustin/go-humanize"
    38  
    39  	xjwt "storj.io/minio/cmd/jwt"
    40  	"storj.io/minio/pkg/hash"
    41  )
    42  
    43  // Implement a dummy flush writer.
    44  type flushWriter struct {
    45  	io.Writer
    46  }
    47  
    48  // Flush writer is a dummy writer compatible with http.Flusher and http.ResponseWriter.
    49  func (f *flushWriter) Flush()                            {}
    50  func (f *flushWriter) Write(b []byte) (n int, err error) { return f.Writer.Write(b) }
    51  func (f *flushWriter) Header() http.Header               { return http.Header{} }
    52  func (f *flushWriter) WriteHeader(code int)              {}
    53  
    54  func newFlushWriter(writer io.Writer) http.ResponseWriter {
    55  	return &flushWriter{writer}
    56  }
    57  
    58  // Tests private function writeWebErrorResponse.
    59  func TestWriteWebErrorResponse(t *testing.T) {
    60  	var buffer bytes.Buffer
    61  	testCases := []struct {
    62  		webErr     error
    63  		apiErrCode APIErrorCode
    64  	}{
    65  		// List of various errors and their corresponding API errors.
    66  		{
    67  			webErr:     StorageFull{},
    68  			apiErrCode: ErrStorageFull,
    69  		},
    70  		{
    71  			webErr:     BucketNotFound{},
    72  			apiErrCode: ErrNoSuchBucket,
    73  		},
    74  		{
    75  			webErr:     BucketNameInvalid{},
    76  			apiErrCode: ErrInvalidBucketName,
    77  		},
    78  		{
    79  			webErr:     hash.BadDigest{},
    80  			apiErrCode: ErrBadDigest,
    81  		},
    82  		{
    83  			webErr:     IncompleteBody{},
    84  			apiErrCode: ErrIncompleteBody,
    85  		},
    86  		{
    87  			webErr:     ObjectExistsAsDirectory{},
    88  			apiErrCode: ErrObjectExistsAsDirectory,
    89  		},
    90  		{
    91  			webErr:     ObjectNotFound{},
    92  			apiErrCode: ErrNoSuchKey,
    93  		},
    94  		{
    95  			webErr:     ObjectNameInvalid{},
    96  			apiErrCode: ErrNoSuchKey,
    97  		},
    98  		{
    99  			webErr:     InsufficientWriteQuorum{},
   100  			apiErrCode: ErrWriteQuorum,
   101  		},
   102  		{
   103  			webErr:     InsufficientReadQuorum{},
   104  			apiErrCode: ErrReadQuorum,
   105  		},
   106  		{
   107  			webErr:     NotImplemented{},
   108  			apiErrCode: ErrNotImplemented,
   109  		},
   110  	}
   111  
   112  	// Validate all the test cases.
   113  	for i, testCase := range testCases {
   114  		writeWebErrorResponse(newFlushWriter(&buffer), testCase.webErr)
   115  		desc := GetAPIError(testCase.apiErrCode).Description
   116  		if testCase.apiErrCode == ErrNotImplemented {
   117  			desc = "Functionality not implemented"
   118  		}
   119  		recvDesc := buffer.Bytes()
   120  		// Check if the written desc is same as the one expected.
   121  		if !bytes.Equal(recvDesc, []byte(desc)) {
   122  			t.Errorf("Test %d: Unexpected response, expecting %s, got %s", i+1, desc, buffer.String())
   123  		}
   124  		buffer.Reset()
   125  	}
   126  }
   127  
   128  // Authenticate and get JWT token - will be called before every webrpc handler invocation
   129  func getWebRPCToken(apiRouter http.Handler, accessKey, secretKey string) (token string, err error) {
   130  	return authenticateWeb(accessKey, secretKey)
   131  }
   132  
   133  // Wrapper for calling Login Web Handler
   134  func TestWebHandlerLogin(t *testing.T) {
   135  	ExecObjectLayerTest(t, testLoginWebHandler)
   136  }
   137  
   138  // testLoginWebHandler - Test login web handler
   139  func testLoginWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
   140  	// Register the API end points with Erasure/FS object layer.
   141  	apiRouter := initTestWebRPCEndPoint(obj)
   142  	credentials := globalActiveCred
   143  
   144  	// test cases with sample input and expected output.
   145  	testCases := []struct {
   146  		username string
   147  		password string
   148  		success  bool
   149  	}{
   150  		{"", "", false},
   151  		{"azerty", "foo", false},
   152  		{"", "foo", false},
   153  		{"azerty", "", false},
   154  		{"azerty", "foo", false},
   155  		{"azerty", "azerty123", false},
   156  		{credentials.AccessKey, credentials.SecretKey, true},
   157  	}
   158  
   159  	// Iterating over the test cases, calling the function under test and asserting the response.
   160  	for i, testCase := range testCases {
   161  		_, err := getWebRPCToken(apiRouter, testCase.username, testCase.password)
   162  		if err != nil && testCase.success {
   163  			t.Fatalf("Test %d: Expected to succeed but it failed, %v", i+1, err)
   164  		}
   165  		if err == nil && !testCase.success {
   166  			t.Fatalf("Test %d: Expected to fail but it didn't, %v", i+1, err)
   167  		}
   168  
   169  	}
   170  }
   171  
   172  // Wrapper for calling StorageInfo Web Handler
   173  func TestWebHandlerStorageInfo(t *testing.T) {
   174  	ExecObjectLayerTest(t, testStorageInfoWebHandler)
   175  }
   176  
   177  // testStorageInfoWebHandler - Test StorageInfo web handler
   178  func testStorageInfoWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
   179  	// get random bucket name.
   180  	// Register the API end points with Erasure/FS object layer.
   181  	apiRouter := initTestWebRPCEndPoint(obj)
   182  	credentials := globalActiveCred
   183  
   184  	authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey)
   185  	if err != nil {
   186  		t.Fatal("Cannot authenticate")
   187  	}
   188  
   189  	rec := httptest.NewRecorder()
   190  
   191  	storageInfoRequest := &WebGenericArgs{}
   192  	storageInfoReply := &StorageInfoRep{}
   193  	req, err := newTestWebRPCRequest("web.StorageInfo", authorization, storageInfoRequest)
   194  	if err != nil {
   195  		t.Fatalf("Failed to create HTTP request: <ERROR> %v", err)
   196  	}
   197  	apiRouter.ServeHTTP(rec, req)
   198  	if rec.Code != http.StatusOK {
   199  		t.Fatalf("Expected the response status to be 200, but instead found `%d`", rec.Code)
   200  	}
   201  	if err = getTestWebRPCResponse(rec, &storageInfoReply); err != nil {
   202  		t.Fatalf("Failed %v", err)
   203  	}
   204  }
   205  
   206  // Wrapper for calling ServerInfo Web Handler
   207  func TestWebHandlerServerInfo(t *testing.T) {
   208  	ExecObjectLayerTest(t, testServerInfoWebHandler)
   209  }
   210  
   211  // testServerInfoWebHandler - Test ServerInfo web handler
   212  func testServerInfoWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
   213  	// Register the API end points with Erasure/FS object layer.
   214  	apiRouter := initTestWebRPCEndPoint(obj)
   215  	credentials := globalActiveCred
   216  
   217  	authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey)
   218  	if err != nil {
   219  		t.Fatal("Cannot authenticate")
   220  	}
   221  
   222  	rec := httptest.NewRecorder()
   223  
   224  	serverInfoRequest := &WebGenericArgs{}
   225  	serverInfoReply := &ServerInfoRep{}
   226  	req, err := newTestWebRPCRequest("web.ServerInfo", authorization, serverInfoRequest)
   227  	if err != nil {
   228  		t.Fatalf("Failed to create HTTP request: <ERROR> %v", err)
   229  	}
   230  	apiRouter.ServeHTTP(rec, req)
   231  	if rec.Code != http.StatusOK {
   232  		t.Fatalf("Expected the response status to be 200, but instead found `%d`", rec.Code)
   233  	}
   234  	err = getTestWebRPCResponse(rec, &serverInfoReply)
   235  	if err != nil {
   236  		t.Fatalf("Failed, %v", err)
   237  	}
   238  	if serverInfoReply.MinioVersion != Version {
   239  		t.Fatalf("Cannot get minio version from server info handler")
   240  	}
   241  	serverInfoReply.MinioGlobalInfo["domains"] = []string(nil)
   242  	globalInfo := getGlobalInfo()
   243  	if !reflect.DeepEqual(serverInfoReply.MinioGlobalInfo, globalInfo) {
   244  		t.Fatalf("Global info did not match got %#v, expected %#v", serverInfoReply.MinioGlobalInfo, globalInfo)
   245  	}
   246  }
   247  
   248  // Wrapper for calling MakeBucket Web Handler
   249  func TestWebHandlerMakeBucket(t *testing.T) {
   250  	ExecObjectLayerTest(t, testMakeBucketWebHandler)
   251  }
   252  
   253  // testMakeBucketWebHandler - Test MakeBucket web handler
   254  func testMakeBucketWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
   255  	// Register the API end points with Erasure/FS object layer.
   256  	apiRouter := initTestWebRPCEndPoint(obj)
   257  	credentials := globalActiveCred
   258  
   259  	authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey)
   260  	if err != nil {
   261  		t.Fatal("Cannot authenticate")
   262  	}
   263  
   264  	rec := httptest.NewRecorder()
   265  
   266  	bucketName := getRandomBucketName()
   267  
   268  	testCases := []struct {
   269  		bucketName string
   270  		success    bool
   271  	}{
   272  		{"", false},
   273  		{".", false},
   274  		{"ab", false},
   275  		{"minio", false},
   276  		{minioMetaBucket, false},
   277  		{bucketName, true},
   278  	}
   279  
   280  	for i, testCase := range testCases {
   281  		makeBucketRequest := MakeBucketArgs{BucketName: testCase.bucketName}
   282  		makeBucketReply := &WebGenericRep{}
   283  		req, err := newTestWebRPCRequest("web.MakeBucket", authorization, makeBucketRequest)
   284  		if err != nil {
   285  			t.Fatalf("Test %d: Failed to create HTTP request: <ERROR> %v", i+1, err)
   286  		}
   287  		apiRouter.ServeHTTP(rec, req)
   288  		if rec.Code != http.StatusOK {
   289  			t.Fatalf("Test %d: Expected the response status to be 200, but instead found `%d`", i+1, rec.Code)
   290  		}
   291  		err = getTestWebRPCResponse(rec, &makeBucketReply)
   292  		if testCase.success && err != nil {
   293  			t.Fatalf("Test %d: Should succeed but it didn't, %v", i+1, err)
   294  		}
   295  		if !testCase.success && err == nil {
   296  			t.Fatalf("Test %d: Should fail but it didn't (%s)", i+1, testCase.bucketName)
   297  		}
   298  	}
   299  }
   300  
   301  // Wrapper for calling DeleteBucket handler
   302  func TestWebHandlerDeleteBucket(t *testing.T) {
   303  	ExecObjectLayerTest(t, testDeleteBucketWebHandler)
   304  }
   305  
   306  // testDeleteBucketWebHandler - Test DeleteBucket web handler
   307  func testDeleteBucketWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
   308  	apiRouter := initTestWebRPCEndPoint(obj)
   309  
   310  	credentials := globalActiveCred
   311  	token, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey)
   312  	if err != nil {
   313  		t.Fatalf("could not get RPC token, %s", err.Error())
   314  	}
   315  
   316  	bucketName := getRandomBucketName()
   317  	var opts ObjectOptions
   318  
   319  	err = obj.MakeBucketWithLocation(context.Background(), bucketName, BucketOptions{})
   320  	if err != nil {
   321  		t.Fatalf("failed to create bucket: %s (%s)", err.Error(), instanceType)
   322  	}
   323  
   324  	testCases := []struct {
   325  		bucketName string
   326  		// Whether or not to put an object into the bucket.
   327  		initWithObject bool
   328  		token          string
   329  		// Expected error (error must only contain this string to pass test)
   330  		// Empty string = no error
   331  		expect string
   332  	}{
   333  		{"", false, token, "Bucket Name  is invalid. Lowercase letters, period, " +
   334  			"hyphen, numerals are the only allowed characters and should be minimum " +
   335  			"3 characters in length."},
   336  		{".", false, "auth", "Authentication failed"},
   337  		{".", false, token, "Bucket Name . is invalid. Lowercase letters, period, " +
   338  			"hyphen, numerals are the only allowed characters and should be minimum " +
   339  			"3 characters in length."},
   340  		{"..", false, token, "Bucket Name .. is invalid. Lowercase letters, period, " +
   341  			"hyphen, numerals are the only allowed characters and should be minimum " +
   342  			"3 characters in length."},
   343  		{"ab", false, token, "Bucket Name ab is invalid. Lowercase letters, period, " +
   344  			"hyphen, numerals are the only allowed characters and should be minimum " +
   345  			"3 characters in length."},
   346  		{"minio", false, "false token", "Authentication failed"},
   347  		{"minio", false, token, "Bucket Name minio is invalid. Lowercase letters, period, " +
   348  			"hyphen, numerals are the only allowed characters and should be minimum " +
   349  			"3 characters in length."},
   350  		{bucketName, false, token, ""},
   351  		{bucketName, true, token, "The bucket you tried to delete is not empty"},
   352  		{bucketName, false, "", "JWT token missing"},
   353  	}
   354  
   355  	for _, test := range testCases {
   356  		if test.initWithObject {
   357  			data := bytes.NewBufferString("hello")
   358  			_, err = obj.PutObject(context.Background(), test.bucketName, "object", mustGetPutObjReader(t, data, int64(data.Len()), "", ""), opts)
   359  			// _, err = obj.PutObject(test.bucketName, "object", int64(data.Len()), data, nil, "")
   360  			if err != nil {
   361  				t.Fatalf("could not put object to %s, %s", test.bucketName, err.Error())
   362  			}
   363  		}
   364  
   365  		rec := httptest.NewRecorder()
   366  
   367  		makeBucketRequest := MakeBucketArgs{BucketName: test.bucketName}
   368  		makeBucketReply := &WebGenericRep{}
   369  
   370  		req, err := newTestWebRPCRequest("web.DeleteBucket", test.token, makeBucketRequest)
   371  		if err != nil {
   372  			t.Errorf("failed to create HTTP request: <ERROR> %v", err)
   373  		}
   374  
   375  		apiRouter.ServeHTTP(rec, req)
   376  		if rec.Code != http.StatusOK {
   377  			t.Errorf("expected the response status to be `%d`, but instead found `%d`", http.StatusOK, rec.Code)
   378  		}
   379  		err = getTestWebRPCResponse(rec, &makeBucketReply)
   380  
   381  		if test.expect != "" {
   382  			if err == nil {
   383  				// If we expected an error, but didn't get one.
   384  				t.Errorf("expected `..%s..` but got nil error", test.expect)
   385  			} else if !strings.Contains(err.Error(), test.expect) {
   386  				// If we got an error that wasn't what we expected.
   387  				t.Errorf("expected `..%s..` but got `%s`", test.expect, err.Error())
   388  			}
   389  		} else if test.expect == "" && err != nil {
   390  			t.Errorf("expected test success, but got `%s`", err.Error())
   391  		}
   392  
   393  		// If we created the bucket with an object, now delete the object to cleanup.
   394  		if test.initWithObject {
   395  			_, err = obj.DeleteObject(context.Background(), test.bucketName, "object", ObjectOptions{})
   396  			if err != nil {
   397  				t.Fatalf("could not delete object, %s", err.Error())
   398  			}
   399  		}
   400  
   401  		// If it did not succeed in deleting the bucket, don't try and recreate it.
   402  		// Or, it'll fail if there was an object.
   403  		if err != nil || test.initWithObject {
   404  			continue
   405  		}
   406  
   407  		err = obj.MakeBucketWithLocation(context.Background(), bucketName, BucketOptions{})
   408  		if err != nil {
   409  			// failed to create new bucket, abort.
   410  			t.Fatalf("failed to create new bucket (%s): %s", instanceType, err.Error())
   411  		}
   412  	}
   413  }
   414  
   415  // Wrapper for calling ListBuckets Web Handler
   416  func TestWebHandlerListBuckets(t *testing.T) {
   417  	ExecObjectLayerTest(t, testListBucketsWebHandler)
   418  }
   419  
   420  // testListBucketsHandler - Test ListBuckets web handler
   421  func testListBucketsWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
   422  	// Register the API end points with Erasure/FS object layer.
   423  	apiRouter := initTestWebRPCEndPoint(obj)
   424  	credentials := globalActiveCred
   425  
   426  	authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey)
   427  	if err != nil {
   428  		t.Fatal("Cannot authenticate")
   429  	}
   430  
   431  	rec := httptest.NewRecorder()
   432  
   433  	bucketName := getRandomBucketName()
   434  	// Create bucket.
   435  	err = obj.MakeBucketWithLocation(context.Background(), bucketName, BucketOptions{})
   436  	if err != nil {
   437  		// failed to create newbucket, abort.
   438  		t.Fatalf("%s : %s", instanceType, err)
   439  	}
   440  
   441  	listBucketsRequest := WebGenericArgs{}
   442  	listBucketsReply := &ListBucketsRep{}
   443  	req, err := newTestWebRPCRequest("web.ListBuckets", authorization, listBucketsRequest)
   444  	if err != nil {
   445  		t.Fatalf("Failed to create HTTP request: <ERROR> %v", err)
   446  	}
   447  	apiRouter.ServeHTTP(rec, req)
   448  	if rec.Code != http.StatusOK {
   449  		t.Fatalf("Expected the response status to be 200, but instead found `%d`", rec.Code)
   450  	}
   451  	err = getTestWebRPCResponse(rec, &listBucketsReply)
   452  	if err != nil {
   453  		t.Fatalf("Failed, %v", err)
   454  	}
   455  	if len(listBucketsReply.Buckets) == 0 {
   456  		t.Fatalf("Cannot find the bucket already created by MakeBucket")
   457  	}
   458  	if listBucketsReply.Buckets[0].Name != bucketName {
   459  		t.Fatalf("Found another bucket %q other than already created by MakeBucket", listBucketsReply.Buckets[0].Name)
   460  	}
   461  }
   462  
   463  // Wrapper for calling ListObjects Web Handler
   464  func TestWebHandlerListObjects(t *testing.T) {
   465  	ExecObjectLayerTest(t, testListObjectsWebHandler)
   466  }
   467  
   468  // testListObjectsHandler - Test ListObjects web handler
   469  func testListObjectsWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
   470  	// Register the API end points with Erasure/FS object layer.
   471  	apiRouter := initTestWebRPCEndPoint(obj)
   472  	credentials := globalActiveCred
   473  
   474  	rec := httptest.NewRecorder()
   475  
   476  	authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey)
   477  	if err != nil {
   478  		t.Fatal("Cannot authenticate")
   479  	}
   480  
   481  	bucketName := getRandomBucketName()
   482  	objectName := "object"
   483  	objectSize := 1 * humanize.KiByte
   484  
   485  	// Create bucket.
   486  	err = obj.MakeBucketWithLocation(context.Background(), bucketName, BucketOptions{})
   487  	if err != nil {
   488  		// failed to create newbucket, abort.
   489  		t.Fatalf("%s : %s", instanceType, err)
   490  	}
   491  
   492  	data := bytes.Repeat([]byte("a"), objectSize)
   493  	metadata := map[string]string{"etag": "c9a34cfc85d982698c6ac89f76071abd"}
   494  	_, err = obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), metadata["etag"], ""), ObjectOptions{UserDefined: metadata})
   495  
   496  	if err != nil {
   497  		t.Fatalf("Was not able to upload an object, %v", err)
   498  	}
   499  
   500  	test := func(token string) (*ListObjectsRep, error) {
   501  		listObjectsRequest := ListObjectsArgs{BucketName: bucketName, Prefix: ""}
   502  		listObjectsReply := &ListObjectsRep{}
   503  		var req *http.Request
   504  		req, err = newTestWebRPCRequest("web.ListObjects", token, listObjectsRequest)
   505  		if err != nil {
   506  			return nil, err
   507  		}
   508  		apiRouter.ServeHTTP(rec, req)
   509  		if rec.Code != http.StatusOK {
   510  			return listObjectsReply, fmt.Errorf("Expected the response status to be 200, but instead found `%d`", rec.Code)
   511  		}
   512  		err = getTestWebRPCResponse(rec, &listObjectsReply)
   513  		if err != nil {
   514  			return listObjectsReply, err
   515  		}
   516  		return listObjectsReply, nil
   517  	}
   518  	verifyReply := func(reply *ListObjectsRep) {
   519  		if len(reply.Objects) == 0 {
   520  			t.Fatalf("Cannot find the object")
   521  		}
   522  		if reply.Objects[0].Key != objectName {
   523  			t.Fatalf("Found another object other than already created by PutObject")
   524  		}
   525  		if reply.Objects[0].Size != int64(objectSize) {
   526  			t.Fatalf("Found a object with the same name but with a different size")
   527  		}
   528  	}
   529  
   530  	// Authenticated ListObjects should succeed.
   531  	reply, err := test(authorization)
   532  	if err != nil {
   533  		t.Fatal(err)
   534  	}
   535  	verifyReply(reply)
   536  
   537  	// Unauthenticated ListObjects should fail.
   538  	_, err = test("")
   539  	if err == nil {
   540  		t.Fatalf("Expected error `%s`", err)
   541  	}
   542  }
   543  
   544  // Wrapper for calling RemoveObject Web Handler
   545  func TestWebHandlerRemoveObject(t *testing.T) {
   546  	ExecObjectLayerTest(t, testRemoveObjectWebHandler)
   547  }
   548  
   549  // testRemoveObjectWebHandler - Test RemoveObjectObject web handler
   550  func testRemoveObjectWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
   551  	// Register the API end points with Erasure/FS object layer.
   552  	apiRouter := initTestWebRPCEndPoint(obj)
   553  	credentials := globalActiveCred
   554  
   555  	rec := httptest.NewRecorder()
   556  	authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey)
   557  	if err != nil {
   558  		t.Fatal("Cannot authenticate")
   559  	}
   560  
   561  	bucketName := getRandomBucketName()
   562  	objectName := "object"
   563  	objectSize := 1 * humanize.KiByte
   564  
   565  	// Create bucket.
   566  	err = obj.MakeBucketWithLocation(context.Background(), bucketName, BucketOptions{})
   567  	if err != nil {
   568  		// failed to create newbucket, abort.
   569  		t.Fatalf("%s : %s", instanceType, err)
   570  	}
   571  
   572  	data := bytes.Repeat([]byte("a"), objectSize)
   573  	metadata := map[string]string{"etag": "c9a34cfc85d982698c6ac89f76071abd"}
   574  	_, err = obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), metadata["etag"], ""), ObjectOptions{UserDefined: metadata})
   575  	if err != nil {
   576  		t.Fatalf("Was not able to upload an object, %v", err)
   577  	}
   578  
   579  	objectName = "a/object"
   580  	metadata = map[string]string{"etag": "c9a34cfc85d982698c6ac89f76071abd"}
   581  	_, err = obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), metadata["etag"], ""), ObjectOptions{UserDefined: metadata})
   582  	if err != nil {
   583  		t.Fatalf("Was not able to upload an object, %v", err)
   584  	}
   585  
   586  	removeRequest := RemoveObjectArgs{BucketName: bucketName, Objects: []string{"a/", "object"}}
   587  	removeReply := &WebGenericRep{}
   588  	req, err := newTestWebRPCRequest("web.RemoveObject", authorization, removeRequest)
   589  	if err != nil {
   590  		t.Fatalf("Failed to create HTTP request: <ERROR> %v", err)
   591  	}
   592  	apiRouter.ServeHTTP(rec, req)
   593  	if rec.Code != http.StatusOK {
   594  		t.Fatalf("Expected the response status to be 200, but instead found `%d`", rec.Code)
   595  	}
   596  	err = getTestWebRPCResponse(rec, &removeReply)
   597  	if err != nil {
   598  		t.Fatalf("Failed, %v", err)
   599  	}
   600  
   601  	removeRequest = RemoveObjectArgs{BucketName: bucketName, Objects: []string{"a/", "object"}}
   602  	removeReply = &WebGenericRep{}
   603  	req, err = newTestWebRPCRequest("web.RemoveObject", authorization, removeRequest)
   604  	if err != nil {
   605  		t.Fatalf("Failed to create HTTP request: <ERROR> %v", err)
   606  	}
   607  	apiRouter.ServeHTTP(rec, req)
   608  	if rec.Code != http.StatusOK {
   609  		t.Fatalf("Expected the response status to be 200, but instead found `%d`", rec.Code)
   610  	}
   611  	err = getTestWebRPCResponse(rec, &removeReply)
   612  	if err != nil {
   613  		t.Fatalf("Failed, %v", err)
   614  	}
   615  
   616  	removeRequest = RemoveObjectArgs{BucketName: bucketName}
   617  	removeReply = &WebGenericRep{}
   618  	req, err = newTestWebRPCRequest("web.RemoveObject", authorization, removeRequest)
   619  	if err != nil {
   620  		t.Fatalf("Failed to create HTTP request: <ERROR> %v", err)
   621  	}
   622  	apiRouter.ServeHTTP(rec, req)
   623  	if rec.Code != http.StatusOK {
   624  		t.Fatalf("Expected the response status to be 200, but instead found `%d`", rec.Code)
   625  	}
   626  	b, err := ioutil.ReadAll(rec.Body)
   627  	if err != nil {
   628  		t.Fatal(err)
   629  	}
   630  	if !bytes.Contains(b, []byte("Invalid arguments specified")) {
   631  		t.Fatalf("Expected response wrong %s", string(b))
   632  	}
   633  }
   634  
   635  func TestWebCreateURLToken(t *testing.T) {
   636  	ExecObjectLayerTest(t, testCreateURLToken)
   637  }
   638  
   639  func getTokenString(accessKey, secretKey string) (string, error) {
   640  	claims := xjwt.NewMapClaims()
   641  	claims.SetExpiry(UTCNow().Add(defaultJWTExpiry))
   642  	claims.SetAccessKey(accessKey)
   643  	token := jwtgo.NewWithClaims(jwtgo.SigningMethodHS512, claims)
   644  	return token.SignedString([]byte(secretKey))
   645  }
   646  
   647  func testCreateURLToken(obj ObjectLayer, instanceType string, t TestErrHandler) {
   648  	apiRouter := initTestWebRPCEndPoint(obj)
   649  	credentials := globalActiveCred
   650  
   651  	authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey)
   652  	if err != nil {
   653  		t.Fatal(err)
   654  	}
   655  
   656  	args := WebGenericArgs{}
   657  	tokenReply := &URLTokenReply{}
   658  
   659  	req, err := newTestWebRPCRequest("web.CreateURLToken", authorization, args)
   660  	if err != nil {
   661  		t.Fatal(err)
   662  	}
   663  
   664  	rec := httptest.NewRecorder()
   665  	apiRouter.ServeHTTP(rec, req)
   666  
   667  	if rec.Code != http.StatusOK {
   668  		t.Fatalf("Expected the response status to be 200, but instead found `%d`", rec.Code)
   669  	}
   670  
   671  	err = getTestWebRPCResponse(rec, &tokenReply)
   672  	if err != nil {
   673  		t.Fatal(err)
   674  	}
   675  
   676  	// Ensure the token is valid now. It will expire later.
   677  	if !isAuthTokenValid(tokenReply.Token) {
   678  		t.Fatalf("token is not valid")
   679  	}
   680  
   681  	// Token is invalid.
   682  	if isAuthTokenValid("") {
   683  		t.Fatalf("token shouldn't be valid, but it is")
   684  	}
   685  
   686  	token, err := getTokenString("invalid-access", credentials.SecretKey)
   687  	if err != nil {
   688  		t.Fatal(err)
   689  	}
   690  
   691  	// Token has invalid access key.
   692  	if isAuthTokenValid(token) {
   693  		t.Fatalf("token shouldn't be valid, but it is")
   694  	}
   695  }
   696  
   697  // Wrapper for calling Upload Handler
   698  func TestWebHandlerUpload(t *testing.T) {
   699  	ExecObjectLayerTest(t, testUploadWebHandler)
   700  }
   701  
   702  // testUploadWebHandler - Test Upload web handler
   703  func testUploadWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
   704  	// Register the API end points with Erasure/FS object layer.
   705  	apiRouter := initTestWebRPCEndPoint(obj)
   706  	credentials := globalActiveCred
   707  
   708  	content := []byte("temporary file's content")
   709  	authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey)
   710  	if err != nil {
   711  		t.Fatal("Cannot authenticate")
   712  	}
   713  
   714  	objectName := "test.file"
   715  	bucketName := getRandomBucketName()
   716  
   717  	test := func(token string, sendContentLength bool) int {
   718  		rec := httptest.NewRecorder()
   719  		req, rErr := http.NewRequest(http.MethodPut, "/minio/upload/"+bucketName+SlashSeparator+objectName, nil)
   720  		if rErr != nil {
   721  			t.Fatalf("Cannot create upload request, %v", rErr)
   722  		}
   723  
   724  		req.Header.Set("x-amz-date", "20160814T114029Z")
   725  		req.Header.Set("Accept", "*/*")
   726  		req.Header.Set("User-Agent", "Mozilla")
   727  
   728  		req.Body = ioutil.NopCloser(bytes.NewReader(content))
   729  
   730  		if !sendContentLength {
   731  			req.ContentLength = -1
   732  		} else {
   733  			req.ContentLength = int64(len(content))
   734  		}
   735  
   736  		if token != "" {
   737  			req.Header.Set("Authorization", "Bearer "+authorization)
   738  		}
   739  		apiRouter.ServeHTTP(rec, req)
   740  		return rec.Code
   741  	}
   742  	// Create bucket.
   743  	err = obj.MakeBucketWithLocation(context.Background(), bucketName, BucketOptions{})
   744  	if err != nil {
   745  		// failed to create newbucket, abort.
   746  		t.Fatalf("%s : %s", instanceType, err)
   747  	}
   748  
   749  	// Authenticated upload should succeed.
   750  	code := test(authorization, true)
   751  	if code != http.StatusOK {
   752  		t.Fatalf("Expected the response status to be 200, but instead found `%d`", code)
   753  	}
   754  
   755  	var byteBuffer bytes.Buffer
   756  	err = GetObject(context.Background(), obj, bucketName, objectName, 0, int64(len(content)), &byteBuffer, "", ObjectOptions{})
   757  	if err != nil {
   758  		t.Fatalf("Failed, %v", err)
   759  	}
   760  
   761  	if !bytes.Equal(byteBuffer.Bytes(), content) {
   762  		t.Fatalf("The upload file is different from the download file")
   763  	}
   764  
   765  	// Authenticated upload without content-length should fail
   766  	code = test(authorization, false)
   767  	if code != http.StatusBadRequest {
   768  		t.Fatalf("Expected the response status to be 200, but instead found `%d`", code)
   769  	}
   770  
   771  	// Unauthenticated upload should fail.
   772  	code = test("", true)
   773  	if code != http.StatusForbidden {
   774  		t.Fatalf("Expected the response status to be 403, but instead found `%d`", code)
   775  	}
   776  
   777  }
   778  
   779  // Wrapper for calling Download Handler
   780  func TestWebHandlerDownload(t *testing.T) {
   781  	ExecObjectLayerTest(t, testDownloadWebHandler)
   782  }
   783  
   784  // testDownloadWebHandler - Test Download web handler
   785  func testDownloadWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
   786  	// Register the API end points with Erasure/FS object layer.
   787  	apiRouter := initTestWebRPCEndPoint(obj)
   788  	credentials := globalActiveCred
   789  
   790  	authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey)
   791  	if err != nil {
   792  		t.Fatal("Cannot authenticate")
   793  	}
   794  
   795  	objectName := "test.file"
   796  	bucketName := getRandomBucketName()
   797  
   798  	test := func(token string) (int, []byte) {
   799  		rec := httptest.NewRecorder()
   800  		path := "/minio/download/" + bucketName + SlashSeparator + objectName + "?token="
   801  		if token != "" {
   802  			path = path + token
   803  		}
   804  		var req *http.Request
   805  		req, err = http.NewRequest(http.MethodGet, path, nil)
   806  
   807  		if err != nil {
   808  			t.Fatalf("Cannot create upload request, %v", err)
   809  		}
   810  
   811  		req.Header.Set("User-Agent", "Mozilla")
   812  
   813  		apiRouter.ServeHTTP(rec, req)
   814  		return rec.Code, rec.Body.Bytes()
   815  	}
   816  
   817  	// Create bucket.
   818  	err = obj.MakeBucketWithLocation(context.Background(), bucketName, BucketOptions{})
   819  	if err != nil {
   820  		// failed to create newbucket, abort.
   821  		t.Fatalf("%s : %s", instanceType, err)
   822  	}
   823  
   824  	content := []byte("temporary file's content")
   825  	metadata := map[string]string{"etag": "01ce59706106fe5e02e7f55fffda7f34"}
   826  	_, err = obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader(content), int64(len(content)), metadata["etag"], ""), ObjectOptions{UserDefined: metadata})
   827  	if err != nil {
   828  		t.Fatalf("Was not able to upload an object, %v", err)
   829  	}
   830  
   831  	// Authenticated download should succeed.
   832  	code, bodyContent := test(authorization)
   833  
   834  	if code != http.StatusOK {
   835  		t.Fatalf("Expected the response status to be 200, but instead found `%d`", code)
   836  	}
   837  
   838  	if !bytes.Equal(bodyContent, content) {
   839  		t.Fatalf("The downloaded file is corrupted")
   840  	}
   841  
   842  	// Temporary token should succeed.
   843  	tmpToken, err := authenticateURL(credentials.AccessKey, credentials.SecretKey)
   844  	if err != nil {
   845  		t.Fatal(err)
   846  	}
   847  
   848  	code, bodyContent = test(tmpToken)
   849  
   850  	if code != http.StatusOK {
   851  		t.Fatalf("Expected the response status to be 200, but instead found `%d`", code)
   852  	}
   853  
   854  	if !bytes.Equal(bodyContent, content) {
   855  		t.Fatalf("The downloaded file is corrupted")
   856  	}
   857  
   858  	// Old token should fail.
   859  	code, bodyContent = test("eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MDAzMzIwOTUsImlhdCI6MTUwMDMzMjAzNSwic3ViIjoiRFlLSU01VlRZNDBJMVZQSE5VMTkifQ.tXQ45GJc8eOFet_a4VWVyeqJEOPWybotQYNr2zVxBpEOICkGbu_YWGhd9TkLLe1E65oeeiLHPdXSN8CzcbPoRA")
   860  	if code != http.StatusForbidden {
   861  		t.Fatalf("Expected the response status to be 403, but instead found `%d`", code)
   862  	}
   863  
   864  	if !bytes.Equal(bodyContent, bytes.NewBufferString("Authentication failed, check your access credentials").Bytes()) {
   865  		t.Fatalf("Expected authentication error message, got %s", string(bodyContent))
   866  	}
   867  
   868  	// Unauthenticated download should fail.
   869  	code, _ = test("")
   870  	if code != http.StatusForbidden {
   871  		t.Fatalf("Expected the response status to be 403, but instead found `%d`", code)
   872  	}
   873  }
   874  
   875  // Test web.DownloadZip
   876  func TestWebHandlerDownloadZip(t *testing.T) {
   877  	ExecObjectLayerTest(t, testWebHandlerDownloadZip)
   878  }
   879  
   880  func testWebHandlerDownloadZip(obj ObjectLayer, instanceType string, t TestErrHandler) {
   881  	apiRouter := initTestWebRPCEndPoint(obj)
   882  	credentials := globalActiveCred
   883  	var opts ObjectOptions
   884  
   885  	authorization, err := authenticateURL(credentials.AccessKey, credentials.SecretKey)
   886  	if err != nil {
   887  		t.Fatal("Cannot authenticate")
   888  	}
   889  
   890  	bucket := getRandomBucketName()
   891  	fileOne := "aaaaaaaaaaaaaa"
   892  	fileTwo := "bbbbbbbbbbbbbb"
   893  	fileThree := "cccccccccccccc"
   894  
   895  	// Create bucket.
   896  	err = obj.MakeBucketWithLocation(context.Background(), bucket, BucketOptions{})
   897  	if err != nil {
   898  		// failed to create newbucket, abort.
   899  		t.Fatalf("%s : %s", instanceType, err)
   900  	}
   901  
   902  	for objName, value := range map[string]string{
   903  		"a/one":     fileOne,
   904  		"a/b/two":   fileTwo,
   905  		"a/c/three": fileThree,
   906  	} {
   907  		_, err = obj.PutObject(context.Background(), bucket, objName, mustGetPutObjReader(t, strings.NewReader(value), int64(len(value)), "", ""), opts)
   908  		if err != nil {
   909  			t.Fatal(err)
   910  		}
   911  	}
   912  
   913  	test := func(token string) (int, []byte) {
   914  		rec := httptest.NewRecorder()
   915  		path := "/minio/zip" + "?token="
   916  		if token != "" {
   917  			path = path + token
   918  		}
   919  		args := DownloadZipArgs{
   920  			Objects:    []string{"one", "b/", "c/"},
   921  			Prefix:     "a/",
   922  			BucketName: bucket,
   923  		}
   924  
   925  		var argsData []byte
   926  		argsData, err = json.Marshal(args)
   927  		if err != nil {
   928  			return 0, nil
   929  		}
   930  		var req *http.Request
   931  		req, err = http.NewRequest(http.MethodPost, path, bytes.NewBuffer(argsData))
   932  
   933  		if err != nil {
   934  			t.Fatalf("Cannot create upload request, %v", err)
   935  		}
   936  
   937  		req.Header.Set("User-Agent", "Mozilla")
   938  
   939  		apiRouter.ServeHTTP(rec, req)
   940  		return rec.Code, rec.Body.Bytes()
   941  	}
   942  	code, _ := test("")
   943  	if code != 403 {
   944  		t.Fatal("Expected to receive authentication error")
   945  	}
   946  	code, data := test(authorization)
   947  	if code != 200 {
   948  		t.Fatal("web.DownloadsZip() failed")
   949  	}
   950  	reader, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
   951  	if err != nil {
   952  		t.Fatal(err)
   953  	}
   954  	h := md5.New()
   955  	for _, file := range reader.File {
   956  		fileReader, err := file.Open()
   957  		if err != nil {
   958  			t.Fatal(err)
   959  		}
   960  		io.Copy(h, fileReader)
   961  	}
   962  	// Verify the md5 of the response.
   963  	if hex.EncodeToString(h.Sum(nil)) != "ac7196449b14bea42775d29e8bb29f50" {
   964  		t.Fatal("Incorrect zip contents")
   965  	}
   966  }
   967  
   968  // Wrapper for calling PresignedGet handler
   969  func TestWebHandlerPresignedGetHandler(t *testing.T) {
   970  	ExecObjectLayerTest(t, testWebPresignedGetHandler)
   971  }
   972  
   973  func testWebPresignedGetHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
   974  	// Register the API end points with Erasure/FS object layer.
   975  	apiRouter := initTestWebRPCEndPoint(obj)
   976  	credentials := globalActiveCred
   977  
   978  	authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey)
   979  	if err != nil {
   980  		t.Fatal("Cannot authenticate")
   981  	}
   982  
   983  	rec := httptest.NewRecorder()
   984  
   985  	bucketName := getRandomBucketName()
   986  	objectName := "object"
   987  	objectSize := 1 * humanize.KiByte
   988  
   989  	// Create bucket.
   990  	err = obj.MakeBucketWithLocation(context.Background(), bucketName, BucketOptions{})
   991  	if err != nil {
   992  		// failed to create newbucket, abort.
   993  		t.Fatalf("%s : %s", instanceType, err)
   994  	}
   995  
   996  	data := bytes.Repeat([]byte("a"), objectSize)
   997  	metadata := map[string]string{"etag": "c9a34cfc85d982698c6ac89f76071abd"}
   998  	_, err = obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), metadata["etag"], ""), ObjectOptions{UserDefined: metadata})
   999  	if err != nil {
  1000  		t.Fatalf("Was not able to upload an object, %v", err)
  1001  	}
  1002  
  1003  	presignGetReq := PresignedGetArgs{
  1004  		HostName:   "",
  1005  		BucketName: bucketName,
  1006  		ObjectName: objectName,
  1007  		Expiry:     1000,
  1008  	}
  1009  	presignGetRep := &PresignedGetRep{}
  1010  	req, err := newTestWebRPCRequest("web.PresignedGet", authorization, presignGetReq)
  1011  	if err != nil {
  1012  		t.Fatalf("Failed to create HTTP request: <ERROR> %v", err)
  1013  	}
  1014  	apiRouter.ServeHTTP(rec, req)
  1015  	if rec.Code != http.StatusOK {
  1016  		t.Fatalf("Expected the response status to be 200, but instead found `%d`", rec.Code)
  1017  	}
  1018  	err = getTestWebRPCResponse(rec, &presignGetRep)
  1019  	if err != nil {
  1020  		t.Fatalf("Failed, %v", err)
  1021  	}
  1022  
  1023  	// Register the API end points with Erasure/FS object layer.
  1024  	apiRouter = initTestAPIEndPoints(obj, []string{"GetObject"})
  1025  
  1026  	// Initialize a new api recorder.
  1027  	arec := httptest.NewRecorder()
  1028  
  1029  	req, err = newTestRequest(http.MethodGet, presignGetRep.URL, 0, nil)
  1030  	req.Header.Del("x-amz-content-sha256")
  1031  	if err != nil {
  1032  		t.Fatal("Failed to initialized a new request", err)
  1033  	}
  1034  	apiRouter.ServeHTTP(arec, req)
  1035  	if arec.Code != http.StatusOK {
  1036  		t.Fatalf("Expected the response status to be 200, but instead found `%d`", arec.Code)
  1037  	}
  1038  	savedData, err := ioutil.ReadAll(arec.Body)
  1039  	if err != nil {
  1040  		t.Fatal("Reading body failed", err)
  1041  	}
  1042  	if !bytes.Equal(data, savedData) {
  1043  		t.Fatal("Read data is not equal was what was expected")
  1044  	}
  1045  
  1046  	// Register the API end points with Erasure/FS object layer.
  1047  	apiRouter = initTestWebRPCEndPoint(obj)
  1048  
  1049  	presignGetReq = PresignedGetArgs{
  1050  		HostName:   "",
  1051  		BucketName: "",
  1052  		ObjectName: "",
  1053  	}
  1054  	presignGetRep = &PresignedGetRep{}
  1055  	req, err = newTestWebRPCRequest("web.PresignedGet", authorization, presignGetReq)
  1056  	if err != nil {
  1057  		t.Fatalf("Failed to create HTTP request: <ERROR> %v", err)
  1058  	}
  1059  	apiRouter.ServeHTTP(rec, req)
  1060  	if rec.Code != http.StatusOK {
  1061  		t.Fatalf("Expected the response status to be 200, but instead found `%d`", rec.Code)
  1062  	}
  1063  	err = getTestWebRPCResponse(rec, &presignGetRep)
  1064  	if err == nil {
  1065  		t.Fatalf("Failed, %v", err)
  1066  	}
  1067  	if err.Error() != "Bucket and Object are mandatory arguments." {
  1068  		t.Fatalf("Unexpected, expected `Bucket and Object are mandatory arguments`, got %s", err)
  1069  	}
  1070  }
  1071  
  1072  // TestWebCheckAuthorization - Test Authorization for all web handlers
  1073  func TestWebCheckAuthorization(t *testing.T) {
  1074  	ctx, cancel := context.WithCancel(context.Background())
  1075  	defer cancel()
  1076  
  1077  	// Prepare Erasure backend
  1078  	obj, fsDirs, err := prepareErasure16(ctx)
  1079  	if err != nil {
  1080  		t.Fatalf("Initialization of object layer failed for Erasure setup: %s", err)
  1081  	}
  1082  	// Executing the object layer tests for Erasure.
  1083  	defer removeRoots(fsDirs)
  1084  
  1085  	// Register the API end points with Erasure/FS object layer.
  1086  	apiRouter := initTestWebRPCEndPoint(obj)
  1087  
  1088  	// initialize the server and obtain the credentials and root.
  1089  	// credentials are necessary to sign the HTTP request.
  1090  	err = newTestConfig(globalMinioDefaultRegion, obj)
  1091  	if err != nil {
  1092  		t.Fatal("Init Test config failed", err)
  1093  	}
  1094  
  1095  	rec := httptest.NewRecorder()
  1096  
  1097  	// Check if web rpc calls return unauthorized request with an incorrect token
  1098  	webRPCs := []string{
  1099  		"ServerInfo", "StorageInfo", "MakeBucket",
  1100  		"ListBuckets", "ListObjects", "RemoveObject",
  1101  		"SetAuth", "GetBucketPolicy", "SetBucketPolicy",
  1102  		"ListAllBucketPolicies", "PresignedGet",
  1103  	}
  1104  	for _, rpcCall := range webRPCs {
  1105  		reply := &WebGenericRep{}
  1106  		req, nerr := newTestWebRPCRequest("web."+rpcCall, "Bearer fooauthorization", &WebGenericArgs{})
  1107  		if nerr != nil {
  1108  			t.Fatalf("Test %s: Failed to create HTTP request: <ERROR> %v", rpcCall, nerr)
  1109  		}
  1110  		apiRouter.ServeHTTP(rec, req)
  1111  		if rec.Code != http.StatusOK {
  1112  			t.Fatalf("Test %s: Expected the response status to be 200, but instead found `%d`", rpcCall, rec.Code)
  1113  		}
  1114  		err = getTestWebRPCResponse(rec, &reply)
  1115  		if err == nil {
  1116  			t.Fatalf("Test %s: Should fail", rpcCall)
  1117  		} else {
  1118  			if !strings.Contains(err.Error(), errAuthentication.Error()) {
  1119  				t.Fatalf("Test %s: should fail with Unauthorized request. Found error: %v", rpcCall, err)
  1120  			}
  1121  		}
  1122  	}
  1123  
  1124  	rec = httptest.NewRecorder()
  1125  	// Test authorization of web.Download
  1126  	req, err := http.NewRequest(http.MethodGet, "/minio/download/bucket/object?token=wrongauth", nil)
  1127  	if err != nil {
  1128  		t.Fatalf("Cannot create upload request, %v", err)
  1129  	}
  1130  	req.Header.Set("User-Agent", "Mozilla")
  1131  	apiRouter.ServeHTTP(rec, req)
  1132  	if rec.Code != http.StatusForbidden {
  1133  		t.Fatalf("Expected the response status to be 403, but instead found `%d`", rec.Code)
  1134  	}
  1135  	resp := rec.Body.String()
  1136  	if !strings.EqualFold(resp, errAuthentication.Error()) {
  1137  		t.Fatalf("Unexpected error message, expected: %s, found: `%s`", errAuthentication, resp)
  1138  	}
  1139  
  1140  	rec = httptest.NewRecorder()
  1141  	// Test authorization of web.Upload
  1142  	content := []byte("temporary file's content")
  1143  	req, err = http.NewRequest(http.MethodPut, "/minio/upload/bucket/object", nil)
  1144  	req.Header.Set("Authorization", "Bearer foo-authorization")
  1145  	req.Header.Set("User-Agent", "Mozilla")
  1146  	req.Header.Set("Content-Length", strconv.Itoa(len(content)))
  1147  	req.Header.Set("x-amz-date", "20160814T114029Z")
  1148  	req.Header.Set("Accept", "*/*")
  1149  	req.Body = ioutil.NopCloser(bytes.NewReader(content))
  1150  	if err != nil {
  1151  		t.Fatalf("Cannot create upload request, %v", err)
  1152  	}
  1153  	apiRouter.ServeHTTP(rec, req)
  1154  	if rec.Code != http.StatusForbidden {
  1155  		t.Fatalf("Expected the response status to be 403, but instead found `%d`", rec.Code)
  1156  	}
  1157  	resp = rec.Body.String()
  1158  	if !strings.EqualFold(resp, errAuthentication.Error()) {
  1159  		t.Fatalf("Unexpected error message, expected: `%s`, found: `%s`", errAuthentication, resp)
  1160  	}
  1161  }
  1162  
  1163  // TestWebObjectLayerFaultyDisks - Test Web RPC responses with faulty disks
  1164  func TestWebObjectLayerFaultyDisks(t *testing.T) {
  1165  	ctx, cancel := context.WithCancel(context.Background())
  1166  	defer cancel()
  1167  
  1168  	// Prepare Erasure backend
  1169  	obj, fsDirs, err := prepareErasure16(ctx)
  1170  	if err != nil {
  1171  		t.Fatalf("Initialization of object layer failed for Erasure setup: %s", err)
  1172  	}
  1173  	// Executing the object layer tests for Erasure.
  1174  	defer removeRoots(fsDirs)
  1175  
  1176  	// initialize the server and obtain the credentials and root.
  1177  	// credentials are necessary to sign the HTTP request.
  1178  	err = newTestConfig(globalMinioDefaultRegion, obj)
  1179  	if err != nil {
  1180  		t.Fatal("Init Test config failed", err)
  1181  	}
  1182  
  1183  	bucketName := "mybucket"
  1184  	err = obj.MakeBucketWithLocation(context.Background(), bucketName, BucketOptions{})
  1185  	if err != nil {
  1186  		t.Fatal("Cannot make bucket:", err)
  1187  	}
  1188  
  1189  	// Set faulty disks to Erasure backend
  1190  	z := obj.(*erasureServerPools)
  1191  	xl := z.serverPools[0].sets[0]
  1192  	erasureDisks := xl.getDisks()
  1193  	z.serverPools[0].erasureDisksMu.Lock()
  1194  	xl.getDisks = func() []StorageAPI {
  1195  		for i, d := range erasureDisks {
  1196  			erasureDisks[i] = newNaughtyDisk(d, nil, errFaultyDisk)
  1197  		}
  1198  		return erasureDisks
  1199  	}
  1200  	z.serverPools[0].erasureDisksMu.Unlock()
  1201  
  1202  	// Initialize web rpc endpoint.
  1203  	apiRouter := initTestWebRPCEndPoint(obj)
  1204  
  1205  	rec := httptest.NewRecorder()
  1206  
  1207  	credentials := globalActiveCred
  1208  	authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey)
  1209  	if err != nil {
  1210  		t.Fatal("Cannot authenticate", err)
  1211  	}
  1212  
  1213  	// Check if web rpc calls return errors with faulty disks.  ServerInfo, GenerateAuth, SetAuth, GetAuth are not concerned
  1214  	// RemoveObject is also not concerned since it always returns success.
  1215  	webRPCs := []struct {
  1216  		webRPCName string
  1217  		ReqArgs    interface{}
  1218  		RepArgs    interface{}
  1219  	}{
  1220  		{"MakeBucket", MakeBucketArgs{BucketName: bucketName}, WebGenericRep{}},
  1221  		{"ListBuckets", WebGenericArgs{}, ListBucketsRep{}},
  1222  		{"ListObjects", ListObjectsArgs{BucketName: bucketName, Prefix: ""}, ListObjectsRep{}},
  1223  		{"GetBucketPolicy", GetBucketPolicyArgs{BucketName: bucketName, Prefix: ""}, GetBucketPolicyRep{}},
  1224  		{"SetBucketPolicy", SetBucketPolicyWebArgs{BucketName: bucketName, Prefix: "", Policy: "none"}, WebGenericRep{}},
  1225  	}
  1226  
  1227  	for _, rpcCall := range webRPCs {
  1228  		args := &rpcCall.ReqArgs
  1229  		reply := &rpcCall.RepArgs
  1230  		req, nerr := newTestWebRPCRequest("web."+rpcCall.webRPCName, authorization, args)
  1231  		if nerr != nil {
  1232  			t.Fatalf("Test %s: Failed to create HTTP request: <ERROR> %v", rpcCall, nerr)
  1233  		}
  1234  		apiRouter.ServeHTTP(rec, req)
  1235  		if rec.Code != http.StatusOK {
  1236  			t.Fatalf("Test %s: Expected the response status to be 200, but instead found `%d`", rpcCall, rec.Code)
  1237  		}
  1238  		err = getTestWebRPCResponse(rec, &reply)
  1239  		if err == nil {
  1240  			t.Errorf("Test %s: Should fail", rpcCall)
  1241  		}
  1242  	}
  1243  
  1244  	// Test web.StorageInfo
  1245  	storageInfoRequest := &WebGenericArgs{}
  1246  	storageInfoReply := &StorageInfoRep{}
  1247  	req, err := newTestWebRPCRequest("web.StorageInfo", authorization, storageInfoRequest)
  1248  	if err != nil {
  1249  		t.Fatalf("Failed to create HTTP request: <ERROR> %v", err)
  1250  	}
  1251  	apiRouter.ServeHTTP(rec, req)
  1252  	if rec.Code != http.StatusOK {
  1253  		t.Fatalf("Expected the response status to be 200, but instead found `%d`", rec.Code)
  1254  	}
  1255  	err = getTestWebRPCResponse(rec, &storageInfoReply)
  1256  	if err != nil {
  1257  		t.Fatalf("Failed %v", err)
  1258  	}
  1259  
  1260  	// Test authorization of web.Download
  1261  	req, err = http.NewRequest(http.MethodGet, "/minio/download/bucket/object?token="+authorization, nil)
  1262  	if err != nil {
  1263  		t.Fatalf("Cannot create upload request, %v", err)
  1264  	}
  1265  	apiRouter.ServeHTTP(rec, req)
  1266  	if rec.Code != http.StatusOK {
  1267  		t.Fatalf("Expected the response status to be 200, but instead found `%d`", rec.Code)
  1268  	}
  1269  
  1270  	// Test authorization of web.Upload
  1271  	content := []byte("temporary file's content")
  1272  	req, err = http.NewRequest(http.MethodPut, "/minio/upload/bucket/object", nil)
  1273  	req.Header.Set("Authorization", "Bearer "+authorization)
  1274  	req.Header.Set("Content-Length", strconv.Itoa(len(content)))
  1275  	req.Header.Set("x-amz-date", "20160814T114029Z")
  1276  	req.Header.Set("Accept", "*/*")
  1277  	req.Body = ioutil.NopCloser(bytes.NewReader(content))
  1278  	if err != nil {
  1279  		t.Fatalf("Cannot create upload request, %v", err)
  1280  	}
  1281  	apiRouter.ServeHTTP(rec, req)
  1282  	if rec.Code != http.StatusOK {
  1283  		t.Fatalf("Expected the response status to be 200, but instead found `%d`", rec.Code)
  1284  	}
  1285  }