mirror of
https://github.com/minio/minio.git
synced 2024-12-23 21:55:53 -05:00
Add tests for presigned-get (#2767)
* web-handlers: support for presigned-get json-rpc call for MinioBrowser's "share" feature. * Add tests for presigned-get
This commit is contained in:
parent
ca5ca8332b
commit
1e53316241
@ -27,6 +27,7 @@ import (
|
||||
"path"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
jwtgo "github.com/dgrijalva/jwt-go"
|
||||
@ -669,3 +670,67 @@ func (web *webAPIHandlers) SetBucketPolicy(r *http.Request, args *SetBucketPolic
|
||||
reply.UIVersion = miniobrowser.UIVersion
|
||||
return nil
|
||||
}
|
||||
|
||||
// PresignedGetArgs - presigned-get API args.
|
||||
type PresignedGetArgs struct {
|
||||
// Host header required for signed headers.
|
||||
HostName string `json:"host"`
|
||||
|
||||
// Bucket name of the object to be presigned.
|
||||
BucketName string `json:"bucket"`
|
||||
|
||||
// Object name to be presigned.
|
||||
ObjectName string `json:"object"`
|
||||
}
|
||||
|
||||
// PresignedGetRep - presigned-get URL reply.
|
||||
type PresignedGetRep struct {
|
||||
// Presigned URL of the object.
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
// PresignedGET - returns presigned-Get url.
|
||||
func (web *webAPIHandlers) PresignedGet(r *http.Request, args *PresignedGetArgs, reply *PresignedGetRep) error {
|
||||
if !isJWTReqAuthenticated(r) {
|
||||
return &json2.Error{Message: "Unauthorized request"}
|
||||
}
|
||||
if args.BucketName == "" || args.ObjectName == "" {
|
||||
return &json2.Error{Message: "Required arguments: Host, Bucket, Object"}
|
||||
}
|
||||
reply.URL = presignedGet(args.HostName, args.BucketName, args.ObjectName)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns presigned url for GET method.
|
||||
func presignedGet(host, bucket, object string) string {
|
||||
cred := serverConfig.GetCredential()
|
||||
region := serverConfig.GetRegion()
|
||||
|
||||
accessKey := cred.AccessKeyID
|
||||
secretKey := cred.SecretAccessKey
|
||||
|
||||
date := time.Now().UTC()
|
||||
dateStr := date.Format("20060102T150405Z")
|
||||
credential := fmt.Sprintf("%s/%s", accessKey, getScope(date, region))
|
||||
|
||||
query := strings.Join([]string{
|
||||
"X-Amz-Algorithm=" + signV4Algorithm,
|
||||
"X-Amz-Credential=" + strings.Replace(credential, "/", "%2F", -1),
|
||||
"X-Amz-Date=" + dateStr,
|
||||
"X-Amz-Expires=" + "604800", // Default set to be expire in 7days.
|
||||
"X-Amz-SignedHeaders=host",
|
||||
}, "&")
|
||||
|
||||
path := "/" + path.Join(bucket, object)
|
||||
|
||||
// Headers are empty, since "host" is the only header required to be signed for Presigned URLs.
|
||||
var extractedSignedHeaders http.Header
|
||||
|
||||
canonicalRequest := getCanonicalRequest(extractedSignedHeaders, unsignedPayload, query, path, "GET", host)
|
||||
stringToSign := getStringToSign(canonicalRequest, date, region)
|
||||
signingKey := getSigningKey(secretKey, date, region)
|
||||
signature := getSignature(signingKey, stringToSign)
|
||||
|
||||
// Construct the final presigned URL.
|
||||
return host + path + "?" + query + "&" + "X-Amz-Signature=" + signature
|
||||
}
|
||||
|
@ -717,6 +717,92 @@ func testDownloadWebHandler(obj ObjectLayer, instanceType string, t TestErrHandl
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper for calling PresignedGet handler
|
||||
func TestWebHandlerPresignedGetHandler(t *testing.T) {
|
||||
ExecObjectLayerTest(t, testWebPresignedGetHandler)
|
||||
}
|
||||
|
||||
func testWebPresignedGetHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
||||
// Register the API end points with XL/FS object layer.
|
||||
apiRouter := initTestWebRPCEndPoint(obj)
|
||||
// initialize the server and obtain the credentials and root.
|
||||
// credentials are necessary to sign the HTTP request.
|
||||
rootPath, err := newTestConfig("us-east-1")
|
||||
if err != nil {
|
||||
t.Fatalf("Init Test config failed")
|
||||
}
|
||||
// remove the root folder after the test ends.
|
||||
defer removeAll(rootPath)
|
||||
|
||||
credentials := serverConfig.GetCredential()
|
||||
|
||||
authorization, err := getWebRPCToken(apiRouter, credentials.AccessKeyID, credentials.SecretAccessKey)
|
||||
if err != nil {
|
||||
t.Fatal("Cannot authenticate")
|
||||
}
|
||||
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
bucketName := getRandomBucketName()
|
||||
objectName := "object"
|
||||
objectSize := 1024
|
||||
|
||||
// Create bucket.
|
||||
err = obj.MakeBucket(bucketName)
|
||||
if err != nil {
|
||||
// failed to create newbucket, abort.
|
||||
t.Fatalf("%s : %s", instanceType, err)
|
||||
}
|
||||
|
||||
data := bytes.Repeat([]byte("a"), objectSize)
|
||||
_, err = obj.PutObject(bucketName, objectName, int64(len(data)), bytes.NewReader(data), map[string]string{"md5Sum": "c9a34cfc85d982698c6ac89f76071abd"})
|
||||
if err != nil {
|
||||
t.Fatalf("Was not able to upload an object, %v", err)
|
||||
}
|
||||
|
||||
presignGetReq := PresignedGetArgs{
|
||||
HostName: "",
|
||||
BucketName: bucketName,
|
||||
ObjectName: objectName,
|
||||
}
|
||||
presignGetRep := &PresignedGetRep{}
|
||||
req, err := newTestWebRPCRequest("Web.PresignedGet", authorization, presignGetReq)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create HTTP request: <ERROR> %v", err)
|
||||
}
|
||||
apiRouter.ServeHTTP(rec, req)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("Expected the response status to be 200, but instead found `%d`", rec.Code)
|
||||
}
|
||||
err = getTestWebRPCResponse(rec, &presignGetRep)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed, %v", err)
|
||||
}
|
||||
|
||||
// Register the API end points with XL/FS object layer.
|
||||
apiRouter = initTestAPIEndPoints(obj, []string{"GetObject"})
|
||||
|
||||
// Initialize a new api recorder.
|
||||
arec := httptest.NewRecorder()
|
||||
|
||||
req, err = newTestRequest("GET", presignGetRep.URL, 0, nil)
|
||||
req.Header.Del("x-amz-content-sha256")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to initialized a new request", err)
|
||||
}
|
||||
apiRouter.ServeHTTP(arec, req)
|
||||
if arec.Code != http.StatusOK {
|
||||
t.Fatalf("Expected the response status to be 200, but instead found `%d`", arec.Code)
|
||||
}
|
||||
savedData, err := ioutil.ReadAll(arec.Body)
|
||||
if err != nil {
|
||||
t.Fatal("Reading body failed", err)
|
||||
}
|
||||
if !bytes.Equal(data, savedData) {
|
||||
t.Fatal("Read data is not equal was what was expected")
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper for calling GetBucketPolicy Handler
|
||||
func TestWebHandlerGetBucketPolicyHandler(t *testing.T) {
|
||||
ExecObjectLayerTest(t, testWebGetBucketPolicyHandler)
|
||||
|
Loading…
Reference in New Issue
Block a user